sync with remote
Browse files- app.py +137 -0
- requirements.txt +8 -0
- trained_model.pkl +3 -0
app.py
ADDED
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import torch
|
3 |
+
import torch.nn as nn
|
4 |
+
import pickle
|
5 |
+
from torch.utils.data import Dataset, DataLoader
|
6 |
+
from torchvision import transforms
|
7 |
+
from PIL import Image
|
8 |
+
import requests
|
9 |
+
import pandas as pd
|
10 |
+
|
11 |
+
# Enable GPU if available
|
12 |
+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
13 |
+
st.write(f"Enabled GPU = {torch.cuda.is_available()}")
|
14 |
+
|
15 |
+
MODEL_REPO_ID = "louiecerv/amer_sign_lang_neuralnet"
|
16 |
+
DATASET_REPO_ID = "louiecerv/american_sign_language"
|
17 |
+
|
18 |
+
# Load dataset from Hugging Face API
|
19 |
+
def load_dataset_from_api(repo_id, split, offset, length):
|
20 |
+
url = f"https://datasets-server.huggingface.co/rows?dataset={repo_id}&config=default&split={split}&offset={offset}&length={length}"
|
21 |
+
response = requests.get(url)
|
22 |
+
data = response.json()
|
23 |
+
df = pd.DataFrame(data)
|
24 |
+
return df
|
25 |
+
|
26 |
+
train_data = load_dataset_from_api(DATASET_REPO_ID, "train", 0, 1000)
|
27 |
+
valid_data = load_dataset_from_api(DATASET_REPO_ID, "validation", 0, 100)
|
28 |
+
|
29 |
+
# Define the model architecture (must match training code)
|
30 |
+
class SimpleNN(nn.Module):
|
31 |
+
def __init__(self, input_size=28*28, hidden_size=512, num_classes=26):
|
32 |
+
super(SimpleNN, self).__init__()
|
33 |
+
self.flatten = nn.Flatten()
|
34 |
+
self.fc1 = nn.Linear(input_size, hidden_size)
|
35 |
+
self.relu1 = nn.ReLU()
|
36 |
+
self.fc2 = nn.Linear(hidden_size, hidden_size)
|
37 |
+
self.relu2 = nn.ReLU()
|
38 |
+
self.fc3 = nn.Linear(hidden_size, num_classes)
|
39 |
+
|
40 |
+
def forward(self, x):
|
41 |
+
x = self.flatten(x)
|
42 |
+
x = self.fc1(x)
|
43 |
+
x = self.relu1(x)
|
44 |
+
x = self.fc2(x)
|
45 |
+
x = self.relu2(x)
|
46 |
+
x = self.fc3(x)
|
47 |
+
return x
|
48 |
+
|
49 |
+
# Load pre-trained model from Hugging Face (pickle file)
|
50 |
+
@st.cache_resource
|
51 |
+
def load_model():
|
52 |
+
url = f"https://huggingface.co/{MODEL_REPO_ID}/resolve/main/trained_model.pkl"
|
53 |
+
response = requests.get(url)
|
54 |
+
with open("trained_model.pkl", "wb") as f:
|
55 |
+
f.write(response.content)
|
56 |
+
with open("trained_model.pkl", "rb") as f:
|
57 |
+
model = pickle.load(f)
|
58 |
+
model.to(device)
|
59 |
+
model.eval() # Set model to evaluation mode
|
60 |
+
return model
|
61 |
+
|
62 |
+
model = load_model()
|
63 |
+
|
64 |
+
# Custom dataset class
|
65 |
+
class ASLDataset(Dataset):
|
66 |
+
def __init__(self, data):
|
67 |
+
self.data = data
|
68 |
+
self.transform = transforms.Compose([
|
69 |
+
transforms.Grayscale(num_output_channels=1),
|
70 |
+
transforms.Resize((28, 28)),
|
71 |
+
transforms.ToTensor(),
|
72 |
+
transforms.Normalize(mean=[0.5], std=[0.5])
|
73 |
+
])
|
74 |
+
|
75 |
+
def __len__(self):
|
76 |
+
return len(self.data)
|
77 |
+
|
78 |
+
def __getitem__(self, idx):
|
79 |
+
sample = self.data.iloc[idx]
|
80 |
+
image_path = sample['image']
|
81 |
+
image = Image.open(requests.get(image_path, stream=True).raw).convert("L")
|
82 |
+
label = sample['label']
|
83 |
+
image = self.transform(image)
|
84 |
+
return image, torch.tensor(label, dtype=torch.long)
|
85 |
+
|
86 |
+
train_dataset = ASLDataset(train_data)
|
87 |
+
valid_dataset = ASLDataset(valid_data)
|
88 |
+
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
|
89 |
+
valid_loader = DataLoader(valid_dataset, batch_size=32, shuffle=False)
|
90 |
+
|
91 |
+
# Prediction function
|
92 |
+
def predict_image(model, image):
|
93 |
+
image = image.view(-1, 28*28).to(device) # Flatten image to match model input
|
94 |
+
model.eval()
|
95 |
+
with torch.no_grad():
|
96 |
+
output = model(image)
|
97 |
+
predicted_class = torch.argmax(output, dim=1).item()
|
98 |
+
return chr(predicted_class + 65) # Convert index to ASL letter (A-Z)
|
99 |
+
|
100 |
+
# Streamlit App
|
101 |
+
st.title("American Sign Language Recognition Using CNN")
|
102 |
+
|
103 |
+
# Tabs: Dataset, Model, Prediction
|
104 |
+
tab1, tab2, tab3 = st.tabs(["Dataset", "Model", "Prediction"])
|
105 |
+
|
106 |
+
# Dataset Tab
|
107 |
+
with tab1:
|
108 |
+
st.header("Dataset Overview")
|
109 |
+
st.write("Displaying sample images from the training dataset.")
|
110 |
+
col1, col2, col3, col4, col5 = st.columns(5)
|
111 |
+
for i in range(5):
|
112 |
+
image, label = train_dataset[i]
|
113 |
+
img = transforms.ToPILImage()(image.cpu())
|
114 |
+
with [col1, col2, col3, col4, col5][i]:
|
115 |
+
st.image(img, caption=f"Label: {chr(label.item() + 65)}", use_container_width=True)
|
116 |
+
|
117 |
+
with tab2:
|
118 |
+
st.header("Model Training")
|
119 |
+
st.write("Training is done offline. The pre-trained model is loaded from Hugging Face.")
|
120 |
+
st.write(model)
|
121 |
+
|
122 |
+
with tab3:
|
123 |
+
st.header("Make a Prediction")
|
124 |
+
uploaded_file = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"])
|
125 |
+
if uploaded_file is not None:
|
126 |
+
image = Image.open(uploaded_file).convert("L")
|
127 |
+
st.image(image, caption="Original Image", use_container_width=True)
|
128 |
+
transform = transforms.Compose([
|
129 |
+
transforms.Grayscale(num_output_channels=1),
|
130 |
+
transforms.Resize((28, 28)),
|
131 |
+
transforms.ToTensor(),
|
132 |
+
transforms.Normalize(mean=[0.5], std=[0.5])
|
133 |
+
])
|
134 |
+
processed_image = transform(image)
|
135 |
+
|
136 |
+
predicted_class = predict_image(model, processed_image)
|
137 |
+
st.success(f"Predicted ASL Letter: {predicted_class}")
|
requirements.txt
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit
|
2 |
+
pandas
|
3 |
+
torch
|
4 |
+
torchvision
|
5 |
+
transformers
|
6 |
+
datasets
|
7 |
+
Pillow
|
8 |
+
matplotlib
|
trained_model.pkl
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:770e12bc4831914e44eb69e2283089a02c60229b3d510e6b6111bc67adc45230
|
3 |
+
size 2715024
|