|
27 | 27 | "get_eigenbasis_eigh", |
28 | 28 | "get_eigenbasis_qr", |
29 | 29 | "get_eigenbasis_svd", |
| 30 | + "permute_eigenbasis_and_exp_avg_sq", |
30 | 31 | ] |
31 | 32 |
|
32 | 33 |
|
@@ -78,47 +79,70 @@ def get_eigenbasis_svd( |
78 | 79 | return updated_eigenbasis_list |
79 | 80 |
|
80 | 81 |
|
81 | | -def get_eigenbasis_qr( |
| 82 | +def permute_eigenbasis_and_exp_avg_sq( |
82 | 83 | kronecker_factor_list: TensorList, |
83 | 84 | eigenbasis_list: TensorList, |
84 | 85 | exp_avg_sq: torch.Tensor, |
| 86 | +) -> tuple[TensorList, torch.Tensor]: |
| 87 | + """Permute each eigenbasis and the matching ``exp_avg_sq`` axis by descending approximate eigenvalues. |
| 88 | +
|
| 89 | + Computes the approximate eigenvalues of each eigenbasis against its kronecker factor (the Rayleigh |
| 90 | + quotients :math:`\\mathrm{diag}(Q^{\\top} K Q)`) and permutes the eigenbasis columns into descending |
| 91 | + order, permuting ``exp_avg_sq`` along the corresponding axis so its per-slot statistics stay |
| 92 | + aligned. Used before :func:`get_eigenbasis_qr`, whose orthogonal iteration is column-order |
| 93 | + sensitive; the eigh path does not need it since it rebuilds the eigenbasis from scratch. |
| 94 | +
|
| 95 | + Args: |
| 96 | + kronecker_factor_list: List of preconditioner matrices (L and R). |
| 97 | + eigenbasis_list: List of current eigenbases (QL and QR). |
| 98 | + exp_avg_sq: Inner Adam second moment tensor, permuted along each kronecker-factor axis to |
| 99 | + match the new descending-eigenvalue column ordering. |
| 100 | +
|
| 101 | + Returns: |
| 102 | + ``(permuted_eigenbasis_list, permuted_exp_avg_sq)``. |
| 103 | + """ |
| 104 | + permuted_eigenbasis_list: TensorList = [] |
| 105 | + for ind, (kronecker_factor, eigenbasis) in enumerate(zip(kronecker_factor_list, eigenbasis_list, strict=True)): |
| 106 | + approx_eigvals = eig_utils.conjugate(kronecker_factor, eigenbasis, diag=True) |
| 107 | + sort_idx = torch.argsort(approx_eigvals, descending=True) |
| 108 | + permuted_eigenbasis_list.append(eigenbasis[:, sort_idx]) |
| 109 | + exp_avg_sq = exp_avg_sq.index_select(ind, sort_idx) |
| 110 | + return permuted_eigenbasis_list, exp_avg_sq |
| 111 | + |
| 112 | + |
| 113 | +def get_eigenbasis_qr( |
| 114 | + kronecker_factor_list: TensorList, |
| 115 | + eigenbasis_list: TensorList, |
85 | 116 | power_iter_steps: int = 1, |
86 | | -) -> tuple[TensorList, TensorList, torch.Tensor]: |
| 117 | +) -> tuple[TensorList, TensorList]: |
87 | 118 | """Updates the eigenbases of the preconditioner using power iteration and QR. |
88 | 119 |
|
89 | | - Each eigenbasis is refined with multiple rounds of power iteration followed by QR decomposition |
90 | | - (orthogonal iteration), then its columns are sorted by descending approximate eigenvalues of the |
91 | | - kronecker factor (the Rayleigh quotients :math:`\\mathrm{diag}(Q^{\\top} K Q)`), so the returned |
92 | | - eigenvalues and eigenbases are in descending order like :func:`get_eigenbasis_eigh`. |
93 | | - ``exp_avg_sq`` is permuted along each kronecker-factor axis by the same sort, so its per-slot |
94 | | - statistics stay aligned with the eigenbasis columns. |
| 120 | + Computes using multiple rounds of power iteration followed by QR decomposition (orthogonal |
| 121 | + iteration). ``eigenbasis_list`` is expected to be already sorted by descending approximate |
| 122 | + eigenvalues (see :func:`permute_eigenbasis_and_exp_avg_sq`). The returned approximate eigenvalues |
| 123 | + (the Rayleigh quotients :math:`\\mathrm{diag}(Q^{\\top} K Q)`) are aligned with the updated |
| 124 | + eigenbasis columns. |
95 | 125 |
|
96 | 126 | Args: |
97 | 127 | kronecker_factor_list: List of preconditioner matrices (L and R). |
98 | 128 | eigenbasis_list: List of current eigenbases (QL and QR). |
99 | | - exp_avg_sq: Inner Adam second moment tensor, permuted along each kronecker-factor axis to |
100 | | - match the sorted eigenbasis columns. |
101 | 129 | power_iter_steps: Number of power iteration steps to perform before QR decomposition. |
102 | 130 | More steps can lead to better convergence but increased computation time. |
103 | 131 |
|
104 | 132 | Returns: |
105 | 133 | Tuple of (list of approximate eigenvalues of each kronecker factor in its updated eigenbasis, |
106 | | - in descending order, updated list of orthonormal eigenbases (QL and QR) with columns ordered to |
107 | | - match, ``exp_avg_sq`` permuted to match). |
| 134 | + updated list of orthonormal eigenbases (QL and QR)). |
108 | 135 | """ |
109 | 136 | updated_eigenbasis_list: TensorList = [] |
110 | 137 | updated_eigvals_list: TensorList = [] |
111 | | - for ind, (kronecker_factor, eigenbasis) in enumerate(zip(kronecker_factor_list, eigenbasis_list, strict=True)): |
| 138 | + for kronecker_factor, eigenbasis in zip(kronecker_factor_list, eigenbasis_list, strict=True): |
112 | 139 | Q = eig_utils.orthogonal_iteration( |
113 | 140 | kronecker_factor=kronecker_factor, |
114 | 141 | eigenbasis=eigenbasis, |
115 | 142 | power_iter_steps=power_iter_steps, |
116 | 143 | ) |
117 | 144 | with utils.fp32_matmul_precision("highest"): |
118 | | - approx_eigvals = eig_utils.conjugate(kronecker_factor, Q, diag=True) |
119 | | - approx_eigvals, sort_idx = torch.sort(approx_eigvals, descending=True) |
120 | | - updated_eigvals_list.append(approx_eigvals) |
121 | | - updated_eigenbasis_list.append(Q[:, sort_idx]) |
122 | | - exp_avg_sq = exp_avg_sq.index_select(ind, sort_idx) |
| 145 | + updated_eigvals_list.append(eig_utils.conjugate(kronecker_factor, Q, diag=True)) |
| 146 | + updated_eigenbasis_list.append(Q) |
123 | 147 |
|
124 | | - return updated_eigvals_list, updated_eigenbasis_list, exp_avg_sq |
| 148 | + return updated_eigvals_list, updated_eigenbasis_list |
0 commit comments