Hokeno commited on
Commit
3ac3892
·
verified ·
1 Parent(s): 254a4f1

Upload 9 files

Browse files
app.py ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ import subprocess
4
+ import numpy as np
5
+ from datasets import load_dataset
6
+ from transformers import AutoTokenizer, AutoModelForTokenClassification, DataCollatorForTokenClassification
7
+ import torch
8
+ import gradio as gr
9
+ import pandas as pd
10
+
11
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
12
+ print(f"Menggunakan perangkat: {device}")
13
+
14
+ # Load dataset to get label list
15
+ try:
16
+ dataset = load_dataset("indonlp/indonlu", "nergrit", trust_remote_code=True)
17
+ except Exception as e:
18
+ print(f"Gagal memuat dataset: {e}")
19
+ sys.exit(1)
20
+
21
+ # Verify dataset structure
22
+ if "train" not in dataset or "test" not in dataset:
23
+ print("Dataset tidak memiliki split train/test yang diharapkan.")
24
+ sys.exit(1)
25
+ if "tokens" not in dataset["train"].column_names or "ner_tags" not in dataset["train"].column_names:
26
+ print("Dataset tidak memiliki kolom 'tokens' atau 'ner_tags'.")
27
+ sys.exit(1)
28
+
29
+ # Define label list
30
+ try:
31
+ label_list = dataset["train"].features["ner_tags"].feature.names
32
+ id2label = {i: label for i, label in enumerate(label_list)}
33
+ label2id = {label: i for i, label in enumerate(label_list)}
34
+ except Exception as e:
35
+ print(f"Gagal mendapatkan label: {e}")
36
+ sys.exit(1)
37
+
38
+ # Load tokenizer and model from saved directory
39
+ try:
40
+ tokenizer = AutoTokenizer.from_pretrained("./ner_model")
41
+ model = AutoModelForTokenClassification.from_pretrained(
42
+ "./ner_model",
43
+ num_labels=len(label_list),
44
+ id2label=id2label,
45
+ label2id=label2id
46
+ )
47
+ model.to(device)
48
+ except Exception as e:
49
+ print(f"Gagal memuat model atau tokenizer dari './ner_model': {e}")
50
+ print("Pastikan folder './ner_model' ada dan berisi model yang telah dilatih.")
51
+ sys.exit(1)
52
+
53
+ # Tokenize and align labels for test data
54
+ def tokenize_and_align_labels(examples):
55
+ tokenized_inputs = tokenizer(examples["tokens"], truncation=True, is_split_into_words=True)
56
+ labels = []
57
+ for i, label in enumerate(examples["ner_tags"]):
58
+ word_ids = tokenized_inputs.word_ids(batch_index=i)
59
+ previous_word_idx = None
60
+ label_ids = []
61
+ for word_idx in word_ids:
62
+ if word_idx is None:
63
+ label_ids.append(-100)
64
+ elif word_idx != previous_word_idx:
65
+ label_ids.append(label[word_idx])
66
+ else:
67
+ label_ids.append(-100)
68
+ previous_word_idx = word_idx
69
+ labels.append(label_ids)
70
+ tokenized_inputs["labels"] = labels
71
+ return tokenized_inputs
72
+
73
+ # Tokenize test dataset
74
+ try:
75
+ tokenized_dataset = dataset.map(tokenize_and_align_labels, batched=True)
76
+ except Exception as e:
77
+ print(f"Gagal menokenisasi dataset: {e}")
78
+ sys.exit(1)
79
+
80
+ # Function to predict entities for input text
81
+ def predict_entities(input_text):
82
+ if not input_text.strip():
83
+ return "Masukkan teks untuk diprediksi."
84
+
85
+ # Tokenize input text
86
+ inputs = tokenizer(input_text, return_tensors="pt", truncation=True)
87
+ input_ids = inputs["input_ids"].to(device)
88
+ attention_mask = inputs["attention_mask"].to(device)
89
+
90
+ # Predict
91
+ model.eval()
92
+ with torch.no_grad():
93
+ outputs = model(input_ids, attention_mask=attention_mask)
94
+ predictions = outputs.logits.argmax(dim=2)[0].cpu().numpy()
95
+
96
+ # Get tokens and predicted labels
97
+ tokens = tokenizer.convert_ids_to_tokens(input_ids[0])
98
+ labels = [id2label[pred] for pred in predictions]
99
+
100
+ # Remove special tokens ([CLS], [SEP]) and align
101
+ result = []
102
+ for token, label in zip(tokens, labels):
103
+ if token not in ["[CLS]", "[SEP]"]:
104
+ result.append({"Token": token, "Entity": label})
105
+
106
+ # Convert to DataFrame for display
107
+ return pd.DataFrame(result)
108
+
109
+ # Gradio interface
110
+ with gr.Blocks() as demo:
111
+ gr.Markdown("# Named Entity Recognition (NER) dengan IndoBERT")
112
+ gr.Markdown("Masukkan teks dalam bahasa Indonesia untuk mendeteksi entitas seperti PERSON, ORGANISATION, PLACE, dll.")
113
+
114
+ gr.Markdown("## Keterangan Label Entitas")
115
+ gr.Markdown("""
116
+ - **O**: Token bukan entitas (contoh: "dan", "mengunjungi").
117
+ - **B-PERSON**: Awal nama orang (contoh: "Joko" dalam "Joko Widodo").
118
+ - **I-PERSON**: Lanjutan nama orang (contoh: "Widodo" atau "##do" dalam "Joko Widodo").
119
+ - **B-PLACE**: Awal nama tempat (contoh: "Bali").
120
+ - **I-PLACE**: Lanjutan nama tempat (contoh: "Indonesia" dalam "Bali, Indonesia").
121
+ """)
122
+
123
+ with gr.Row():
124
+ text_input = gr.Textbox(
125
+ label="Masukkan Teks",
126
+ placeholder="Contoh: Joko Widodo menghadiri acara di Universitas Indonesia pada tanggal 14 Juni 2025",
127
+ lines=3
128
+ )
129
+ submit_button = gr.Button("Prediksi")
130
+ clear_button = gr.Button("Bersihkan")
131
+
132
+ output_table = gr.Dataframe(label="Hasil Prediksi")
133
+
134
+ gr.Markdown("## Contoh Teks")
135
+ gr.Markdown("- SBY berkunjung ke Bali bersama Jokowi.\n- Universitas Gadjah Mada menyelenggarakan seminar pada 10 Maret 2025.")
136
+
137
+ gr.Markdown("## Pertimbangan Keamanan Data, Privasi, dan Etika")
138
+ gr.Markdown("""
139
+ - **Keamanan Data**: Dataset bersumber dari berita publik, tidak mengandung informasi sensitif seperti alamat atau nomor identitas.
140
+ - **Privasi**: Input pengguna tidak disimpan, menjaga privasi.
141
+ - **Etika AI**: Dataset mencakup berbagai topik berita (politik, olahraga, budaya), mengurangi risiko bias terhadap entitas tertentu.
142
+ """)
143
+
144
+ submit_button.click(fn=predict_entities, inputs=text_input, outputs=output_table)
145
+ clear_button.click(fn=lambda: "", inputs=None, outputs=text_input)
146
+
147
+ # Launch Gradio interface
148
+ demo.launch()
main4.ipynb ADDED
@@ -0,0 +1,1188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "id": "2a409dd5",
7
+ "metadata": {},
8
+ "outputs": [
9
+ {
10
+ "name": "stdout",
11
+ "output_type": "stream",
12
+ "text": [
13
+ "WARNING:tensorflow:From d:\\Anaconda\\Lib\\site-packages\\tf_keras\\src\\losses.py:2976: The name tf.losses.sparse_softmax_cross_entropy is deprecated. Please use tf.compat.v1.losses.sparse_softmax_cross_entropy instead.\n",
14
+ "\n",
15
+ "Menggunakan perangkat: cuda\n"
16
+ ]
17
+ },
18
+ {
19
+ "name": "stderr",
20
+ "output_type": "stream",
21
+ "text": [
22
+ "[I 2025-07-18 06:26:20,055] A new study created in memory with name: no-name-50af0249-7af4-476f-988c-7342adeab58c\n"
23
+ ]
24
+ },
25
+ {
26
+ "name": "stdout",
27
+ "output_type": "stream",
28
+ "text": [
29
+ "Memulai hyperparameter tuning dengan Optuna...\n"
30
+ ]
31
+ },
32
+ {
33
+ "name": "stderr",
34
+ "output_type": "stream",
35
+ "text": [
36
+ "Some weights of BertForTokenClassification were not initialized from the model checkpoint at indobenchmark/indobert-base-p1 and are newly initialized: ['classifier.bias', 'classifier.weight']\n",
37
+ "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n",
38
+ "C:\\Users\\BUDI\\AppData\\Local\\Temp\\ipykernel_6152\\2584540621.py:147: FutureWarning: `tokenizer` is deprecated and will be removed in version 5.0.0 for `Trainer.__init__`. Use `processing_class` instead.\n",
39
+ " trainer = Trainer(\n"
40
+ ]
41
+ },
42
+ {
43
+ "data": {
44
+ "text/html": [
45
+ "\n",
46
+ " <div>\n",
47
+ " \n",
48
+ " <progress value='836' max='836' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
49
+ " [836/836 03:00, Epoch 4/4]\n",
50
+ " </div>\n",
51
+ " <table border=\"1\" class=\"dataframe\">\n",
52
+ " <thead>\n",
53
+ " <tr style=\"text-align: left;\">\n",
54
+ " <th>Epoch</th>\n",
55
+ " <th>Training Loss</th>\n",
56
+ " <th>Validation Loss</th>\n",
57
+ " <th>Precision</th>\n",
58
+ " <th>Recall</th>\n",
59
+ " <th>F1</th>\n",
60
+ " <th>Accuracy</th>\n",
61
+ " <th>Per Entity</th>\n",
62
+ " </tr>\n",
63
+ " </thead>\n",
64
+ " <tbody>\n",
65
+ " <tr>\n",
66
+ " <td>1</td>\n",
67
+ " <td>0.124700</td>\n",
68
+ " <td>0.166868</td>\n",
69
+ " <td>0.748068</td>\n",
70
+ " <td>0.731118</td>\n",
71
+ " <td>0.739496</td>\n",
72
+ " <td>0.945582</td>\n",
73
+ " <td>{}</td>\n",
74
+ " </tr>\n",
75
+ " <tr>\n",
76
+ " <td>2</td>\n",
77
+ " <td>0.103800</td>\n",
78
+ " <td>0.157893</td>\n",
79
+ " <td>0.750355</td>\n",
80
+ " <td>0.799094</td>\n",
81
+ " <td>0.773958</td>\n",
82
+ " <td>0.952456</td>\n",
83
+ " <td>{}</td>\n",
84
+ " </tr>\n",
85
+ " <tr>\n",
86
+ " <td>3</td>\n",
87
+ " <td>0.096100</td>\n",
88
+ " <td>0.171932</td>\n",
89
+ " <td>0.800613</td>\n",
90
+ " <td>0.788520</td>\n",
91
+ " <td>0.794521</td>\n",
92
+ " <td>0.955606</td>\n",
93
+ " <td>{}</td>\n",
94
+ " </tr>\n",
95
+ " <tr>\n",
96
+ " <td>4</td>\n",
97
+ " <td>0.032800</td>\n",
98
+ " <td>0.178615</td>\n",
99
+ " <td>0.750704</td>\n",
100
+ " <td>0.805136</td>\n",
101
+ " <td>0.776968</td>\n",
102
+ " <td>0.954031</td>\n",
103
+ " <td>{}</td>\n",
104
+ " </tr>\n",
105
+ " </tbody>\n",
106
+ "</table><p>"
107
+ ],
108
+ "text/plain": [
109
+ "<IPython.core.display.HTML object>"
110
+ ]
111
+ },
112
+ "metadata": {},
113
+ "output_type": "display_data"
114
+ },
115
+ {
116
+ "name": "stderr",
117
+ "output_type": "stream",
118
+ "text": [
119
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
120
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
121
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
122
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
123
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
124
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
125
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
126
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n"
127
+ ]
128
+ },
129
+ {
130
+ "data": {
131
+ "text/html": [
132
+ "\n",
133
+ " <div>\n",
134
+ " \n",
135
+ " <progress value='27' max='27' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
136
+ " [27/27 00:01]\n",
137
+ " </div>\n",
138
+ " "
139
+ ],
140
+ "text/plain": [
141
+ "<IPython.core.display.HTML object>"
142
+ ]
143
+ },
144
+ "metadata": {},
145
+ "output_type": "display_data"
146
+ },
147
+ {
148
+ "name": "stderr",
149
+ "output_type": "stream",
150
+ "text": [
151
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
152
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
153
+ "[I 2025-07-18 06:29:29,091] Trial 0 finished with value: 0.7945205479452055 and parameters: {'learning_rate': 2.3555847899573657e-05, 'batch_size': 8, 'num_epochs': 4}. Best is trial 0 with value: 0.7945205479452055.\n",
154
+ "Some weights of BertForTokenClassification were not initialized from the model checkpoint at indobenchmark/indobert-base-p1 and are newly initialized: ['classifier.bias', 'classifier.weight']\n",
155
+ "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n",
156
+ "C:\\Users\\BUDI\\AppData\\Local\\Temp\\ipykernel_6152\\2584540621.py:147: FutureWarning: `tokenizer` is deprecated and will be removed in version 5.0.0 for `Trainer.__init__`. Use `processing_class` instead.\n",
157
+ " trainer = Trainer(\n"
158
+ ]
159
+ },
160
+ {
161
+ "data": {
162
+ "text/html": [
163
+ "\n",
164
+ " <div>\n",
165
+ " \n",
166
+ " <progress value='1045' max='1045' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
167
+ " [1045/1045 04:05, Epoch 5/5]\n",
168
+ " </div>\n",
169
+ " <table border=\"1\" class=\"dataframe\">\n",
170
+ " <thead>\n",
171
+ " <tr style=\"text-align: left;\">\n",
172
+ " <th>Epoch</th>\n",
173
+ " <th>Training Loss</th>\n",
174
+ " <th>Validation Loss</th>\n",
175
+ " <th>Precision</th>\n",
176
+ " <th>Recall</th>\n",
177
+ " <th>F1</th>\n",
178
+ " <th>Accuracy</th>\n",
179
+ " <th>Per Entity</th>\n",
180
+ " </tr>\n",
181
+ " </thead>\n",
182
+ " <tbody>\n",
183
+ " <tr>\n",
184
+ " <td>1</td>\n",
185
+ " <td>0.123500</td>\n",
186
+ " <td>0.163488</td>\n",
187
+ " <td>0.728788</td>\n",
188
+ " <td>0.726586</td>\n",
189
+ " <td>0.727685</td>\n",
190
+ " <td>0.945009</td>\n",
191
+ " <td>{}</td>\n",
192
+ " </tr>\n",
193
+ " <tr>\n",
194
+ " <td>2</td>\n",
195
+ " <td>0.108800</td>\n",
196
+ " <td>0.155614</td>\n",
197
+ " <td>0.737346</td>\n",
198
+ " <td>0.814199</td>\n",
199
+ " <td>0.773869</td>\n",
200
+ " <td>0.953745</td>\n",
201
+ " <td>{}</td>\n",
202
+ " </tr>\n",
203
+ " <tr>\n",
204
+ " <td>3</td>\n",
205
+ " <td>0.110300</td>\n",
206
+ " <td>0.170470</td>\n",
207
+ " <td>0.763314</td>\n",
208
+ " <td>0.779456</td>\n",
209
+ " <td>0.771300</td>\n",
210
+ " <td>0.953172</td>\n",
211
+ " <td>{}</td>\n",
212
+ " </tr>\n",
213
+ " <tr>\n",
214
+ " <td>4</td>\n",
215
+ " <td>0.045800</td>\n",
216
+ " <td>0.182373</td>\n",
217
+ " <td>0.765557</td>\n",
218
+ " <td>0.799094</td>\n",
219
+ " <td>0.781966</td>\n",
220
+ " <td>0.954031</td>\n",
221
+ " <td>{}</td>\n",
222
+ " </tr>\n",
223
+ " <tr>\n",
224
+ " <td>5</td>\n",
225
+ " <td>0.022400</td>\n",
226
+ " <td>0.191159</td>\n",
227
+ " <td>0.758571</td>\n",
228
+ " <td>0.802115</td>\n",
229
+ " <td>0.779736</td>\n",
230
+ " <td>0.953315</td>\n",
231
+ " <td>{}</td>\n",
232
+ " </tr>\n",
233
+ " </tbody>\n",
234
+ "</table><p>"
235
+ ],
236
+ "text/plain": [
237
+ "<IPython.core.display.HTML object>"
238
+ ]
239
+ },
240
+ "metadata": {},
241
+ "output_type": "display_data"
242
+ },
243
+ {
244
+ "name": "stderr",
245
+ "output_type": "stream",
246
+ "text": [
247
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
248
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
249
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
250
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
251
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
252
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
253
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
254
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
255
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
256
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n"
257
+ ]
258
+ },
259
+ {
260
+ "data": {
261
+ "text/html": [
262
+ "\n",
263
+ " <div>\n",
264
+ " \n",
265
+ " <progress value='27' max='27' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
266
+ " [27/27 00:01]\n",
267
+ " </div>\n",
268
+ " "
269
+ ],
270
+ "text/plain": [
271
+ "<IPython.core.display.HTML object>"
272
+ ]
273
+ },
274
+ "metadata": {},
275
+ "output_type": "display_data"
276
+ },
277
+ {
278
+ "name": "stderr",
279
+ "output_type": "stream",
280
+ "text": [
281
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
282
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
283
+ "[I 2025-07-18 06:33:40,086] Trial 1 finished with value: 0.7819660014781965 and parameters: {'learning_rate': 1.7904807706862636e-05, 'batch_size': 8, 'num_epochs': 5}. Best is trial 0 with value: 0.7945205479452055.\n",
284
+ "Some weights of BertForTokenClassification were not initialized from the model checkpoint at indobenchmark/indobert-base-p1 and are newly initialized: ['classifier.bias', 'classifier.weight']\n",
285
+ "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n",
286
+ "C:\\Users\\BUDI\\AppData\\Local\\Temp\\ipykernel_6152\\2584540621.py:147: FutureWarning: `tokenizer` is deprecated and will be removed in version 5.0.0 for `Trainer.__init__`. Use `processing_class` instead.\n",
287
+ " trainer = Trainer(\n"
288
+ ]
289
+ },
290
+ {
291
+ "data": {
292
+ "text/html": [
293
+ "\n",
294
+ " <div>\n",
295
+ " \n",
296
+ " <progress value='420' max='420' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
297
+ " [420/420 05:47, Epoch 4/4]\n",
298
+ " </div>\n",
299
+ " <table border=\"1\" class=\"dataframe\">\n",
300
+ " <thead>\n",
301
+ " <tr style=\"text-align: left;\">\n",
302
+ " <th>Epoch</th>\n",
303
+ " <th>Training Loss</th>\n",
304
+ " <th>Validation Loss</th>\n",
305
+ " <th>Precision</th>\n",
306
+ " <th>Recall</th>\n",
307
+ " <th>F1</th>\n",
308
+ " <th>Accuracy</th>\n",
309
+ " <th>Per Entity</th>\n",
310
+ " </tr>\n",
311
+ " </thead>\n",
312
+ " <tbody>\n",
313
+ " <tr>\n",
314
+ " <td>1</td>\n",
315
+ " <td>0.138600</td>\n",
316
+ " <td>0.185550</td>\n",
317
+ " <td>0.738769</td>\n",
318
+ " <td>0.670695</td>\n",
319
+ " <td>0.703088</td>\n",
320
+ " <td>0.942432</td>\n",
321
+ " <td>{}</td>\n",
322
+ " </tr>\n",
323
+ " <tr>\n",
324
+ " <td>2</td>\n",
325
+ " <td>0.109800</td>\n",
326
+ " <td>0.154619</td>\n",
327
+ " <td>0.781899</td>\n",
328
+ " <td>0.796073</td>\n",
329
+ " <td>0.788922</td>\n",
330
+ " <td>0.955463</td>\n",
331
+ " <td>{}</td>\n",
332
+ " </tr>\n",
333
+ " <tr>\n",
334
+ " <td>3</td>\n",
335
+ " <td>0.069800</td>\n",
336
+ " <td>0.155078</td>\n",
337
+ " <td>0.807750</td>\n",
338
+ " <td>0.818731</td>\n",
339
+ " <td>0.813203</td>\n",
340
+ " <td>0.960332</td>\n",
341
+ " <td>{}</td>\n",
342
+ " </tr>\n",
343
+ " <tr>\n",
344
+ " <td>4</td>\n",
345
+ " <td>0.027200</td>\n",
346
+ " <td>0.174292</td>\n",
347
+ " <td>0.765292</td>\n",
348
+ " <td>0.812689</td>\n",
349
+ " <td>0.788278</td>\n",
350
+ " <td>0.954747</td>\n",
351
+ " <td>{}</td>\n",
352
+ " </tr>\n",
353
+ " </tbody>\n",
354
+ "</table><p>"
355
+ ],
356
+ "text/plain": [
357
+ "<IPython.core.display.HTML object>"
358
+ ]
359
+ },
360
+ "metadata": {},
361
+ "output_type": "display_data"
362
+ },
363
+ {
364
+ "name": "stderr",
365
+ "output_type": "stream",
366
+ "text": [
367
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
368
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
369
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
370
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
371
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
372
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
373
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
374
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n"
375
+ ]
376
+ },
377
+ {
378
+ "data": {
379
+ "text/html": [
380
+ "\n",
381
+ " <div>\n",
382
+ " \n",
383
+ " <progress value='14' max='14' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
384
+ " [14/14 00:00]\n",
385
+ " </div>\n",
386
+ " "
387
+ ],
388
+ "text/plain": [
389
+ "<IPython.core.display.HTML object>"
390
+ ]
391
+ },
392
+ "metadata": {},
393
+ "output_type": "display_data"
394
+ },
395
+ {
396
+ "name": "stderr",
397
+ "output_type": "stream",
398
+ "text": [
399
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
400
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
401
+ "[I 2025-07-18 06:39:32,835] Trial 2 finished with value: 0.8132033008252062 and parameters: {'learning_rate': 3.672145523121866e-05, 'batch_size': 16, 'num_epochs': 4}. Best is trial 2 with value: 0.8132033008252062.\n",
402
+ "Some weights of BertForTokenClassification were not initialized from the model checkpoint at indobenchmark/indobert-base-p1 and are newly initialized: ['classifier.bias', 'classifier.weight']\n",
403
+ "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n",
404
+ "C:\\Users\\BUDI\\AppData\\Local\\Temp\\ipykernel_6152\\2584540621.py:147: FutureWarning: `tokenizer` is deprecated and will be removed in version 5.0.0 for `Trainer.__init__`. Use `processing_class` instead.\n",
405
+ " trainer = Trainer(\n"
406
+ ]
407
+ },
408
+ {
409
+ "data": {
410
+ "text/html": [
411
+ "\n",
412
+ " <div>\n",
413
+ " \n",
414
+ " <progress value='525' max='525' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
415
+ " [525/525 07:42, Epoch 5/5]\n",
416
+ " </div>\n",
417
+ " <table border=\"1\" class=\"dataframe\">\n",
418
+ " <thead>\n",
419
+ " <tr style=\"text-align: left;\">\n",
420
+ " <th>Epoch</th>\n",
421
+ " <th>Training Loss</th>\n",
422
+ " <th>Validation Loss</th>\n",
423
+ " <th>Precision</th>\n",
424
+ " <th>Recall</th>\n",
425
+ " <th>F1</th>\n",
426
+ " <th>Accuracy</th>\n",
427
+ " <th>Per Entity</th>\n",
428
+ " </tr>\n",
429
+ " </thead>\n",
430
+ " <tbody>\n",
431
+ " <tr>\n",
432
+ " <td>1</td>\n",
433
+ " <td>0.143200</td>\n",
434
+ " <td>0.170970</td>\n",
435
+ " <td>0.745514</td>\n",
436
+ " <td>0.690332</td>\n",
437
+ " <td>0.716863</td>\n",
438
+ " <td>0.945869</td>\n",
439
+ " <td>{}</td>\n",
440
+ " </tr>\n",
441
+ " <tr>\n",
442
+ " <td>2</td>\n",
443
+ " <td>0.107300</td>\n",
444
+ " <td>0.154406</td>\n",
445
+ " <td>0.766141</td>\n",
446
+ " <td>0.806647</td>\n",
447
+ " <td>0.785872</td>\n",
448
+ " <td>0.953029</td>\n",
449
+ " <td>{}</td>\n",
450
+ " </tr>\n",
451
+ " <tr>\n",
452
+ " <td>3</td>\n",
453
+ " <td>0.075100</td>\n",
454
+ " <td>0.158503</td>\n",
455
+ " <td>0.795420</td>\n",
456
+ " <td>0.787009</td>\n",
457
+ " <td>0.791192</td>\n",
458
+ " <td>0.956895</td>\n",
459
+ " <td>{}</td>\n",
460
+ " </tr>\n",
461
+ " <tr>\n",
462
+ " <td>4</td>\n",
463
+ " <td>0.025800</td>\n",
464
+ " <td>0.179348</td>\n",
465
+ " <td>0.764791</td>\n",
466
+ " <td>0.800604</td>\n",
467
+ " <td>0.782288</td>\n",
468
+ " <td>0.954461</td>\n",
469
+ " <td>{}</td>\n",
470
+ " </tr>\n",
471
+ " <tr>\n",
472
+ " <td>5</td>\n",
473
+ " <td>0.013400</td>\n",
474
+ " <td>0.185257</td>\n",
475
+ " <td>0.766049</td>\n",
476
+ " <td>0.811178</td>\n",
477
+ " <td>0.787968</td>\n",
478
+ " <td>0.953888</td>\n",
479
+ " <td>{}</td>\n",
480
+ " </tr>\n",
481
+ " </tbody>\n",
482
+ "</table><p>"
483
+ ],
484
+ "text/plain": [
485
+ "<IPython.core.display.HTML object>"
486
+ ]
487
+ },
488
+ "metadata": {},
489
+ "output_type": "display_data"
490
+ },
491
+ {
492
+ "name": "stderr",
493
+ "output_type": "stream",
494
+ "text": [
495
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
496
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
497
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
498
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
499
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
500
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
501
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
502
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
503
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
504
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n"
505
+ ]
506
+ },
507
+ {
508
+ "data": {
509
+ "text/html": [
510
+ "\n",
511
+ " <div>\n",
512
+ " \n",
513
+ " <progress value='14' max='14' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
514
+ " [14/14 00:01]\n",
515
+ " </div>\n",
516
+ " "
517
+ ],
518
+ "text/plain": [
519
+ "<IPython.core.display.HTML object>"
520
+ ]
521
+ },
522
+ "metadata": {},
523
+ "output_type": "display_data"
524
+ },
525
+ {
526
+ "name": "stderr",
527
+ "output_type": "stream",
528
+ "text": [
529
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
530
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
531
+ "[I 2025-07-18 06:47:22,280] Trial 3 finished with value: 0.7911921032649962 and parameters: {'learning_rate': 3.713773945286763e-05, 'batch_size': 16, 'num_epochs': 5}. Best is trial 2 with value: 0.8132033008252062.\n",
532
+ "Some weights of BertForTokenClassification were not initialized from the model checkpoint at indobenchmark/indobert-base-p1 and are newly initialized: ['classifier.bias', 'classifier.weight']\n",
533
+ "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n",
534
+ "C:\\Users\\BUDI\\AppData\\Local\\Temp\\ipykernel_6152\\2584540621.py:147: FutureWarning: `tokenizer` is deprecated and will be removed in version 5.0.0 for `Trainer.__init__`. Use `processing_class` instead.\n",
535
+ " trainer = Trainer(\n"
536
+ ]
537
+ },
538
+ {
539
+ "data": {
540
+ "text/html": [
541
+ "\n",
542
+ " <div>\n",
543
+ " \n",
544
+ " <progress value='1045' max='1045' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
545
+ " [1045/1045 04:30, Epoch 5/5]\n",
546
+ " </div>\n",
547
+ " <table border=\"1\" class=\"dataframe\">\n",
548
+ " <thead>\n",
549
+ " <tr style=\"text-align: left;\">\n",
550
+ " <th>Epoch</th>\n",
551
+ " <th>Training Loss</th>\n",
552
+ " <th>Validation Loss</th>\n",
553
+ " <th>Precision</th>\n",
554
+ " <th>Recall</th>\n",
555
+ " <th>F1</th>\n",
556
+ " <th>Accuracy</th>\n",
557
+ " <th>Per Entity</th>\n",
558
+ " </tr>\n",
559
+ " </thead>\n",
560
+ " <tbody>\n",
561
+ " <tr>\n",
562
+ " <td>1</td>\n",
563
+ " <td>0.132700</td>\n",
564
+ " <td>0.169205</td>\n",
565
+ " <td>0.715361</td>\n",
566
+ " <td>0.717523</td>\n",
567
+ " <td>0.716440</td>\n",
568
+ " <td>0.944007</td>\n",
569
+ " <td>{}</td>\n",
570
+ " </tr>\n",
571
+ " <tr>\n",
572
+ " <td>2</td>\n",
573
+ " <td>0.120000</td>\n",
574
+ " <td>0.155390</td>\n",
575
+ " <td>0.750700</td>\n",
576
+ " <td>0.809668</td>\n",
577
+ " <td>0.779070</td>\n",
578
+ " <td>0.953458</td>\n",
579
+ " <td>{}</td>\n",
580
+ " </tr>\n",
581
+ " <tr>\n",
582
+ " <td>3</td>\n",
583
+ " <td>0.136600</td>\n",
584
+ " <td>0.163555</td>\n",
585
+ " <td>0.761974</td>\n",
586
+ " <td>0.793051</td>\n",
587
+ " <td>0.777202</td>\n",
588
+ " <td>0.954174</td>\n",
589
+ " <td>{}</td>\n",
590
+ " </tr>\n",
591
+ " <tr>\n",
592
+ " <td>4</td>\n",
593
+ " <td>0.067900</td>\n",
594
+ " <td>0.172124</td>\n",
595
+ " <td>0.766476</td>\n",
596
+ " <td>0.808157</td>\n",
597
+ " <td>0.786765</td>\n",
598
+ " <td>0.953888</td>\n",
599
+ " <td>{}</td>\n",
600
+ " </tr>\n",
601
+ " <tr>\n",
602
+ " <td>5</td>\n",
603
+ " <td>0.035200</td>\n",
604
+ " <td>0.180249</td>\n",
605
+ " <td>0.759943</td>\n",
606
+ " <td>0.808157</td>\n",
607
+ " <td>0.783309</td>\n",
608
+ " <td>0.953745</td>\n",
609
+ " <td>{}</td>\n",
610
+ " </tr>\n",
611
+ " </tbody>\n",
612
+ "</table><p>"
613
+ ],
614
+ "text/plain": [
615
+ "<IPython.core.display.HTML object>"
616
+ ]
617
+ },
618
+ "metadata": {},
619
+ "output_type": "display_data"
620
+ },
621
+ {
622
+ "name": "stderr",
623
+ "output_type": "stream",
624
+ "text": [
625
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
626
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
627
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
628
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
629
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
630
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
631
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
632
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
633
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
634
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n"
635
+ ]
636
+ },
637
+ {
638
+ "data": {
639
+ "text/html": [
640
+ "\n",
641
+ " <div>\n",
642
+ " \n",
643
+ " <progress value='27' max='27' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
644
+ " [27/27 00:01]\n",
645
+ " </div>\n",
646
+ " "
647
+ ],
648
+ "text/plain": [
649
+ "<IPython.core.display.HTML object>"
650
+ ]
651
+ },
652
+ "metadata": {},
653
+ "output_type": "display_data"
654
+ },
655
+ {
656
+ "name": "stderr",
657
+ "output_type": "stream",
658
+ "text": [
659
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
660
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
661
+ "[I 2025-07-18 06:51:59,633] Trial 4 finished with value: 0.7867647058823529 and parameters: {'learning_rate': 1.1923156920458335e-05, 'batch_size': 8, 'num_epochs': 5}. Best is trial 2 with value: 0.8132033008252062.\n"
662
+ ]
663
+ },
664
+ {
665
+ "name": "stdout",
666
+ "output_type": "stream",
667
+ "text": [
668
+ "\n",
669
+ "Hyperparameter terbaik:\n",
670
+ "{'learning_rate': 3.672145523121866e-05, 'batch_size': 16, 'num_epochs': 4}\n",
671
+ "F1-Score terbaik: 0.8132\n"
672
+ ]
673
+ },
674
+ {
675
+ "name": "stderr",
676
+ "output_type": "stream",
677
+ "text": [
678
+ "Some weights of BertForTokenClassification were not initialized from the model checkpoint at indobenchmark/indobert-base-p1 and are newly initialized: ['classifier.bias', 'classifier.weight']\n",
679
+ "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n",
680
+ "C:\\Users\\BUDI\\AppData\\Local\\Temp\\ipykernel_6152\\2584540621.py:195: FutureWarning: `tokenizer` is deprecated and will be removed in version 5.0.0 for `Trainer.__init__`. Use `processing_class` instead.\n",
681
+ " trainer = Trainer(\n"
682
+ ]
683
+ },
684
+ {
685
+ "name": "stdout",
686
+ "output_type": "stream",
687
+ "text": [
688
+ "\n",
689
+ "Memulai pelatihan dengan hyperparameter terbaik...\n"
690
+ ]
691
+ },
692
+ {
693
+ "data": {
694
+ "text/html": [
695
+ "\n",
696
+ " <div>\n",
697
+ " \n",
698
+ " <progress value='420' max='420' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
699
+ " [420/420 07:01, Epoch 4/4]\n",
700
+ " </div>\n",
701
+ " <table border=\"1\" class=\"dataframe\">\n",
702
+ " <thead>\n",
703
+ " <tr style=\"text-align: left;\">\n",
704
+ " <th>Epoch</th>\n",
705
+ " <th>Training Loss</th>\n",
706
+ " <th>Validation Loss</th>\n",
707
+ " <th>Precision</th>\n",
708
+ " <th>Recall</th>\n",
709
+ " <th>F1</th>\n",
710
+ " <th>Accuracy</th>\n",
711
+ " <th>Per Entity</th>\n",
712
+ " </tr>\n",
713
+ " </thead>\n",
714
+ " <tbody>\n",
715
+ " <tr>\n",
716
+ " <td>1</td>\n",
717
+ " <td>0.138600</td>\n",
718
+ " <td>0.185550</td>\n",
719
+ " <td>0.738769</td>\n",
720
+ " <td>0.670695</td>\n",
721
+ " <td>0.703088</td>\n",
722
+ " <td>0.942432</td>\n",
723
+ " <td>{}</td>\n",
724
+ " </tr>\n",
725
+ " <tr>\n",
726
+ " <td>2</td>\n",
727
+ " <td>0.109800</td>\n",
728
+ " <td>0.154619</td>\n",
729
+ " <td>0.781899</td>\n",
730
+ " <td>0.796073</td>\n",
731
+ " <td>0.788922</td>\n",
732
+ " <td>0.955463</td>\n",
733
+ " <td>{}</td>\n",
734
+ " </tr>\n",
735
+ " <tr>\n",
736
+ " <td>3</td>\n",
737
+ " <td>0.069800</td>\n",
738
+ " <td>0.155078</td>\n",
739
+ " <td>0.807750</td>\n",
740
+ " <td>0.818731</td>\n",
741
+ " <td>0.813203</td>\n",
742
+ " <td>0.960332</td>\n",
743
+ " <td>{}</td>\n",
744
+ " </tr>\n",
745
+ " <tr>\n",
746
+ " <td>4</td>\n",
747
+ " <td>0.027200</td>\n",
748
+ " <td>0.174292</td>\n",
749
+ " <td>0.765292</td>\n",
750
+ " <td>0.812689</td>\n",
751
+ " <td>0.788278</td>\n",
752
+ " <td>0.954747</td>\n",
753
+ " <td>{}</td>\n",
754
+ " </tr>\n",
755
+ " </tbody>\n",
756
+ "</table><p>"
757
+ ],
758
+ "text/plain": [
759
+ "<IPython.core.display.HTML object>"
760
+ ]
761
+ },
762
+ "metadata": {},
763
+ "output_type": "display_data"
764
+ },
765
+ {
766
+ "name": "stderr",
767
+ "output_type": "stream",
768
+ "text": [
769
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
770
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
771
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
772
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
773
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
774
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n",
775
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
776
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n"
777
+ ]
778
+ },
779
+ {
780
+ "name": "stdout",
781
+ "output_type": "stream",
782
+ "text": [
783
+ "\n",
784
+ "Mengevaluasi model pada data test...\n"
785
+ ]
786
+ },
787
+ {
788
+ "data": {
789
+ "text/html": [
790
+ "\n",
791
+ " <div>\n",
792
+ " \n",
793
+ " <progress value='14' max='14' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
794
+ " [14/14 00:05]\n",
795
+ " </div>\n",
796
+ " "
797
+ ],
798
+ "text/plain": [
799
+ "<IPython.core.display.HTML object>"
800
+ ]
801
+ },
802
+ "metadata": {},
803
+ "output_type": "display_data"
804
+ },
805
+ {
806
+ "name": "stderr",
807
+ "output_type": "stream",
808
+ "text": [
809
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval_per_entity\" as a metric. MLflow's log_metric() only accepts float and int types so we dropped this attribute.\n",
810
+ "Trainer is attempting to log a value of \"{}\" of type <class 'dict'> for key \"eval/per_entity\" as a scalar. This invocation of Tensorboard's writer.add_scalar() is incorrect so we dropped this attribute.\n"
811
+ ]
812
+ },
813
+ {
814
+ "name": "stdout",
815
+ "output_type": "stream",
816
+ "text": [
817
+ "\n",
818
+ "Hasil Evaluasi:\n",
819
+ "Precision: 0.7528\n",
820
+ "Recall: 0.7878\n",
821
+ "F1-Score: 0.7699\n",
822
+ "Accuracy: 0.9497\n",
823
+ "\n",
824
+ "Metrik per Entitas:\n",
825
+ "\n",
826
+ "Model dan tokenizer telah disimpan ke './ner_model'\n",
827
+ "\n",
828
+ "Contoh Prediksi pada Data Test (5 Sampel):\n",
829
+ "\n",
830
+ "Sampel 1:\n",
831
+ "Tokens: [CLS] joe ##tat ##a hadi ##hard ##aja dan dihadiri oleh rektor undip prof . [SEP]\n",
832
+ "True Labels: ['B-PERSON', 'I-PERSON', 'O', 'O', 'O', 'O', 'B-ORGANISATION', 'O', 'O']\n",
833
+ "Predicted Labels: ['B-PERSON', 'I-PERSON', 'O', 'O', 'O', 'O', 'B-PLACE', 'O', 'O']\n",
834
+ "\n",
835
+ "Sampel 2:\n",
836
+ "Tokens: [CLS] sejak masih duduk di bangku sekolah tk kevin sudah belajar alat musik piano secara formal dan ketika ia menginjak sekolah smp pemilik nama asli kevin april ##io sum ##aat ##maj ##a ini , mulai belajar menulis lagu sendiri . [SEP]\n",
837
+ "True Labels: ['O', 'O', 'O', 'O', 'O', 'O', 'O', 'B-PERSON', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'B-PERSON', 'I-PERSON', 'I-PERSON', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O']\n",
838
+ "Predicted Labels: ['O', 'O', 'O', 'O', 'O', 'O', 'O', 'B-PERSON', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'B-PERSON', 'I-PERSON', 'I-PERSON', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O']\n",
839
+ "\n",
840
+ "Sampel 3:\n",
841
+ "Tokens: [CLS] pada tanggal 6 februari 1976 , wakil ketua lock ##he ##ed corporation memberitahu subk ##omi ##te senat as bahwa tana ##ka selaku pm telah dibayar ( dis ##ogo ##k ) sebagai ganjaran pembelian pesawat lock ##he ##ed l - 1011 . [SEP]\n",
842
+ "True Labels: ['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'B-ORGANISATION', 'I-ORGANISATION', 'O', 'O', 'O', 'B-PLACE', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'B-ORGANISATION', 'O', 'O', 'O', 'O']\n",
843
+ "Predicted Labels: ['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'B-ORGANISATION', 'I-ORGANISATION', 'O', 'O', 'O', 'B-PLACE', 'O', 'B-PERSON', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'B-ORGANISATION', 'O', 'O', 'O', 'O']\n",
844
+ "\n",
845
+ "Sampel 4:\n",
846
+ "Tokens: [CLS] dengan kondisi alam yang sejuk dan curah hujan yang tinggi maka didaerah tersebut banyak didapati bermacam jenis flora dan fauna seperti : gajah yang di kenal dengan legenda poc ##ut me ##urah ##nya , rusa , harimau , beruang , kancil , babi hutan , tengg ##iling , landak dan ular , juga terdapat berbagai macam jenis burung yang selalu menghiasi kawasan ini . [SEP]\n",
847
+ "True Labels: ['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O']\n",
848
+ "Predicted Labels: ['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O']\n",
849
+ "\n",
850
+ "Sampel 5:\n",
851
+ "Tokens: [CLS] awak pesawat yang terdiri atas pilot ard ##y ted ##jo , kopi ##lot h ribuan dan dua awak lainnya perry reh ##ata dan mei ##nas ##ta segera membuka pintu pesawat dan menurunkan penumpang dengan selamat . tanggal 14 juni 2009 , hari minggu , pukul 09 . 20 , pesawat terbang express air jenis dor ##nie ##r d ##32 ##8 - 100 bernomor badan pk - tx ##n , mengalami kecelakaan saat mendarat . [SEP]\n",
852
+ "True Labels: ['O', 'O', 'O', 'O', 'O', 'O', 'B-PERSON', 'I-PERSON', 'O', 'O', 'B-PERSON', 'I-PERSON', 'O', 'O', 'O', 'O', 'B-PERSON', 'I-PERSON', 'O', 'B-PERSON', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'B-ORGANISATION', 'I-ORGANISATION', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O']\n",
853
+ "Predicted Labels: ['O', 'O', 'O', 'O', 'O', 'O', 'B-PERSON', 'I-PERSON', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'B-PERSON', 'I-PERSON', 'O', 'B-PERSON', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O']\n",
854
+ "\n",
855
+ "Analisis Pola Error (Tanggal diprediksi sebagai Lokasi):\n",
856
+ "Tidak ditemukan contoh tanggal yang diprediksi sebagai lokasi dalam 100 sampel.\n",
857
+ "\n",
858
+ "Pertimbangan Keamanan Data, Privasi, dan Etika:\n",
859
+ "- Dataset bersumber dari berita publik, tidak mengandung informasi sensitif seperti alamat atau nomor identitas.\n",
860
+ "- Nama orang dalam dataset berasal dari media publik, aman untuk digunakan.\n",
861
+ "- Dataset mencakup berbagai topik berita, mengurangi risiko bias terhadap entitas tertentu.\n"
862
+ ]
863
+ }
864
+ ],
865
+ "source": [
866
+ "import os\n",
867
+ "import sys\n",
868
+ "import subprocess\n",
869
+ "import numpy as np\n",
870
+ "from datasets import load_dataset\n",
871
+ "from transformers import AutoTokenizer, AutoModelForTokenClassification, DataCollatorForTokenClassification, Trainer, TrainingArguments\n",
872
+ "import evaluate\n",
873
+ "import torch\n",
874
+ "import optuna\n",
875
+ "\n",
876
+ "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
877
+ "print(f\"Menggunakan perangkat: {device}\")\n",
878
+ "\n",
879
+ "# Load dataset\n",
880
+ "try:\n",
881
+ " dataset = load_dataset(\"indonlp/indonlu\", \"nergrit\", trust_remote_code=True)\n",
882
+ "except Exception as e:\n",
883
+ " print(f\"Gagal memuat dataset: {e}\")\n",
884
+ " sys.exit(1)\n",
885
+ "\n",
886
+ "# Verify dataset structure\n",
887
+ "if \"train\" not in dataset or \"validation\" not in dataset or \"test\" not in dataset:\n",
888
+ " print(\"Dataset tidak memiliki split train/validation/test yang diharapkan.\")\n",
889
+ " sys.exit(1)\n",
890
+ "if \"tokens\" not in dataset[\"train\"].column_names or \"ner_tags\" not in dataset[\"train\"].column_names:\n",
891
+ " print(\"Dataset tidak memiliki kolom 'tokens' atau 'ner_tags'.\")\n",
892
+ " sys.exit(1)\n",
893
+ "\n",
894
+ "# Define label list\n",
895
+ "try:\n",
896
+ " label_list = dataset[\"train\"].features[\"ner_tags\"].feature.names\n",
897
+ " label2id = {label: i for i, label in enumerate(label_list)}\n",
898
+ " id2label = {i: label for i, label in enumerate(label_list)}\n",
899
+ "except Exception as e:\n",
900
+ " print(f\"Gagal mendapatkan label: {e}\")\n",
901
+ " sys.exit(1)\n",
902
+ "\n",
903
+ "# Load tokenizer\n",
904
+ "try:\n",
905
+ " tokenizer = AutoTokenizer.from_pretrained(\"indobenchmark/indobert-base-p1\")\n",
906
+ "except Exception as e:\n",
907
+ " print(f\"Gagal memuat tokenizer: {e}\")\n",
908
+ " sys.exit(1)\n",
909
+ "\n",
910
+ "# Tokenize and align labels\n",
911
+ "def tokenize_and_align_labels(examples):\n",
912
+ " tokenized_inputs = tokenizer(examples[\"tokens\"], truncation=True, is_split_into_words=True)\n",
913
+ " labels = []\n",
914
+ " for i, label in enumerate(examples[\"ner_tags\"]):\n",
915
+ " word_ids = tokenized_inputs.word_ids(batch_index=i)\n",
916
+ " previous_word_idx = None\n",
917
+ " label_ids = []\n",
918
+ " for word_idx in word_ids:\n",
919
+ " if word_idx is None:\n",
920
+ " label_ids.append(-100)\n",
921
+ " elif word_idx != previous_word_idx:\n",
922
+ " label_ids.append(label[word_idx])\n",
923
+ " else:\n",
924
+ " label_ids.append(-100)\n",
925
+ " previous_word_idx = word_idx\n",
926
+ " labels.append(label_ids)\n",
927
+ " tokenized_inputs[\"labels\"] = labels\n",
928
+ " return tokenized_inputs\n",
929
+ "\n",
930
+ "# Tokenize dataset\n",
931
+ "try:\n",
932
+ " tokenized_dataset = dataset.map(tokenize_and_align_labels, batched=True)\n",
933
+ "except Exception as e:\n",
934
+ " print(f\"Gagal menokenisasi dataset: {e}\")\n",
935
+ " sys.exit(1)\n",
936
+ "\n",
937
+ "# Data collator\n",
938
+ "data_collator = DataCollatorForTokenClassification(tokenizer)\n",
939
+ "\n",
940
+ "# Load evaluation metric\n",
941
+ "metric = evaluate.load(\"seqeval\")\n",
942
+ "\n",
943
+ "# Compute metrics\n",
944
+ "def compute_metrics(p):\n",
945
+ " predictions, labels = p\n",
946
+ " predictions = np.argmax(predictions, axis=2)\n",
947
+ " true_labels = [[id2label[l] for l in label if l != -100] for label in labels]\n",
948
+ " pred_labels = [[id2label[p] for p, l in zip(prediction, label) if l != -100] for prediction, label in zip(predictions, labels)]\n",
949
+ " results = metric.compute(predictions=pred_labels, references=true_labels)\n",
950
+ " per_entity = {}\n",
951
+ " for entity in [\"PERSON\", \"ORGANISATION\", \"PLACE\", \"DATE\"]:\n",
952
+ " if entity.lower() in results:\n",
953
+ " per_entity[entity] = {\n",
954
+ " \"precision\": results[entity.lower()][\"precision\"],\n",
955
+ " \"recall\": results[entity.lower()][\"recall\"],\n",
956
+ " \"f1\": results[entity.lower()][\"f1\"],\n",
957
+ " }\n",
958
+ " return {\n",
959
+ " \"precision\": results[\"overall_precision\"],\n",
960
+ " \"recall\": results[\"overall_recall\"],\n",
961
+ " \"f1\": results[\"overall_f1\"],\n",
962
+ " \"accuracy\": results[\"overall_accuracy\"],\n",
963
+ " \"per_entity\": per_entity,\n",
964
+ " }\n",
965
+ "\n",
966
+ "# Define objective function for Optuna\n",
967
+ "def objective(trial):\n",
968
+ " # Define hyperparameter search space\n",
969
+ " learning_rate = trial.suggest_float(\"learning_rate\", 1e-5, 5e-5, log=True)\n",
970
+ " batch_size = trial.suggest_categorical(\"batch_size\", [8, 16, 32])\n",
971
+ " num_epochs = trial.suggest_int(\"num_epochs\", 3, 5)\n",
972
+ "\n",
973
+ " # Load model for each trial\n",
974
+ " model = AutoModelForTokenClassification.from_pretrained(\n",
975
+ " \"indobenchmark/indobert-base-p1\",\n",
976
+ " num_labels=len(label_list),\n",
977
+ " id2label=id2label,\n",
978
+ " label2id=label2id\n",
979
+ " )\n",
980
+ " model.to(device)\n",
981
+ "\n",
982
+ " # Set training arguments\n",
983
+ " training_args = TrainingArguments(\n",
984
+ " output_dir=f\"./results_trial_{trial.number}\",\n",
985
+ " eval_strategy=\"epoch\",\n",
986
+ " learning_rate=learning_rate,\n",
987
+ " per_device_train_batch_size=batch_size,\n",
988
+ " per_device_eval_batch_size=batch_size,\n",
989
+ " num_train_epochs=num_epochs,\n",
990
+ " weight_decay=0.01,\n",
991
+ " logging_dir=f\"./logs_trial_{trial.number}\",\n",
992
+ " logging_steps=10,\n",
993
+ " save_strategy=\"epoch\",\n",
994
+ " load_best_model_at_end=True,\n",
995
+ " metric_for_best_model=\"f1\",\n",
996
+ " )\n",
997
+ "\n",
998
+ " # Initialize Trainer\n",
999
+ " trainer = Trainer(\n",
1000
+ " model=model,\n",
1001
+ " args=training_args,\n",
1002
+ " train_dataset=tokenized_dataset[\"train\"],\n",
1003
+ " eval_dataset=tokenized_dataset[\"validation\"],\n",
1004
+ " tokenizer=tokenizer,\n",
1005
+ " data_collator=data_collator,\n",
1006
+ " compute_metrics=compute_metrics,\n",
1007
+ " )\n",
1008
+ "\n",
1009
+ " # Train and evaluate\n",
1010
+ " trainer.train()\n",
1011
+ " eval_results = trainer.evaluate()\n",
1012
+ " return eval_results[\"eval_f1\"]\n",
1013
+ "\n",
1014
+ "# Run Optuna optimization\n",
1015
+ "print(\"Memulai hyperparameter tuning dengan Optuna...\")\n",
1016
+ "study = optuna.create_study(direction=\"maximize\")\n",
1017
+ "study.optimize(objective, n_trials=5) # Adjust n_trials as needed\n",
1018
+ "print(\"\\nHyperparameter terbaik:\")\n",
1019
+ "print(study.best_params)\n",
1020
+ "print(f\"F1-Score terbaik: {study.best_value:.4f}\")\n",
1021
+ "\n",
1022
+ "# Train final model with best hyperparameters\n",
1023
+ "best_params = study.best_params\n",
1024
+ "model = AutoModelForTokenClassification.from_pretrained(\n",
1025
+ " \"indobenchmark/indobert-base-p1\",\n",
1026
+ " num_labels=len(label_list),\n",
1027
+ " id2label=id2label,\n",
1028
+ " label2id=label2id\n",
1029
+ ")\n",
1030
+ "model.to(device)\n",
1031
+ "\n",
1032
+ "training_args = TrainingArguments(\n",
1033
+ " output_dir=\"./results\",\n",
1034
+ " eval_strategy=\"epoch\",\n",
1035
+ " learning_rate=best_params[\"learning_rate\"],\n",
1036
+ " per_device_train_batch_size=best_params[\"batch_size\"],\n",
1037
+ " per_device_eval_batch_size=best_params[\"batch_size\"],\n",
1038
+ " num_train_epochs=best_params[\"num_epochs\"],\n",
1039
+ " weight_decay=0.01,\n",
1040
+ " logging_dir=\"./logs\",\n",
1041
+ " logging_steps=10,\n",
1042
+ " save_strategy=\"epoch\",\n",
1043
+ " load_best_model_at_end=True,\n",
1044
+ " metric_for_best_model=\"f1\",\n",
1045
+ ")\n",
1046
+ "\n",
1047
+ "trainer = Trainer(\n",
1048
+ " model=model,\n",
1049
+ " args=training_args,\n",
1050
+ " train_dataset=tokenized_dataset[\"train\"],\n",
1051
+ " eval_dataset=tokenized_dataset[\"validation\"],\n",
1052
+ " tokenizer=tokenizer,\n",
1053
+ " data_collator=data_collator,\n",
1054
+ " compute_metrics=compute_metrics,\n",
1055
+ ")\n",
1056
+ "\n",
1057
+ "# Train the model\n",
1058
+ "print(\"\\nMemulai pelatihan dengan hyperparameter terbaik...\")\n",
1059
+ "try:\n",
1060
+ " trainer.train()\n",
1061
+ "except Exception as e:\n",
1062
+ " print(f\"Gagal melatih model: {e}\")\n",
1063
+ " sys.exit(1)\n",
1064
+ "\n",
1065
+ "# Evaluate on test set\n",
1066
+ "print(\"\\nMengevaluasi model pada data test...\")\n",
1067
+ "try:\n",
1068
+ " results = trainer.evaluate(tokenized_dataset[\"test\"])\n",
1069
+ "except Exception as e:\n",
1070
+ " print(f\"Gagal mengevaluasi model: {e}\")\n",
1071
+ " sys.exit(1)\n",
1072
+ "\n",
1073
+ "# Print evaluation results\n",
1074
+ "print(\"\\nHasil Evaluasi:\")\n",
1075
+ "print(f\"Precision: {results['eval_precision']:.4f}\")\n",
1076
+ "print(f\"Recall: {results['eval_recall']:.4f}\")\n",
1077
+ "print(f\"F1-Score: {results['eval_f1']:.4f}\")\n",
1078
+ "print(f\"Accuracy: {results['eval_accuracy']:.4f}\")\n",
1079
+ "print(\"\\nMetrik per Entitas:\")\n",
1080
+ "for entity, metrics in results.get(\"eval_per_entity\", {}).items():\n",
1081
+ " print(f\"{entity}:\")\n",
1082
+ " print(f\" Precision: {metrics['precision']:.4f}\")\n",
1083
+ " print(f\" Recall: {metrics['recall']:.4f}\")\n",
1084
+ " print(f\" F1-Score: {metrics['f1']:.4f}\")\n",
1085
+ "\n",
1086
+ "# Save the model\n",
1087
+ "try:\n",
1088
+ " model.save_pretrained(\"./ner_model\")\n",
1089
+ " tokenizer.save_pretrained(\"./ner_model\")\n",
1090
+ " print(\"\\nModel dan tokenizer telah disimpan ke './ner_model'\")\n",
1091
+ "except Exception as e:\n",
1092
+ " print(f\"Gagal menyimpan model: {e}\")\n",
1093
+ " sys.exit(1)\n",
1094
+ "\n",
1095
+ "# Example inference on test samples\n",
1096
+ "print(\"\\nContoh Prediksi pada Data Test (5 Sampel):\")\n",
1097
+ "try:\n",
1098
+ " for i in range(min(5, len(tokenized_dataset[\"test\"]))):\n",
1099
+ " sample = tokenized_dataset[\"test\"][i]\n",
1100
+ " input_ids = torch.tensor([sample[\"input_ids\"]], device=device)\n",
1101
+ " attention_mask = torch.tensor([sample[\"attention_mask\"]], device=device)\n",
1102
+ " model.eval()\n",
1103
+ " with torch.no_grad():\n",
1104
+ " outputs = model(input_ids, attention_mask=attention_mask)\n",
1105
+ " predictions = outputs.logits.argmax(dim=2)[0].cpu().numpy()\n",
1106
+ " tokens = tokenizer.convert_ids_to_tokens(sample[\"input_ids\"])\n",
1107
+ " labels = [id2label[pred] for pred, label in zip(predictions, sample[\"labels\"]) if label != -100]\n",
1108
+ " true_labels = [id2label[label] for label in sample[\"labels\"] if label != -100]\n",
1109
+ " print(f\"\\nSampel {i+1}:\")\n",
1110
+ " print(f\"Tokens: {' '.join(tokens)}\")\n",
1111
+ " print(f\"True Labels: {true_labels}\")\n",
1112
+ " print(f\"Predicted Labels: {labels}\")\n",
1113
+ "except Exception as e:\n",
1114
+ " print(f\"Gagal melakukan inferensi: {e}\")\n",
1115
+ " sys.exit(1)\n",
1116
+ "\n",
1117
+ "# Analyze error patterns (DATE predicted as LOC)\n",
1118
+ "print(\"\\nAnalisis Pola Error (Tanggal diprediksi sebagai Lokasi):\")\n",
1119
+ "found_error = False\n",
1120
+ "for i in range(min(100, len(tokenized_dataset[\"test\"]))):\n",
1121
+ " sample = tokenized_dataset[\"test\"][i]\n",
1122
+ " input_ids = torch.tensor([sample[\"input_ids\"]], device=device)\n",
1123
+ " attention_mask = torch.tensor([sample[\"attention_mask\"]], device=device)\n",
1124
+ " with torch.no_grad():\n",
1125
+ " outputs = model(input_ids, attention_mask=attention_mask)\n",
1126
+ " predictions = outputs.logits.argmax(dim=2)[0].cpu().numpy()\n",
1127
+ " true_labels = [id2label[label] for label in sample[\"labels\"] if label != -100]\n",
1128
+ " pred_labels = [id2label[pred] for pred, label in zip(predictions, sample[\"labels\"]) if label != -100]\n",
1129
+ " for j, (true, pred) in enumerate(zip(true_labels, pred_labels)):\n",
1130
+ " if true.startswith(\"B-DATE\") and pred.startswith(\"B-LOC\"):\n",
1131
+ " tokens = tokenizer.convert_ids_to_tokens(sample[\"input_ids\"])\n",
1132
+ " print(f\"\\nSampel dengan Error (DATE diprediksi sebagai LOC):\")\n",
1133
+ " print(f\"Tokens: {' '.join(tokens)}\")\n",
1134
+ " print(f\"True Labels: {true_labels}\")\n",
1135
+ " print(f\"Predicted Labels: {pred_labels}\")\n",
1136
+ " found_error = True\n",
1137
+ " break\n",
1138
+ " if found_error:\n",
1139
+ " break\n",
1140
+ "if not found_error:\n",
1141
+ " print(\"Tidak ditemukan contoh tanggal yang diprediksi sebagai lokasi dalam 100 sampel.\")\n",
1142
+ "\n",
1143
+ "# Data Security, Privacy, and Ethics\n",
1144
+ "print(\"\\nPertimbangan Keamanan Data, Privasi, dan Etika:\")\n",
1145
+ "print(\"- Dataset bersumber dari berita publik, tidak mengandung informasi sensitif seperti alamat atau nomor identitas.\")\n",
1146
+ "print(\"- Nama orang dalam dataset berasal dari media publik, aman untuk digunakan.\")\n",
1147
+ "print(\"- Dataset mencakup berbagai topik berita, mengurangi risiko bias terhadap entitas tertentu.\")"
1148
+ ]
1149
+ },
1150
+ {
1151
+ "cell_type": "code",
1152
+ "execution_count": null,
1153
+ "id": "714cfb72",
1154
+ "metadata": {},
1155
+ "outputs": [],
1156
+ "source": []
1157
+ },
1158
+ {
1159
+ "cell_type": "code",
1160
+ "execution_count": null,
1161
+ "id": "93508875",
1162
+ "metadata": {},
1163
+ "outputs": [],
1164
+ "source": []
1165
+ }
1166
+ ],
1167
+ "metadata": {
1168
+ "kernelspec": {
1169
+ "display_name": "base",
1170
+ "language": "python",
1171
+ "name": "python3"
1172
+ },
1173
+ "language_info": {
1174
+ "codemirror_mode": {
1175
+ "name": "ipython",
1176
+ "version": 3
1177
+ },
1178
+ "file_extension": ".py",
1179
+ "mimetype": "text/x-python",
1180
+ "name": "python",
1181
+ "nbconvert_exporter": "python",
1182
+ "pygments_lexer": "ipython3",
1183
+ "version": "3.12.7"
1184
+ }
1185
+ },
1186
+ "nbformat": 4,
1187
+ "nbformat_minor": 5
1188
+ }
ner_model/config.json ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_num_labels": 5,
3
+ "architectures": [
4
+ "BertForTokenClassification"
5
+ ],
6
+ "attention_probs_dropout_prob": 0.1,
7
+ "classifier_dropout": null,
8
+ "directionality": "bidi",
9
+ "hidden_act": "gelu",
10
+ "hidden_dropout_prob": 0.1,
11
+ "hidden_size": 768,
12
+ "id2label": {
13
+ "0": "I-PERSON",
14
+ "1": "B-ORGANISATION",
15
+ "2": "I-ORGANISATION",
16
+ "3": "B-PLACE",
17
+ "4": "I-PLACE",
18
+ "5": "O",
19
+ "6": "B-PERSON"
20
+ },
21
+ "initializer_range": 0.02,
22
+ "intermediate_size": 3072,
23
+ "label2id": {
24
+ "B-ORGANISATION": 1,
25
+ "B-PERSON": 6,
26
+ "B-PLACE": 3,
27
+ "I-ORGANISATION": 2,
28
+ "I-PERSON": 0,
29
+ "I-PLACE": 4,
30
+ "O": 5
31
+ },
32
+ "layer_norm_eps": 1e-12,
33
+ "max_position_embeddings": 512,
34
+ "model_type": "bert",
35
+ "num_attention_heads": 12,
36
+ "num_hidden_layers": 12,
37
+ "output_past": true,
38
+ "pad_token_id": 0,
39
+ "pooler_fc_size": 768,
40
+ "pooler_num_attention_heads": 12,
41
+ "pooler_num_fc_layers": 3,
42
+ "pooler_size_per_head": 128,
43
+ "pooler_type": "first_token_transform",
44
+ "position_embedding_type": "absolute",
45
+ "torch_dtype": "float32",
46
+ "transformers_version": "4.53.1",
47
+ "type_vocab_size": 2,
48
+ "use_cache": true,
49
+ "vocab_size": 50000
50
+ }
ner_model/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:37b28df302c0498855d30b937557b567a7be050c81501056a493828385199064
3
+ size 495447892
ner_model/special_tokens_map.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "cls_token": "[CLS]",
3
+ "mask_token": "[MASK]",
4
+ "pad_token": "[PAD]",
5
+ "sep_token": "[SEP]",
6
+ "unk_token": "[UNK]"
7
+ }
ner_model/tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
ner_model/tokenizer_config.json ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "0": {
4
+ "content": "[PAD]",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ },
11
+ "1": {
12
+ "content": "[UNK]",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "2": {
20
+ "content": "[CLS]",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ },
27
+ "3": {
28
+ "content": "[SEP]",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false,
33
+ "special": true
34
+ },
35
+ "4": {
36
+ "content": "[MASK]",
37
+ "lstrip": false,
38
+ "normalized": false,
39
+ "rstrip": false,
40
+ "single_word": false,
41
+ "special": true
42
+ }
43
+ },
44
+ "clean_up_tokenization_spaces": true,
45
+ "cls_token": "[CLS]",
46
+ "do_basic_tokenize": true,
47
+ "do_lower_case": true,
48
+ "extra_special_tokens": {},
49
+ "mask_token": "[MASK]",
50
+ "model_max_length": 1000000000000000019884624838656,
51
+ "never_split": null,
52
+ "pad_token": "[PAD]",
53
+ "sep_token": "[SEP]",
54
+ "strip_accents": null,
55
+ "tokenize_chinese_chars": true,
56
+ "tokenizer_class": "BertTokenizer",
57
+ "unk_token": "[UNK]"
58
+ }
ner_model/vocab.txt ADDED
The diff for this file is too large to render. See raw diff
 
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ transformers==4.44.2
2
+ datasets==2.21.0
3
+ torch==2.4.1
4
+ gradio==4.44.0
5
+ pandas==2.2.2
6
+ numpy==1.26.4