Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,219 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import torch
|
3 |
+
from torchvision import models, transforms
|
4 |
+
from PIL import Image
|
5 |
+
import streamlit as st
|
6 |
+
from huggingface_hub import hf_hub_download
|
7 |
+
import requests
|
8 |
+
import pandas as pd
|
9 |
+
|
10 |
+
st.set_page_config(
|
11 |
+
page_title="Mineral Classification",
|
12 |
+
page_icon="🍎",
|
13 |
+
layout="wide",
|
14 |
+
initial_sidebar_state="expanded"
|
15 |
+
)
|
16 |
+
|
17 |
+
st.markdown(
|
18 |
+
"""
|
19 |
+
<style>
|
20 |
+
.css-18e3th9 {
|
21 |
+
background-color: #f0f2f6;
|
22 |
+
color: #000000;
|
23 |
+
}
|
24 |
+
.css-1lcbz8d {
|
25 |
+
background-color: #F63366;
|
26 |
+
}
|
27 |
+
.highlight {
|
28 |
+
color: #FF0000;
|
29 |
+
font-weight: bold;
|
30 |
+
}
|
31 |
+
</style>
|
32 |
+
""", unsafe_allow_html=True
|
33 |
+
)
|
34 |
+
|
35 |
+
st.sidebar.title("Navigation")
|
36 |
+
add_sidebar_selectbox = st.sidebar.selectbox(
|
37 |
+
"Go to",
|
38 |
+
('Home', 'Dataset', 'Model Description', 'Prediction', 'Contact')
|
39 |
+
)
|
40 |
+
|
41 |
+
def home():
|
42 |
+
st.write('''
|
43 |
+
# Final Project AI Engineering
|
44 |
+
Hello, I'm Ahmad Alfian Faisal. This is the deployed result of my AI project, a deep learning model, which is part of my Final Project for the AI Engineering SkillAcademy at Ruangguru. If you have any questions or feedback, feel free to reach out to me via [LinkedIn](www.linkedin.com/in/ahmadalfianfaisal).
|
45 |
+
''')
|
46 |
+
st.write('''
|
47 |
+
### AI-Based Fruit and Nutrition Prediction Model for Healthy Food Alternatives
|
48 |
+
This project emphasizes the importance of easy access to nutritional information, particularly in the face of fast food dominance, which is often low in nutrients and poses health risks. Using deep learning technology, this model can detect fruits or vegetables and quickly provide accurate nutritional information. It makes it easier for people to compare the nutritional content of healthy foods with fast foods, supporting the global trend of AI in creating more efficient and affordable health solutions.
|
49 |
+
''')
|
50 |
+
# st.image("gambar_buah_home.jpg", width=800)
|
51 |
+
|
52 |
+
def dataset():
|
53 |
+
"""
|
54 |
+
Display the dataset information used in this project.
|
55 |
+
"""
|
56 |
+
st.title("Datasets Used")
|
57 |
+
|
58 |
+
st.subheader("1. Fruit and Vegetable Image Dataset")
|
59 |
+
st.markdown("""
|
60 |
+
- **Source**: [Kaggle - Fruit and Vegetable Image Recognition](https://www.kaggle.com/datasets/kritikseth/fruit-and-vegetable-image-recognition)
|
61 |
+
- **Purpose**: This dataset is used to train the deep learning model to detect and classify fruits and vegetables based on images.
|
62 |
+
- **Description**: The dataset contains thousands of labeled images of fruits and vegetables in various categories (e.g., apple, banana, tomato).
|
63 |
+
- **Total Classes**: 36 classes of fruits and vegetables.
|
64 |
+
- **Dataset Split**:
|
65 |
+
- **Train**: 100 images per category.
|
66 |
+
- **Validation**: 10 images per category.
|
67 |
+
- **Test**: 10 images per category.
|
68 |
+
""")
|
69 |
+
|
70 |
+
def model_description():
|
71 |
+
st.title("Model Description")
|
72 |
+
|
73 |
+
st.markdown("""
|
74 |
+
In this project, we use three fine-tuned models for classifying images of fruits and vegetables:
|
75 |
+
**SqueezeNet1_1**, **DenseNet121**, and **MobileNet_V2**.
|
76 |
+
SqueezeNet1_1 is known for its small size and efficiency, while DenseNet121 excels at detecting deep features due to its dense architecture.
|
77 |
+
MobileNet_V2 is designed for high performance on resource-limited devices, making it an ideal choice for mobile applications.
|
78 |
+
""")
|
79 |
+
|
80 |
+
hyperparameters = {
|
81 |
+
"Hyperparameter": ["Transformations", "Data Loader", "Optimizer", "Learning Rate", "Loss Function", "Epochs"],
|
82 |
+
"Value": [
|
83 |
+
"Resize (224, 224), ToTensor, Normalize (mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])",
|
84 |
+
"Batch Size: 32",
|
85 |
+
"Adam",
|
86 |
+
"0.001",
|
87 |
+
"Cross Entropy Loss",
|
88 |
+
"20"
|
89 |
+
]
|
90 |
+
}
|
91 |
+
|
92 |
+
hyperparam_df = pd.DataFrame(hyperparameters)
|
93 |
+
|
94 |
+
st.subheader("Hyperparameters Used in the Models")
|
95 |
+
st.table(hyperparam_df)
|
96 |
+
|
97 |
+
|
98 |
+
def prediction():
|
99 |
+
|
100 |
+
def load_model(model_name):
|
101 |
+
if model_name == "DenseNet":
|
102 |
+
model_path = hf_hub_download(repo_id="ahmadalfian/mineral-classification",
|
103 |
+
filename="densenet_finetuned.pth")
|
104 |
+
model = models.densenet121(pretrained=False)
|
105 |
+
num_classes = 36
|
106 |
+
model.classifier = torch.nn.Linear(in_features=1024, out_features=num_classes)
|
107 |
+
|
108 |
+
elif model_name == "MobileNet":
|
109 |
+
model_path = hf_hub_download(repo_id="ahmadalfian/mineral-classification",
|
110 |
+
filename="mobilenet_finetuned.pth")
|
111 |
+
model = models.mobilenet_v2(pretrained=False)
|
112 |
+
num_classes = 36
|
113 |
+
model.classifier[1] = torch.nn.Linear(in_features=1280, out_features=num_classes)
|
114 |
+
|
115 |
+
elif model_name == "SqueezeNet":
|
116 |
+
model_path = hf_hub_download(repo_id="ahmadalfian/mineral-classification",
|
117 |
+
filename="squeezenet1_finetuned.pth")
|
118 |
+
model = models.squeezenet1_1(pretrained=False)
|
119 |
+
num_classes = 36
|
120 |
+
model.classifier[1] = torch.nn.Conv2d(512, num_classes, kernel_size=(1, 1), stride=(1, 1))
|
121 |
+
|
122 |
+
else:
|
123 |
+
raise ValueError("Model not supported.")
|
124 |
+
|
125 |
+
model.load_state_dict(torch.load(model_path, map_location=torch.device('cpu')))
|
126 |
+
model.eval()
|
127 |
+
return model
|
128 |
+
|
129 |
+
def process_image(image):
|
130 |
+
if image.mode == 'RGBA':
|
131 |
+
image = image.convert('RGB')
|
132 |
+
print("Image converted from RGBA to RGB.")
|
133 |
+
|
134 |
+
preprocess = transforms.Compose([
|
135 |
+
transforms.Resize((224, 224)),
|
136 |
+
transforms.ToTensor(),
|
137 |
+
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
|
138 |
+
])
|
139 |
+
|
140 |
+
img_tensor = preprocess(image)
|
141 |
+
print(f"Image tensor shape: {img_tensor.shape}")
|
142 |
+
return img_tensor.unsqueeze(0)
|
143 |
+
|
144 |
+
def classify_image(model, image):
|
145 |
+
img_tensor = process_image(image)
|
146 |
+
|
147 |
+
print(f"Image tensor shape after unsqueeze: {img_tensor.shape}")
|
148 |
+
|
149 |
+
model.eval()
|
150 |
+
|
151 |
+
with torch.no_grad():
|
152 |
+
outputs = model(img_tensor)
|
153 |
+
|
154 |
+
print(f"Model output shape: {outputs.shape}")
|
155 |
+
|
156 |
+
probabilities = torch.nn.functional.softmax(outputs, dim=1)
|
157 |
+
|
158 |
+
confidence, predicted = torch.max(probabilities, 1)
|
159 |
+
|
160 |
+
return predicted.item(), confidence.item()
|
161 |
+
|
162 |
+
|
163 |
+
st.markdown("## 🍎 Fruit and Vegetable Classifier")
|
164 |
+
st.markdown("Upload an image of a fruit or vegetable, and I will classify it for you!")
|
165 |
+
|
166 |
+
st.sidebar.header("Model Settings")
|
167 |
+
model_name = st.sidebar.selectbox("Select Model", ("DenseNet", "SqueezeNet", "MobileNet"))
|
168 |
+
|
169 |
+
confidence_threshold = st.sidebar.number_input("Set Confidence Threshold", min_value=0.0, max_value=1.0, value=0.5,
|
170 |
+
step=0.01)
|
171 |
+
|
172 |
+
uploaded_file = st.file_uploader("Choose an image...", type=["jpg", "jpeg", "png"])
|
173 |
+
|
174 |
+
predict_button = st.sidebar.button("Predict")
|
175 |
+
|
176 |
+
if uploaded_file is not None and predict_button:
|
177 |
+
with st.spinner("Processing the image..."):
|
178 |
+
image = Image.open(uploaded_file)
|
179 |
+
|
180 |
+
model = load_model(model_name)
|
181 |
+
label, confidence = classify_image(model, image)
|
182 |
+
|
183 |
+
food_name = label_to_food.get(label, "Unknown Food")
|
184 |
+
nutrition_info = get_nutrition_info(food_name)
|
185 |
+
|
186 |
+
health_benefits = get_health_benefits(food_name)
|
187 |
+
|
188 |
+
col1, col2 = st.columns([1, 2])
|
189 |
+
|
190 |
+
with col1:
|
191 |
+
st.image(image, caption='Uploaded Image', width=250)
|
192 |
+
|
193 |
+
with col2:
|
194 |
+
st.write(f"**Prediction**: {food_name.capitalize()}")
|
195 |
+
st.write(f"**Confidence**: {confidence:.4f}")
|
196 |
+
|
197 |
+
def contact():
|
198 |
+
st.header('About Me')
|
199 |
+
st.image('foto_profil.jpeg', width=500)
|
200 |
+
st.write('''
|
201 |
+
Hello, I’m Ahmad Alfian Faisal, a graduate from the Mining Engineering department at Universitas Hasanuddin. Since my university days, I’ve had a strong interest in data, particularly in Data Science and AI Engineering. To deepen my knowledge and skills in this field, I joined the AI Engineering SkillAcademy by Ruangguru.
|
202 |
+
As part of this program, I completed a Final Project, which serves as my capstone to apply the knowledge I have gained. I’m very excited to pursue a career in the data science and AI field, and I’m eager to contribute meaningfully to this area.
|
203 |
+
''')
|
204 |
+
st.write('''
|
205 |
+
**Contact Me**
|
206 |
+
- [LinkedIn]("www.linkedin.com/in/ahmadalfianfaisal")
|
207 |
+
- [Instagram]("https://instagram.com/ahmad.alfian.faisal?igshid=NzZlODBkYWE4Ng==")
|
208 |
+
''')
|
209 |
+
|
210 |
+
if add_sidebar_selectbox == 'Home':
|
211 |
+
home()
|
212 |
+
elif add_sidebar_selectbox == 'Dataset':
|
213 |
+
dataset()
|
214 |
+
elif add_sidebar_selectbox == 'Model Description':
|
215 |
+
model_description()
|
216 |
+
elif add_sidebar_selectbox == 'Prediction':
|
217 |
+
prediction()
|
218 |
+
elif add_sidebar_selectbox == 'Contact':
|
219 |
+
contact()
|