Krippa commited on
Commit
3a2b1aa
·
verified ·
1 Parent(s): f8d3653

Deploying CNN App (clean)

Browse files
.dockerignore ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ __pycache__
2
+ .git
3
+ .venv
4
+ .env
5
+ *.pyc
6
+ *.pyo
7
+ *.pyd
8
+ .DS_Store
9
+ MNIST/
Dockerfile ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9
2
+
3
+ WORKDIR /app
4
+
5
+ COPY requirements.txt requirements.txt
6
+ RUN pip install --no-cache-dir -r requirements.txt
7
+
8
+ COPY . .
9
+
10
+ # Create uploads directory and set permissions for potentially non-root user
11
+ RUN mkdir -p uploads && chmod 777 uploads
12
+
13
+ EXPOSE 7860
14
+
15
+ CMD ["flask", "run", "--host=0.0.0.0", "--port=7860"]
README.md CHANGED
@@ -1,10 +1,30 @@
1
- ---
2
- title: CNN CIFAR10 Classifier
3
- emoji: 🐢
4
- colorFrom: gray
5
- colorTo: green
6
- sdk: docker
7
- pinned: false
8
- ---
9
-
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: CNN Cifar10 Classifier
3
+ emoji: 🚀
4
+ colorFrom: blue
5
+ colorTo: indigo
6
+ sdk: docker
7
+ pinned: false
8
+ license: mit
9
+ ---
10
+ # CNN Image Classification
11
+
12
+ This project implements a Convolutional Neural Network (CNN) to classify images from the CIFAR-10 dataset using PyTorch.
13
+
14
+
15
+ ## Structure
16
+
17
+ - `src/`: Source code for the model and data processing.
18
+ - `main.py`: Entry point for training and evaluation.
19
+
20
+ ## Usage
21
+
22
+ 1. Install dependencies:
23
+ ```bash
24
+ pip install -r requirements.txt
25
+ ```
26
+
27
+ 2. Run the training pipeline:
28
+ ```bash
29
+ python main.py
30
+ ```
app.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os
3
+ import torch
4
+ import torchvision.transforms as transforms
5
+ from flask import Flask, request, render_template, redirect, url_for
6
+ from PIL import Image
7
+ from src.model import create_model
8
+
9
+ app = Flask(__name__)
10
+ UPLOAD_FOLDER = 'uploads'
11
+ if not os.path.exists(UPLOAD_FOLDER):
12
+ os.makedirs(UPLOAD_FOLDER)
13
+ app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
14
+
15
+ # Load Model
16
+ device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
17
+ model = create_model()
18
+ model.load_state_dict(torch.load('models/cifar10_cnn.pth', map_location=device))
19
+ model.to(device)
20
+ model.eval()
21
+
22
+ # Classes
23
+ CLASSES = ('plane', 'car', 'bird', 'cat',
24
+ 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
25
+
26
+ def transform_image(image_path):
27
+ transform = transforms.Compose([
28
+ transforms.Resize((32, 32)),
29
+ transforms.ToTensor(),
30
+ transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
31
+ ])
32
+ image = Image.open(image_path)
33
+ return transform(image).unsqueeze(0).to(device)
34
+
35
+ @app.route('/', methods=['GET', 'POST'])
36
+ def index():
37
+ if request.method == 'POST':
38
+ if 'file' not in request.files:
39
+ return redirect(request.url)
40
+ file = request.files['file']
41
+ if file.filename == '':
42
+ return redirect(request.url)
43
+ if file:
44
+ file_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
45
+ file.save(file_path)
46
+
47
+ # Predict
48
+ input_tensor = transform_image(file_path)
49
+ with torch.no_grad():
50
+ output = model(input_tensor)
51
+ _, predicted = torch.max(output, 1)
52
+ predicted_class = CLASSES[predicted.item()]
53
+
54
+ return render_template('index.html', prediction=predicted_class, image_path=file_path)
55
+ return render_template('index.html', prediction=None, image_path=None)
56
+
57
+ if __name__ == '__main__':
58
+ app.run(debug=True)
deploy_to_hf.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from huggingface_hub import HfApi, create_repo
2
+ import os
3
+
4
+ def deploy():
5
+ api = HfApi()
6
+ username = api.whoami()["name"]
7
+ repo_name = "CNN-CIFAR10-Classifier"
8
+ repo_id = f"{username}/{repo_name}"
9
+
10
+ print(f"Deploying to Space: {repo_id}")
11
+
12
+ # Clean up existing repo to free quota
13
+ try:
14
+ from huggingface_hub import delete_repo
15
+ print("Deleting existing repository to ensure clean state...")
16
+ delete_repo(repo_id, repo_type="space")
17
+ print("Repository deleted.")
18
+ except Exception as e:
19
+ print(f"Repository deletion skipped or failed (might not exist): {e}")
20
+
21
+ # Create the Space
22
+ try:
23
+ create_repo(repo_id, repo_type="space", space_sdk="docker", private=False)
24
+ print("Space repository created.")
25
+ except Exception as e:
26
+ print(f"Creation error: {e}")
27
+
28
+ # Determine ignore patterns
29
+ ignore_patterns = [
30
+ ".git*",
31
+ ".venv*",
32
+ "__pycache__*",
33
+ "*.pyc",
34
+ ".DS_Store",
35
+ "data/*", # Exclude dataset
36
+ "MNIST/*", # Exclude unrelated folder
37
+ "uploads/*" # Exclude user uploads
38
+ ]
39
+
40
+ print("Uploading files...")
41
+ api.upload_folder(
42
+ folder_path=".",
43
+ repo_id=repo_id,
44
+ repo_type="space",
45
+ ignore_patterns=ignore_patterns,
46
+ commit_message="Deploying CNN App (clean)"
47
+ )
48
+ print(f"Successfully uploaded files to https://huggingface.co/spaces/{repo_id}")
49
+
50
+ if __name__ == "__main__":
51
+ deploy()
main.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from src.data_loader import load_data
3
+ from src.model import create_model
4
+ from src.train import train_model
5
+ from src.evaluate import evaluate_model
6
+ import torch
7
+ import os
8
+
9
+ def main():
10
+ print("Starting CNN CIFAR-10 Project (PyTorch)...")
11
+
12
+ # Load Data
13
+ print("Loading data...")
14
+ trainloader, testloader, classes = load_data()
15
+ print(f"Data loaded: Train batches {len(trainloader)}, Test batches {len(testloader)}")
16
+
17
+ # Create Model
18
+ print("Creating model...")
19
+ model = create_model()
20
+ # print(model)
21
+
22
+ # Train Model
23
+ print("Training model...")
24
+ # Using 1 epoch for verification
25
+ history = train_model(model, trainloader, testloader, epochs=10)
26
+
27
+ # Evaluate Model
28
+ print("Evaluating model...")
29
+ accuracy = evaluate_model(model, testloader)
30
+ print(f"Test Accuracy: {accuracy:.4f}")
31
+
32
+ # Save Model
33
+ if not os.path.exists('models'):
34
+ os.makedirs('models')
35
+ torch.save(model.state_dict(), 'models/cifar10_cnn.pth')
36
+ print("Model saved to models/cifar10_cnn.pth")
37
+
38
+ if __name__ == "__main__":
39
+ main()
models/cifar10_cnn.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c285a2b53075ba6ba234c5eed862d68c3bc602e21597acce4104d16ae3497dd7
3
+ size 2208203
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ torch
2
+ torchvision
3
+ numpy
4
+ matplotlib
5
+ scikit-learn
6
+ flask
7
+ pillow
src/__init__.py ADDED
File without changes
src/data_loader.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import torch
3
+ import torchvision
4
+ import torchvision.transforms as transforms
5
+
6
+ def load_data(batch_size=64):
7
+ """
8
+ Loads and preprocesses the CIFAR-10 dataset using PyTorch.
9
+
10
+ Returns:
11
+ tuple: (trainloader, testloader)
12
+ """
13
+ transform = transforms.Compose(
14
+ [transforms.ToTensor(),
15
+ transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
16
+
17
+ trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
18
+ download=True, transform=transform)
19
+ trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size,
20
+ shuffle=True, num_workers=0)
21
+
22
+ testset = torchvision.datasets.CIFAR10(root='./data', train=False,
23
+ download=True, transform=transform)
24
+ testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size,
25
+ shuffle=False, num_workers=0)
26
+
27
+ classes = ('plane', 'car', 'bird', 'cat',
28
+ 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
29
+
30
+ return trainloader, testloader, classes
src/evaluate.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import torch
3
+
4
+ def evaluate_model(model, testloader):
5
+ """
6
+ Evaluates the model on the test set.
7
+ """
8
+ correct = 0
9
+ total = 0
10
+ device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
11
+ model.to(device)
12
+ model.eval()
13
+
14
+ with torch.no_grad():
15
+ for data in testloader:
16
+ images, labels = data[0].to(device), data[1].to(device)
17
+ outputs = model(images)
18
+ _, predicted = torch.max(outputs.data, 1)
19
+ total += labels.size(0)
20
+ correct += (predicted == labels).sum().item()
21
+
22
+ accuracy = correct / total
23
+ return accuracy
src/model.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import torch
3
+ import torch.nn as nn
4
+ import torch.nn.functional as F
5
+
6
+ class Net(nn.Module):
7
+ def __init__(self):
8
+ super(Net, self).__init__()
9
+ # First Conv Block
10
+ self.conv1_1 = nn.Conv2d(3, 32, 3, padding=1)
11
+ self.conv1_2 = nn.Conv2d(32, 32, 3, padding=1)
12
+ self.pool = nn.MaxPool2d(2, 2)
13
+ self.dropout1 = nn.Dropout(0.2)
14
+
15
+ # Second Conv Block
16
+ self.conv2_1 = nn.Conv2d(32, 64, 3, padding=1)
17
+ self.conv2_2 = nn.Conv2d(64, 64, 3, padding=1)
18
+ self.dropout2 = nn.Dropout(0.3)
19
+
20
+ # Third Conv Block
21
+ self.conv3_1 = nn.Conv2d(64, 128, 3, padding=1)
22
+ self.conv3_2 = nn.Conv2d(128, 128, 3, padding=1)
23
+ self.dropout3 = nn.Dropout(0.4)
24
+
25
+ # Dense Layers
26
+ self.fc1 = nn.Linear(128 * 4 * 4, 128)
27
+ self.dropout4 = nn.Dropout(0.5)
28
+ self.fc2 = nn.Linear(128, 10)
29
+
30
+ def forward(self, x):
31
+ # Block 1
32
+ x = F.relu(self.conv1_1(x))
33
+ x = F.relu(self.conv1_2(x))
34
+ x = self.pool(x)
35
+ x = self.dropout1(x)
36
+
37
+ # Block 2
38
+ x = F.relu(self.conv2_1(x))
39
+ x = F.relu(self.conv2_2(x))
40
+ x = self.pool(x)
41
+ x = self.dropout2(x)
42
+
43
+ # Block 3
44
+ x = F.relu(self.conv3_1(x))
45
+ x = F.relu(self.conv3_2(x))
46
+ x = self.pool(x)
47
+ x = self.dropout3(x)
48
+
49
+ # Flatten
50
+ x = x.view(-1, 128 * 4 * 4)
51
+
52
+ # Dense
53
+ x = F.relu(self.fc1(x))
54
+ x = self.dropout4(x)
55
+ x = self.fc2(x)
56
+ return x
57
+
58
+ def create_model():
59
+ return Net()
src/train.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import torch
3
+ import torch.optim as optim
4
+ import torch.nn as nn
5
+
6
+ def train_model(model, trainloader, testloader, epochs=10, learning_rate=0.001):
7
+ """
8
+ Trains the PyTorch model.
9
+ """
10
+ device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
11
+ print(f"Training on device: {device}")
12
+ model.to(device)
13
+
14
+ criterion = nn.CrossEntropyLoss()
15
+ optimizer = optim.Adam(model.parameters(), lr=learning_rate)
16
+
17
+ history = {'accuracy': [], 'loss': []}
18
+
19
+ for epoch in range(epochs):
20
+ running_loss = 0.0
21
+ correct = 0
22
+ total = 0
23
+
24
+ model.train()
25
+ for i, data in enumerate(trainloader, 0):
26
+ inputs, labels = data[0].to(device), data[1].to(device)
27
+
28
+ optimizer.zero_grad()
29
+
30
+ outputs = model(inputs)
31
+ loss = criterion(outputs, labels)
32
+ loss.backward()
33
+ optimizer.step()
34
+
35
+ running_loss += loss.item()
36
+ _, predicted = torch.max(outputs.data, 1)
37
+ total += labels.size(0)
38
+ correct += (predicted == labels).sum().item()
39
+
40
+ epoch_loss = running_loss / len(trainloader)
41
+ epoch_acc = correct / total
42
+ history['loss'].append(epoch_loss)
43
+ history['accuracy'].append(epoch_acc)
44
+
45
+ print(f'Epoch {epoch + 1}/{epochs} - Loss: {epoch_loss:.4f} - Accuracy: {epoch_acc:.4f}')
46
+
47
+ print('Finished Training')
48
+ return history
templates/index.html ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>CIFAR-10 Classifier</title>
8
+ <style>
9
+ body {
10
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
11
+ background-color: #f4f4f9;
12
+ color: #333;
13
+ display: flex;
14
+ flex-direction: column;
15
+ align-items: center;
16
+ justify-content: center;
17
+ height: 100vh;
18
+ margin: 0;
19
+ }
20
+ h1 {
21
+ color: #4a90e2;
22
+ }
23
+ .container {
24
+ background: white;
25
+ padding: 2rem;
26
+ border-radius: 10px;
27
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
28
+ text-align: center;
29
+ }
30
+ input[type="file"] {
31
+ margin: 1rem 0;
32
+ }
33
+ button {
34
+ background-color: #4a90e2;
35
+ color: white;
36
+ border: none;
37
+ padding: 10px 20px;
38
+ border-radius: 5px;
39
+ cursor: pointer;
40
+ font-size: 1rem;
41
+ }
42
+ button:hover {
43
+ background-color: #357abd;
44
+ }
45
+ .result {
46
+ margin-top: 2rem;
47
+ font-size: 1.2rem;
48
+ font-weight: bold;
49
+ }
50
+ </style>
51
+ </head>
52
+ <body>
53
+ <div class="container">
54
+ <h1>CIFAR-10 Image Classifier</h1>
55
+ <form method="post" enctype="multipart/form-data">
56
+ <input type="file" name="file" accept="image/*" required>
57
+ <br>
58
+ <button type="submit">Classify Image</button>
59
+ </form>
60
+
61
+ {% if prediction %}
62
+ <div class="result">
63
+ <p>Prediction: <span style="color: #e74c3c;">{{ prediction }}</span></p>
64
+ </div>
65
+ {% endif %}
66
+ </div>
67
+ </body>
68
+ </html>