Skip to content

Commit 31a856d

Browse files
committed
rtl_predict in alkaid converter tests
1 parent d5cce9d commit 31a856d

2 files changed

Lines changed: 39 additions & 47 deletions

File tree

tests/test_keras_alkaid_conversion.py

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ def _build_model(config):
6363
return keras.Model([img_in, seq_in], x)
6464

6565

66+
def _rtl_predict(comb, path, data):
67+
"""Write the RTL project, compile the simulation emulator, and run bit-accurate inference."""
68+
rtl_model = RTLModel(comb, str(path), "model", flavor="verilog", latency_cutoff=5, clock_period=5.0, print_latency=False)
69+
rtl_model.write()
70+
rtl_model.compile()
71+
if isinstance(data, list):
72+
data = [a.astype(np.float64) for a in data]
73+
else:
74+
data = data.astype(np.float64)
75+
return rtl_model.predict(data)
76+
77+
6678
def _random_prune(layer, fraction, rng):
6779
"""Zero exactly ``fraction`` of the layer's weights via its pruning mask."""
6880
mask = layer.pruning_layer.mask
@@ -123,20 +135,12 @@ def test_alkaid_rtl_matches_model(tmp_path):
123135
seq = rng.integers(0, 16, size=(n_samples,) + SEQ_SHAPE).astype("float32") / 16.0
124136

125137
reference = np.asarray(model([img, seq]), dtype=np.float64) # (n_samples, OUT_FEATURES)
126-
emulated = np.stack(
127-
[
128-
np.asarray(comb(np.concatenate([img[n].ravel(), seq[n].ravel()]), quantize=True), dtype=np.float64)
129-
for n in range(n_samples)
130-
]
131-
)
138+
emulated = _rtl_predict(comb, tmp_path, [img, seq])
139+
assert (tmp_path / "src" / "model.v").exists()
132140

133141
assert np.any(reference != 0) # the comparison is non-trivial
134142
np.testing.assert_allclose(emulated, reference, rtol=0, atol=1e-9)
135143

136-
# Generate the actual RTL project from the same combinational logic.
137-
RTLModel(comb, str(tmp_path), "model", flavor="verilog", print_latency=False).write()
138-
assert (tmp_path / "src" / "model.v").exists()
139-
140144

141145
# --- Coverage of every PQ layer the keras Alkaid plugin handles ---------------
142146

@@ -231,19 +235,12 @@ def test_alkaid_conversion_all_layer_types(tmp_path):
231235
img = rng.integers(0, 16, size=(n_samples,) + ALL_IMG_SHAPE).astype("float32") / 16.0
232236
seq = rng.integers(0, 16, size=(n_samples,) + ALL_SEQ_SHAPE).astype("float32") / 16.0
233237
reference = np.asarray(model([img, seq]), dtype=np.float64)
234-
emulated = np.stack(
235-
[
236-
np.asarray(comb(np.concatenate([img[n].ravel(), seq[n].ravel()]), quantize=True), dtype=np.float64)
237-
for n in range(n_samples)
238-
]
239-
)
238+
emulated = _rtl_predict(comb, tmp_path, [img, seq])
239+
assert (tmp_path / "src" / "model.v").exists()
240240

241241
assert np.any(reference != 0)
242242
np.testing.assert_allclose(emulated, reference, rtol=0, atol=1e-9)
243243

244-
RTLModel(comb, str(tmp_path), "model", flavor="verilog", print_latency=False).write()
245-
assert (tmp_path / "src" / "model.v").exists()
246-
247244

248245
# --- Per-layer conversion: a model that is a single layer ---------------------
249246

@@ -313,7 +310,7 @@ def _single_layer_model(input_shape, layer, tail=None):
313310

314311

315312
@pytest.mark.parametrize("case_id", list(_SINGLE_LAYER_CASES))
316-
def test_alkaid_single_layer(case_id):
313+
def test_alkaid_single_layer(case_id, tmp_path):
317314
config = pdp_config()
318315
config.quantization_parameters.enable_quantization = True
319316
input_shape, model = _SINGLE_LAYER_CASES[case_id](config)
@@ -328,7 +325,7 @@ def test_alkaid_single_layer(case_id):
328325
n_samples = 16
329326
x = rng.integers(0, 16, size=(n_samples,) + input_shape).astype("float32") / 16.0
330327
reference = np.asarray(model(x), dtype=np.float64).reshape(n_samples, -1)
331-
emulated = np.stack([np.asarray(comb(x[i].ravel(), quantize=True), dtype=np.float64) for i in range(n_samples)])
328+
emulated = _rtl_predict(comb, tmp_path, x)
332329

333330
assert np.any(reference != 0)
334331
np.testing.assert_allclose(emulated, reference, rtol=0, atol=1e-9)
@@ -370,10 +367,8 @@ def test_alkaid_multihead_attention(tmp_path):
370367
n_samples = 16
371368
x = rng.integers(0, 16, size=(n_samples, MHA_SEQ_LEN, MHA_EMBED_DIM)).astype("float32") / 16.0
372369
reference = np.asarray(model(x), dtype=np.float64).reshape(n_samples, -1)
373-
emulated = np.stack([np.asarray(comb(x[i].ravel(), quantize=True), dtype=np.float64) for i in range(n_samples)])
370+
emulated = _rtl_predict(comb, tmp_path, x)
371+
assert (tmp_path / "src" / "model.v").exists()
374372

375373
assert np.any(reference != 0)
376374
np.testing.assert_allclose(emulated, reference, rtol=0, atol=1e-9)
377-
378-
RTLModel(comb, str(tmp_path), "model", flavor="verilog", print_latency=False).write()
379-
assert (tmp_path / "src" / "model.v").exists()

tests/test_torch_alkaid_conversion.py

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,18 @@ def _fixed_point_input(shape, kif=INPUT_KIF):
8484
return FVArray.from_kif(k, i, f, HWCONF, 0, None)
8585

8686

87+
def _rtl_predict(comb, path, data):
88+
"""Write the RTL project, compile the simulation emulator, and run bit-accurate inference."""
89+
rtl_model = RTLModel(comb, str(path), "model", flavor="verilog", latency_cutoff=5, clock_period=5.0, print_latency=False)
90+
rtl_model.write()
91+
rtl_model.compile()
92+
if isinstance(data, list):
93+
data = [a.astype(np.float64) for a in data]
94+
else:
95+
data = data.astype(np.float64)
96+
return rtl_model.predict(data)
97+
98+
8799
def _build_pruned_compressed_model(config, rng):
88100
"""Build the model, build it (one forward), prune 90%, apply final compression, eval."""
89101
model = TwoBranchNet(config)
@@ -140,20 +152,12 @@ def test_alkaid_rtl_matches_model(tmp_path):
140152
model(torch.tensor(img, device=device), torch.tensor(seq, device=device)).cpu().numpy().astype(np.float64)
141153
) # (n_samples, OUT_FEATURES)
142154

143-
emulated = np.stack(
144-
[
145-
np.asarray(comb(np.concatenate([img[n].ravel(), seq[n].ravel()]), quantize=True), dtype=np.float64)
146-
for n in range(n_samples)
147-
]
148-
)
155+
emulated = _rtl_predict(comb, tmp_path, [img, seq])
156+
assert (tmp_path / "src" / "model.v").exists()
149157

150158
assert np.any(reference != 0) # the comparison is non-trivial
151159
np.testing.assert_allclose(emulated, reference, rtol=0, atol=1e-9)
152160

153-
# Generate the actual RTL project from the same combinational logic.
154-
RTLModel(comb, str(tmp_path), "model", flavor="verilog", print_latency=False).write()
155-
assert (tmp_path / "src" / "model.v").exists()
156-
157161

158162
# --- Coverage of every PQ layer the torch Alkaid plugin handles ---------------
159163

@@ -243,19 +247,12 @@ def test_alkaid_conversion_all_layer_types(tmp_path):
243247
reference = (
244248
model(torch.tensor(img, device=device), torch.tensor(seq, device=device)).cpu().numpy().astype(np.float64)
245249
)
246-
emulated = np.stack(
247-
[
248-
np.asarray(comb(np.concatenate([img[n].ravel(), seq[n].ravel()]), quantize=True), dtype=np.float64)
249-
for n in range(n_samples)
250-
]
251-
)
250+
emulated = _rtl_predict(comb, tmp_path, [img, seq])
251+
assert (tmp_path / "src" / "model.v").exists()
252252

253253
assert np.any(reference != 0)
254254
np.testing.assert_allclose(emulated, reference, rtol=0, atol=1e-9)
255255

256-
RTLModel(comb, str(tmp_path), "model", flavor="verilog", print_latency=False).write()
257-
assert (tmp_path / "src" / "model.v").exists()
258-
259256

260257
# --- Per-layer conversion: a model that is a single layer ---------------------
261258

@@ -309,7 +306,7 @@ def forward(self, x):
309306

310307

311308
@pytest.mark.parametrize("case_id", list(_SINGLE_LAYER_CASES))
312-
def test_alkaid_single_layer(case_id):
309+
def test_alkaid_single_layer(case_id, tmp_path):
313310
config = pdp_config()
314311
config.quantization_parameters.enable_quantization = True
315312
shape, model = _SINGLE_LAYER_CASES[case_id](config)
@@ -328,7 +325,7 @@ def test_alkaid_single_layer(case_id):
328325
x = rng.integers(0, 16, size=(n_samples,) + shape[1:]).astype("float32") / 16.0
329326
with torch.no_grad():
330327
reference = model(torch.tensor(x)).cpu().numpy().reshape(n_samples, -1).astype(np.float64)
331-
emulated = np.stack([np.asarray(comb(x[i].ravel(), quantize=True), dtype=np.float64) for i in range(n_samples)])
328+
emulated = _rtl_predict(comb, tmp_path, x)
332329

333330
assert np.any(reference != 0)
334331
np.testing.assert_allclose(emulated, reference, rtol=0, atol=1e-9)
@@ -384,7 +381,7 @@ def test_alkaid_multihead_attention(tmp_path):
384381
x = rng.integers(0, 16, size=(n_samples, MHA_SEQ_LEN, MHA_EMBED_DIM)).astype("float32") / 16.0
385382
with torch.no_grad():
386383
reference = model(torch.tensor(x)).cpu().numpy().reshape(n_samples, -1).astype(np.float64)
387-
emulated = np.stack([np.asarray(comb(x[i].ravel(), quantize=True), dtype=np.float64) for i in range(n_samples)])
384+
emulated = _rtl_predict(comb, tmp_path, x)
388385

389386
assert np.any(reference != 0)
390387
np.testing.assert_allclose(emulated, reference, rtol=0, atol=1e-9)

0 commit comments

Comments
 (0)