ByteJoseph commited on
Commit
9277f2e
·
verified ·
1 Parent(s): 23cda5c

Upload folder using huggingface_hub

Browse files
Files changed (8) hide show
  1. .gitignore +2 -0
  2. app.py +57 -0
  3. digits.py +125 -0
  4. inference.py +10 -0
  5. model.py +18 -0
  6. requirements.txt +4 -0
  7. train.py +52 -0
  8. weights.pth +3 -0
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ data
2
+ __pycache__
app.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pygame, torch, cv2, numpy as np
2
+ from inference import predict
3
+
4
+ def draw_digi():
5
+ pygame.init()
6
+ window_size = 280
7
+ display_height = window_size+50
8
+ screen = pygame.display.set_mode((window_size,display_height))
9
+ pygame.display.set_caption("Draw a digit")
10
+ clock = pygame.time.Clock()
11
+ screen.fill((0,0,0))
12
+ drawing = False
13
+ prediction = None
14
+
15
+ font = pygame.font.Font(None,36)
16
+ while True:
17
+ # screen.fill((0,0,0))
18
+ for event in pygame.event.get():
19
+ if event.type == pygame.QUIT:
20
+ pygame.quit()
21
+ return
22
+ if event.type == pygame.MOUSEBUTTONDOWN:
23
+ drawing = True
24
+ if event.type == pygame.MOUSEBUTTONUP:
25
+ drawing = False
26
+ prediction = predict_digit(screen)
27
+ if event.type == pygame.KEYDOWN:
28
+ if event.key == pygame.K_c:
29
+ screen.fill((0,0,0))
30
+ prediction = None
31
+
32
+ if event.type == pygame.MOUSEMOTION and drawing:
33
+ pygame.draw.circle(screen,(255,255,255),event.pos,8)
34
+
35
+ if prediction is not None:
36
+ text = font.render(f"Prediction: {prediction}",True,(0,255,0))
37
+ screen.blit(text,(10,window_size+10))
38
+
39
+ pygame.display.flip()
40
+ clock.tick(60)
41
+
42
+ def process_drawing(screen):
43
+ surface = pygame.surfarray.array3d(screen)
44
+ gray = np.dot(surface[...,:3],[0.2989,0.5870,0.1140])
45
+ gray = np.transpose(gray,(1,0))
46
+ gray = cv2.resize(gray,(28,28),interpolation=cv2.INTER_AREA)
47
+ gray = gray.astype(np.float32)/255.0
48
+ gray = (gray - 0.5)/0.5
49
+ tensor = torch.tensor(gray,dtype=torch.float32).unsqueeze(0).unsqueeze(0)
50
+ return tensor
51
+ def predict_digit(screen):
52
+ image = process_drawing(screen)
53
+ if image is None:
54
+ return None
55
+ return predict(image)
56
+
57
+ draw_digi()
digits.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.optim as optim
4
+ import torchvision
5
+ import torchvision.transforms as transforms
6
+ from torch.utils.data import DataLoader
7
+ import pygame
8
+ import numpy as np
9
+ import cv2
10
+
11
+ class ANN(nn.Module):
12
+ def __init__(self):
13
+ super(ANN,self).__init__()
14
+ self.fc1 = nn.Linear(28*28,128)
15
+ self.fc2 = nn.Linear(128,128)
16
+ self.fc3 = nn.Linear(128,128)
17
+ self.fc4 = nn.Linear(128,10)
18
+ self.activation = nn.ReLU()
19
+ def forward(self,x):
20
+ x = x.view(-1,28*28)
21
+ x = self.activation(self.fc1(x))
22
+ x = self.activation(self.fc2(x))
23
+ x = self.activation(self.fc3(x))
24
+ x = self.fc4(x)
25
+ return x
26
+ # load dataset
27
+ transform = transforms.Compose([
28
+ transforms.ToTensor(),
29
+ transforms.Normalize((0.5,),(0.5,))]
30
+ )
31
+ trainset = torchvision.datasets.MNIST(root='./data',train=True,download=True,transform=transform)
32
+ testset = torchvision.datasets.MNIST(root='./data',train=False,download=True,transform=transform)
33
+
34
+ trainloader = DataLoader(trainset,batch_size=64,shuffle=True)
35
+ testloader = DataLoader(testset,batch_size=64,shuffle=False)
36
+
37
+ model = ANN()
38
+ los_fn = nn.CrossEntropyLoss()
39
+ optimizer = optim.Adam(model.parameters(),lr=0.001)
40
+
41
+ # training loop
42
+ episodes = 10
43
+
44
+
45
+ for epoch in range(episodes):
46
+ running_loss = 0.0
47
+ for images, labels in trainloader:
48
+ optimizer.zero_grad()
49
+ outputs = model(images)
50
+ loss = los_fn(outputs,labels)
51
+ loss.backward()
52
+ optimizer.step()
53
+ running_loss += loss.item()
54
+ print(f"Epoch {epoch+1}, Loss: {running_loss/len(trainloader)}")
55
+
56
+ # evaluation
57
+ correct = 0
58
+ total = 0
59
+ model.eval()
60
+ with torch.no_grad():
61
+ for images, labels in testloader:
62
+ outputs = model(images)
63
+ _, predicted = torch.max(outputs.data,1)
64
+ total += labels.size(0)
65
+ correct += (predicted == labels).sum().item()
66
+ print(f"Test Accuracy: {100 * correct / total}%")
67
+
68
+ def draw_digi():
69
+ pygame.init()
70
+ window_size = 280
71
+ display_height = window_size+50
72
+ screen = pygame.display.set_mode((window_size,display_height))
73
+ pygame.display.set_caption("Draw a digit")
74
+ clock = pygame.time.Clock()
75
+ screen.fill((0,0,0))
76
+ drawing = False
77
+ prediction = None
78
+
79
+ font = pygame.font.Font(None,36)
80
+ while True:
81
+ # screen.fill((0,0,0))
82
+ for event in pygame.event.get():
83
+ if event.type == pygame.QUIT:
84
+ pygame.quit()
85
+ return
86
+ if event.type == pygame.MOUSEBUTTONDOWN:
87
+ drawing = True
88
+ if event.type == pygame.MOUSEBUTTONUP:
89
+ drawing = False
90
+ prediction = predict_digit(screen)
91
+ if event.type == pygame.KEYDOWN:
92
+ if event.key == pygame.K_c:
93
+ screen.fill((0,0,0))
94
+ prediction = None
95
+
96
+ if event.type == pygame.MOUSEMOTION and drawing:
97
+ pygame.draw.circle(screen,(255,255,255),event.pos,8)
98
+
99
+ if prediction is not None:
100
+ text = font.render(f"Prediction: {prediction}",True,(0,255,0))
101
+ screen.blit(text,(10,window_size+10))
102
+
103
+ pygame.display.flip()
104
+ clock.tick(60)
105
+
106
+ def process_drawing(screen):
107
+ surface = pygame.surfarray.array3d(screen)
108
+ gray = np.dot(surface[...,:3],[0.2989,0.5870,0.1140])
109
+ gray = np.transpose(gray,(1,0))
110
+ gray = cv2.resize(gray,(28,28),interpolation=cv2.INTER_AREA)
111
+ gray = gray.astype(np.float32)/255.0
112
+ gray = (gray - 0.5)/0.5
113
+ tensor = torch.tensor(gray,dtype=torch.float32).unsqueeze(0).unsqueeze(0)
114
+ return tensor
115
+ def predict_digit(screen):
116
+ image = process_drawing(screen)
117
+ if image is None:
118
+ return None
119
+ model.eval()
120
+ with torch.no_grad():
121
+ output = model(image)
122
+ _, predicted = torch.max(output.data,1)
123
+ return predicted.item()
124
+
125
+ draw_digi()
inference.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from model import ANN
3
+
4
+ model = ANN()
5
+ model.load_state_dict(torch.load("weights.pth", map_location="cpu"))
6
+ model.eval()
7
+
8
+ def predict(image_tensor):
9
+ with torch.no_grad():
10
+ return model(image_tensor).argmax(1).item()
model.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch.nn as nn
2
+
3
+ class ANN(nn.Module):
4
+ def __init__(self):
5
+ super().__init__()
6
+ self.fc1 = nn.Linear(28*28,128)
7
+ self.fc2 = nn.Linear(128,128)
8
+ self.fc3 = nn.Linear(128,128)
9
+ self.fc4 = nn.Linear(128,10)
10
+ self.relu = nn.ReLU()
11
+
12
+ def forward(self,x):
13
+ x = x.view(-1,28*28)
14
+ x = self.relu(self.fc1(x))
15
+ x = self.relu(self.fc2(x))
16
+ x = self.relu(self.fc3(x))
17
+ x = self.relu(self.fc4(x))
18
+ return x
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ torch
2
+ numpy
3
+ pygame
4
+ opencv-python
train.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.optim as optim
4
+ import torchvision
5
+ import torchvision.transforms as transforms
6
+ from torch.utils.data import DataLoader
7
+ from model import ANN
8
+
9
+ transform = transforms.Compose([
10
+ transforms.ToTensor(),
11
+ transforms.Normalize((0.5,),(0.5,))
12
+ ])
13
+
14
+ trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
15
+ testset = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)
16
+
17
+ trainloader = DataLoader(trainset, batch_size=64, shuffle=True)
18
+ testloader = DataLoader(testset, batch_size=64, shuffle=False)
19
+
20
+ model = ANN()
21
+ los_fn = nn.CrossEntropyLoss()
22
+ optimizer = optim.Adam(model.parameters(), lr=0.001)
23
+
24
+ # training loop
25
+ episodes = 10
26
+
27
+
28
+ for epoch in range(episodes):
29
+ running_loss = 0.0
30
+ for images, labels in trainloader:
31
+ optimizer.zero_grad()
32
+ outputs = model(images)
33
+ loss = los_fn(outputs,labels)
34
+ loss.backward()
35
+ optimizer.step()
36
+ running_loss += loss.item()
37
+ print(f"Epoch {epoch+1}, Loss: {running_loss/len(trainloader)}")
38
+
39
+ # evaluation
40
+ correct = 0
41
+ total = 0
42
+ model.eval()
43
+ with torch.no_grad():
44
+ for images, labels in testloader:
45
+ outputs = model(images)
46
+ _, predicted = torch.max(outputs.data,1)
47
+ total += labels.size(0)
48
+ correct += (predicted == labels).sum().item()
49
+ print(f"Test Accuracy: {100 * correct / total}%")
50
+
51
+ torch.save(model.state_dict(), "weights.pth")
52
+ print("weights saved")
weights.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7e84878aaa5df761b8e3abe83422f165c807f56feb612edf0091b7bbf43f40e5
3
+ size 542221