changes in structure
Browse files- README.md +3 -1
- config.json +5 -0
- scripts/evaluate.py +2 -2
- scripts/train.py +1 -1
- symmetric_test/evaluate.py +22 -23
- symmetric_test/model.py +5 -6
- symmetric_test/train.py +27 -19
README.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
| 1 |
---
|
|
|
|
| 2 |
tags:
|
| 3 |
- image-classification
|
| 4 |
- mnist
|
| 5 |
- pytorch
|
| 6 |
-
license:
|
|
|
|
| 7 |
---
|
| 8 |
|
| 9 |
# MNIST Digit Classifier
|
|
|
|
| 1 |
---
|
| 2 |
+
library_name: pytorch
|
| 3 |
tags:
|
| 4 |
- image-classification
|
| 5 |
- mnist
|
| 6 |
- pytorch
|
| 7 |
+
license: apache-2.0
|
| 8 |
+
pipeline_tag: image-classification
|
| 9 |
---
|
| 10 |
|
| 11 |
# MNIST Digit Classifier
|
config.json
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": ["DigitClassifier"],
|
| 3 |
+
"model_type": "pytorch",
|
| 4 |
+
"num_labels": 10
|
| 5 |
+
}
|
scripts/evaluate.py
CHANGED
|
@@ -4,6 +4,6 @@ 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()
|
|
|
|
| 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
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
from symmetric_test.train import train
|
| 2 |
|
| 3 |
if __name__ == "__main__":
|
| 4 |
-
train()
|
|
|
|
| 1 |
from symmetric_test.train import train
|
| 2 |
|
| 3 |
if __name__ == "__main__":
|
| 4 |
+
train()
|
symmetric_test/evaluate.py
CHANGED
|
@@ -8,34 +8,31 @@ 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 |
-
|
| 26 |
-
])
|
| 27 |
test_set = datasets.MNIST(
|
| 28 |
-
root=
|
| 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)
|
|
@@ -43,38 +40,40 @@ def evaluate_model(model_path="model_weights.pth", output_dir="results"):
|
|
| 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(
|
| 51 |
-
|
|
|
|
|
|
|
| 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=
|
| 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 |
-
|
|
|
|
| 8 |
from huggingface_hub import HfApi
|
| 9 |
from .model import DigitClassifier
|
| 10 |
|
| 11 |
+
|
| 12 |
def evaluate_model(model_path="model_weights.pth", output_dir="results"):
|
| 13 |
# Setup
|
| 14 |
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
| 15 |
Path(output_dir).mkdir(exist_ok=True)
|
| 16 |
+
|
| 17 |
# Load model
|
| 18 |
model = DigitClassifier()
|
| 19 |
model.load_state_dict(torch.load(model_path))
|
| 20 |
model.to(device)
|
| 21 |
model.eval()
|
| 22 |
+
|
| 23 |
# Data (MNIST Test Set)
|
| 24 |
+
transform = transforms.Compose(
|
| 25 |
+
[transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]
|
| 26 |
+
)
|
|
|
|
| 27 |
test_set = datasets.MNIST(
|
| 28 |
+
root="./data", train=False, download=True, transform=transform
|
|
|
|
|
|
|
|
|
|
| 29 |
)
|
| 30 |
test_loader = torch.utils.data.DataLoader(test_set, batch_size=64, shuffle=False)
|
| 31 |
+
|
| 32 |
# Evaluation
|
| 33 |
all_preds = []
|
| 34 |
all_targets = []
|
| 35 |
+
|
| 36 |
with torch.no_grad():
|
| 37 |
for images, labels in test_loader:
|
| 38 |
images = images.to(device)
|
|
|
|
| 40 |
_, preds = torch.max(outputs, 1)
|
| 41 |
all_preds.extend(preds.cpu().numpy())
|
| 42 |
all_targets.extend(labels.cpu().numpy())
|
| 43 |
+
|
| 44 |
# Metrics
|
| 45 |
metrics = {
|
| 46 |
"accuracy": np.mean(np.array(all_preds) == np.array(all_targets)),
|
| 47 |
+
"classification_report": classification_report(
|
| 48 |
+
all_targets, all_preds, output_dict=True
|
| 49 |
+
),
|
| 50 |
+
"confusion_matrix": confusion_matrix(all_targets, all_preds).tolist(),
|
| 51 |
}
|
| 52 |
+
|
| 53 |
# Save metrics
|
| 54 |
+
with open(Path(output_dir) / "metrics.json", "w") as f:
|
| 55 |
json.dump(metrics, f, indent=2)
|
| 56 |
+
|
| 57 |
# Plot confusion matrix
|
| 58 |
plt.figure(figsize=(10, 8))
|
| 59 |
+
plt.imshow(metrics["confusion_matrix"], cmap="Blues")
|
| 60 |
plt.colorbar()
|
| 61 |
plt.title("Confusion Matrix")
|
| 62 |
plt.xlabel("Predicted")
|
| 63 |
plt.ylabel("True")
|
| 64 |
plt.xticks(range(10))
|
| 65 |
plt.yticks(range(10))
|
| 66 |
+
plt.savefig(Path(output_dir) / "confusion_matrix.png")
|
| 67 |
plt.close()
|
| 68 |
+
|
| 69 |
return metrics
|
| 70 |
|
| 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 |
)
|
|
|
symmetric_test/model.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
import torch.nn as nn
|
| 2 |
|
|
|
|
| 3 |
class DigitClassifier(nn.Module):
|
| 4 |
def __init__(self):
|
| 5 |
super().__init__()
|
|
@@ -9,15 +10,13 @@ class DigitClassifier(nn.Module):
|
|
| 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)
|
|
|
|
| 1 |
import torch.nn as nn
|
| 2 |
|
| 3 |
+
|
| 4 |
class DigitClassifier(nn.Module):
|
| 5 |
def __init__(self):
|
| 6 |
super().__init__()
|
|
|
|
| 10 |
nn.MaxPool2d(2),
|
| 11 |
nn.Conv2d(32, 64, 3),
|
| 12 |
nn.ReLU(),
|
| 13 |
+
nn.MaxPool2d(2),
|
| 14 |
)
|
| 15 |
self.classifier = nn.Sequential(
|
| 16 |
+
nn.Linear(64 * 5 * 5, 128), nn.ReLU(), nn.Linear(128, 10)
|
|
|
|
|
|
|
| 17 |
)
|
| 18 |
+
|
| 19 |
def forward(self, x):
|
| 20 |
x = self.conv_block(x)
|
| 21 |
x = x.view(x.size(0), -1)
|
| 22 |
+
return self.classifier(x)
|
symmetric_test/train.py
CHANGED
|
@@ -10,24 +10,24 @@ 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 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
train_loader = torch.utils.data.DataLoader(
|
| 26 |
-
datasets.MNIST(
|
| 27 |
batch_size=BATCH_SIZE,
|
| 28 |
-
shuffle=True
|
| 29 |
)
|
| 30 |
-
|
| 31 |
# Training loop
|
| 32 |
for epoch in range(EPOCHS):
|
| 33 |
model.train()
|
|
@@ -37,16 +37,24 @@ def train():
|
|
| 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 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
EPOCHS = 5
|
| 11 |
LR = 0.001
|
| 12 |
|
| 13 |
+
|
| 14 |
def train():
|
| 15 |
# Initialize
|
| 16 |
model = DigitClassifier()
|
| 17 |
optimizer = optim.Adam(model.parameters(), lr=LR)
|
| 18 |
criterion = nn.CrossEntropyLoss()
|
| 19 |
+
|
| 20 |
# Data
|
| 21 |
+
transform = transforms.Compose(
|
| 22 |
+
[transforms.ToTensor(), 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()
|
|
|
|
| 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 |
+
torch.save(model, "pytorch_model.bin") # Standard HF naming
|
| 44 |
+
|
| 45 |
# Upload to Hub
|
| 46 |
+
api = HfApi()
|
| 47 |
+
api.upload_file(
|
| 48 |
+
path_or_fileobj="model_weights.pth",
|
| 49 |
+
path_in_repo="model_weights.pth",
|
| 50 |
+
repo_id="SupremoUGH/symmetric_test",
|
| 51 |
+
repo_type="model",
|
| 52 |
+
token=True, # Explicitly use your credentials
|
| 53 |
+
)
|
| 54 |
+
api.upload_file(
|
| 55 |
+
path_or_fileobj="pytorch_model.bin",
|
| 56 |
+
path_in_repo="pytorch_model.bin",
|
| 57 |
+
repo_id="SupremoUGH/symmetric_test",
|
| 58 |
+
repo_type="model",
|
| 59 |
+
token=True, # Explicitly use your credentials
|
| 60 |
+
)
|