{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":121150,"databundleVersionId":15061024,"sourceType":"competition"},{"sourceId":705977,"sourceType":"modelInstanceVersion","modelInstanceId":535965,"modelId":543330}],"dockerImageVersionId":31259,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-01-26T16:41:26.671152Z","iopub.execute_input":"2026-01-26T16:41:26.671514Z","iopub.status.idle":"2026-01-26T16:41:26.943864Z","shell.execute_reply.started":"2026-01-26T16:41:26.671471Z","shell.execute_reply":"2026-01-26T16:41:26.943150Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install -U \"transformers<4.46.0\" \"peft<0.14.0\" \"accelerate<1.1.0\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T16:41:26.945207Z","iopub.execute_input":"2026-01-26T16:41:26.945551Z","iopub.status.idle":"2026-01-26T16:41:43.213523Z","shell.execute_reply.started":"2026-01-26T16:41:26.945527Z","shell.execute_reply":"2026-01-26T16:41:43.212656Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nfrom sklearn.model_selection import train_test_split\nfrom transformers import AutoTokenizer, AutoModelForSeq2SeqLM, DataCollatorForSeq2Seq, Seq2SeqTrainingArguments, Seq2SeqTrainer\nfrom datasets import Dataset\nfrom peft import LoraConfig, get_peft_model, TaskType\nimport torch\nimport kagglehub\nimport warnings\nimport textwrap\n\nimport os\nos.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' # Membisukan log TensorFlow\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T16:41:43.214844Z","iopub.execute_input":"2026-01-26T16:41:43.215140Z","iopub.status.idle":"2026-01-26T16:42:12.003927Z","shell.execute_reply.started":"2026-01-26T16:41:43.215112Z","shell.execute_reply":"2026-01-26T16:42:12.003166Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load data utama\ntrain_df = pd.read_csv('/kaggle/input/deep-past-initiative-machine-translation/train.csv')\ntest_df = pd.read_csv('/kaggle/input/deep-past-initiative-machine-translation/test.csv')\n\n# Melihat 5 baris pertama\nprint(\"--- Tampilan Data Train ---\")\nprint(train_df.head())\n\n# Cek kolom apa saja yang tersedia\nprint(\"\\n--- Kolom di Train ---\")\nprint(train_df.columns)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T16:42:12.005468Z","iopub.execute_input":"2026-01-26T16:42:12.005968Z","iopub.status.idle":"2026-01-26T16:42:12.077158Z","shell.execute_reply.started":"2026-01-26T16:42:12.005945Z","shell.execute_reply":"2026-01-26T16:42:12.076573Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# !pip install -q transformers[torch] datasets evaluate sacrebleu","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T16:42:12.077950Z","iopub.execute_input":"2026-01-26T16:42:12.078193Z","iopub.status.idle":"2026-01-26T16:42:16.425147Z","shell.execute_reply.started":"2026-01-26T16:42:12.078174Z","shell.execute_reply":"2026-01-26T16:42:16.424429Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_id = kagglehub.model_download(\"manwithacat/nllb-akkadian/transformers/transformers\") # Sesuai pilihan di gambar\n\n# Gunakan device_map=\"auto\" agar otomatis membagi beban ke GPU/CPU\ntokenizer = AutoTokenizer.from_pretrained(model_id)\nmodel = AutoModelForSeq2SeqLM.from_pretrained(\n    model_id, \n    device_map=\"auto\", \n    torch_dtype=torch.bfloat16 # Lebih hemat memori tapi tetap akurat\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T16:44:55.645886Z","iopub.execute_input":"2026-01-26T16:44:55.646542Z","iopub.status.idle":"2026-01-26T16:45:29.376256Z","shell.execute_reply.started":"2026-01-26T16:44:55.646511Z","shell.execute_reply":"2026-01-26T16:45:29.375525Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def preprocess_function(examples):\n    # Gunakan tokenizer sebagai context manager untuk menentukan target language\n    # 'eng_Latn' adalah kode standar NLLB untuk English\n    tokenizer.src_lang = \"eng_Latn\" # Saya \"tipu\" sedikit agar dia pakai karakter latin\n    tokenizer.tgt_lang = \"eng_Latn\" \n    \n    inputs = [str(doc) for doc in examples[\"transliteration\"]]\n    targets = [str(doc) for doc in examples[\"translation\"]]\n    \n    model_inputs = tokenizer(\n        inputs, \n        text_target=targets, \n        max_length=128, \n        truncation=True\n    )\n    return model_inputs","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T16:47:02.070880Z","iopub.execute_input":"2026-01-26T16:47:02.071356Z","iopub.status.idle":"2026-01-26T16:47:02.075763Z","shell.execute_reply.started":"2026-01-26T16:47:02.071328Z","shell.execute_reply":"2026-01-26T16:47:02.075104Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Konfigurasi LoRA khusus untuk model Seq2Seq (seperti T5)\nlora_config = LoraConfig(\n    r=20, # Rank: semakin besar semakin teliti tapi makan memori\n    lora_alpha=32,\n    target_modules=[\"q_proj\", \"v_proj\", \"k_proj\", \"out_proj\", \"fc1\", \"fc2\"], # Bagian otak model yang akan kita \"tempeli\" stiker pintar\n    lora_dropout=0.05,\n    bias=\"none\",\n    task_type=TaskType.SEQ_2_SEQ_LM\n)\n\n# Bungkus model asli dengan LoRA\nmodel = get_peft_model(model, lora_config)\nmodel.print_trainable_parameters() # Kamu akan lihat hanya sedikit parameter yang dilatih!","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T16:50:42.060154Z","iopub.execute_input":"2026-01-26T16:50:42.060802Z","iopub.status.idle":"2026-01-26T16:50:42.672505Z","shell.execute_reply.started":"2026-01-26T16:50:42.060771Z","shell.execute_reply":"2026-01-26T16:50:42.671665Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Ubah dataframe pandas ke Dataset Hugging Face\nraw_dataset = Dataset.from_pandas(train_df[['transliteration', 'translation']])\n\n# Bagi data menjadi Train dan Validation (misal 10% untuk tes internal)\nsplit_dataset = raw_dataset.train_test_split(test_size=0.1)\n\n# Jalankan pemrosesan (tokenisasi) secara massal\ntokenized_datasets = split_dataset.map(preprocess_function, batched=True)\n\nprint(\"Data siap! Contoh input IDs:\", tokenized_datasets[\"train\"][0][\"input_ids\"][:10])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T16:50:47.301060Z","iopub.execute_input":"2026-01-26T16:50:47.301340Z","iopub.status.idle":"2026-01-26T16:50:48.634354Z","shell.execute_reply.started":"2026-01-26T16:50:47.301315Z","shell.execute_reply":"2026-01-26T16:50:48.633645Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Data Collator: Memastikan input dan target dipotong/ditambah (pad) dengan benar di setiap batch\ndata_collator = DataCollatorForSeq2Seq(tokenizer, model=model)\n\n# Pengaturan Training\ntraining_args = Seq2SeqTrainingArguments(\n    output_dir=\"./hasil_translation_akkadia\",\n    eval_strategy=\"epoch\", # Cek akurasi setiap selesai 1 putaran data\n    learning_rate=5e-5,          # Sedikit lebih tinggi karena kita pakai LoRA\n    per_device_train_batch_size=8, # Kalau OOM, turunkan ke 4 atau 2\n    per_device_eval_batch_size=4,\n    weight_decay=0.01,\n    save_total_limit=2,          # Jangan simpan terlalu banyak file (hemat storage)\n    num_train_epochs=10,          # Coba 3 kali putaran dulu\n    predict_with_generate=True,  # Agar model menghasilkan teks saat evaluasi\n    fp16=True,                   # WAJIB: Mempercepat training & hemat VRAM\n    logging_strategy=\"steps\",\n    logging_steps=10,          \n    report_to=\"none\",         # Penting: agar output tidak \"nyangkut\" nunggu login WandB\n    disable_tqdm=False,       # Pastikan bar progres aktif\n    gradient_checkpointing=False, # Pastikan ini False\n    \n)\n\n# Objek utama yang akan menjalankan training\ntrainer = Seq2SeqTrainer(\n    model=model,\n    args=training_args,\n    train_dataset=tokenized_datasets[\"train\"],\n    eval_dataset=tokenized_datasets[\"test\"],\n    tokenizer=tokenizer,\n    data_collator=data_collator,\n)\n\nwith warnings.catch_warnings():\n    warnings.simplefilter(\"ignore\")\n    trainer.train()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T16:53:31.331032Z","iopub.execute_input":"2026-01-26T16:53:31.331550Z","iopub.status.idle":"2026-01-26T17:16:37.820357Z","shell.execute_reply.started":"2026-01-26T16:53:31.331520Z","shell.execute_reply":"2026-01-26T17:16:37.819795Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tentukan nama folder penyimpanan\nsave_path = \"./nllb-akkadian-finetuned\"\n\n# Simpan model (hanya adapter LoRA yang disimpan, jadi filenya kecil)\ntrainer.save_model(save_path)\n\n# Simpan tokenizer\ntokenizer.save_pretrained(save_path)\n\nprint(f\"Model berhasil disimpan di: {save_path}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T17:25:47.913637Z","iopub.execute_input":"2026-01-26T17:25:47.913948Z","iopub.status.idle":"2026-01-26T17:25:49.420282Z","shell.execute_reply.started":"2026-01-26T17:25:47.913922Z","shell.execute_reply":"2026-01-26T17:25:49.419535Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def translate_final(text):\n    # Set target language ke English\n    tokenizer.tgt_lang = \"eng_Latn\" \n    \n    inputs = tokenizer(text, return_tensors=\"pt\").to(\"cuda\")\n    \n    # Cara yang benar untuk NllbTokenizer mendapatkan ID bahasa\n    forced_bos_token_id = tokenizer.convert_tokens_to_ids(\"eng_Latn\")\n    \n    with torch.no_grad():\n        outputs = model.generate(\n            **inputs, \n            forced_bos_token_id=forced_bos_token_id,\n            max_length=256,\n            num_beams=4,              # Beam search membantu menjaga logika kalimat\n            repetition_penalty=1.5,   # NAIKKAN ini untuk menghentikan pengulangan halu\n            no_repeat_ngram_size=3,   # Jangan biarkan 3 kata yang sama muncul berurutan\n            early_stopping=True       # Hentikan segera jika model merasa kalimat sudah logis\n        )\n    return tokenizer.decode(outputs[0], skip_special_tokens=True)\n\n# Ambil 5 contoh dari dataset test (evaluasi) yang dibuat tadi\ndef print_styled_results(input_text, actual, pred, index):\n    width = 80\n    header = f\" CONTOH KE-{index+1} \"\n    print(\"\\n\" + \"=\"*width)\n    print(header.center(width, \"█\"))\n    print(\"=\"*width)\n    \n    print(\"\\n[DATA ASLI / AKKADIA]:\")\n    print(textwrap.fill(str(input_text), width=width))\n    \n    print(\"\\n\" + \"-\"*width)\n    print(\"[JAWABAN BENAR / TARGET]:\")\n    print(textwrap.fill(str(actual), width=width))\n    \n    print(\"\\n\" + \"-\"*width)\n    print(\"[PREDIKSI MODEL]:\")\n    # Saya beri tanda khusus agar kamu bisa melihat perbedaannya\n    print(textwrap.fill(str(pred), width=width))\n    print(\"\\n\" + \"=\"*width + \"\\n\")\n\n# Jalankan pengetesan dengan tampilan rapi\nfor i in range(5):\n    # Ambil teks mentah (bukan ID)\n    input_text = split_dataset[\"test\"][i][\"transliteration\"]\n    actual_label = split_dataset[\"test\"][i][\"translation\"]\n    \n    # Prediksi\n    prediction = translate_final(input_text)\n    \n    # Cetak dengan gaya rapi\n    print_styled_results(input_text, actual_label, prediction, i)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T17:19:31.194818Z","iopub.execute_input":"2026-01-26T17:19:31.195496Z","iopub.status.idle":"2026-01-26T17:20:20.175122Z","shell.execute_reply.started":"2026-01-26T17:19:31.195468Z","shell.execute_reply":"2026-01-26T17:20:20.174450Z"}},"outputs":[],"execution_count":null}]}