Sekpim's picture
Duplicate from aryap2/klasifikasi_kematangan_pisang
346ecc2
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")