import pandas as pd import streamlit as st import plotly.graph_objects as go import plotly.express as px from utils.metrics_data import load_metrics st.markdown("## 📈 Performa Model") st.caption("Evaluasi komprehensif model IndoBERT yang telah di-fine-tune pada dataset PRDECT-ID.") metrics = load_metrics() if metrics.get("is_demo"): st.warning( "Menampilkan data demo (hasil aktual dari Progress Proposal). " "Letakkan `metrics.json` hasil training di `model/metrics.json` untuk data real-time. " "Lihat `export_metrics_snippet.py`." ) cm = metrics["confusion_matrix"] # ---- 4 kartu metrik ---- c1, c2, c3, c4 = st.columns(4) card_specs = [ ("ACCURACY", metrics["accuracy"], "Persentase prediksi benar dari seluruh data uji", c1), ("PRECISION", metrics["precision"], "Ketepatan prediksi positif dari semua prediksi positif", c2), ("RECALL", metrics["recall"], "Kemampuan menemukan semua sampel positif aktual", c3), ("F1-SCORE", metrics["f1"], "Harmonic mean dari Precision dan Recall", c4), ] for label, val, desc, col in card_specs: with col: with st.container(border=True): st.caption(f"⭐ {label}") st.markdown(f"### {val*100:.1f}%") st.caption(desc) st.write("") col_cm, col_curve = st.columns(2) with col_cm: with st.container(border=True): st.markdown(f"**Confusion Matrix**") st.caption(f"Test set · {metrics.get('n_test', cm['tn']+cm['fp']+cm['fn']+cm['tp'])} sampel") z = [[cm["tp"], cm["fn"]], [cm["fp"], cm["tn"]]] x_labels = ["Pred: Positive", "Pred: Negative"] y_labels = ["Actual: Positive", "Actual: Negative"] fig_cm = go.Figure(data=go.Heatmap( z=z, x=x_labels, y=y_labels, colorscale=[[0, "#eef2ff"], [1, "#4338ca"]], text=z, texttemplate="%{text}", textfont={"size": 20}, showscale=False, )) fig_cm.update_layout(margin=dict(l=10, r=10, t=10, b=10), height=320) st.plotly_chart(fig_cm, use_container_width=True) m1, m2 = st.columns(2) m1.metric("True Positive + True Negative", cm["tp"] + cm["tn"]) m2.metric("False Positive + False Negative", cm["fp"] + cm["fn"]) with col_curve: with st.container(border=True): st.markdown("**Kurva Pelatihan**") st.caption("Training & validation loss per epoch") epochs = list(range(1, len(metrics["train_loss"]) + 1)) fig_curve = go.Figure() fig_curve.add_trace(go.Scatter( x=epochs, y=metrics["train_loss"], mode="lines+markers", name="Training Loss", line=dict(color="#4338ca"), )) fig_curve.add_trace(go.Scatter( x=epochs, y=metrics["val_loss"], mode="lines+markers", name="Validation Loss", line=dict(color="#e74c3c"), )) fig_curve.update_layout( margin=dict(l=10, r=10, t=10, b=10), height=280, xaxis_title="Epoch", yaxis_title="Loss", legend=dict(orientation="h", yanchor="bottom", y=1.02), ) st.plotly_chart(fig_curve, use_container_width=True) bcol1, bcol2 = st.columns(2) bcol1.metric("Best Val Loss", f"{min(metrics['val_loss']):.3f}") bcol2.metric("Total Epoch", len(metrics["train_loss"])) st.write("") with st.expander("Lihat akurasi training vs validation per epoch"): df_acc = pd.DataFrame({ "Epoch": list(range(1, len(metrics["train_acc"]) + 1)), "Train Accuracy": metrics["train_acc"], "Val Accuracy": metrics["val_acc"], }) fig_acc = px.line( df_acc, x="Epoch", y=["Train Accuracy", "Val Accuracy"], markers=True, color_discrete_sequence=["#4338ca", "#e74c3c"], ) fig_acc.update_layout(yaxis_title="Accuracy", legend_title="") st.plotly_chart(fig_acc, use_container_width=True) st.dataframe(df_acc, use_container_width=True, hide_index=True)