Skip to content

Commit 2cde4f5

Browse files
committed
Adapting CPU script, fixing bug in slicing
1 parent d93193c commit 2cde4f5

2 files changed

Lines changed: 33 additions & 38 deletions

File tree

examples/mnist.py

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
sys.path.insert(0, str(Path(__file__).parent.parent / "python_lib"))
55

66
import math
7+
import random
78
import numpy as np
89
from sklearn.datasets import fetch_openml
910
from sklearn.model_selection import train_test_split
@@ -20,7 +21,7 @@
2021
def load_mnist():
2122
print("Loading MNIST...")
2223
mnist = fetch_openml("mnist_784", version=1, as_frame=False)
23-
x = mnist.data.astype(np.float32) / 255.0 # normalize to [0,1]
24+
x = mnist.data.astype(np.float32) / 255.0
2425
y = mnist.target.astype(np.int32)
2526
return x, y
2627

@@ -32,16 +33,6 @@ def to_one_hot(y, n_classes=10):
3233
return one_hot
3334

3435

35-
def make_batches(x, y, batch_size, shuffle=True):
36-
n = x.shape[0]
37-
indices = np.arange(n)
38-
if shuffle:
39-
np.random.shuffle(indices)
40-
for start in range(0, n, batch_size):
41-
batch_idx = indices[start : start + batch_size]
42-
yield x[batch_idx], y[batch_idx]
43-
44-
4536
# ─── network ─────────────────────────────────────────────────────────────────
4637

4738
def make_net():
@@ -67,18 +58,24 @@ def print_weight_stats(net, batch_num):
6758

6859
# ─── training ────────────────────────────────────────────────────────────────
6960

70-
def train_epoch(net, loss_fn, optim, x, y, batch_size=64):
71-
#print_weight_stats(net, 0)
61+
def train_epoch(net, loss_fn, optim, x_t, y_t, batch_size=64):
62+
n = x_t.dims[0]
63+
64+
indices = list(range(n))
65+
random.shuffle(indices)
66+
x_shuf = x_t.slice(indices)
67+
y_shuf = y_t.slice(indices)
7268

7369
total_loss = 0.0
7470
n_batches = 0
75-
max_batches = math.ceil(x.shape[0] / batch_size)
76-
for xb, yb in make_batches(x, y, batch_size):
77-
xTensor = fromNumpy(xb)
78-
yTensor = fromNumpy(yb)
71+
max_batches = math.ceil(n / batch_size)
72+
for start in range(0, n, batch_size):
73+
end = min(start + batch_size, n)
74+
xb = x_shuf.slice(start, end)
75+
yb = y_shuf.slice(start, end)
7976

80-
pred = net.forward(xTensor)
81-
loss = loss_fn(yTensor, pred)
77+
pred = net.forward(xb)
78+
loss = loss_fn(yb, pred)
8279
loss.backward()
8380

8481
optim.clipGradients(1.0)
@@ -89,30 +86,25 @@ def train_epoch(net, loss_fn, optim, x, y, batch_size=64):
8986
n_batches += 1
9087
if n_batches == 1 or n_batches % 10 == 0:
9188
print(f"Batch {n_batches} / {max_batches}, loss {loss.getitem(0)}")
92-
#print_weight_stats(net, n_batches)
9389

9490
return total_loss / n_batches
9591

9692

97-
def evaluate(net, x, y_int, batch_size=256):
93+
def evaluate(net, x_t, y_np, batch_size=256):
94+
n = x_t.dims[0]
9895
correct = 0
99-
total = 0
100-
for xb, yb in make_batches(x, y_int, batch_size, shuffle=False):
101-
xTensor = fromNumpy(xb)
102-
pred = net.forward(xTensor)
96+
for start in range(0, n, batch_size):
97+
end = min(start + batch_size, n)
98+
pred = net.forward(x_t.slice(start, end))
10399
pred_np = toNumpy(pred)
104-
105100
predicted = np.argmax(pred_np, axis=1)
106-
107-
correct += np.sum(predicted == np.argmax(yb, axis=1))
108-
total += len(yb)
109-
return correct / total
101+
correct += np.sum(predicted == np.argmax(y_np[start:end], axis=1))
102+
return correct / n
110103

111104

112105
# ─── main ────────────────────────────────────────────────────────────────────
113106

114107
if __name__ == "__main__":
115-
# load and split data
116108
x, y_int = load_mnist()
117109
y = to_one_hot(y_int)
118110

@@ -122,16 +114,18 @@ def evaluate(net, x, y_int, batch_size=256):
122114

123115
print(f"Train: {x_train.shape}, Val: {x_val.shape}")
124116

125-
# setup
117+
x_train_t = fromNumpy(x_train)
118+
y_train_t = fromNumpy(y_train)
119+
x_val_t = fromNumpy(x_val)
120+
126121
net = make_net()
127122
loss_fn = CrossEntropyWithSoftmax()
128-
optim = RmsProp(net.parameters(), 0.0001, 0.999) # lr and decay
123+
optim = RmsProp(net.parameters(), 0.0001, 0.999)
129124

130-
# training loop
131125
n_epochs = 5
132126
for epoch in range(n_epochs):
133-
train_loss = train_epoch(net, loss_fn, optim, x_train, y_train)
134-
val_acc = evaluate(net, x_val, y_val)
127+
train_loss = train_epoch(net, loss_fn, optim, x_train_t, y_train_t)
128+
val_acc = evaluate(net, x_val_t, y_val)
135129
print(
136130
f"Epoch {epoch+1}/{n_epochs} "
137131
f"loss={train_loss:.4f} "

src/backend/data_modeling/tensor.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -948,11 +948,12 @@ Tensor Tensor::getSlice(const tensorSize_t low, const tensorSize_t high) const {
948948
}
949949

950950
makeContiguous();
951-
951+
952+
const tensorSize_t stride = dims.getStride(0);
952953
auto resDims = dims.toVector();
953954
resDims[0] = high-low;
954955
Tensor res(std::move(resDims), values->getDevice(), false);
955-
values->copyValues(*res.values, low, high, 0);
956+
values->copyValues(*res.values, low * stride, high * stride, 0);
956957
return res;
957958
}
958959

0 commit comments

Comments
 (0)