Spaces:
Sleeping
Sleeping
| 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) | |