Skip to content

Commit f414c26

Browse files
committed
1D matrix fixing
1 parent f00cfd2 commit f414c26

4 files changed

Lines changed: 35 additions & 11 deletions

File tree

examples/keras_manual_apply.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""
66

77
import keras
8+
import tensorflow as tf
89

910
from neat_optim import NEAT
1011

@@ -14,7 +15,7 @@ def main() -> None:
1415
gradient = keras.ops.array([0.5, -0.25], dtype="float32")
1516
optimizer = NEAT(learning_rate=0.1, alpha=0.25, beta=0.9)
1617
optimizer.apply_gradients([(gradient, variable)])
17-
print(keras.ops.convert_to_numpy(variable))
18+
print(tf.convert_to_tensor(variable).numpy())
1819

1920

2021
if __name__ == "__main__":

src/neat_optim/engine/reference.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,25 @@ def _as_float32(array: np.ndarray) -> np.ndarray:
1111
return np.asarray(array, dtype=np.float32)
1212

1313

14+
def _flat_dot(left: np.ndarray, right: np.ndarray) -> float:
15+
return float(np.dot(left.reshape(-1), right.reshape(-1)))
16+
17+
1418
def _safe_projection(
1519
gradient: np.ndarray, vector: np.ndarray, eps: float
1620
) -> np.ndarray:
17-
denom = float(np.dot(vector, vector))
21+
denom = _flat_dot(vector, vector)
1822
if denom <= eps:
1923
return np.zeros_like(gradient)
20-
return (float(np.dot(gradient, vector)) / (denom + eps)) * vector
24+
return (_flat_dot(gradient, vector) / (denom + eps)) * vector
2125

2226

2327
def _conflict_ratio(gradient: np.ndarray, vector: np.ndarray, eps: float) -> float:
2428
grad_norm = l2_norm(gradient)
2529
vec_norm = l2_norm(vector)
2630
if grad_norm <= eps or vec_norm <= eps:
2731
return 0.0
28-
cosine = float(np.dot(gradient, vector) / ((grad_norm * vec_norm) + eps))
32+
cosine = _flat_dot(gradient, vector) / ((grad_norm * vec_norm) + eps)
2933
return max(0.0, -cosine)
3034

3135

tests/integration/test_keras_optimizer.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
from neat_optim.state import ArrayState # noqa: E402
1111

1212

13+
def _to_numpy(tensor) -> np.ndarray:
14+
return tensorflow.convert_to_tensor(tensor).numpy()
15+
16+
1317
def _run_reference(
1418
initial_param: np.ndarray,
1519
gradients: list[np.ndarray],
@@ -38,7 +42,7 @@ def _run_keras(
3842
optimizer.apply_gradients(
3943
[(keras.ops.array(gradient, dtype="float32"), variable)]
4044
)
41-
return optimizer, keras.ops.convert_to_numpy(variable)
45+
return optimizer, _to_numpy(variable)
4246

4347

4448
def test_keras_optimizer_can_apply_gradients() -> None:
@@ -49,7 +53,7 @@ def test_keras_optimizer_can_apply_gradients() -> None:
4953

5054
optimizer.apply_gradients([(gradient, variable)])
5155

52-
values = keras.ops.convert_to_numpy(variable)
56+
values = _to_numpy(variable)
5357
assert values.shape == (2,)
5458
assert optimizer.variables
5559

@@ -99,12 +103,12 @@ def test_keras_optimizer_matches_reference_projection_mode() -> None:
99103

100104
np.testing.assert_allclose(keras_param, reference.param, atol=1e-6)
101105
np.testing.assert_allclose(
102-
keras.ops.convert_to_numpy(optimizer.momentums[0]),
106+
_to_numpy(optimizer.momentums[0]),
103107
reference.state.momentum,
104108
atol=1e-6,
105109
)
106110
np.testing.assert_allclose(
107-
keras.ops.convert_to_numpy(optimizer.nces[0]),
111+
_to_numpy(optimizer.nces[0]),
108112
reference.state.nce,
109113
atol=1e-6,
110114
)
@@ -134,7 +138,7 @@ def test_keras_optimizer_matches_reference_with_weight_decay_modes() -> None:
134138
)
135139
np.testing.assert_allclose(decoupled_param, decoupled_reference.param, atol=1e-6)
136140
np.testing.assert_allclose(
137-
keras.ops.convert_to_numpy(decoupled_optimizer.momentums[0]),
141+
_to_numpy(decoupled_optimizer.momentums[0]),
138142
decoupled_reference.state.momentum,
139143
atol=1e-6,
140144
)
@@ -159,7 +163,7 @@ def test_keras_optimizer_matches_reference_with_weight_decay_modes() -> None:
159163
)
160164
np.testing.assert_allclose(coupled_param, coupled_reference.param, atol=1e-6)
161165
np.testing.assert_allclose(
162-
keras.ops.convert_to_numpy(coupled_optimizer.momentums[0]),
166+
_to_numpy(coupled_optimizer.momentums[0]),
163167
coupled_reference.state.momentum,
164168
atol=1e-6,
165169
)
@@ -191,7 +195,7 @@ def test_keras_optimizer_matches_reference_when_nce_is_disabled() -> None:
191195

192196
np.testing.assert_allclose(keras_param, reference.param, atol=1e-6)
193197
np.testing.assert_allclose(
194-
keras.ops.convert_to_numpy(optimizer.nces[0]),
198+
_to_numpy(optimizer.nces[0]),
195199
np.zeros_like(initial_param),
196200
atol=1e-6,
197201
)

tests/unit/test_reference_step.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,18 @@ def test_correction_is_clipped_to_gradient_norm() -> None:
7676
result = neat_step_reference(param, grad, state, config)
7777

7878
assert np.linalg.norm(result.state.nce) == pytest.approx(0.25, abs=1e-6)
79+
80+
81+
def test_reference_step_supports_matrix_parameters() -> None:
82+
param = np.array([[1.0, -2.0], [0.5, 3.0]], dtype=np.float32)
83+
grad = np.array([[0.5, -0.25], [0.1, -0.2]], dtype=np.float32)
84+
state = ArrayState.zeros_like(param)
85+
config = NEATConfig(learning_rate=0.05, alpha=0.25, beta=0.9)
86+
87+
result = neat_step_reference(param, grad, state, config)
88+
89+
assert result.state.step == 1
90+
assert result.param.shape == param.shape
91+
assert result.state.momentum.shape == param.shape
92+
assert result.state.nce.shape == param.shape
93+
assert np.isfinite(result.param).all()

0 commit comments

Comments
 (0)