File size: 10,138 Bytes
346ecc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
import streamlit as st
from PIL import Image
from io import BytesIO
import requests
import os
import time
import torch
import torch.nn.functional as F
from torchvision.transforms import (Compose,
Normalize,
CenterCrop,
Resize,
ToTensor)
# Variabel global untuk menyimpan token API
TOKEN = st.secrets["TOKEN"]
# Header yang digunakan untuk mengautentikasi ke API dengan token
headers = {"Authorization": f"Bearer {TOKEN}"}
# Perangkat yang digunakan (misal: CPU) untuk mengeksekusi model PyTorch
device = torch.device('cpu')
# Transformasi data untuk memproses gambar sebelum penggunaan pada model
pred_transforms = Compose(
[
Resize(224),
CenterCrop(224),
ToTensor(),
Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]),
]
)
# Kamus untuk memetakan indeks kelas menjadi label kematangan pisang
id2label = {0: 'matang', 1: 'mentah', 2: 'setengah-matang', 3: 'terlalu-matang'}
# Fungsi untuk mengirimkan permintaan prediksi gambar ke API menggunakan model dari Hugging Face
def query_hf(filename):
# Membaca data gambar dari file yang diunggah
with open(filename, "rb") as f:
data = f.read()
# Mengirimkan permintaan prediksi gambar ke API menggunakan HTTP POST request dengan data gambar
response = requests.post(API_URL, headers=headers, data=data)
return response.json()
# Fungsi untuk memproses gambar menggunakan model PyTorch
def query_pytorch(image, model):
# Mengubah gambar menjadi tensor dan memprosesnya dengan model PyTorch
input_tensor = pred_transforms(image.convert("RGB")).to(device)
encoding = input_tensor.unsqueeze(0)
with torch.no_grad():
# Mengubah gambar menjadi tensor dan memprosesnya dengan model PyTorch
input_tensor = pred_transforms(image.convert("RGB"))
encoding = input_tensor.unsqueeze(0)
# Mengirimkan gambar yang telah diubah menjadi tensor melalui model PyTorch untuk mendapatkan output prediksi
outputs = model(encoding)
# Menghitung probabilitas kelas menggunakan fungsi softmax
probabilities = F.softmax(outputs, dim=1)
return probabilities
# Fungsi untuk menampilkan hasil prediksi menggunakan model dari Hugging Face
def hunggingface_pred(upload):
# Membuka gambar yang diunggah
image = Image.open(upload)
with st.spinner("memprediksi..."):
# Mengirimkan permintaan prediksi gambar ke API menggunakan model dari Hugging Face
response = query_hf(upload)
# Jika terdapat kesalahan pada response (misalnya model sedang dimuat), tampilkan indikator progres
while 'error' in response:
estimated_time = round(response['estimated_time'])
progress_text = "Model sedang dimuat. Mohon tunggu..."
my_bar = st.progress(0, text=progress_text)
start_time = time.time()
# Menunggu hingga model selesai dimuat berdasarkan estimated_time
while time.time() - start_time < estimated_time:
time.sleep(0.1)
elapsed_time = time.time() - start_time
progress_percent = min(
100, int((elapsed_time / estimated_time) * 100))
my_bar.progress(progress_percent,
text=f"{progress_text} {progress_percent}%")
# Mengirimkan permintaan kembali jika terdapat kesalahan pada response
response = query_hf(upload)
# Menghilangkan progress bar saat sudah mencapai 100%
if my_bar is not None:
my_bar.empty()
# Menampilkan gambar yang diunggah dan hasil prediksi dari model Vision Transformer
img1.image(image, width=300)
for i, item in enumerate(response, start=1):
label = item["label"]
score = item["score"]
score_percent = score * 100
labels[i - 1].text(f"{i}. {label:<15}: {score_percent:.1f}%")
# Fungsi untuk menampilkan hasil prediksi menggunakan model dari PyTorch
def pytorch_pred(upload, PATH):
# Membuka gambar yang diunggah
image = Image.open(upload)
with st.spinner("memprediksi..."):
# Memuat model PyTorch yang telah dilatih
model = torch.load(PATH, map_location=device)
model = model.eval()
# Memproses gambar dengan model PyTorch dan menghitung probabilitas kelas menggunakan fungsi softmax
response = query_pytorch(image, model)
# Menampilkan gambar yang diunggah dan hasil prediksi dari model Convolutional Neural Network
img1.image(image, width=300)
# Mengurutkan hasil prediksi berdasarkan probabilitas tertinggi
sorted_indices = torch.argsort(response, descending=True)
for i, idx in enumerate(sorted_indices[0]):
class_name = id2label[idx.item()]
score_percent = response[0, idx].item() * 100
labels[i].text(f"{i+1}. {class_name:<15}: {score_percent:.1f}%")
# Fungsi untuk mendapatkan ekstensi file dari nama file yang diunggah
def get_extension(file_name):
_, ext = os.path.splitext(file_name)
return ext.lower()
# Fungsi untuk mengubah gambar menjadi format PNG
def convert_image(img):
buf = BytesIO()
img.save(buf, format="PNG")
byte_im = buf.getvalue()
return byte_im
# Mengatur konfigurasi halaman aplikasi
st.set_page_config(
layout="wide", page_title="KlaKePi", page_icon=":banana:"
)
# Menampilkan judul dan deskripsi aplikasi
st.write("## Klasifikasi Tingkat Kematangan Pisang (KlaKePi)")
st.write("Unggah gambar pisang untuk memprediksi tingkat kematangannya.")
st.markdown("---")
# Menampilkan bagian pengaturan arsitektur model
st.write("## Pengaturan :wrench:")
arsitektur = st.radio(
"Arsitektur Model",
('Vision Transformer (ViT)', 'Convolutional Neural Network (CNN)')
)
# Jika dipilih arsitektur Vision Transformer (ViT), maka tampilkan pilihan varian model
if arsitektur == 'Vision Transformer (ViT)':
option = st.selectbox(
"Varian Model",
("ViT-B/16-in1k", "ViT-B/32-in1k", "ViT-L/16-in1k", "ViT-L/32-in1k", "ViT-H/14-in1k",
"ViT-B/16-in21k", "ViT-B/32-in21k", "ViT-L/16-in21k", "ViT-L/32-in21k", "ViT-H/14-in21k"),
index=7, help="in1k = Model pre-trained pada ImageNet-1k dan fine-tuned pada citra pisang primer\n\nin21k = Model pre-trained pada ImageNet-21k dan fine-tuned pada citra pisang primer"
)
# Jika dipilih arsitektur Convolutional Neural Network (CNN), maka tampilkan pilihan varian model
elif arsitektur == 'Convolutional Neural Network (CNN)':
option = st.selectbox(
"Varian Model",
("Alexnet-in1k", "Densenet121-in1k", "Densenet201-in1k", "MobileNet V2-in1k", "MobileNet V3-in1k",
"Resnet152-in1k", "Resnet50-in1k", "Squeezenet-in1k", "VGG16-in1k", "VGG19-in1k"),
index=0, help="in1k = Model pre-trained pada ImageNet-1k dan fine-tuned pada citra pisang primer"
)
st.markdown("---")
# Menampilkan bagian untuk mengunggah gambar pisang
st.write("## Unggah Gambar :arrow_down:")
my_upload = st.file_uploader(
"Unggah gambar pisang", type=["png", "jpg", "jpeg"]
)
if my_upload is not None:
# Menyimpan gambar yang diunggah ke dalam folder 'uploaded_images'
ext = get_extension(my_upload.name)
output_filename_with_ext = f"pisangup{ext}"
if not os.path.exists("uploaded_images"):
os.makedirs("uploaded_images")
with open(os.path.join("uploaded_images", output_filename_with_ext), "wb") as f:
f.write(my_upload.read())
st.markdown("---")
# Menampilkan bagian output hasil prediksi
st.write("## Output :arrow_down:")
# Membagi halaman menjadi dua kolom
col1, col2 = st.columns(2)
# Menampilkan gambar pada kolom pertama
col1.write("### Gambar :camera:")
img1 = col1.empty()
# Menampilkan teks header untuk hasil prediksi pada kolom kedua
col2.write("### Label dan Skor Terdeteksi:")
labels = [col2.empty() for _ in range(4)]
# Daftar path model yang tersedia
model_paths = {
"Alexnet-in1k": "./models/alexnet.pt",
"Densenet121-in1k": "./models/densenet121.pt",
"Densenet201-in1k": "./models/densenet201.pt",
"MobileNet V2-in1k": "./models/mobilenet_V2.pt",
"MobileNet V3-in1k": "./models/mobilenet_V3.pt",
"Resnet50-in1k": "./models/resnet50.pt",
"Resnet152-in1k": "./models/resnet152.pt",
"Squeezenet-in1k": "./models/squeezenet.pt",
"VGG16-in1k": "./models/vgg16.pt",
"VGG19-in1k": "./models/vgg19.pt",
"ViT-B/16-in1k": "./models/vit_b_16.pt",
"ViT-B/32-in1k": "./models/vit_b_32.pt",
"ViT-L/16-in1k": "./models/vit_l_16.pt",
"ViT-L/32-in1k": "./models/vit_l_32.pt",
"ViT-H/14-in1k": "./models/vit_h_14.pt",
}
# Daftar API URL untuk model Vision Transformer
api_urls = {
"ViT-B/16-in21k": "https://api-inference.huggingface.co/models/aryap2/kematangan-pisang-vit-b-16-100eph-224-v4.4",
"ViT-B/32-in21k": "https://api-inference.huggingface.co/models/aryap2/kematangan-pisang-vit-b-32-100eph-224-v4.4",
"ViT-L/16-in21k": "https://api-inference.huggingface.co/models/aryap2/kematangan-pisang-vit-l-16-100eph-224-v4.4",
"ViT-L/32-in21k": "https://api-inference.huggingface.co/models/aryap2/kematangan-pisang-vit-l-32-100eph-224-v4.4",
"ViT-H/14-in21k": "https://api-inference.huggingface.co/models/aryap2/kematangan-pisang-vit-h-14-100eph-224-telyu",
}
# Jika model yang dipilih ada dalam daftar path model, maka gunakan model tersebut dengan fungsi pytorch_pred
if option in model_paths:
PATH = model_paths[option]
if my_upload is not None:
pytorch_pred(f"./uploaded_images/{output_filename_with_ext}", PATH)
else:
pytorch_pred("./pisang.jpg", PATH)
# Jika model yang dipilih ada dalam daftar API URL, maka gunakan model tersebut dengan fungsi hunggingface_pred
elif option in api_urls:
API_URL = api_urls[option]
if my_upload is not None:
hunggingface_pred(f"./uploaded_images/{output_filename_with_ext}")
else:
hunggingface_pred("./pisang.jpg")
|