Upload 11 files
Browse files- .gitignore +4 -0
- app.py +38 -0
- models/__pycache__/cnn.cpython-313.pyc +0 -0
- models/cnn.py +19 -0
- requirements.txt +5 -3
- saved_models/cnn_model.pth +3 -0
- train.py +77 -0
- utils/__pycache__/data_loader.cpython-313.pyc +0 -0
- utils/__pycache__/transforms.cpython-313.pyc +0 -0
- utils/metrics.py +5 -0
- utils/transforms.py +18 -0
.gitignore
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/data/
|
2 |
+
/models/model.pth
|
3 |
+
kaggle.json
|
4 |
+
*.zip
|
app.py
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from PIL import Image
|
3 |
+
import torch
|
4 |
+
from torchvision import transforms
|
5 |
+
from models.cnn import CNNModel
|
6 |
+
from utils.transforms import get_transforms
|
7 |
+
|
8 |
+
@st.cache_resource
|
9 |
+
def load_model(model_path='saved_models/cnn_model.pth'):
|
10 |
+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
11 |
+
checkpoint = torch.load(model_path, map_location=device)
|
12 |
+
class_names = checkpoint['class_names']
|
13 |
+
model = CNNModel(num_classes=len(class_names))
|
14 |
+
model.load_state_dict(checkpoint['model_state_dict'])
|
15 |
+
model.to(device)
|
16 |
+
model.eval()
|
17 |
+
return model, class_names, device
|
18 |
+
|
19 |
+
st.title("📸 Intel Image Classification")
|
20 |
+
st.write("Upload an image to classify it into one of the image categories: buildings, forest, glacier, mountain, sea, or street.")
|
21 |
+
|
22 |
+
model, class_names, device = load_model()
|
23 |
+
|
24 |
+
uploaded_file = st.file_uploader("Upload an image", type=["jpg", "jpeg", "png"])
|
25 |
+
|
26 |
+
if uploaded_file:
|
27 |
+
image = Image.open(uploaded_file).convert("RGB")
|
28 |
+
st.image(image, caption="Uploaded Image", use_container_width=True)
|
29 |
+
|
30 |
+
transform = get_transforms(train=False)
|
31 |
+
image_tensor = transform(image).unsqueeze(0).to(device)
|
32 |
+
|
33 |
+
with torch.no_grad():
|
34 |
+
output = model(image_tensor)
|
35 |
+
predicted_idx = torch.argmax(output, 1).item()
|
36 |
+
predicted_class = class_names[predicted_idx]
|
37 |
+
|
38 |
+
st.success(f"Predicted class: {predicted_class}")
|
models/__pycache__/cnn.cpython-313.pyc
ADDED
Binary file (1.9 kB). View file
|
|
models/cnn.py
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch.nn as nn
|
2 |
+
import torch.nn.functional as F
|
3 |
+
|
4 |
+
class CNNModel(nn.Module):
|
5 |
+
def __init__(self, num_classes):
|
6 |
+
super(CNNModel, self).__init__()
|
7 |
+
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)
|
8 |
+
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
|
9 |
+
self.pool = nn.MaxPool2d(2, 2)
|
10 |
+
self.fc1 = nn.Linear(64 * 37 * 37, 128)
|
11 |
+
self.fc2 = nn.Linear(128, num_classes)
|
12 |
+
|
13 |
+
def forward(self, x):
|
14 |
+
x = self.pool(F.relu(self.conv1(x))) # 150->75
|
15 |
+
x = self.pool(F.relu(self.conv2(x))) # 75->37
|
16 |
+
x = x.view(-1, 64 * 37 * 37)
|
17 |
+
x = F.relu(self.fc1(x))
|
18 |
+
x = self.fc2(x)
|
19 |
+
return x
|
requirements.txt
CHANGED
@@ -1,3 +1,5 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
streamlit
|
|
|
|
|
|
1 |
+
torch
|
2 |
+
torchvision
|
3 |
+
streamlit
|
4 |
+
Pillow
|
5 |
+
kaggle
|
saved_models/cnn_model.pth
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:4aaa29782a55510abe97ac09c662d0673440964297b0b504157f67b61e2477ec
|
3 |
+
size 44944297
|
train.py
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import torch
|
3 |
+
import torch.nn as nn
|
4 |
+
from torch.utils.data import DataLoader, random_split
|
5 |
+
from torchvision.datasets import ImageFolder
|
6 |
+
from torchvision import transforms
|
7 |
+
from models.cnn import CNNModel
|
8 |
+
from utils.transforms import get_transforms
|
9 |
+
|
10 |
+
def train_model(data_dir='data/intel/seg_train', epochs=10, batch_size=32, save_path='saved_models/cnn_model.pth'):
|
11 |
+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
12 |
+
|
13 |
+
# Load dataset with ImageFolder (expects folder structure: class subfolders)
|
14 |
+
full_dataset = ImageFolder(root=data_dir, transform=get_transforms(train=True))
|
15 |
+
class_names = full_dataset.classes
|
16 |
+
print(f"Classes: {class_names}")
|
17 |
+
|
18 |
+
# Split dataset 80% train, 20% val
|
19 |
+
train_size = int(0.8 * len(full_dataset))
|
20 |
+
val_size = len(full_dataset) - train_size
|
21 |
+
train_ds, val_ds = random_split(full_dataset, [train_size, val_size])
|
22 |
+
|
23 |
+
# Update val transforms (no augmentation)
|
24 |
+
val_ds.dataset.transform = get_transforms(train=False)
|
25 |
+
|
26 |
+
train_loader = DataLoader(train_ds, batch_size=batch_size, shuffle=True)
|
27 |
+
val_loader = DataLoader(val_ds, batch_size=batch_size)
|
28 |
+
|
29 |
+
model = CNNModel(num_classes=len(class_names)).to(device)
|
30 |
+
criterion = nn.CrossEntropyLoss()
|
31 |
+
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
|
32 |
+
|
33 |
+
for epoch in range(epochs):
|
34 |
+
model.train()
|
35 |
+
total_loss = 0
|
36 |
+
total_correct = 0
|
37 |
+
|
38 |
+
for images, labels in train_loader:
|
39 |
+
images, labels = images.to(device), labels.to(device)
|
40 |
+
optimizer.zero_grad()
|
41 |
+
outputs = model(images)
|
42 |
+
loss = criterion(outputs, labels)
|
43 |
+
loss.backward()
|
44 |
+
optimizer.step()
|
45 |
+
|
46 |
+
total_loss += loss.item() * images.size(0)
|
47 |
+
total_correct += (outputs.argmax(1) == labels).sum().item()
|
48 |
+
|
49 |
+
train_loss = total_loss / len(train_loader.dataset)
|
50 |
+
train_acc = total_correct / len(train_loader.dataset)
|
51 |
+
|
52 |
+
# Validation
|
53 |
+
model.eval()
|
54 |
+
val_loss = 0
|
55 |
+
val_correct = 0
|
56 |
+
with torch.no_grad():
|
57 |
+
for images, labels in val_loader:
|
58 |
+
images, labels = images.to(device), labels.to(device)
|
59 |
+
outputs = model(images)
|
60 |
+
loss = criterion(outputs, labels)
|
61 |
+
val_loss += loss.item() * images.size(0)
|
62 |
+
val_correct += (outputs.argmax(1) == labels).sum().item()
|
63 |
+
|
64 |
+
val_loss /= len(val_loader.dataset)
|
65 |
+
val_acc = val_correct / len(val_loader.dataset)
|
66 |
+
|
67 |
+
print(f"Epoch {epoch+1}/{epochs} — Train loss: {train_loss:.4f}, Train acc: {train_acc:.4f}, Val loss: {val_loss:.4f}, Val acc: {val_acc:.4f}")
|
68 |
+
|
69 |
+
os.makedirs(os.path.dirname(save_path), exist_ok=True)
|
70 |
+
torch.save({
|
71 |
+
'model_state_dict': model.state_dict(),
|
72 |
+
'class_names': class_names
|
73 |
+
}, save_path)
|
74 |
+
print(f"Model saved to {save_path}")
|
75 |
+
|
76 |
+
if __name__ == "__main__":
|
77 |
+
train_model()
|
utils/__pycache__/data_loader.cpython-313.pyc
ADDED
Binary file (1.4 kB). View file
|
|
utils/__pycache__/transforms.cpython-313.pyc
ADDED
Binary file (1.01 kB). View file
|
|
utils/metrics.py
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
|
3 |
+
def accuracy(outputs, labels):
|
4 |
+
_, preds = torch.max(outputs, 1)
|
5 |
+
return torch.sum(preds == labels).item() / len(labels)
|
utils/transforms.py
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from torchvision import transforms
|
2 |
+
|
3 |
+
def get_transforms(train=True):
|
4 |
+
if train:
|
5 |
+
return transforms.Compose([
|
6 |
+
transforms.Resize((150, 150)),
|
7 |
+
transforms.RandomHorizontalFlip(),
|
8 |
+
transforms.ToTensor(),
|
9 |
+
transforms.Normalize(mean=[0.485, 0.456, 0.406],
|
10 |
+
std=[0.229, 0.224, 0.225])
|
11 |
+
])
|
12 |
+
else:
|
13 |
+
return transforms.Compose([
|
14 |
+
transforms.Resize((150, 150)),
|
15 |
+
transforms.ToTensor(),
|
16 |
+
transforms.Normalize(mean=[0.485, 0.456, 0.406],
|
17 |
+
std=[0.229, 0.224, 0.225])
|
18 |
+
])
|