SupremoUGH commited on
Commit
f617b01
·
unverified ·
1 Parent(s): aa4ef04
.gitignore ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # Training data
2
+ data
3
+ # Results (this is where the model stats are saved)
4
+ results
5
+ # Model weights
6
+ model_weights.pth
7
+ # Python metadata
8
+ venv
9
+ __pycache__
10
+ symmetric_test.egg-info
README.md CHANGED
@@ -1,3 +1,30 @@
1
  ---
 
 
 
 
2
  license: mit
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ tags:
3
+ - image-classification
4
+ - mnist
5
+ - pytorch
6
  license: mit
7
  ---
8
+
9
+ # MNIST Digit Classifier
10
+
11
+ A convolutional neural network trained on MNIST to classify digits 0-9.
12
+
13
+ ## Usage
14
+
15
+ ```python
16
+ from src.model import DigitClassifier
17
+ import torch
18
+
19
+ model = DigitClassifier()
20
+ model.load_state_dict(torch.load("model_weights.pth"))
21
+ model.eval()
22
+
23
+ # Preprocessing (same as training):
24
+ transform = transforms.Compose([
25
+ transforms.Resize((28, 28)),
26
+ transforms.Grayscale(),
27
+ transforms.ToTensor(),
28
+ transforms.Normalize((0.1307,), (0.3081,))
29
+ ])
30
+ ```
pyproject.toml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [build-system]
2
+ requires = ["setuptools", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "symmetric_test"
7
+ version = "0.1.0"
8
+ description = "Classifies images of numbers from 0-9"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ authors = [
12
+ { name = "SupremoUGH" }
13
+ ]
14
+ license = { text = "MIT License" }
15
+ dependencies = [] # Add dependencies here if needed
16
+
17
+ [project.urls]
18
+ Homepage = "https://huggingface.co/SupremoUGH/symmetric_test"
19
+
20
+ [tool.setuptools.packages.find]
21
+ include = ["symmetric_test"] # Ensure it finds the correct package
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ torch>=2.0.1
2
+ torchvision>=0.15.2
3
+ huggingface_hub>=0.16.4
scripts/evaluate.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ from symmetric_test.evaluate import evaluate_model, upload_results
2
+
3
+ if __name__ == "__main__":
4
+ # Evaluate
5
+ metrics = evaluate_model()
6
+ print(f"Test Accuracy: {metrics['accuracy']:.2%}")
7
+
8
+ # Upload results to Hub
9
+ upload_results()
scripts/train.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from symmetric_test.train import train
2
+
3
+ if __name__ == "__main__":
4
+ train()
symmetric_test/__init__.py ADDED
File without changes
symmetric_test/evaluate.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import numpy as np
3
+ from torchvision import datasets, transforms
4
+ from sklearn.metrics import classification_report, confusion_matrix
5
+ import matplotlib.pyplot as plt
6
+ import json
7
+ from pathlib import Path
8
+ from huggingface_hub import HfApi
9
+ from .model import DigitClassifier
10
+
11
+ def evaluate_model(model_path="model_weights.pth", output_dir="results"):
12
+ # Setup
13
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
14
+ Path(output_dir).mkdir(exist_ok=True)
15
+
16
+ # Load model
17
+ model = DigitClassifier()
18
+ model.load_state_dict(torch.load(model_path))
19
+ model.to(device)
20
+ model.eval()
21
+
22
+ # Data (MNIST Test Set)
23
+ transform = transforms.Compose([
24
+ transforms.ToTensor(),
25
+ transforms.Normalize((0.1307,), (0.3081,))
26
+ ])
27
+ test_set = datasets.MNIST(
28
+ root='./data',
29
+ train=False,
30
+ download=True,
31
+ transform=transform
32
+ )
33
+ test_loader = torch.utils.data.DataLoader(test_set, batch_size=64, shuffle=False)
34
+
35
+ # Evaluation
36
+ all_preds = []
37
+ all_targets = []
38
+
39
+ with torch.no_grad():
40
+ for images, labels in test_loader:
41
+ images = images.to(device)
42
+ outputs = model(images)
43
+ _, preds = torch.max(outputs, 1)
44
+ all_preds.extend(preds.cpu().numpy())
45
+ all_targets.extend(labels.cpu().numpy())
46
+
47
+ # Metrics
48
+ metrics = {
49
+ "accuracy": np.mean(np.array(all_preds) == np.array(all_targets)),
50
+ "classification_report": classification_report(all_targets, all_preds, output_dict=True),
51
+ "confusion_matrix": confusion_matrix(all_targets, all_preds).tolist()
52
+ }
53
+
54
+ # Save metrics
55
+ with open(Path(output_dir)/"metrics.json", "w") as f:
56
+ json.dump(metrics, f, indent=2)
57
+
58
+ # Plot confusion matrix
59
+ plt.figure(figsize=(10, 8))
60
+ plt.imshow(metrics["confusion_matrix"], cmap='Blues')
61
+ plt.colorbar()
62
+ plt.title("Confusion Matrix")
63
+ plt.xlabel("Predicted")
64
+ plt.ylabel("True")
65
+ plt.xticks(range(10))
66
+ plt.yticks(range(10))
67
+ plt.savefig(Path(output_dir)/"confusion_matrix.png")
68
+ plt.close()
69
+
70
+ return metrics
71
+
72
+ def upload_results(repo_id="SupremoUGH/symmetric_test"):
73
+ api = HfApi()
74
+ api.upload_folder(
75
+ folder_path="results",
76
+ path_in_repo="evaluation",
77
+ repo_id=repo_id,
78
+ repo_type="model"
79
+ )
80
+
symmetric_test/model.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch.nn as nn
2
+
3
+ class DigitClassifier(nn.Module):
4
+ def __init__(self):
5
+ super().__init__()
6
+ self.conv_block = nn.Sequential(
7
+ nn.Conv2d(1, 32, 3),
8
+ nn.ReLU(),
9
+ nn.MaxPool2d(2),
10
+ nn.Conv2d(32, 64, 3),
11
+ nn.ReLU(),
12
+ nn.MaxPool2d(2)
13
+ )
14
+ self.classifier = nn.Sequential(
15
+ nn.Linear(64*5*5, 128),
16
+ nn.ReLU(),
17
+ nn.Linear(128, 10)
18
+ )
19
+
20
+ def forward(self, x):
21
+ x = self.conv_block(x)
22
+ x = x.view(x.size(0), -1)
23
+ return self.classifier(x)
symmetric_test/train.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ from torch import optim
4
+ from torchvision import datasets, transforms
5
+ from huggingface_hub import HfApi, Repository
6
+ from .model import DigitClassifier
7
+
8
+ # Config (better to put in separate config.yaml)
9
+ BATCH_SIZE = 64
10
+ EPOCHS = 5
11
+ LR = 0.001
12
+
13
+ def train():
14
+ # Initialize
15
+ model = DigitClassifier()
16
+ optimizer = optim.Adam(model.parameters(), lr=LR)
17
+ criterion = nn.CrossEntropyLoss()
18
+
19
+ # Data
20
+ transform = transforms.Compose([
21
+ transforms.ToTensor(),
22
+ transforms.Normalize((0.1307,), (0.3081,))
23
+ ])
24
+
25
+ train_loader = torch.utils.data.DataLoader(
26
+ datasets.MNIST('./data', train=True, download=True, transform=transform),
27
+ batch_size=BATCH_SIZE,
28
+ shuffle=True
29
+ )
30
+
31
+ # Training loop
32
+ for epoch in range(EPOCHS):
33
+ model.train()
34
+ for batch_idx, (data, target) in enumerate(train_loader):
35
+ optimizer.zero_grad()
36
+ output = model(data)
37
+ loss = criterion(output, target)
38
+ loss.backward()
39
+ optimizer.step()
40
+
41
+ # Save artifacts
42
+ torch.save(model.state_dict(), "model_weights.pth")
43
+
44
+ # Upload to Hub
45
+ api = HfApi()
46
+ api.upload_file(
47
+ path_or_fileobj="model_weights.pth",
48
+ path_in_repo="model_weights.pth",
49
+ repo_id="SupremoUGH/symmetric_test",
50
+ repo_type="model",
51
+ token=True # Explicitly use your credentials
52
+ )