diff --git a/answer_padded.npy b/answer_padded.npy index af9a235..bf1ef61 100644 Binary files a/answer_padded.npy and b/answer_padded.npy differ diff --git a/context_padded.npy b/context_padded.npy index d155ec6..ebe62cc 100644 Binary files a/context_padded.npy and b/context_padded.npy differ diff --git a/dataset/testing_dataset.json b/dataset/testing_dataset.json deleted file mode 100644 index e69de29..0000000 diff --git a/dataset/training_dataset.json b/dataset/training_dataset.json index c3f8f61..5d39bd2 100644 --- a/dataset/training_dataset.json +++ b/dataset/training_dataset.json @@ -4,7 +4,7 @@ "qa_pairs": [ { "type": "fill_in_the_blank", - "question": "_______ mengembangkan teori relativitas.", + "question": "Siapa yang mengembangkan teori relativitas?", "answer": "Albert Einstein" }, { @@ -150,7 +150,7 @@ "qa_pairs": [ { "type": "fill_in_the_blank", - "question": "Teori evolusi dikembangkan oleh _______.", + "question": "Teori evolusi dikembangkan oleh?", "answer": "Charles Darwin" }, { @@ -191,5 +191,499 @@ "answer": "29 April 1945" } ] + }, + { + "context": "Kerajaan Majapahit adalah kerajaan besar Hindu-Buddha yang berpusat di Jawa Timur, berdiri sekitar tahun 1293 hingga 1500 M. Majapahit mencapai puncak kejayaan di bawah pemerintahan Raja Hayam Wuruk dengan patihnya, Gajah Mada.", + "qa_pairs": [ + { + "type": "fill_in_the_blank", + "question": "Kerajaan Majapahit mencapai puncak kejayaannya di bawah raja _______.", + "answer": "Hayam Wuruk" + }, + { + "type": "multiple_choice", + "question": "Siapakah patih terkenal yang mengabdi pada Raja Hayam Wuruk?", + "options": ["Empu Sindok", "Gajah Mada", "Ken Arok", "Raden Wijaya"], + "answer": "Gajah Mada" + }, + { + "type": "true_false", + "question": "Kerajaan Majapahit adalah kerajaan Islam pertama di Indonesia.", + "answer": "False" + } + ] + }, + { + "context": "Kerajaan Sriwijaya adalah kerajaan maritim yang berpusat di Sumatera Selatan dari abad ke-7 hingga abad ke-13. Kerajaan ini menjadi pusat perdagangan dan penyebaran agama Buddha terbesar di Asia Tenggara.", + "qa_pairs": [ + { + "type": "fill_in_the_blank", + "question": "Kerajaan Sriwijaya adalah pusat penyebaran agama _______ terbesar di Asia Tenggara.", + "answer": "Buddha" + }, + { + "type": "multiple_choice", + "question": "Di mana pusat Kerajaan Sriwijaya berada?", + "options": ["Jawa Barat", "Jawa Timur", "Sumatera Selatan", "Bali"], + "answer": "Sumatera Selatan" + }, + { + "type": "true_false", + "question": "Sriwijaya dikenal sebagai kerajaan darat terbesar di Asia Tenggara.", + "answer": "False" + } + ] + }, + { + "context": "Candi Borobudur adalah candi Buddha terbesar di dunia yang terletak di Magelang, Jawa Tengah. Dibangun pada abad ke-8 oleh Wangsa Sailendra, candi ini merupakan simbol puncak kebudayaan Buddha di Jawa.", + "qa_pairs": [ + { + "type": "fill_in_the_blank", + "question": "Candi Borobudur dibangun oleh wangsa _______.", + "answer": "Sailendra" + }, + { + "type": "multiple_choice", + "question": "Di provinsi mana letak Candi Borobudur?", + "options": ["Yogyakarta", "Jawa Timur", "Jawa Tengah", "Bali"], + "answer": "Jawa Tengah" + }, + { + "type": "true_false", + "question": "Borobudur adalah candi Hindu terbesar di Indonesia.", + "answer": "False" + } + ] + }, + { + "context": "VOC (Vereenigde Oostindische Compagnie) adalah perusahaan dagang Belanda yang memonopoli perdagangan rempah-rempah di Nusantara dari abad ke-17 hingga awal abad ke-18.", + "qa_pairs": [ + { + "type": "fill_in_the_blank", + "question": "VOC adalah singkatan dari _______.", + "answer": "Vereenigde Oostindische Compagnie" + }, + { + "type": "multiple_choice", + "question": "VOC terkenal karena monopoli dalam perdagangan apa?", + "options": ["Emas", "Kopi", "Rempah-rempah", "Beras"], + "answer": "Rempah-rempah" + }, + { + "type": "true_false", + "question": "VOC adalah perusahaan dagang milik Inggris.", + "answer": "False" + } + ] + }, + { + "context": "Pertempuran Surabaya terjadi pada 10 November 1945 antara pasukan Indonesia melawan pasukan sekutu Inggris yang berusaha mengambil alih kota setelah Jepang menyerah dalam Perang Dunia II. Pertempuran ini dikenang sebagai Hari Pahlawan di Indonesia.", + "qa_pairs": [ + { + "type": "fill_in_the_blank", + "question": "Pertempuran Surabaya terjadi pada tanggal _______.", + "answer": "10 November 1945" + }, + { + "type": "multiple_choice", + "question": "Pasukan yang dihadapi Indonesia dalam Pertempuran Surabaya berasal dari negara apa?", + "options": ["Jepang", "Belanda", "Inggris", "Australia"], + "answer": "Inggris" + }, + { + "type": "true_false", + "question": "Pertempuran Surabaya diperingati sebagai Hari Pahlawan di Indonesia.", + "answer": "True" + } + ] + }, + { + "context": "Kerajaan Demak adalah kerajaan Islam pertama di Jawa yang berdiri pada akhir abad ke-15. Kerajaan ini terkenal karena penyebaran agama Islam di Jawa melalui Wali Songo.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Kerajaan Demak adalah kerajaan Islam pertama di Jawa.", + "answer": "True" + }, + { + "type": "true_false", + "question": "Kerajaan Demak berdiri pada abad ke-10.", + "answer": "False" + } + ] + }, + { + "context": "Sumpah Pemuda terjadi pada 28 Oktober 1928, di mana pemuda Indonesia berikrar untuk bersatu dalam satu tanah air, satu bangsa, dan satu bahasa Indonesia.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Sumpah Pemuda menyatakan persatuan dalam satu agama.", + "answer": "False" + }, + { + "type": "true_false", + "question": "Sumpah Pemuda dilaksanakan sebelum Proklamasi Kemerdekaan Indonesia.", + "answer": "True" + } + ] + }, + { + "context": "Gajah Mada adalah seorang patih terkenal dari Kerajaan Majapahit yang berhasil menyatukan sebagian besar wilayah Nusantara melalui politik ekspansinya. Ia terkenal dengan sumpahnya yang disebut Sumpah Palapa.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Gajah Mada berasal dari Kerajaan Majapahit.", + "answer": "True" + }, + { + "type": "true_false", + "question": "Sumpah Palapa bertujuan untuk menaklukkan benua Amerika.", + "answer": "False" + } + ] + }, + { + "context": "Kerajaan Aceh mencapai puncak kejayaannya di bawah pemerintahan Sultan Iskandar Muda pada abad ke-17. Aceh menjadi pusat perdagangan dan kebudayaan Islam di wilayah Nusantara.", + "qa_pairs": [ + { + "type": "multiple_choice", + "question": "Siapakah sultan yang membawa Kerajaan Aceh ke puncak kejayaan?", + "options": [ + "Sultan Ageng", + "Sultan Iskandar Muda", + "Sultan Agung", + "Sultan Hasanuddin" + ], + "answer": "Sultan Iskandar Muda" + } + ] + }, + { + "context": "Perang Diponegoro berlangsung dari tahun 1825 hingga 1830. Perang ini dipimpin oleh Pangeran Diponegoro melawan pemerintah kolonial Belanda di Jawa Tengah.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Perang Diponegoro berlangsung selama lima tahun.", + "answer": "True" + }, + { + "type": "true_false", + "question": "Perang Diponegoro berakhir pada tahun 1850.", + "answer": "False" + } + ] + }, + { + "context": "Candi Prambanan adalah candi Hindu terbesar di Indonesia yang terletak di perbatasan antara Yogyakarta dan Jawa Tengah. Dibangun pada abad ke-9, candi ini merupakan peninggalan Kerajaan Mataram Kuno.", + "qa_pairs": [ + { + "type": "fill_in_the_blank", + "question": "Candi Prambanan dibangun pada abad ke-_______.", + "answer": "9" + } + ] + }, + { + "context": "Pangeran Antasari adalah pahlawan nasional Indonesia yang memimpin perlawanan rakyat Kalimantan Selatan terhadap penjajahan Belanda pada abad ke-19.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Pangeran Antasari berasal dari Kalimantan Selatan.", + "answer": "True" + }, + { + "type": "multiple_choice", + "question": "Pangeran Antasari terkenal karena perjuangannya melawan penjajah dari negara mana?", + "options": ["Inggris", "Belanda", "Portugis", "Spanyol"], + "answer": "Belanda" + } + ] + }, + { + "context": "Perjanjian Linggarjati adalah perjanjian yang ditandatangani pada 25 Maret 1947 antara Indonesia dengan Belanda. Perjanjian ini mengakui secara de facto Republik Indonesia yang mencakup Jawa, Sumatra, dan Madura.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Perjanjian Linggarjati ditandatangani pada tahun 1947.", + "answer": "True" + } + ] + }, + { + "context": "Raden Adjeng Kartini adalah tokoh emansipasi wanita Indonesia yang lahir pada 21 April 1879. Ia dikenal melalui surat-suratnya yang memperjuangkan hak perempuan untuk memperoleh pendidikan dan kesetaraan.", + "qa_pairs": [ + { + "type": "multiple_choice", + "question": "Tanggal berapa diperingati sebagai Hari Kartini di Indonesia?", + "options": ["17 Agustus", "21 April", "20 Mei", "10 November"], + "answer": "21 April" + } + ] + }, + { + "context": "Kerajaan Kutai merupakan kerajaan Hindu tertua di Indonesia yang berdiri sekitar abad ke-4 di Kalimantan Timur. Bukti keberadaan kerajaan ini ditemukan dalam prasasti Yupa.", + "qa_pairs": [ + { + "type": "fill_in_the_blank", + "question": "Kerajaan Kutai adalah kerajaan Hindu tertua di Indonesia yang ditemukan melalui prasasti _______.", + "answer": "Yupa" + }, + { + "type": "true_false", + "question": "Kerajaan Kutai berdiri di Kalimantan Barat.", + "answer": "False" + } + ] + }, + { + "context": "Raden Ajeng Kartini merupakan tokoh penting dalam sejarah perjuangan emansipasi wanita Indonesia. Ia lahir di Jepara dan dikenal melalui bukunya berjudul 'Habis Gelap Terbitlah Terang'.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Kartini dikenal sebagai pejuang emansipasi wanita.", + "answer": "True" + } + ] + }, + { + "context": "Ekspedisi Palembang dilakukan oleh VOC pada tahun 1659 untuk menguasai perdagangan lada di Sumatera Selatan. Ekspedisi ini berakhir dengan kemenangan VOC dan penegakan monopoli lada di daerah tersebut.", + "qa_pairs": [ + { + "type": "fill_in_the_blank", + "question": "Ekspedisi Palembang terjadi pada tahun _______.", + "answer": "1659" + }, + { + "type": "true_false", + "question": "Ekspedisi Palembang bertujuan menguasai perdagangan kopi.", + "answer": "False" + } + ] + }, + { + "context": "Fotosintesis adalah proses pembuatan makanan oleh tumbuhan hijau menggunakan cahaya matahari, air, dan karbon dioksida yang menghasilkan oksigen sebagai produk sampingan.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Fotosintesis terjadi pada siang hari.", + "answer": "True" + }, + { + "type": "fill_in_the_blank", + "question": "Pigmen hijau dalam tumbuhan yang penting untuk fotosintesis adalah _______.", + "answer": "klorofil" + } + ] + }, + { + "context": "Sel adalah unit terkecil kehidupan. Sel memiliki berbagai komponen, seperti membran sel, sitoplasma, dan inti sel (nukleus).", + "qa_pairs": [ + { + "type": "multiple_choice", + "question": "Apa fungsi utama nukleus dalam sel?", + "options": [ + "Mengatur metabolisme sel", + "Penyimpanan energi", + "Pencernaan makanan", + "Pergerakan sel" + ], + "answer": "Mengatur metabolisme sel" + } + ] + }, + { + "context": "DNA (asam deoksiribonukleat) adalah molekul yang menyimpan informasi genetik pada hampir semua makhluk hidup.", + "qa_pairs": [ + { + "type": "true_false", + "question": "DNA ditemukan di dalam nukleus sel.", + "answer": "True" + } + ] + }, + { + "context": "Enzim adalah protein yang berfungsi sebagai katalisator yang mempercepat reaksi kimia dalam tubuh tanpa ikut bereaksi secara permanen.", + "qa_pairs": [ + { + "type": "fill_in_the_blank", + "question": "Enzim berfungsi sebagai _______ yang mempercepat reaksi kimia.", + "answer": "katalisator" + }, + { + "type": "true_false", + "question": "Enzim selalu ikut bereaksi secara permanen dalam reaksi kimia.", + "answer": "False" + } + ] + }, + { + "context": "Proses respirasi pada manusia terjadi di dalam mitokondria sel, yang menggunakan oksigen untuk menghasilkan energi dalam bentuk ATP.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Respirasi manusia terjadi tanpa menggunakan oksigen.", + "answer": "False" + }, + { + "type": "multiple_choice", + "question": "Di bagian mana dalam sel proses respirasi terjadi?", + "options": ["Membran sel", "Sitoplasma", "Mitokondria", "Kloroplas"], + "answer": "Mitokondria" + } + ] + }, + { + "context": "Kloroplas adalah organel yang ditemukan dalam sel tumbuhan yang berfungsi sebagai tempat berlangsungnya fotosintesis.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Kloroplas hanya ditemukan pada sel tumbuhan.", + "answer": "True" + } + ] + }, + { + "context": "Mutasi adalah perubahan yang terjadi pada materi genetik yang dapat menyebabkan variasi genetik dalam suatu populasi.", + "qa_pairs": [ + { + "type": "multiple_choice", + "question": "Mutasi pada materi genetik dapat menyebabkan apa?", + "options": ["Kloning", "Variasi genetik", "Fotosintesis", "Respirasi"], + "answer": "Variasi genetik" + } + ] + }, + { + "context": "Jantung adalah organ vital dalam tubuh manusia yang berfungsi memompa darah ke seluruh tubuh melalui sistem peredaran darah.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Jantung memiliki empat ruang.", + "answer": "True" + } + ] + }, + { + "context": "Hormon insulin dihasilkan oleh pankreas dan berfungsi mengatur kadar gula dalam darah.", + "qa_pairs": [ + { + "type": "fill_in_the_blank", + "question": "Hormon insulin dihasilkan oleh organ _______.", + "answer": "pankreas" + }, + { + "type": "true_false", + "question": "Insulin membantu menurunkan kadar gula darah.", + "answer": "True" + } + ] + }, + { + "context": "Tulang adalah jaringan tubuh manusia yang berfungsi memberi bentuk tubuh, melindungi organ dalam, dan tempat pembentukan sel darah.", + "qa_pairs": [ + { + "type": "multiple_choice", + "question": "Apa fungsi utama tulang pada manusia?", + "options": [ + "Mencerna makanan", + "Melindungi organ dalam", + "Menghasilkan hormon", + "Mengatur suhu tubuh" + ], + "answer": "Melindungi organ dalam" + }, + { + "type": "true_false", + "question": "Tulang berfungsi sebagai tempat pembentukan sel darah.", + "answer": "True" + } + ] + }, + { + "context": "Ginjal adalah organ yang berfungsi menyaring limbah dari darah dan membentuk urin.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Ginjal berfungsi menghasilkan hormon insulin.", + "answer": "False" + } + ] + }, + { + "context": "Paru-paru merupakan organ pernapasan yang bertanggung jawab untuk pertukaran oksigen dan karbon dioksida.", + "qa_pairs": [ + { + "type": "fill_in_the_blank", + "question": "Paru-paru berfungsi untuk pertukaran gas yaitu oksigen dan _______.", + "answer": "karbon dioksida" + } + ] + }, + { + "context": "Sistem saraf manusia terdiri dari sistem saraf pusat dan sistem saraf perifer yang berfungsi mengatur koordinasi tubuh dan merespon rangsangan.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Sistem saraf manusia mencakup otak dan sumsum tulang belakang.", + "answer": "True" + }, + { + "type": "true_false", + "question": "Sistem saraf perifer terdiri dari otak dan sumsum tulang belakang.", + "answer": "False" + } + ] + }, + { + "context": "Kelenjar tiroid adalah organ yang menghasilkan hormon tiroksin, yang penting untuk mengatur metabolisme tubuh.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Kelenjar tiroid terletak di leher.", + "answer": "True" + } + ] + }, + { + "context": "Eritrosit adalah sel darah merah yang berfungsi membawa oksigen ke seluruh jaringan tubuh.", + "qa_pairs": [ + { + "type": "multiple_choice", + "question": "Apa fungsi utama eritrosit dalam tubuh manusia?", + "options": [ + "Melawan infeksi", + "Pembekuan darah", + "Mengangkut oksigen", + "Melawan virus" + ], + "answer": "Mengangkut oksigen" + } + ] + }, + { + "context": "Limfosit merupakan jenis sel darah putih yang berperan penting dalam sistem kekebalan tubuh.", + "qa_pairs": [ + { + "type": "true_false", + "question": "Limfosit berperan dalam sistem kekebalan tubuh.", + "answer": "True" + } + ] + }, + { + "context": "Protein adalah makromolekul yang terdiri dari rantai asam amino dan berfungsi dalam pertumbuhan, perbaikan jaringan, serta produksi enzim.", + "qa_pairs": [ + { + "type": "multiple_choice", + "question": "Protein terdiri dari rantai molekul apa?", + "options": ["Karbohidrat", "Asam amino", "Lipid", "Glukosa"], + "answer": "Asam amino" + }, + { + "type": "true_false", + "question": "Protein hanya berfungsi dalam pembentukan otot.", + "answer": "False" + } + ] } ] diff --git a/lstm_multi_output_model.keras b/lstm_multi_output_model.keras index c99856d..4c1922f 100644 Binary files a/lstm_multi_output_model.keras and b/lstm_multi_output_model.keras differ diff --git a/question_padded.npy b/question_padded.npy index 1f749bf..a6e76c2 100644 Binary files a/question_padded.npy and b/question_padded.npy differ diff --git a/question_type_labels.npy b/question_type_labels.npy index e0ef0bc..1beff69 100644 Binary files a/question_type_labels.npy and b/question_type_labels.npy differ diff --git a/tokenizer.pkl b/tokenizer.pkl index dc6290e..46096ac 100644 Binary files a/tokenizer.pkl and b/tokenizer.pkl differ diff --git a/training_model.ipynb b/training_model.ipynb index 2a2efb9..5f1ff96 100644 --- a/training_model.ipynb +++ b/training_model.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 38, "metadata": {}, "outputs": [], "source": [ @@ -12,6 +12,7 @@ "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import json\n", "\n", "# Natural language processing\n", "import re\n", @@ -28,6 +29,9 @@ "from tensorflow.keras.layers import Input, Embedding, LSTM, Dense, Concatenate\n", "from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint\n", "\n", + "\n", + "from sklearn.model_selection import train_test_split\n", + "\n", "# Metrics for model evaluation\n", "from sklearn.metrics import classification_report, precision_score, recall_score, accuracy_score\n", "\n", @@ -37,7 +41,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 39, "metadata": {}, "outputs": [ { @@ -60,7 +64,7 @@ "True" ] }, - "execution_count": 48, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" } @@ -75,94 +79,54 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 40, "metadata": {}, "outputs": [ { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
contextqa_pairs
0Albert Einstein adalah fisikawan teoretis kela...[{'type': 'fill_in_the_blank', 'question': '__...
1Samudra Pasifik adalah yang terbesar dan terda...[{'type': 'fill_in_the_blank', 'question': 'Sa...
2Proklamasi Kemerdekaan Indonesia dibacakan pad...[{'type': 'fill_in_the_blank', 'question': 'Pr...
3Hukum Newton adalah tiga hukum fisika yang men...[{'type': 'fill_in_the_blank', 'question': 'Hu...
4Budi Utomo adalah organisasi pemuda yang didir...[{'type': 'fill_in_the_blank', 'question': 'Bu...
\n", - "
" - ], - "text/plain": [ - " context \\\n", - "0 Albert Einstein adalah fisikawan teoretis kela... \n", - "1 Samudra Pasifik adalah yang terbesar dan terda... \n", - "2 Proklamasi Kemerdekaan Indonesia dibacakan pad... \n", - "3 Hukum Newton adalah tiga hukum fisika yang men... \n", - "4 Budi Utomo adalah organisasi pemuda yang didir... \n", - "\n", - " qa_pairs \n", - "0 [{'type': 'fill_in_the_blank', 'question': '__... \n", - "1 [{'type': 'fill_in_the_blank', 'question': 'Sa... \n", - "2 [{'type': 'fill_in_the_blank', 'question': 'Pr... \n", - "3 [{'type': 'fill_in_the_blank', 'question': 'Hu... \n", - "4 [{'type': 'fill_in_the_blank', 'question': 'Bu... " - ] - }, - "execution_count": 49, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + " context \\\n", + "0 Albert Einstein adalah fisikawan teoretis kela... \n", + "1 Samudra Pasifik adalah yang terbesar dan terda... \n", + "2 Proklamasi Kemerdekaan Indonesia dibacakan pad... \n", + "3 Hukum Newton adalah tiga hukum fisika yang men... \n", + "4 Budi Utomo adalah organisasi pemuda yang didir... \n", + "\n", + " qa_pairs \n", + "0 [{'type': 'fill_in_the_blank', 'question': 'Si... \n", + "1 [{'type': 'fill_in_the_blank', 'question': 'Sa... \n", + "2 [{'type': 'fill_in_the_blank', 'question': 'Pr... \n", + "3 [{'type': 'fill_in_the_blank', 'question': 'Hu... \n", + "4 [{'type': 'fill_in_the_blank', 'question': 'Bu... \n", + "\n", + "Total Context: 25\n", + "Total QA Pairs: 57\n" + ] } ], "source": [ "# load dataset\n", - "df = pd.read_json(\"independent_dataset.json\")\n", - "df.head()" + "df = pd.read_json(\"dataset/training_dataset.json\")\n", + "print(df.head())\n", + "with open(\"dataset/training_dataset.json\", \"r\", encoding=\"utf-8\") as file:\n", + " dataset = json.load(file)\n", + " \n", + " \n", + "# Menghitung total context\n", + "total_context = len(dataset)\n", + "\n", + "# Menghitung total qa_pairs\n", + "total_qa_pairs = sum(len(entry[\"qa_pairs\"]) for entry in dataset)\n", + "\n", + "# Menampilkan hasil\n", + "print(f\"\\nTotal Context: {total_context}\")\n", + "print(f\"Total QA Pairs: {total_qa_pairs}\")" ] }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 41, "metadata": {}, "outputs": [], "source": [ @@ -270,51 +234,37 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "✅ Vocabulary Size: 182\n", - "✅ Sample Tokenized Context: [ 9 10 91 38 92 93 39 5 19 94 95 11 96 97 40 98 99 100\n", - " 101 20 21 22 11 41 102 11 38 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0]\n", - "✅ Sample Tokenized Question: [39 5 19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0]\n", - "✅ Sample Tokenized Answer: [ 9 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0]\n", - "✅ Sample Question Type Label: 0\n" + "✅ Data processing complete!\n", + "Samples: 57\n" ] } ], "source": [ - "with open(\"independent_dataset.json\", \"r\", encoding=\"utf-8\") as file:\n", - " dataset = json.load(file)\n", + "# with open(\"dataset/training_dataset.json\", \"r\", encoding=\"utf-8\") as file:\n", + "# dataset = json.load(file)\n", + "\n", + "# === Extract Data so that each QA pair has its own context === #\n", + "contexts = []\n", + "questions = []\n", + "answers = []\n", + "question_types = []\n", "\n", "for entry in dataset:\n", - " entry[\"context\"] = text_preprocessing(entry[\"context\"])\n", + " processed_context = text_preprocessing(entry[\"context\"])\n", " for qa in entry[\"qa_pairs\"]:\n", - " qa[\"question\"] = text_preprocessing(qa[\"question\"])\n", - " qa[\"answer\"] = text_preprocessing(qa[\"answer\"])\n", + " contexts.append(processed_context)\n", + " questions.append(text_preprocessing(qa[\"question\"]))\n", + " answers.append(text_preprocessing(qa[\"answer\"]))\n", + " question_types.append(qa[\"type\"])\n", "\n", - "# === Extract Contexts, Questions, Answers, and Question Types === #\n", - "contexts = [entry[\"context\"] for entry in dataset]\n", - "questions = [qa[\"question\"] for entry in dataset for qa in entry[\"qa_pairs\"]]\n", - "answers = [qa[\"answer\"] for entry in dataset for qa in entry[\"qa_pairs\"]]\n", - "question_types = [qa[\"type\"] for entry in dataset for qa in entry[\"qa_pairs\"]] # Extract Question Types\n", - "\n", - "# === Initialize Tokenizer === #\n", + "# === Initialize Tokenizer and fit on all text === #\n", "tokenizer = Tokenizer(oov_token=\"\")\n", "tokenizer.fit_on_texts(contexts + questions + answers)\n", "\n", @@ -324,36 +274,62 @@ "answer_sequences = tokenizer.texts_to_sequences(answers)\n", "\n", "# === Define Max Length for Padding === #\n", - "MAX_LENGTH = 100 # Adjust based on dataset analysis\n", + "MAX_LENGTH = 100\n", "context_padded = pad_sequences(context_sequences, maxlen=MAX_LENGTH, padding=\"post\", truncating=\"post\")\n", "question_padded = pad_sequences(question_sequences, maxlen=MAX_LENGTH, padding=\"post\", truncating=\"post\")\n", "answer_padded = pad_sequences(answer_sequences, maxlen=MAX_LENGTH, padding=\"post\", truncating=\"post\")\n", "\n", - "# === Encode Question Types (Convert Categorical Labels to Numeric) === #\n", + "# Encode Question Types\n", "question_type_dict = {\"fill_in_the_blank\": 0, \"true_false\": 1, \"multiple_choice\": 2}\n", "question_type_labels = np.array([question_type_dict[q_type] for q_type in question_types])\n", "\n", - "# === Save Processed Data as .npy Files === #\n", + "# Save the processed data (optional)\n", "np.save(\"context_padded.npy\", context_padded)\n", "np.save(\"question_padded.npy\", question_padded)\n", "np.save(\"answer_padded.npy\", answer_padded)\n", "np.save(\"question_type_labels.npy\", question_type_labels)\n", - "\n", - "# Save Tokenizer for Future Use\n", "with open(\"tokenizer.pkl\", \"wb\") as handle:\n", " pickle.dump(tokenizer, handle, protocol=pickle.HIGHEST_PROTOCOL)\n", "\n", - "# === Check Results === #\n", - "print(f\"✅ Vocabulary Size: {len(tokenizer.word_index) + 1}\")\n", - "print(f\"✅ Sample Tokenized Context: {context_padded[0]}\")\n", - "print(f\"✅ Sample Tokenized Question: {question_padded[0]}\")\n", - "print(f\"✅ Sample Tokenized Answer: {answer_padded[0]}\")\n", - "print(f\"✅ Sample Question Type Label: {question_type_labels[0]}\")" + "print(\"✅ Data processing complete!\")\n", + "print(\"Samples:\", context_padded.shape[0]) # This should now match the number of QA pairs\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Training samples: 45\n", + "Testing samples: 12\n" + ] + } + ], + "source": [ + "# === Split Data into Training and Testing Sets === #\n", + "(context_train, context_test,\n", + " question_train, question_test,\n", + " answer_train, answer_test,\n", + " qtype_train, qtype_test) = train_test_split(\n", + " context_padded,\n", + " question_padded,\n", + " answer_padded,\n", + " question_type_labels,\n", + " test_size=0.2,\n", + " random_state=42\n", + ")\n", + "\n", + "print(\"Training samples:\", context_train.shape[0])\n", + "print(\"Testing samples:\", context_test.shape[0])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 48, "metadata": {}, "outputs": [ { @@ -361,105 +337,67 @@ "output_type": "stream", "text": [ "Epoch 1/10\n", - "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 3s/step - answer_output_accuracy: 0.0000e+00 - answer_output_loss: 5.2070 - loss: 11.5152 - question_output_accuracy: 0.0000e+00 - question_output_loss: 5.2081 - question_type_output_accuracy: 0.3333 - question_type_output_loss: 1.1002 - val_answer_output_accuracy: 0.1250 - val_answer_output_loss: 5.1854 - val_loss: 11.4804 - val_question_output_accuracy: 0.0000e+00 - val_question_output_loss: 5.2043 - val_question_type_output_accuracy: 1.0000 - val_question_type_output_loss: 1.0907\n", + "\u001b[1m2/2\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 536ms/step - answer_output_accuracy: 0.0143 - answer_output_loss: 5.8964 - loss: 12.9070 - question_output_accuracy: 3.7037e-04 - question_output_loss: 5.9030 - question_type_output_accuracy: 0.3843 - question_type_output_loss: 1.0984 - val_answer_output_accuracy: 0.2689 - val_answer_output_loss: 5.8541 - val_loss: 12.8370 - val_question_output_accuracy: 0.0100 - val_question_output_loss: 5.8942 - val_question_type_output_accuracy: 0.4444 - val_question_type_output_loss: 1.0888\n", "Epoch 2/10\n", - "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 184ms/step - answer_output_accuracy: 0.2100 - answer_output_loss: 5.1680 - loss: 11.4156 - question_output_accuracy: 0.0167 - question_output_loss: 5.1820 - question_type_output_accuracy: 1.0000 - question_type_output_loss: 1.0656 - val_answer_output_accuracy: 0.2450 - val_answer_output_loss: 5.1625 - val_loss: 11.4545 - val_question_output_accuracy: 0.0000e+00 - val_question_output_loss: 5.2056 - val_question_type_output_accuracy: 1.0000 - val_question_type_output_loss: 1.0864\n", + "\u001b[1m2/2\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 171ms/step - answer_output_accuracy: 0.3408 - answer_output_loss: 5.8273 - loss: 12.8054 - question_output_accuracy: 0.0138 - question_output_loss: 5.8815 - question_type_output_accuracy: 0.5868 - question_type_output_loss: 1.0860 - val_answer_output_accuracy: 0.9856 - val_answer_output_loss: 5.7489 - val_loss: 12.7114 - val_question_output_accuracy: 0.0100 - val_question_output_loss: 5.8837 - val_question_type_output_accuracy: 0.4444 - val_question_type_output_loss: 1.0788\n", "Epoch 3/10\n", - "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 188ms/step - answer_output_accuracy: 0.2717 - answer_output_loss: 5.1203 - loss: 11.3080 - question_output_accuracy: 0.0250 - question_output_loss: 5.1552 - question_type_output_accuracy: 1.0000 - question_type_output_loss: 1.0326 - val_answer_output_accuracy: 0.3350 - val_answer_output_loss: 5.1270 - val_loss: 11.4122 - val_question_output_accuracy: 0.0000e+00 - val_question_output_loss: 5.2071 - val_question_type_output_accuracy: 1.0000 - val_question_type_output_loss: 1.0781\n", + "\u001b[1m2/2\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 172ms/step - answer_output_accuracy: 0.9826 - answer_output_loss: 5.6819 - loss: 12.6314 - question_output_accuracy: 0.0214 - question_output_loss: 5.8659 - question_type_output_accuracy: 0.5579 - question_type_output_loss: 1.0659 - val_answer_output_accuracy: 0.9856 - val_answer_output_loss: 5.4070 - val_loss: 12.3515 - val_question_output_accuracy: 0.0122 - val_question_output_loss: 5.8714 - val_question_type_output_accuracy: 0.4444 - val_question_type_output_loss: 1.0730\n", "Epoch 4/10\n", - "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 174ms/step - answer_output_accuracy: 0.3417 - answer_output_loss: 5.0458 - loss: 11.1663 - question_output_accuracy: 0.0333 - question_output_loss: 5.1257 - question_type_output_accuracy: 1.0000 - question_type_output_loss: 0.9948 - val_answer_output_accuracy: 0.9700 - val_answer_output_loss: 5.0661 - val_loss: 11.3417 - val_question_output_accuracy: 0.0000e+00 - val_question_output_loss: 5.2090 - val_question_type_output_accuracy: 1.0000 - val_question_type_output_loss: 1.0665\n", + "\u001b[1m2/2\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 170ms/step - answer_output_accuracy: 0.9825 - answer_output_loss: 4.9562 - loss: 12.0453 - question_output_accuracy: 0.0214 - question_output_loss: 5.8386 - question_type_output_accuracy: 0.5972 - question_type_output_loss: 1.0674 - val_answer_output_accuracy: 0.9856 - val_answer_output_loss: 4.0363 - val_loss: 10.9596 - val_question_output_accuracy: 0.0078 - val_question_output_loss: 5.8545 - val_question_type_output_accuracy: 0.4444 - val_question_type_output_loss: 1.0688\n", "Epoch 5/10\n", - "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 166ms/step - answer_output_accuracy: 0.9883 - answer_output_loss: 4.9145 - loss: 10.9538 - question_output_accuracy: 0.0333 - question_output_loss: 5.0917 - question_type_output_accuracy: 1.0000 - question_type_output_loss: 0.9476 - val_answer_output_accuracy: 0.9700 - val_answer_output_loss: 4.9497 - val_loss: 11.2111 - val_question_output_accuracy: 0.0000e+00 - val_question_output_loss: 5.2115 - val_question_type_output_accuracy: 1.0000 - val_question_type_output_loss: 1.0498\n", + "\u001b[1m2/2\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 180ms/step - answer_output_accuracy: 0.9827 - answer_output_loss: 3.0621 - loss: 10.1366 - question_output_accuracy: 0.0117 - question_output_loss: 5.8038 - question_type_output_accuracy: 0.5868 - question_type_output_loss: 1.0336 - val_answer_output_accuracy: 0.9856 - val_answer_output_loss: 1.7133 - val_loss: 8.5937 - val_question_output_accuracy: 0.0078 - val_question_output_loss: 5.8148 - val_question_type_output_accuracy: 0.5556 - val_question_type_output_loss: 1.0657\n", "Epoch 6/10\n", - "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 176ms/step - answer_output_accuracy: 0.9883 - answer_output_loss: 4.6563 - loss: 10.5922 - question_output_accuracy: 0.0333 - question_output_loss: 5.0504 - question_type_output_accuracy: 1.0000 - question_type_output_loss: 0.8855 - val_answer_output_accuracy: 0.9700 - val_answer_output_loss: 4.6939 - val_loss: 10.9339 - val_question_output_accuracy: 0.0000e+00 - val_question_output_loss: 5.2154 - val_question_type_output_accuracy: 1.0000 - val_question_type_output_loss: 1.0247\n", + "\u001b[1m2/2\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 167ms/step - answer_output_accuracy: 0.9824 - answer_output_loss: 1.1229 - loss: 8.0884 - question_output_accuracy: 0.0054 - question_output_loss: 5.7361 - question_type_output_accuracy: 0.5394 - question_type_output_loss: 1.1969 - val_answer_output_accuracy: 0.9856 - val_answer_output_loss: 0.6490 - val_loss: 7.4129 - val_question_output_accuracy: 0.0078 - val_question_output_loss: 5.6864 - val_question_type_output_accuracy: 0.5556 - val_question_type_output_loss: 1.0775\n", "Epoch 7/10\n", - "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 189ms/step - answer_output_accuracy: 0.9867 - answer_output_loss: 4.0798 - loss: 9.8799 - question_output_accuracy: 0.0333 - question_output_loss: 4.9974 - question_type_output_accuracy: 1.0000 - question_type_output_loss: 0.8027 - val_answer_output_accuracy: 0.9700 - val_answer_output_loss: 4.0274 - val_loss: 10.2376 - val_question_output_accuracy: 0.0000e+00 - val_question_output_loss: 5.2215 - val_question_type_output_accuracy: 1.0000 - val_question_type_output_loss: 0.9888\n", + "\u001b[1m2/2\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 171ms/step - answer_output_accuracy: 0.9824 - answer_output_loss: 0.5961 - loss: 7.2279 - question_output_accuracy: 0.0045 - question_output_loss: 5.4419 - question_type_output_accuracy: 0.4340 - question_type_output_loss: 1.1878 - val_answer_output_accuracy: 0.9856 - val_answer_output_loss: 0.5096 - val_loss: 7.2387 - val_question_output_accuracy: 0.0078 - val_question_output_loss: 5.5038 - val_question_type_output_accuracy: 0.2222 - val_question_type_output_loss: 1.2253\n", "Epoch 8/10\n", - "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 172ms/step - answer_output_accuracy: 0.9867 - answer_output_loss: 2.9405 - loss: 8.5655 - question_output_accuracy: 0.0333 - question_output_loss: 4.9250 - question_type_output_accuracy: 1.0000 - question_type_output_loss: 0.7000 - val_answer_output_accuracy: 0.9700 - val_answer_output_loss: 2.6667 - val_loss: 8.8361 - val_question_output_accuracy: 0.0000e+00 - val_question_output_loss: 5.2325 - val_question_type_output_accuracy: 1.0000 - val_question_type_output_loss: 0.9369\n", + "\u001b[1m2/2\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 183ms/step - answer_output_accuracy: 0.9824 - answer_output_loss: 0.6082 - loss: 6.8731 - question_output_accuracy: 0.0045 - question_output_loss: 5.1820 - question_type_output_accuracy: 0.4132 - question_type_output_loss: 1.0811 - val_answer_output_accuracy: 0.9856 - val_answer_output_loss: 0.5227 - val_loss: 7.0044 - val_question_output_accuracy: 0.0067 - val_question_output_loss: 5.4302 - val_question_type_output_accuracy: 0.5556 - val_question_type_output_loss: 1.0514\n", "Epoch 9/10\n", - "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 186ms/step - answer_output_accuracy: 0.9867 - answer_output_loss: 1.7502 - loss: 7.1458 - question_output_accuracy: 0.0317 - question_output_loss: 4.8152 - question_type_output_accuracy: 1.0000 - question_type_output_loss: 0.5805 - val_answer_output_accuracy: 0.9700 - val_answer_output_loss: 1.5605 - val_loss: 7.6711 - val_question_output_accuracy: 0.0000e+00 - val_question_output_loss: 5.2582 - val_question_type_output_accuracy: 0.5000 - val_question_type_output_loss: 0.8525\n", + "\u001b[1m2/2\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 164ms/step - answer_output_accuracy: 0.9824 - answer_output_loss: 0.6137 - loss: 6.7673 - question_output_accuracy: 0.0045 - question_output_loss: 4.9309 - question_type_output_accuracy: 0.4815 - question_type_output_loss: 1.3263 - val_answer_output_accuracy: 0.9856 - val_answer_output_loss: 0.5185 - val_loss: 6.9885 - val_question_output_accuracy: 0.0044 - val_question_output_loss: 5.4844 - val_question_type_output_accuracy: 0.6667 - val_question_type_output_loss: 0.9857\n", "Epoch 10/10\n", - "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 196ms/step - answer_output_accuracy: 0.9867 - answer_output_loss: 0.9620 - loss: 6.0314 - question_output_accuracy: 0.0250 - question_output_loss: 4.6111 - question_type_output_accuracy: 1.0000 - question_type_output_loss: 0.4584 - val_answer_output_accuracy: 0.9700 - val_answer_output_loss: 0.8570 - val_loss: 6.9187 - val_question_output_accuracy: 0.0000e+00 - val_question_output_loss: 5.3395 - val_question_type_output_accuracy: 0.5000 - val_question_type_output_loss: 0.7221\n", - "✅ Model LSTM Multi-Output berhasil dilatih dan disimpan!\n" + "\u001b[1m2/2\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 176ms/step - answer_output_accuracy: 0.9824 - answer_output_loss: 0.6061 - loss: 6.6094 - question_output_accuracy: 0.0045 - question_output_loss: 4.8379 - question_type_output_accuracy: 0.4132 - question_type_output_loss: 1.1360 - val_answer_output_accuracy: 0.9856 - val_answer_output_loss: 0.4949 - val_loss: 7.1082 - val_question_output_accuracy: 0.0044 - val_question_output_loss: 5.5818 - val_question_type_output_accuracy: 0.5556 - val_question_type_output_loss: 1.0315\n", + "✅ Model training complete and saved!\n" ] } ], "source": [ - "# Implementation of lstm with semantic analyz\n", - "# === Load Tokenizer === #\n", - "with open(\"tokenizer.pkl\", \"rb\") as handle:\n", - " tokenizer = pickle.load(handle)\n", - "\n", - "# === Load Data yang Sudah Diproses === #\n", - "MAX_LENGTH = 100\n", + "# === Model Hyperparameters === #\n", "VOCAB_SIZE = len(tokenizer.word_index) + 1\n", - "\n", - "context_padded = np.load(\"context_padded.npy\")\n", - "question_padded = np.load(\"question_padded.npy\")\n", - "answer_padded = np.load(\"answer_padded.npy\")\n", - "question_type_labels = np.load(\n", - " \"question_type_labels.npy\"\n", - ") # Label tipe soal (0 = Fill, 1 = True/False, 2 = Multiple Choice)\n", - "\n", - "# === Hyperparameter === #\n", "EMBEDDING_DIM = 300\n", "LSTM_UNITS = 256\n", "BATCH_SIZE = 32\n", "EPOCHS = 10\n", "\n", - "\n", - "# === Input Encoder (Konteks) === #\n", + "# === Build Model === #\n", + "# Encoder for Context\n", "context_input = Input(shape=(MAX_LENGTH,), name=\"context_input\")\n", - "context_embedding = Embedding(\n", - " input_dim=VOCAB_SIZE,\n", - " output_dim=EMBEDDING_DIM,\n", - " mask_zero=True,\n", - " name=\"context_embedding\",\n", - ")(context_input)\n", + "context_embedding = Embedding(input_dim=VOCAB_SIZE, output_dim=EMBEDDING_DIM, mask_zero=True, name=\"context_embedding\")(context_input)\n", "encoder_lstm = LSTM(LSTM_UNITS, return_state=True, name=\"encoder_lstm\")\n", "encoder_output, state_h, state_c = encoder_lstm(context_embedding)\n", "\n", - "# === Decoder untuk Pertanyaan === #\n", + "# Decoder for Question (Teacher Forcing)\n", "question_decoder_input = Input(shape=(MAX_LENGTH,), name=\"question_decoder_input\")\n", - "question_embedding = Embedding(\n", - " input_dim=VOCAB_SIZE,\n", - " output_dim=EMBEDDING_DIM,\n", - " mask_zero=True,\n", - " name=\"question_embedding\",\n", - ")(question_decoder_input)\n", - "question_lstm = LSTM(\n", - " LSTM_UNITS, return_sequences=True, return_state=True, name=\"question_lstm\"\n", - ")\n", - "question_output, _, _ = question_lstm(\n", - " question_embedding, initial_state=[state_h, state_c]\n", - ")\n", - "question_dense = Dense(VOCAB_SIZE, activation=\"softmax\", name=\"question_output\")(\n", - " question_output\n", - ")\n", + "question_embedding = Embedding(input_dim=VOCAB_SIZE, output_dim=EMBEDDING_DIM, mask_zero=True, name=\"question_embedding\")(question_decoder_input)\n", + "question_lstm = LSTM(LSTM_UNITS, return_sequences=True, return_state=True, name=\"question_lstm\")\n", + "question_output, _, _ = question_lstm(question_embedding, initial_state=[state_h, state_c])\n", + "question_dense = Dense(VOCAB_SIZE, activation=\"softmax\", name=\"question_output\")(question_output)\n", "\n", - "# === Decoder untuk Jawaban === #\n", - "answer_lstm = LSTM(\n", - " LSTM_UNITS, return_sequences=True, return_state=True, name=\"answer_lstm\"\n", - ")\n", + "# Decoder for Answer\n", + "answer_lstm = LSTM(LSTM_UNITS, return_sequences=True, return_state=True, name=\"answer_lstm\")\n", "answer_output, _, _ = answer_lstm(context_embedding, initial_state=[state_h, state_c])\n", - "answer_dense = Dense(VOCAB_SIZE, activation=\"softmax\", name=\"answer_output\")(\n", - " answer_output\n", - ")\n", + "answer_dense = Dense(VOCAB_SIZE, activation=\"softmax\", name=\"answer_output\")(answer_output)\n", "\n", - "# === Prediksi Tipe Soal (Fill, True/False, Multiple Choice) === #\n", + "# Classification Output for Question Type\n", "type_dense = Dense(128, activation=\"relu\")(encoder_output)\n", - "question_type_output = Dense(3, activation=\"softmax\", name=\"question_type_output\")(\n", - " type_dense\n", - ") # 3 Kategori soal\n", + "question_type_output = Dense(3, activation=\"softmax\", name=\"question_type_output\")(type_dense)\n", "\n", - "# === Membangun Model Multi-Output === #\n", + "# Construct the Model\n", "model = Model(\n", " inputs=[context_input, question_decoder_input],\n", " outputs=[question_dense, answer_dense, question_type_output],\n", ")\n", "\n", - "# === Compile Model === #\n", - "# Compile Model (Fix for multiple outputs)\n", + "# === Compile the Model === #\n", "model.compile(\n", " optimizer=\"adam\",\n", " loss={\n", @@ -474,120 +412,88 @@ " },\n", ")\n", "\n", - "\n", - "early_stop = EarlyStopping(monitor='val_loss', patience=3)\n", - "checkpoint = ModelCheckpoint(\"best_model.h5\", monitor='val_loss', save_best_only=True)\n", - "\n", - "\n", - "# === Training Model === #\n", + "# === Train the Model === #\n", "model.fit(\n", - " [context_padded, question_padded],\n", + " [context_train, question_train],\n", " {\n", - " \"question_output\": question_padded,\n", - " \"answer_output\": answer_padded,\n", - " \"question_type_output\": question_type_labels,\n", + " \"question_output\": question_train,\n", + " \"answer_output\": answer_train,\n", + " \"question_type_output\": qtype_train,\n", " },\n", " batch_size=BATCH_SIZE,\n", " epochs=EPOCHS,\n", " validation_split=0.2,\n", ")\n", "\n", - "# === Simpan Model === #\n", + "# Save the Model\n", "model.save(\"lstm_multi_output_model.keras\")\n", - "\n", - "print(\"✅ Model LSTM Multi-Output berhasil dilatih dan disimpan!\")" + "print(\"✅ Model training complete and saved!\")" ] }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 49, "metadata": {}, "outputs": [ { - "ename": "NameError", - "evalue": "name 'context_padded_test' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[53], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m predictions \u001b[38;5;241m=\u001b[39m model\u001b[38;5;241m.\u001b[39mpredict([\u001b[43mcontext_padded_test\u001b[49m, question_padded_test])\n\u001b[1;32m 3\u001b[0m \u001b[38;5;66;03m# predictions[0] corresponds to question_output (shape: [batch_size, MAX_LENGTH, VOCAB_SIZE])\u001b[39;00m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;66;03m# predictions[1] corresponds to answer_output (shape: [batch_size, MAX_LENGTH, VOCAB_SIZE])\u001b[39;00m\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m# predictions[2] corresponds to question_type_output (shape: [batch_size, 3])\u001b[39;00m\n\u001b[1;32m 6\u001b[0m \n\u001b[1;32m 7\u001b[0m \u001b[38;5;66;03m# Convert probabilities to predicted class indices\u001b[39;00m\n\u001b[1;32m 8\u001b[0m question_output_pred \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39margmax(predictions[\u001b[38;5;241m0\u001b[39m], axis\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m) \u001b[38;5;66;03m# shape: (batch_size, MAX_LENGTH)\u001b[39;00m\n", - "\u001b[0;31mNameError\u001b[0m: name 'context_padded_test' is not defined" + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 255ms/step\n", + "=== Evaluation on Test Data ===\n", + "Classification Report for Question Type:\n", + " precision recall f1-score support\n", + "\n", + " 0 0.33 0.40 0.36 5\n", + " 1 0.33 0.50 0.40 4\n", + " 2 0.00 0.00 0.00 3\n", + "\n", + " accuracy 0.33 12\n", + " macro avg 0.22 0.30 0.25 12\n", + "weighted avg 0.25 0.33 0.28 12\n", + "\n", + "Accuracy: 0.3333333333333333\n", + "Precision: 0.25\n", + "Recall: 0.3333333333333333\n", + "BLEU score for first test sample (question generation): 0\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/disc1/code/thesis_quiz_project/lstm-quiz/myenv/lib64/python3.10/site-packages/sklearn/metrics/_classification.py:1565: UndefinedMetricWarning: Precision is ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.\n", + " _warn_prf(average, modifier, f\"{metric.capitalize()} is\", len(result))\n", + "/mnt/disc1/code/thesis_quiz_project/lstm-quiz/myenv/lib64/python3.10/site-packages/sklearn/metrics/_classification.py:1565: UndefinedMetricWarning: Precision is ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.\n", + " _warn_prf(average, modifier, f\"{metric.capitalize()} is\", len(result))\n", + "/mnt/disc1/code/thesis_quiz_project/lstm-quiz/myenv/lib64/python3.10/site-packages/sklearn/metrics/_classification.py:1565: UndefinedMetricWarning: Precision is ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.\n", + " _warn_prf(average, modifier, f\"{metric.capitalize()} is\", len(result))\n", + "/mnt/disc1/code/thesis_quiz_project/lstm-quiz/myenv/lib64/python3.10/site-packages/sklearn/metrics/_classification.py:1565: UndefinedMetricWarning: Precision is ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.\n", + " _warn_prf(average, modifier, f\"{metric.capitalize()} is\", len(result))\n" ] } ], "source": [ - "predictions = model.predict([context_padded_test, question_padded_test])\n", + "# === Evaluate on Test Set === #\n", + "pred_question, pred_answer, pred_qtype = model.predict([context_test, question_test])\n", + "pred_qtype_labels = np.argmax(pred_qtype, axis=1)\n", "\n", - "# predictions[0] corresponds to question_output (shape: [batch_size, MAX_LENGTH, VOCAB_SIZE])\n", - "# predictions[1] corresponds to answer_output (shape: [batch_size, MAX_LENGTH, VOCAB_SIZE])\n", - "# predictions[2] corresponds to question_type_output (shape: [batch_size, 3])\n", + "print(\"=== Evaluation on Test Data ===\")\n", + "print(\"Classification Report for Question Type:\")\n", + "print(classification_report(qtype_test, pred_qtype_labels))\n", + "print(\"Accuracy:\", accuracy_score(qtype_test, pred_qtype_labels))\n", + "print(\"Precision:\", precision_score(qtype_test, pred_qtype_labels, average='weighted'))\n", + "print(\"Recall:\", recall_score(qtype_test, pred_qtype_labels, average='weighted'))\n", "\n", - "# Convert probabilities to predicted class indices\n", - "question_output_pred = np.argmax(predictions[0], axis=-1) # shape: (batch_size, MAX_LENGTH)\n", - "answer_output_pred = np.argmax(predictions[1], axis=-1) # shape: (batch_size, MAX_LENGTH)\n", - "question_type_pred = np.argmax(predictions[2], axis=-1) # shape: (batch_size,)\n", + "# Optional: Evaluate sequence generation using BLEU score for the first sample\n", + "import nltk\n", + "def sequence_to_text(sequence, tokenizer):\n", + " return [tokenizer.index_word.get(idx, \"\") for idx in sequence if idx != 0]\n", "\n", - "# === 3. Evaluate QUESTION TYPE (single-label classification) === #\n", - "print(\"=== Evaluation for Question Type ===\")\n", - "print(classification_report(\n", - " question_type_test, # True labels\n", - " question_type_pred, # Predicted labels\n", - " target_names=[\"Fill\", \"True/False\", \"Multiple Choice\"], # Optionally label your classes\n", - " zero_division=0 # Avoids warning if a class is absent\n", - "))\n", - "\n", - "# If you just want separate metrics (macro-average for multi-class):\n", - "acc_qtype = accuracy_score(question_type_test, question_type_pred)\n", - "prec_qtype = precision_score(question_type_test, question_type_pred, average='macro', zero_division=0)\n", - "rec_qtype = recall_score(question_type_test, question_type_pred, average='macro', zero_division=0)\n", - "\n", - "print(f\"Question Type -> Accuracy: {acc_qtype:.4f}, Precision(macro): {prec_qtype:.4f}, Recall(macro): {rec_qtype:.4f}\")\n", - "print(\"\")\n", - "\n", - "# === 4. Evaluate QUESTION OUTPUT & ANSWER OUTPUT (sequence predictions) === #\n", - "# We do a token-level comparison. We must exclude padded positions to get a fair score.\n", - "\n", - "# A helper function to flatten predictions & true labels while ignoring padding (zeros).\n", - "def flatten_and_mask(true_seq, pred_seq, pad_token=0):\n", - " \"\"\"\n", - " true_seq, pred_seq = [batch_size, MAX_LENGTH]\n", - " Returns flattened arrays of true & predicted labels, ignoring where true_seq == pad_token.\n", - " \"\"\"\n", - " mask = (true_seq != pad_token)\n", - " true_flat = true_seq[mask].flatten()\n", - " pred_flat = pred_seq[mask].flatten()\n", - " return true_flat, pred_flat\n", - "\n", - "# --- 4a. Question Output ---\n", - "q_true_flat, q_pred_flat = flatten_and_mask(question_padded_test, question_output_pred, pad_token=0)\n", - "\n", - "print(\"=== Evaluation for Question Tokens ===\")\n", - "print(classification_report(\n", - " q_true_flat, \n", - " q_pred_flat,\n", - " zero_division=0 # Avoid warnings if a class is absent\n", - "))\n", - "\n", - "acc_q = accuracy_score(q_true_flat, q_pred_flat)\n", - "prec_q = precision_score(q_true_flat, q_pred_flat, average='macro', zero_division=0)\n", - "rec_q = recall_score(q_true_flat, q_pred_flat, average='macro', zero_division=0)\n", - "print(f\"Question Tokens -> Accuracy: {acc_q:.4f}, Precision(macro): {prec_q:.4f}, Recall(macro): {rec_q:.4f}\")\n", - "print(\"\")\n", - "\n", - "# --- 4b. Answer Output ---\n", - "a_true_flat, a_pred_flat = flatten_and_mask(answer_padded_test, answer_output_pred, pad_token=0)\n", - "\n", - "print(\"=== Evaluation for Answer Tokens ===\")\n", - "print(classification_report(\n", - " a_true_flat,\n", - " a_pred_flat,\n", - " zero_division=0\n", - "))\n", - "\n", - "acc_a = accuracy_score(a_true_flat, a_pred_flat)\n", - "prec_a = precision_score(a_true_flat, a_pred_flat, average='macro', zero_division=0)\n", - "rec_a = recall_score(a_true_flat, a_pred_flat, average='macro', zero_division=0)\n", - "print(f\"Answer Tokens -> Accuracy: {acc_a:.4f}, Precision(macro): {prec_a:.4f}, Recall(macro): {rec_a:.4f}\")\n" + "reference = [sequence_to_text(question_test[0], tokenizer)]\n", + "candidate = sequence_to_text(np.argmax(pred_question[0], axis=-1), tokenizer)\n", + "bleu_score = nltk.translate.bleu_score.sentence_bleu(reference, candidate)\n", + "print(\"BLEU score for first test sample (question generation):\", bleu_score)\n" ] } ],