Spaces:
Sleeping
Sleeping
Initial commit
Browse files- .vscode/settings.json +6 -0
- README.md +6 -2
- app.py +32 -0
- dataset.py +63 -0
- model_91_7248.bin +0 -0
- network.py +73 -0
- requirements.txt +1 -0
.vscode/settings.json
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"[python]": {
|
3 |
+
"editor.defaultFormatter": "ms-python.autopep8"
|
4 |
+
},
|
5 |
+
"python.formatting.provider": "none"
|
6 |
+
}
|
README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
emoji: π
|
4 |
colorFrom: indigo
|
5 |
colorTo: pink
|
@@ -10,4 +10,8 @@ pinned: false
|
|
10 |
license: mit
|
11 |
---
|
12 |
|
13 |
-
|
|
|
|
|
|
|
|
|
|
1 |
---
|
2 |
+
title: Simple MNIST Classifier
|
3 |
emoji: π
|
4 |
colorFrom: indigo
|
5 |
colorTo: pink
|
|
|
10 |
license: mit
|
11 |
---
|
12 |
|
13 |
+
The model used is a Neural Network made with Python and Numpy only.
|
14 |
+
Architecture is 784 input units, two hidden layers of 72 and 24 units and a 10 unit output.
|
15 |
+
Training was done on the MNIST training dataset of 60000 images.
|
16 |
+
|
17 |
+
Video (Portuguese-Brazil): https://www.youtube.com/watch?v=NhG8NsHW6fI
|
app.py
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import pickle
|
3 |
+
|
4 |
+
with open('model_91_7248.bin', 'rb') as f:
|
5 |
+
nn = pickle.load(f)
|
6 |
+
|
7 |
+
|
8 |
+
def predict(input):
|
9 |
+
x = input.reshape((784, 1))
|
10 |
+
p = nn.feed_forward(x).reshape((10,))
|
11 |
+
|
12 |
+
return dict(enumerate(p))
|
13 |
+
|
14 |
+
|
15 |
+
demo = gr.Interface(
|
16 |
+
fn=predict,
|
17 |
+
inputs=[
|
18 |
+
gr.Sketchpad(
|
19 |
+
shape=(28, 28),
|
20 |
+
brush_radius=1.2,
|
21 |
+
)
|
22 |
+
],
|
23 |
+
outputs=[
|
24 |
+
gr.Label(
|
25 |
+
num_top_classes=3,
|
26 |
+
scale=2,
|
27 |
+
)
|
28 |
+
],
|
29 |
+
live=True,
|
30 |
+
allow_flagging=False,
|
31 |
+
|
32 |
+
).launch()
|
dataset.py
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
|
3 |
+
|
4 |
+
def load_training():
|
5 |
+
images_file = open('./train-images-idx3-ubyte', 'rb')
|
6 |
+
labels_file = open('./train-labels-idx1-ubyte', 'rb')
|
7 |
+
|
8 |
+
images = load_images(images_file)
|
9 |
+
labels = load_labels(labels_file)
|
10 |
+
|
11 |
+
return images, labels
|
12 |
+
|
13 |
+
|
14 |
+
def bytes_to_int(bytes):
|
15 |
+
return int.from_bytes(bytes, byteorder='big')
|
16 |
+
|
17 |
+
|
18 |
+
def load_images(file, num=60000):
|
19 |
+
magic = bytes_to_int(file.read(4))
|
20 |
+
if (magic != 2051):
|
21 |
+
raise RuntimeError('Wrong file for images')
|
22 |
+
|
23 |
+
num_images = bytes_to_int(file.read(4))
|
24 |
+
num_rows = bytes_to_int(file.read(4))
|
25 |
+
num_cols = bytes_to_int(file.read(4))
|
26 |
+
|
27 |
+
images = []
|
28 |
+
|
29 |
+
for i in range(min(num_images, num)):
|
30 |
+
images.append([
|
31 |
+
bytes_to_int(file.read(1)) for p in range(num_rows * num_cols)
|
32 |
+
])
|
33 |
+
|
34 |
+
return images
|
35 |
+
|
36 |
+
|
37 |
+
def load_labels(file, num=60000):
|
38 |
+
magic = bytes_to_int(file.read(4))
|
39 |
+
if (magic != 2049):
|
40 |
+
raise RuntimeError('Wrong file for labels')
|
41 |
+
|
42 |
+
num_labels = bytes_to_int(file.read(4))
|
43 |
+
|
44 |
+
labels = [
|
45 |
+
bytes_to_int(file.read(1)) for l in range(min(num_labels, num))
|
46 |
+
]
|
47 |
+
|
48 |
+
return labels
|
49 |
+
|
50 |
+
|
51 |
+
def convert_label_to_output(label: int):
|
52 |
+
output = np.zeros((10, 1))
|
53 |
+
output[label][0] = 1.0
|
54 |
+
|
55 |
+
return output
|
56 |
+
|
57 |
+
|
58 |
+
def convert_image_to_input(image: list):
|
59 |
+
return np.reshape(image, (784, 1))
|
60 |
+
|
61 |
+
|
62 |
+
def convert_output_to_label(output: np.ndarray[np.float64]):
|
63 |
+
return np.argmax(output)
|
model_91_7248.bin
ADDED
Binary file (485 kB). View file
|
|
network.py
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
|
3 |
+
class NeuralNetwork():
|
4 |
+
def __init__(self, neurons_per_layer):
|
5 |
+
self.num_layers = len(neurons_per_layer)
|
6 |
+
self.neurons_per_layer = neurons_per_layer
|
7 |
+
|
8 |
+
a = neurons_per_layer[1:]
|
9 |
+
b = neurons_per_layer[:-1]
|
10 |
+
|
11 |
+
self.weights = [
|
12 |
+
np.random.randn(current, previous) for current, previous in
|
13 |
+
zip(a, b)
|
14 |
+
]
|
15 |
+
|
16 |
+
self.bias = [np.random.randn(y, 1) for y in a]
|
17 |
+
|
18 |
+
def activation_fn(self, x):
|
19 |
+
return 1.0 / (1.0 + np.exp(-x))
|
20 |
+
|
21 |
+
def cost_derivative(self, output, expected):
|
22 |
+
return output - expected
|
23 |
+
|
24 |
+
def activation_derivative(self, x):
|
25 |
+
return self.activation_fn(x) * (1 - self.activation_fn(x))
|
26 |
+
|
27 |
+
def feed_forward(self, x):
|
28 |
+
for w, b in zip(self.weights, self.bias):
|
29 |
+
z = np.dot(w, x) + b
|
30 |
+
x = self.activation_fn(z)
|
31 |
+
|
32 |
+
return x
|
33 |
+
|
34 |
+
def backprop(self, x, expected):
|
35 |
+
weight_gradients = [np.zeros(w.shape) for w in self.weights]
|
36 |
+
bias_gradients = [np.zeros(b.shape) for b in self.bias]
|
37 |
+
|
38 |
+
zs = []
|
39 |
+
activation = np.array(x)
|
40 |
+
activations = [np.array(x)]
|
41 |
+
|
42 |
+
for w, b in zip(self.weights, self.bias):
|
43 |
+
z = np.dot(w, activation) + b
|
44 |
+
zs.append(z)
|
45 |
+
activation = self.activation_fn(z)
|
46 |
+
activations.append(activation)
|
47 |
+
|
48 |
+
delta = self.cost_derivative(
|
49 |
+
activation, expected) * self.activation_derivative(zs[-1])
|
50 |
+
|
51 |
+
weight_gradients[-1] = np.dot(delta, activations[-2].T)
|
52 |
+
bias_gradients[-1] = delta
|
53 |
+
|
54 |
+
for layer in range(2, self.num_layers):
|
55 |
+
z = zs[-layer]
|
56 |
+
d = self.activation_derivative(z)
|
57 |
+
delta = np.dot(self.weights[-layer + 1].T, delta) * d
|
58 |
+
|
59 |
+
weight_gradients[-layer] = np.dot(delta, activations[-layer - 1].T)
|
60 |
+
bias_gradients[-layer] = delta
|
61 |
+
|
62 |
+
return (weight_gradients, bias_gradients)
|
63 |
+
|
64 |
+
def adjust(self, lr, weight_gradients, bias_gradients):
|
65 |
+
self.weights = [
|
66 |
+
w - lr * nw for w, nw in
|
67 |
+
zip(self.weights, weight_gradients)
|
68 |
+
]
|
69 |
+
|
70 |
+
self.bias = [
|
71 |
+
b - lr * nb for b, nb in
|
72 |
+
zip(self.bias, bias_gradients)
|
73 |
+
]
|
requirements.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
numpy==1.26.0
|