[refactor] move tests to tests/, add pytest functions and main() entrypoints

- Moved src/tests/ → tests/
- Added test_* functions with assertions to script-style test files
- Added main() to each so IDEs offer it as a separate run target from pytest
- Fixed cupy_test.py: remove spurious x_gpu += x_cpu, fix duplicate xlabel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-02 21:32:58 +02:00
co-authored by Claude Sonnet 4.6
parent 829547d271
commit 3edc124a5c
21 changed files with 214 additions and 71 deletions
+1 -2
View File
@@ -6,5 +6,4 @@ images
*.egg-info
__pycache__
*.npzdata
.ipynb_checkpoints/
cupy_test.py
.ipynb_checkpoints/
-18
View File
@@ -1,18 +0,0 @@
from image.sub_image import SubImageExtract
from rbm.matrix import np
if __name__ == "__main__":
n = 2
c = 3
w = 8
h = 8
img_rbb = np.reshape(np.linspace(1, n*c*w*h, num=n*c*w*h, dtype=np.float64), (n, c, w, h))
sub = SubImageExtract(4, 4, 1, 1)
sub(img_rbb, 3)
img_gray = np.reshape(np.linspace(1, n*w*h, num=n*w*h, dtype=np.float64), (n, w, h))
sub(img_gray, 1)
print("Test: [passed]")
+107
View File
@@ -0,0 +1,107 @@
import time
import numpy as np
import cupy as cp
from matplotlib import pyplot as plt
def warmup_cupy():
a = cp.random.random((10,10))
b = cp.random.random((10,10))
_ = cp.dot(a, b)
def calc_cpu(a: np.array, b: np.array):
return np.dot(a, b)
def calc_gpu(a: np.array, b: np.array):
return cp.dot(a, b)
def perf_test_2():
### Numpy and CPU
print("Creation")
s = time.time()
x_cpu = np.ones((1000, 1000, 1000))
e = time.time()
time_cpu = e - s
s = time.time()
x_gpu = cp.ones((1000, 1000, 1000))
cp.cuda.Stream.null.synchronize()
e = time.time()
time_gpu = e - s
print(f"Speedup: {time_cpu/time_gpu}")
### Numpy and CPU
print("Multiply with constant")
s = time.time()
x_cpu *= 5
e = time.time()
time_cpu = e - s
s = time.time()
x_gpu *= 5
cp.cuda.Stream.null.synchronize()
e = time.time()
time_gpu = e - s
print(f"Speedup: {time_cpu/time_gpu}")
### Numpy and CPU
print("Multiply with constant, Square, Square")
s = time.time()
x_cpu *= 5
x_cpu *= x_cpu
x_cpu += x_cpu
e = time.time()
time_cpu = e - s
s = time.time()
x_gpu *= 5
x_gpu *= x_gpu
x_gpu += x_gpu
cp.cuda.Stream.null.synchronize()
e = time.time()
time_gpu = e - s
print(f"Speedup: {time_cpu/time_gpu}")
def perf_test_1():
n_values = []
np_times = []
cp_times = []
ratio_times = []
for N in range(100, 5100, 100):
a_np = np.random.rand(1024, N)
b_np = np.random.rand(N, 1024)
a_cp = cp.asarray(a_np)
b_cp = cp.asarray(b_np)
start_time = time.time()
c_np = calc_cpu(a_np, b_np)
end_time = time.time()
numpy_time = end_time - start_time
start_time = time.time()
c_cp = calc_gpu(a_cp, b_cp)
c_np = cp.asnumpy(c_cp)
end_time = time.time()
cupy_time = end_time - start_time
n_values.append(N)
np_times.append(numpy_time)
cp_times.append(cupy_time)
ratio_times.append(numpy_time/cupy_time)
plt.plot(n_values, np_times, label='numpy time')
plt.plot(n_values, cp_times, label='cupy time')
plt.plot(n_values, ratio_times, label='numpy/cupy time')
plt.xlabel("Matrix size [N]")
plt.ylabel("Time [s]")
plt.title("Performance numpy vs cupy")
plt.grid()
plt.legend()
plt.show()
def main():
warmup_cupy()
perf_test_2()
if __name__ == "__main__":
main()
@@ -11,7 +11,7 @@ N_HID = 32
N_CASES = 400
class TestModel(Model):
class BinaryAEModel(Model):
def __init__(self, name: str, work_dir: str = '.'):
super().__init__(name, work_dir)
self.unit1 = Entity(
@@ -41,11 +41,18 @@ def make_bars_and_stripes(n_cases: int, n: int = N) -> Mat:
return data
if __name__ == "__main__":
prj_name = "binary_autoencoder"
work_dir = "results"
def test_binary_autoencoder():
model = BinaryAEModel("binary_autoencoder_pytest", "results")
model.unit1.training_params.num_epochs = 500
model.init(0.01)
train_batch = make_bars_and_stripes(N_CASES)
model.train(train_batch)
mae = float(np.mean(np.abs(train_batch - np.array([model.reconstruct(model.forward(x)) for x in train_batch]))))
assert mae < 0.4, f"Reconstruction MAE {mae:.4f} too high"
model = TestModel(prj_name, work_dir)
def main():
model = BinaryAEModel("binary_autoencoder", "results")
model.init(0.01)
train_batch = make_bars_and_stripes(N_CASES)
@@ -73,3 +80,7 @@ if __name__ == "__main__":
print(f"Mean reconstruction error: {total_error / n_show:.4f}")
plt.tight_layout()
plt.show()
if __name__ == "__main__":
main()
@@ -12,7 +12,7 @@ N_HID = 32
N_CASES = 400
class TestModel(Model):
class GaussianAEModel(Model):
def __init__(self, name: str, work_dir: str = '.'):
super().__init__(name, work_dir)
self.unit1 = Entity(
@@ -41,11 +41,19 @@ def make_gaussian_blobs(n_cases: int, n: int = N) -> Mat:
return data
if __name__ == "__main__":
prj_name = "gaussian_autoencoder"
work_dir = "results"
def test_gaussian_autoencoder():
model = GaussianAEModel("gaussian_autoencoder_pytest", "results")
model.unit1.training_params.num_epochs = 1500
model.init(0.01)
train_batch = normalize(make_gaussian_blobs(N_CASES))
model.train(train_batch)
for x in train_batch[:10]:
recon = model.reconstruct(model.forward(x))
assert recon.size == x.size
model = TestModel(prj_name, work_dir)
def main():
model = GaussianAEModel("gaussian_autoencoder", "results")
model.init(0.01)
train_batch = normalize(make_gaussian_blobs(N_CASES))
@@ -73,3 +81,7 @@ if __name__ == "__main__":
print(f"Mean reconstruction error: {total_error / n_show:.4f}")
plt.tight_layout()
plt.show()
if __name__ == "__main__":
main()
@@ -7,7 +7,7 @@ WORK_DIR = "../../results"
USE_OPTIMIZER = True
N_VIS = 3000
N_CASES = 1000
class TestModel(Model):
class LinearModel(Model):
def __init__(self, name: str, work_dir: str = '.', do_gaussian_hidden=False):
super().__init__(name, work_dir)
@@ -28,39 +28,40 @@ class TestModel(Model):
x = self.unit1.reconstruct(x)
return x
def linear():
work_dir = "results"
prj_name = "linear"
prj_root = "/home/jens/work/repos/Rbm"
class _SmallLinearModel(Model):
def __init__(self):
super().__init__("linear_pytest", "results")
self.unit1 = Entity((64, 32), EntityParams(do_gaussian_visible=True),
TrainingParams(learning_rate=0.005, momentum=0.9, num_epochs=100))
# Create layer
model = TestModel(prj_name, "results")
def forward(self, x: Mat):
return self.unit1.forward(x)
# Init weights
def reconstruct(self, x: Mat):
return self.unit1.reconstruct(x)
def test_linear():
model = _SmallLinearModel()
model.init(0.1)
batch = normalize(np.random.randn(50, 64, dtype=np.float64))
model.train(batch)
for pattern in batch:
recon = model.reconstruct(model.forward(pattern))
assert recon.size == pattern.size
# Load weights (if exists)
def main():
model = LinearModel("linear", "results")
model.init(0.1)
model.load()
# Prepare training data
training_batch = np.random.randn(N_CASES, N_VIS, dtype=np.float64)
# Normalize training data
training_batch_norm = normalize(training_batch)
# Train layer
model.train(training_batch_norm)
# Save weights
model.save()
for pattern in training_batch:
model.reconstruct(model.forward(pattern))
# Test with test data
test_batch = training_batch
for pattern in test_batch:
h = model.forward(pattern)
v = model.reconstruct(h)
# print(f"P{pattern} : {v}")
if __name__ == "__main__":
linear()
print("Test: [passed]")
main()
+21 -16
View File
@@ -2,7 +2,7 @@ from model.model import Model
from rbm.entity import Entity, EntityParams, TrainingParams
from rbm.matrix import Mat, np
class TestModel(Model):
class DeepModel(Model):
def __init__(self, name: str, work_dir: str = '.'):
super().__init__(name, work_dir)
self.unit1 = Entity((1024, 333), EntityParams(), TrainingParams(learning_rate=0.1, momentum=0.9, do_rao_blackwell=True, num_epochs=1000))
@@ -24,28 +24,33 @@ class TestModel(Model):
x = self.unit1.reconstruct(x)
return x
if __name__ == "__main__":
# Create model
model = TestModel("TestModel", "results")
# Init state
def test_deep_model():
model = DeepModel("TestModel_pytest", "results")
model.unit1.training_params.num_epochs = 100
model.unit2.training_params.num_epochs = 100
model.unit3.training_params.num_epochs = 100
model.unit4.training_params.num_epochs = 100
model.init(0.1)
# load state
model.load()
# create batch
batch = (np.random.rand(64, 1024) > 0.5).astype(np.float64)
# Train
batch = (np.random.rand(32, 1024) > 0.5).astype(np.float64)
model.train(batch)
errors = [float(np.mean((model.backward(model.forward(x)) - x) ** 2)) for x in batch]
assert sum(errors) / len(errors) < 0.5, "Deep model reconstruction MSE too high"
# save state
def main():
model = DeepModel("TestModel", "results")
model.init(0.1)
model.load()
batch = (np.random.rand(64, 1024) > 0.5).astype(np.float64)
model.train(batch)
model.save()
for index, inp in enumerate(batch):
out = model.backward(model.forward(inp))[0]
print(f"- Pattern {index} -------------------------")
print(f"Input : {inp}")
print(f"Output : {(out > 0.9).astype(np.float64)}")
print(f"Error : {np.mean((out - inp)**2):0.3f}")
if __name__ == "__main__":
main()
+26
View File
@@ -0,0 +1,26 @@
from image.sub_image import SubImageExtract
from rbm.matrix import np
def test_sub_image_rgb():
n, c, w, h = 2, 3, 8, 8
img = np.reshape(np.linspace(1, n*c*w*h, num=n*c*w*h, dtype=np.float64), (n, c, w, h))
sub = SubImageExtract(4, 4, 1, 1)
result = sub(img, 3)
assert result.shape[1] == 3
assert result.shape[2] == 4 and result.shape[3] == 4
def test_sub_image_gray():
n, w, h = 2, 8, 8
img = np.reshape(np.linspace(1, n*w*h, num=n*w*h, dtype=np.float64), (n, w, h))
sub = SubImageExtract(4, 4, 1, 1)
result = sub(img, 1)
assert result.shape[1] == 1
assert result.shape[2] == 4 and result.shape[3] == 4
if __name__ == "__main__":
test_sub_image_rgb()
test_sub_image_gray()
print("Test: [passed]")