{"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"}],"dockerImageVersionId":31260,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport re\nimport torch\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\nfrom datasets import Dataset\nfrom transformers import (\n    MarianMTModel, \n    MarianTokenizer, \n    Seq2SeqTrainingArguments, \n    Seq2SeqTrainer, \n    DataCollatorForSeq2Seq\n)\n\n# 1. Fungsi Pembersih\ndef clean_akkadian(text):\n    if not isinstance(text, str): return \"\"\n    text = text.replace('ḫ', 'h').replace('Ḫ', 'H')\n    text = re.sub(r'[!?/:<>˹˺]', '', text)\n    text = re.sub(r'\\[(.*?)\\]', r'\\1', text) \n    text = text.replace('[x]', '<gap>').replace('...', '<big_gap>')\n    det_map = {'{d}': 'd', '{ki}': 'ki', '{m}': 'm', '{f}': 'f', '{uru}': 'uru'}\n    for det, tag in det_map.items():\n        text = text.replace(det, tag)\n    text = re.sub(r'\\{(.*?)\\}', r'\\1', text)\n    return re.sub(r'\\s+', ' ', text).strip()\n\n# 2. Load Data\n# Pastikan path ini benar sesuai folder input Kaggle-mu\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\ntrain_df['cleaned_src'] = train_df['transliteration'].apply(clean_akkadian)\ntest_df['cleaned_src'] = test_df['transliteration'].apply(clean_akkadian)\n\nprint(\"Data Berhasil Dimuat!\")\nprint(train_df[['cleaned_src', 'translation']].head(3))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T05:55:17.751481Z","iopub.execute_input":"2026-01-26T05:55:17.752065Z","iopub.status.idle":"2026-01-26T05:55:27.404112Z","shell.execute_reply.started":"2026-01-26T05:55:17.752034Z","shell.execute_reply":"2026-01-26T05:55:27.403272Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_name = \"Helsinki-NLP/opus-mt-mul-en\"\ntokenizer = MarianTokenizer.from_pretrained(model_name)\nmodel = MarianMTModel.from_pretrained(model_name)\n\ndef tokenize_function(examples):\n    model_inputs = tokenizer(examples[\"cleaned_src\"], truncation=True, padding=\"max_length\", max_length=128)\n    labels = tokenizer(text_target=examples[\"translation\"], truncation=True, padding=\"max_length\", max_length=128)\n    model_inputs[\"labels\"] = labels[\"input_ids\"]\n    return model_inputs\n\ntrain_ds = Dataset.from_pandas(train_df[['cleaned_src', 'translation']])\ntokenized_train = train_ds.map(tokenize_function, batched=True)\n\nprint(\"Tokenisasi Selesai!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T05:56:15.339836Z","iopub.execute_input":"2026-01-26T05:56:15.340659Z","iopub.status.idle":"2026-01-26T05:56:19.003644Z","shell.execute_reply.started":"2026-01-26T05:56:15.340628Z","shell.execute_reply":"2026-01-26T05:56:19.002990Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"training_args = Seq2SeqTrainingArguments(\n    output_dir=\"./results\",\n    per_device_train_batch_size=8,\n    gradient_accumulation_steps=2,\n    learning_rate=5e-5,\n    num_train_epochs=15, \n    logging_steps=20,\n    save_strategy=\"no\",\n    fp16=True, \n    report_to=\"none\"\n)\n\ntrainer = Seq2SeqTrainer(\n    model=model,\n    args=training_args,\n    train_dataset=tokenized_train,\n    tokenizer=tokenizer,\n    data_collator=DataCollatorForSeq2Seq(tokenizer, model=model),\n)\n\nprint(\"Memulai Training...\")\ntrainer.train()\n\n# Plotting Loss\nhistory = trainer.state.log_history\nlosses = [log['loss'] for log in history if 'loss' in log]\nplt.plot(losses)\nplt.title(\"Grafik Penurunan Error (Loss)\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T05:56:31.668262Z","iopub.execute_input":"2026-01-26T05:56:31.669065Z","iopub.status.idle":"2026-01-26T06:02:51.181841Z","shell.execute_reply.started":"2026-01-26T05:56:31.669034Z","shell.execute_reply":"2026-01-26T06:02:51.181261Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Menerjemahkan data test...\")\nmodel.eval()\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nmodel.to(device)\n\ndef translate_batch(texts):\n    inputs = tokenizer(texts, return_tensors=\"pt\", padding=True, truncation=True).to(device)\n    with torch.no_grad():\n        generated_ids = model.generate(inputs.input_ids, max_length=128)\n    return tokenizer.batch_decode(generated_ids, skip_special_tokens=True)\n\ntranslations = []\nbatch_size = 16\nfor i in tqdm(range(0, len(test_df), batch_size)):\n    batch_texts = test_df['cleaned_src'].iloc[i:i+batch_size].tolist()\n    translations.extend(translate_batch(batch_texts))\n\nsubmission = pd.DataFrame({'id': test_df['id'], 'translation': translations})\nsubmission.to_csv('submission.csv', index=False)\nprint(\"File submission.csv berhasil dibuat! Silakan cek di panel Output.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T06:20:17.689953Z","iopub.execute_input":"2026-01-26T06:20:17.690548Z","iopub.status.idle":"2026-01-26T06:20:18.902313Z","shell.execute_reply.started":"2026-01-26T06:20:17.690519Z","shell.execute_reply":"2026-01-26T06:20:18.901499Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Simpan model dan tokenizer ke folder lokal\nmodel.save_pretrained(\"./my_model_final\")\ntokenizer.save_pretrained(\"./my_model_final\")\nprint(\"Model berhasil disimpan secara lokal!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-26T06:20:25.137261Z","iopub.execute_input":"2026-01-26T06:20:25.137538Z","iopub.status.idle":"2026-01-26T06:20:25.920129Z","shell.execute_reply.started":"2026-01-26T06:20:25.137514Z","shell.execute_reply":"2026-01-26T06:20:25.919397Z"}},"outputs":[],"execution_count":null}]}