Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions Domains/AI-ML/MiniProjects/digit_recognizer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
MNIST DIGIT CLASSIFIER

**Contributor:** Dhiraj201226
**Domain:** AI-ML
**Difficulty:** [Beginner]

## Description
It's a complete machine learning project, written in Python using the PyTorch library. Its entire purpose is to look at a small, grayscale image of a handwritten number and correctly identify what number it is (from 0 to 9 currently).

This project solves the fundamental problem of automatic image classification.

Specifically, it provides an automated solution to the real-world challenge of Optical Character Recognition (OCR) for digits. This is a classic problem in computer vision.

## Dataset
- **Source**: Automatically via torchvision.datasets.MNIST(..., download=True), which automatically downloads the dataset from official mirrors (like one hosted on AWS S3).

- **Size**: 70000 images

- **Features**: Each image is 28*28 pixel grayscale image
and it is flattened into a 1-dimensional vector of 784 features (28 * 28 = 784).

## Model Architecture
- Algorithm/Architecture used:
Simple Feed-Forward Neural Network (MLP) built with PyTorch (nn.Module). It has one hidden layer: Input (784 features) -> Linear(784 -> 512) -> ReLU -> Linear(512 -> 10) -> Output Scores.

KEY HYPERPARAMETERS

->INPUT_SIZE: 784
->NUM_CLASSES: 10
->NUM_EPOCHS: 50
->BATCH_SIZE: 100
->LEARNING_RATE: 0.001

- Training approach
The model is trained on 50 epoches for better accuracy and also the 70k dataset is divided into 56k for training and 14k for test
dataset is traine on 56k immages.

## Requirements
matplotlib==3.9.0
numpy==1.26.4
packaging==24.1
pillow==10.4.0
torch==2.3.1+cpu
torchvision==0.18.1+cpu

# Train model
python train.py{
RUN model.py and config.py before it.
}

# Make predictions
python predict.py

## Results
- Accuracy: 99.76%(training dataset)
- Other metrics: final training loss:
- Sample outputs:In random infernece it predicted all images correct.
refer to Figure_1.png
## References
->Learning representations by back-propagating errors (1986) - Rumelhart, Hinton, Williams
->ImageNet Classification with Deep Convolutional Neural Networks (2012)- Krizhevsky, Sutskever, Hinton
Binary file not shown.
Binary file not shown.
20 changes: 20 additions & 0 deletions Domains/AI-ML/MiniProjects/digit_recognizer/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# config.py
import torch

# --- Model Hyperparameters ---
INPUT_SIZE = 784 # 28x28
HIDDEN_SIZE = 512
NUM_CLASSES = 10

# --- Training Hyperparameters ---
NUM_EPOCHS = 15
BATCH_SIZE = 100
LEARNING_RATE = 0.001
DATA_DIR = './data'
MODEL_PATH = 'mnist_nn1.pth'

# --- Data & Reproducibility ---
RANDOM_SEED = 42

# --- Device ---
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
15 changes: 15 additions & 0 deletions Domains/AI-ML/MiniProjects/digit_recognizer/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# model.py
import torch.nn as nn

class NeuralNetwork(nn.Module):
def __init__(self, input_size, hidden_size, num_classes):
super(NeuralNetwork, self).__init__()
self.l1 = nn.Linear(input_size, hidden_size)
self.relu = nn.ReLU()
self.l2 = nn.Linear(hidden_size, num_classes)

def forward(self, x):
out = self.l1(x)
out = self.relu(out)
out = self.l2(out)
return out
67 changes: 67 additions & 0 deletions Domains/AI-ML/MiniProjects/digit_recognizer/predict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# predict.py
import torch
import torchvision.transforms as transforms
from torchvision.datasets import MNIST
from torch.utils.data import DataLoader, random_split, ConcatDataset
import matplotlib.pyplot as plt

# Import from our custom files
from model import NeuralNetwork
import config as cfg

def get_test_batch():
torch.manual_seed(cfg.RANDOM_SEED)

transform = transforms.ToTensor()

# Load and split data exactly as in train.py
train_dataset = MNIST(root=cfg.DATA_DIR, train=True, transform=transform, download=True)
test_dataset = MNIST(root=cfg.DATA_DIR, train=False, transform=transform, download=True)
combined_dataset = ConcatDataset([train_dataset, test_dataset])
train_size = int(0.8 * len(combined_dataset))
test_size = len(combined_dataset) - train_size
_, test_dataset = random_split(combined_dataset, [train_size, test_size])

# Create the test loader
test_loader = DataLoader(test_dataset, batch_size=cfg.BATCH_SIZE, shuffle=False)

# Get one batch
examples = iter(test_loader)
example_data, example_targets = next(examples)

return example_data, example_targets

def main():
# --- 1. Load a batch of test data ---
example_data, example_targets = get_test_batch()

# --- 2. Initialize and Load Model ---
model = NeuralNetwork(cfg.INPUT_SIZE, cfg.HIDDEN_SIZE, cfg.NUM_CLASSES).to(cfg.DEVICE)
try:
model.load_state_dict(torch.load(cfg.MODEL_PATH, map_location=cfg.DEVICE))
except FileNotFoundError:
print(f"Error: Model file not found at {cfg.MODEL_PATH}")
print("Please run train.py first to train and save the model.")
return

model.eval()

# --- 3. Make Predictions ---
with torch.no_grad():
example_images = example_data.reshape(-1, 28 * 28).to(cfg.DEVICE)
outputs = model(example_images)
_, preds = torch.max(outputs.data, 1)

# --- 4. Visualize Predictions ---
print("Plotting predictions for 6 test images...")
plt.figure(figsize=(10, 4))
for i in range(6):
plt.subplot(2, 3, i + 1)
plt.imshow(example_data[i][0], cmap='gray')
plt.title(f'Actual: {example_targets[i].item()}, Predicted: {preds[i].item()}')
plt.axis('off')
plt.tight_layout()
plt.show()

if __name__ == "__main__":
main()
6 changes: 6 additions & 0 deletions Domains/AI-ML/MiniProjects/digit_recognizer/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
matplotlib==3.9.0
numpy==1.26.4
packaging==24.1
pillow==10.4.0
torch==2.3.1+cpu
torchvision==0.18.1+cpu
101 changes: 101 additions & 0 deletions Domains/AI-ML/MiniProjects/digit_recognizer/train.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# train.py
import torch
import torch.nn as nn
import torchvision.transforms as transforms
from torchvision.datasets import MNIST
from torch.utils.data import DataLoader, random_split, ConcatDataset

# Import from our custom files
from model import NeuralNetwork
import config as cfg

def get_data_loaders(batch_size, random_seed, data_dir):

torch.manual_seed(random_seed)

transform = transforms.ToTensor()

# Load original train and test datasets
train_dataset = MNIST(root=data_dir, train=True, transform=transform, download=True)
test_dataset = MNIST(root=data_dir, train=False, transform=transform, download=True)

# Combine them
combined_dataset = ConcatDataset([train_dataset, test_dataset])

# Create new 80/20 split
train_size = int(0.8 * len(combined_dataset))
test_size = len(combined_dataset) - train_size
train_dataset, test_dataset = random_split(combined_dataset, [train_size, test_size])

# Create DataLoaders
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

return train_loader, test_loader

def main():
# --- 1. Load Data ---
train_loader, test_loader = get_data_loaders(cfg.BATCH_SIZE, cfg.RANDOM_SEED, cfg.DATA_DIR)

# --- 2. Initialize Model, Loss, and Optimizer ---
model = NeuralNetwork(cfg.INPUT_SIZE, cfg.HIDDEN_SIZE, cfg.NUM_CLASSES).to(cfg.DEVICE)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=cfg.LEARNING_RATE)

# --- 3. Training Loop ---
print("Starting training...")
n_total_steps = len(train_loader)
for epoch in range(cfg.NUM_EPOCHS):
for i, (images, labels) in enumerate(train_loader):
# Reshape images to (batch_size, 784) and move to device
images = images.reshape(-1, 28 * 28).to(cfg.DEVICE)
labels = labels.to(cfg.DEVICE)

# Forward pass
predict_outputs = model(images)
loss = criterion(predict_outputs, labels)

# Backward pass and optimization
loss.backward()
optimizer.step()
optimizer.zero_grad()

if (i + 1) % 500 == 0:
print(f'Epoch [{epoch + 1}/{cfg.NUM_EPOCHS}], Step [{i + 1}/{n_total_steps}], Loss: {loss.item():.4f}')

print("Training finished.")

# --- 4. Evaluation ---
with torch.no_grad():
train_correct = 0
train_samples = 0
for images, labels in train_loader:
images = images.reshape(-1, 28 * 28).to(cfg.DEVICE)
labels = labels.to(cfg.DEVICE)
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
train_samples += labels.size(0)
train_correct += (predicted == labels).sum().item()

train_acc = 100.0 * train_correct / train_samples
print(f'Accuracy of the network on the {train_samples} training images: {train_acc:.2f} %')

test_correct = 0
test_samples = 0
for images, labels in test_loader:
images = images.reshape(-1, 28 * 28).to(cfg.DEVICE)
labels = labels.to(cfg.DEVICE)
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
test_samples += labels.size(0)
test_correct += (predicted == labels).sum().item()

test_acc = 100.0 * test_correct / test_samples
print(f'Accuracy of the network on the {test_samples} test images: {test_acc:.2f} %')

# --- 5. Save the Model ---
torch.save(model.state_dict(), cfg.MODEL_PATH)
print(f"Model saved to {cfg.MODEL_PATH}")

if __name__ == "__main__":
main()
8 changes: 0 additions & 8 deletions Domains/Frontend/MiniProjects/TodoApp/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@
</head>
<body>
<div class="container">
<!-- Header -->
<header class="header">
<h1>📝 My Todo List</h1>
<p class="subtitle">Stay organized, stay productive</p>
</header>

<!-- Input Section -->
<div class="input-section">
<input
type="text"
Expand All @@ -30,7 +28,6 @@ <h1>📝 My Todo List</h1>
</button>
</div>

<!-- Filter Section -->
<div class="filter-section">
<div class="filter-buttons">
<button class="filter-btn active" data-filter="all">All</button>
Expand All @@ -42,26 +39,21 @@ <h1>📝 My Todo List</h1>
</div>
</div>

<!-- Tasks List -->
<ul id="taskList" class="task-list">
<!-- Tasks will be dynamically added here -->
</ul>

<!-- Footer Actions -->
<div class="footer-actions">
<button id="clearCompleted" class="clear-btn">
Clear Completed
</button>
</div>

<!-- Empty State -->
<div id="emptyState" class="empty-state">
<div class="empty-icon">📋</div>
<p>No tasks yet. Add one above to get started!</p>
</div>
</div>

<!-- Footer -->
<footer class="app-footer">
<p>Made with ❤️ for ProjectHive | <a href="https://github.com" target="_blank">View on GitHub</a></p>
</footer>
Expand Down
Loading
Loading