{"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":14584339,"sourceType":"datasetVersion","datasetId":9316366},{"sourceId":728390,"sourceType":"modelInstanceVersion","modelInstanceId":554647,"modelId":567212}],"dockerImageVersionId":31260,"isInternetEnabled":false,"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},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install evaluate sacrebleu","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ==========================================\n# Akkadian Translation using ByT5-Base\n# ==========================================\n# انسخ هذا الكود بالكامل وضعه في خلية واحدة داخل مفكرة Kaggle\n# Copy and paste this entire code into a single cell in your Kaggle notebook\n\nimport os\nimport re\nimport pandas as pd\nimport numpy as np\nimport torch\nfrom sklearn.model_selection import train_test_split\nfrom transformers import (\n    AutoTokenizer, \n    AutoModelForSeq2SeqLM, \n    DataCollatorForSeq2Seq, \n    Seq2SeqTrainingArguments, \n    Seq2SeqTrainer\n)\nimport evaluate\n\n# 1. التثبيت (Installation)\n# =========================\n# نحن نستخدم os.system لتشغيل أوامر التثبيت من داخل الكود\nprint(\"⏳ جاري تثبيت المكتبات اللازمة...\")\nos.system(\"pip install -q sacrebleu accelerate evaluate\")\nprint(\"✅ تم التثبيت!\")\n\n# 2. الإعدادات والمسارات (Setup & Paths)\n# ======================================\n# البحث عن مكان الملفات تلقائياً (لأن المسارات قد تختلف)\nTRAIN_FILE = None\nLEXICON_FILE = None\nTEST_FILE = None\n\nprint(\"🔍 جاري البحث عن ملفات البيانات...\")\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        path = os.path.join(dirname, filename)\n        if filename == 'train.csv':\n            TRAIN_FILE = path\n        elif filename == 'OA_Lexicon_eBL.csv':\n            LEXICON_FILE = path\n        elif filename == 'test.csv': # عادة يكون في مجلد المسابقة\n            TEST_FILE = path\n\nif not TRAIN_FILE or not LEXICON_FILE:\n    print(f\"❌ خطأ: لم يتم العثور على train.csv أو OA_Lexicon_eBL.csv\")\n    print(\"تأكد من إضافتها كـ Dataset في القائمة الجانبية (Add Data)\")\n    # Fallback paths just in case\n    # TRAIN_FILE = '/kaggle/input/byt5-new/train.csv'\nelse:\n    print(f\"✅ تم العثور على train.csv في: {TRAIN_FILE}\")\n    print(f\"✅ تم العثور على القاموس في: {LEXICON_FILE}\")\n\n# إعدادات النموذج\nMODEL_CHECKPOINT = \"google/byt5-base\" # النموذج القوي للأحرف\nMAX_INPUT_LENGTH = 128 # يمكن زيادته إلى 256 إذا سمحت الذاكرة\nMAX_TARGET_LENGTH = 128\nBATCH_SIZE = 8 # 8 مناسب لـ P100 GPU، جرب 4 إذا حدثت مشاكل ذاكرة\n\n# 3. معالجة البيانات (Preprocessing)\n# ==================================\n\n# تحميل القاموس\nprint(\"📖 تحميل القاموس...\")\nlexicon_df = pd.read_csv(LEXICON_FILE)\n# إنشاء خريطة: {\"word_form\": \"normalization\"}\nlexicon_map = dict(zip(lexicon_df['form'], lexicon_df['norm']))\n\ndef clean_and_normalize(text):\n    \"\"\" تنظيف النص وتوحيد المصطلحات باستخدام القاموس \"\"\"\n    if not isinstance(text, str): return \"\"\n    \n    # إزالة المحددات بين الأقواس المعقوفة {}\n    # text = re.sub(r'(\\{.*?\\})', r' \\1 ', text) # الخيار لك، إما حذفها أو فصلها\n    # هنا سنقوم بفصلها لتكون واضحة للنموذج\n    text = re.sub(r'(\\{.*?\\})', r' \\1 ', text)\n    \n    words = text.split()\n    normalized_words = []\n    for w in words:\n        if w in lexicon_map:\n            normalized_words.append(lexicon_map[w])\n        else:\n            normalized_words.append(w)\n            \n    return \" \".join(normalized_words)\n\nprint(\"🧹 جاري معالجة بيانات التدريب...\")\ndf = pd.read_csv(TRAIN_FILE)\n# حذف القيم الفارغة\ndf = df.dropna(subset=['transliteration', 'translation'])\n# تطبيق التنظيف\ndf['transliteration'] = df['transliteration'].apply(clean_and_normalize)\n\n# تقسيم البيانات\ntrain_df, val_df = train_test_split(df, test_size=0.05, random_state=42)\nprint(f\"عدد عينات التدريب: {len(train_df)}\")\nprint(f\"عدد عينات التحقق: {len(val_df)}\")\n\n# 4. التجهيز للنموذج (Tokenization)\n# ==================================\ntokenizer = AutoTokenizer.from_pretrained(MODEL_CHECKPOINT)\n\ndef preprocess_function(examples):\n    inputs = examples[\"transliteration\"]\n    targets = examples[\"translation\"]\n    \n    # ByT5 لا يحتاج لتقسيم الكلمات (Tokenization) معقد، هو يعمل على الأحرف\n    model_inputs = tokenizer(inputs, max_length=MAX_INPUT_LENGTH, truncation=True, padding=\"max_length\")\n    labels = tokenizer(targets, max_length=MAX_TARGET_LENGTH, truncation=True, padding=\"max_length\")\n\n    model_inputs[\"labels\"] = labels[\"input_ids\"]\n    return model_inputs\n\n# تحويل الـ DataFrame إلى Dataset خاص بـ HuggingFace\nfrom datasets import Dataset\ntrain_dataset = Dataset.from_pandas(train_df)\nval_dataset = Dataset.from_pandas(val_df)\n\ntokenized_train = train_dataset.map(preprocess_function, batched=True)\ntokenized_val = val_dataset.map(preprocess_function, batched=True)\n\n# 5. التدريب (Training)\n# =====================\nmodel = AutoModelForSeq2SeqLM.from_pretrained(\n    MODEL_CHECKPOINT,\n    device_map=\"auto\" # التوزيع التلقائي على GPU\n)\n\n# إعداد مقياس BLEU\nmetric = evaluate.load(\"sacrebleu\")\n\ndef postprocess_text(preds, labels):\n    preds = [pred.strip() for pred in preds]\n    labels = [[label.strip()] for label in labels]\n    return preds, labels\n\ndef compute_metrics(eval_preds):\n    preds, labels = eval_preds\n    if isinstance(preds, tuple):\n        preds = preds[0]\n    \n    # فك تشفير التنبؤات (من أرقام إلى نصوص)\n    decoded_preds = tokenizer.batch_decode(preds, skip_special_tokens=True)\n    \n    # استبدال -100 في الـ labels لأنها تعني \"تجاهل\"\n    labels = np.where(labels != -100, labels, tokenizer.pad_token_id)\n    decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)\n\n    decoded_preds, decoded_labels = postprocess_text(decoded_preds, decoded_labels)\n\n    result = metric.compute(predictions=decoded_preds, references=decoded_labels)\n    result = {\"bleu\": result[\"score\"]}\n    \n    prediction_lens = [np.count_nonzero(pred != tokenizer.pad_token_id) for pred in preds]\n    result[\"gen_len\"] = np.mean(prediction_lens)\n    return result\n\nargs = Seq2SeqTrainingArguments(\n    output_dir=\"/kaggle/working/byt5-akkadian-model\",\n    eval_strategy=\"epoch\",\n    save_strategy=\"epoch\",\n    learning_rate=5e-4, # ByT5 يتحمل معدل تعلم أعلى قليلاً\n    per_device_train_batch_size=BATCH_SIZE,\n    per_device_eval_batch_size=BATCH_SIZE,\n    weight_decay=0.01,\n    save_total_limit=2,\n    num_train_epochs=3, # زد الرقم إلى 5 أو 10 للحصول على نتائج أفضل\n    predict_with_generate=True,\n    fp16=True, # تفعيل السرعة إذا كان الـ GPU يدعمها\n    push_to_hub=False,\n    logging_dir=\"/kaggle/working/logs\",\n    logging_steps=100,\n    report_to=\"none\" # إيقاف wandb لتجنب طلب تسجيل الدخول\n)\n\ntrainer = Seq2SeqTrainer(\n    model=model,\n    args=args,\n    train_dataset=tokenized_train,\n    eval_dataset=tokenized_val,\n    data_collator=DataCollatorForSeq2Seq(tokenizer, model=model),\n    tokenizer=tokenizer,\n    compute_metrics=compute_metrics,\n)\n\nprint(\"🚀 بدء التدريب...\")\ntrainer.train()\n\n# 6. التنبؤ والملف النهائي (Inference & Submission)\n# =================================================\nprint(\"🔮 جاري التنبؤ على ملف الاختبار...\")\n\n# إعادة تحميل أفضل نموذج (اختياري، هنا نستخدم آخر حالة)\n# model = AutoModelForSeq2SeqLM.from_pretrained(\"/kaggle/working/byt5-akkadian-model/checkpoint-XXX\")\n\nif TEST_FILE and os.path.exists(TEST_FILE):\n    test_df = pd.read_csv(TEST_FILE)\n    # تنظيف المدخلات في الاختبار أيضاً!\n    test_df['transliteration'] = test_df['transliteration'].apply(clean_and_normalize)\n    \n    test_dataset = Dataset.from_pandas(test_df)\n    \n    # تحضير دالة تنبؤ بسيطة\n    def generate_translation(batch):\n        inputs = tokenizer(\n            batch[\"transliteration\"], \n            padding=\"max_length\", \n            truncation=True, \n            max_length=MAX_INPUT_LENGTH, \n            return_tensors=\"pt\"\n        ).input_ids\n        \n        inputs = inputs.to(model.device)\n        \n        outputs = model.generate(\n            inputs, \n            max_length=MAX_TARGET_LENGTH, \n            num_beams=4, # Beam search لتحسين الجودة\n            early_stopping=True\n        )\n        \n        translations = tokenizer.batch_decode(outputs, skip_special_tokens=True)\n        return {\"translation\": translations}\n\n    # التنبؤ (قد يأخذ وقتاً)\n    # نستخدم map للدفعات الصغيرة لتجنب امتلاء الذاكرة\n    results = test_dataset.map(lambda x: generate_translation(x), batched=True, batch_size=8)\n    \n    # حفظ النتيجة\n    submission = pd.DataFrame({\n        \"id\": test_df['id'] if 'id' in test_df else range(len(results)),\n        \"translation\": results['translation']\n    })\n    \n    submission.to_csv(\"submission.csv\", index=False)\n    print(\"✅ تم حفظ ملف Submission.csv بنجاح!\")\n    \nelse:\n    print(\"⚠️ لم يتم العثور على ملف test.csv، لم يتم إنشاء submission.\")\n\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ==========================================\n# Akkadian Translation using ByT5-Base (CORRECTED)\n# ==========================================\n\nimport os\nimport sys\nimport subprocess\n\n# 1. التثبيت التلقائي للمكتبات (Auto-Install)\n# ============================================\n# هذه الخطوة ستحل مشكلة ModuleNotFoundError نهائياً\nprint(\"⏳ جاري تثبيت المكتبات الضرورية (evaluate, sacrebleu)...\")\npackages = [\"sacrebleu\", \"accelerate\", \"evaluate\", \"transformers\", \"datasets\"]\nfor package in packages:\n    try:\n        __import__(package)\n    except ImportError:\n        subprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", \"-q\", package])\nprint(\"✅ تم تثبيت المكتبات بنجاح! سنكمل العمل الآن...\")\n\n# الآن نستدعي المكتبات بأمان\nimport re\nimport pandas as pd\nimport numpy as np\nimport torch\nfrom sklearn.model_selection import train_test_split\nfrom transformers import (\n    AutoTokenizer, \n    AutoModelForSeq2SeqLM, \n    DataCollatorForSeq2Seq, \n    Seq2SeqTrainingArguments, \n    Seq2SeqTrainer\n)\nimport evaluate\nfrom datasets import Dataset\n\n# 2. الإعدادات والمسارات (Setup & Paths)\n# ======================================\nTRAIN_FILE = None\nLEXICON_FILE = None\nTEST_FILE = None\n\nprint(\"🔍 جاري البحث عن ملفات البيانات...\")\n# البحث الذكي عن الملفات في مجلدات Kaggle\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        path = os.path.join(dirname, filename)\n        if 'train' in filename and filename.endswith('.csv'):\n            TRAIN_FILE = path\n        elif 'Lexicon' in filename and filename.endswith('.csv'):\n            LEXICON_FILE = path\n        elif 'test' in filename and filename.endswith('.csv'):\n            TEST_FILE = path\n\n# استخدام مسارات احتياطية إذا لم يجد البحث شيئاً\nif not TRAIN_FILE: TRAIN_FILE = '/kaggle/input/akkadian-data/train.csv' # عدل هذا إذا لزم\nif not LEXICON_FILE: LEXICON_FILE = '/kaggle/input/akkadian-data/OA_Lexicon_eBL.csv'\n\nprint(f\"📁 ملف التدريب: {TRAIN_FILE}\")\nprint(f\"📁 ملف المعجم: {LEXICON_FILE}\")\n\nif not os.path.exists(str(TRAIN_FILE)):\n    print(\"❌ خطأ حرج: لم يتم العثور على ملف train.csv. تأكد من إضافته كـ Dataset!\")\n    # لا نوقف الكود هنا بل ندعه يحاول، لكن هذه نقطة تحذير\n\n# إعدادات النموذج\nMODEL_CHECKPOINT = \"google/byt5-base\" \nMAX_INPUT_LENGTH = 128 \nMAX_TARGET_LENGTH = 128\nBATCH_SIZE = 4  # حجم صغير لتفادي مشاكل الذاكرة\n\n# 3. معالجة البيانات (Preprocessing)\n# ==================================\ndef load_lexicon():\n    if LEXICON_FILE and os.path.exists(LEXICON_FILE):\n        print(\"📖 تحميل القاموس...\")\n        lex_df = pd.read_csv(LEXICON_FILE)\n        return dict(zip(lex_df['form'], lex_df['norm']))\n    return {}\n\nlexicon_map = load_lexicon()\n\ndef clean_and_normalize(text):\n    if not isinstance(text, str): return \"\"\n    # فصل المحددات\n    text = re.sub(r'(\\{.*?\\})', r' \\1 ', text)\n    words = text.split()\n    normalized = [lexicon_map.get(w, w) for w in words]\n    return \" \".join(normalized)\n\nprint(\"🧹 جاري تجهيز البيانات...\")\ntry:\n    df = pd.read_csv(TRAIN_FILE)\n    df = df.dropna(subset=['transliteration', 'translation'])\n    df['transliteration'] = df['transliteration'].apply(clean_and_normalize)\n    \n    # تقسيم البيانات\n    train_df, val_df = train_test_split(df, test_size=0.05, random_state=42)\n    \n    train_dataset = Dataset.from_pandas(train_df)\n    val_dataset = Dataset.from_pandas(val_df)\n    print(f\"✅ البيانات جاهزة: {len(train_df)} تدريب، {len(val_df)} تحقق.\")\nexcept Exception as e:\n    print(f\"❌ حدث خطأ في معالجة البيانات: {e}\")\n    sys.exit(1) # إيقاف إذا لم توجد بيانات\n\n# 4. التجهيز للنموذج (Tokenization)\n# ==================================\nprint(\"⚙️ تحميل النموذج والـ Tokenizer...\")\ntokenizer = AutoTokenizer.from_pretrained(MODEL_CHECKPOINT)\nmodel = AutoModelForSeq2SeqLM.from_pretrained(MODEL_CHECKPOINT)\n\ndef preprocess_function(examples):\n    inputs = [\"translate Akkadian to English: \" + doc for doc in examples[\"transliteration\"]]\n    model_inputs = tokenizer(inputs, max_length=MAX_INPUT_LENGTH, truncation=True, padding=\"max_length\")\n    with tokenizer.as_target_tokenizer():\n        labels = tokenizer(examples[\"translation\"], max_length=MAX_TARGET_LENGTH, truncation=True, padding=\"max_length\")\n    model_inputs[\"labels\"] = labels[\"input_ids\"]\n    return model_inputs\n\ntokenized_train = train_dataset.map(preprocess_function, batched=True)\ntokenized_val = val_dataset.map(preprocess_function, batched=True)\n\n# 5. التدريب (Training)\n# =====================\nmetric = evaluate.load(\"sacrebleu\")\n\ndef compute_metrics(eval_preds):\n    preds, labels = eval_preds\n    if isinstance(preds, tuple): preds = preds[0]\n    decoded_preds = tokenizer.batch_decode(preds, skip_special_tokens=True)\n    labels = np.where(labels != -100, labels, tokenizer.pad_token_id)\n    decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)\n    \n    result = metric.compute(predictions=decoded_preds, references=[[l] for l in decoded_labels])\n    return {\"bleu\": result[\"score\"]}\n\nargs = Seq2SeqTrainingArguments(\n    output_dir=\"/kaggle/working/byt5-akkadian-model\",\n    eval_strategy=\"epoch\",\n    save_strategy=\"epoch\",\n    learning_rate=4e-4,\n    per_device_train_batch_size=BATCH_SIZE,\n    per_device_eval_batch_size=BATCH_SIZE,\n    gradient_accumulation_steps=4, # مهم جداً لتوفير الذاكرة\n    num_train_epochs=3,\n    weight_decay=0.01,\n    save_total_limit=1,\n    predict_with_generate=True,\n    fp16=torch.cuda.is_available(),\n    logging_steps=50,\n    report_to=\"none\"\n)\n\ntrainer = Seq2SeqTrainer(\n    model=model,\n    args=args,\n    train_dataset=tokenized_train,\n    eval_dataset=tokenized_val,\n    data_collator=DataCollatorForSeq2Seq(tokenizer, model=model),\n    tokenizer=tokenizer,\n    compute_metrics=compute_metrics,\n)\n\nprint(\"🚀 انطلاق التدريب (ByT5)...\")\ntrainer.train()\n\n# حفظ النموذج النهائي\ntrainer.save_model(\"/kaggle/working/byt5-final\")\ntokenizer.save_pretrained(\"/kaggle/working/byt5-final\")\nprint(\"💾 تم حفظ النموذج بنجاح!\")\n\n# 6. إنشاء ملف التسليم (Submission)\n# =================================\nif TEST_FILE and os.path.exists(TEST_FILE):\n    print(\"🔮 جاري الترجمة لملف المسابقة...\")\n    test_df = pd.read_csv(TEST_FILE)\n    test_df['transliteration'] = test_df['transliteration'].apply(clean_and_normalize)\n    test_dataset = Dataset.from_pandas(test_df)\n\n    def generate_translation(batch):\n        inputs = tokenizer(\n            [\"translate Akkadian to English: \" + t for t in batch[\"transliteration\"]], \n            padding=\"max_length\", truncation=True, max_length=MAX_INPUT_LENGTH, return_tensors=\"pt\"\n        ).input_ids.to(model.device)\n        \n        outputs = model.generate(inputs, max_length=MAX_TARGET_LENGTH, num_beams=4, early_stopping=True)\n        return {\"translation\": tokenizer.batch_decode(outputs, skip_special_tokens=True)}\n\n    results = test_dataset.map(lambda x: generate_translation(x), batched=True, batch_size=8)\n    \n    submission = pd.DataFrame({\n        \"id\": test_df['id'] if 'id' in test_df else range(len(results)),\n        \"translation\": results['translation']\n    })\n    submission.to_csv(\"submission.csv\", index=False)\n    print(\"✅✅ تم إنشاء ملف submission.csv جاهز للإرسال!\")\nelse:\n    print(\"⚠️ لم يتم العثور على ملف test.csv، تم الاكتفاء بتدريب وحفظ النموذج.\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ==========================================\n# Akkadian Translation using ByT5-Base (CORRECTED)\n# ==========================================\n\nimport os\nimport sys\nimport subprocess\n\n# 1. التثبيت التلقائي للمكتبات (Auto-Install)\n# ============================================\n# هذه الخطوة ستحل مشكلة ModuleNotFoundError نهائياً\nprint(\"⏳ جاري تثبيت المكتبات الضرورية (evaluate, sacrebleu)...\")\npackages = [\"sacrebleu\", \"accelerate\", \"evaluate\", \"transformers\", \"datasets\"]\nfor package in packages:\n    try:\n        __import__(package)\n    except ImportError:\n        subprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", \"-q\", package])\nprint(\"✅ تم تثبيت المكتبات بنجاح! سنكمل العمل الآن...\")\n\n# الآن نستدعي المكتبات بأمان\nimport re\nimport pandas as pd\nimport numpy as np\nimport torch\nfrom sklearn.model_selection import train_test_split\nfrom transformers import (\n    AutoTokenizer, \n    AutoModelForSeq2SeqLM, \n    DataCollatorForSeq2Seq, \n    Seq2SeqTrainingArguments, \n    Seq2SeqTrainer\n)\nimport evaluate\nfrom datasets import Dataset\n\n# 2. الإعدادات والمسارات (Setup & Paths)\n# ======================================\nTRAIN_FILE = None\nLEXICON_FILE = None\nTEST_FILE = None\n\nprint(\"🔍 جاري البحث عن ملفات البيانات...\")\n# البحث الذكي عن الملفات في مجلدات Kaggle\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        path = os.path.join(dirname, filename)\n        if 'train' in filename and filename.endswith('.csv'):\n            TRAIN_FILE = path\n        elif 'Lexicon' in filename and filename.endswith('.csv'):\n            LEXICON_FILE = path\n        elif 'test' in filename and filename.endswith('.csv'):\n            TEST_FILE = path\n\n# استخدام مسارات احتياطية إذا لم يجد البحث شيئاً\nif not TRAIN_FILE: TRAIN_FILE = '/kaggle/input/akkadian-data/train.csv' # عدل هذا إذا لزم\nif not LEXICON_FILE: LEXICON_FILE = '/kaggle/input/akkadian-data/OA_Lexicon_eBL.csv'\n\nprint(f\"📁 ملف التدريب: {TRAIN_FILE}\")\nprint(f\"📁 ملف المعجم: {LEXICON_FILE}\")\n\nif not os.path.exists(str(TRAIN_FILE)):\n    print(\"❌ خطأ حرج: لم يتم العثور على ملف train.csv. تأكد من إضافته كـ Dataset!\")\n    # لا نوقف الكود هنا بل ندعه يحاول، لكن هذه نقطة تحذير\n\n# إعدادات النموذج\nMODEL_CHECKPOINT = \"google/byt5-base\" \nMAX_INPUT_LENGTH = 128 \nMAX_TARGET_LENGTH = 128\nBATCH_SIZE = 4  # حجم صغير لتفادي مشاكل الذاكرة\n\n# 3. معالجة البيانات (Preprocessing)\n# ==================================\ndef load_lexicon():\n    if LEXICON_FILE and os.path.exists(LEXICON_FILE):\n        print(\"📖 تحميل القاموس...\")\n        lex_df = pd.read_csv(LEXICON_FILE)\n        return dict(zip(lex_df['form'], lex_df['norm']))\n    return {}\n\nlexicon_map = load_lexicon()\n\ndef clean_and_normalize(text):\n    if not isinstance(text, str): return \"\"\n    # فصل المحددات\n    text = re.sub(r'(\\{.*?\\})', r' \\1 ', text)\n    words = text.split()\n    normalized = [lexicon_map.get(w, w) for w in words]\n    return \" \".join(normalized)\n\nprint(\"🧹 جاري تجهيز البيانات...\")\ntry:\n    df = pd.read_csv(TRAIN_FILE)\n    df = df.dropna(subset=['transliteration', 'translation'])\n    df['transliteration'] = df['transliteration'].apply(clean_and_normalize)\n    \n    # تقسيم البيانات\n    train_df, val_df = train_test_split(df, test_size=0.05, random_state=42)\n    \n    train_dataset = Dataset.from_pandas(train_df)\n    val_dataset = Dataset.from_pandas(val_df)\n    print(f\"✅ البيانات جاهزة: {len(train_df)} تدريب، {len(val_df)} تحقق.\")\nexcept Exception as e:\n    print(f\"❌ حدث خطأ في معالجة البيانات: {e}\")\n    sys.exit(1) # إيقاف إذا لم توجد بيانات\n\n# 4. التجهيز للنموذج (Tokenization)\n# ==================================\nprint(\"⚙️ تحميل النموذج والـ Tokenizer...\")\ntokenizer = AutoTokenizer.from_pretrained(MODEL_CHECKPOINT)\nmodel = AutoModelForSeq2SeqLM.from_pretrained(MODEL_CHECKPOINT)\n\ndef preprocess_function(examples):\n    inputs = [\"translate Akkadian to English: \" + doc for doc in examples[\"transliteration\"]]\n    model_inputs = tokenizer(inputs, max_length=MAX_INPUT_LENGTH, truncation=True, padding=\"max_length\")\n    with tokenizer.as_target_tokenizer():\n        labels = tokenizer(examples[\"translation\"], max_length=MAX_TARGET_LENGTH, truncation=True, padding=\"max_length\")\n    model_inputs[\"labels\"] = labels[\"input_ids\"]\n    return model_inputs\n\ntokenized_train = train_dataset.map(preprocess_function, batched=True)\ntokenized_val = val_dataset.map(preprocess_function, batched=True)\n\n# 5. التدريب (Training)\n# =====================\nmetric = evaluate.load(\"sacrebleu\")\n\ndef compute_metrics(eval_preds):\n    preds, labels = eval_preds\n    if isinstance(preds, tuple): preds = preds[0]\n    decoded_preds = tokenizer.batch_decode(preds, skip_special_tokens=True)\n    labels = np.where(labels != -100, labels, tokenizer.pad_token_id)\n    decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)\n    \n    result = metric.compute(predictions=decoded_preds, references=[[l] for l in decoded_labels])\n    return {\"bleu\": result[\"score\"]}\n\nargs = Seq2SeqTrainingArguments(\n    output_dir=\"/kaggle/working/byt5-akkadian-model\",\n    eval_strategy=\"epoch\",\n    save_strategy=\"epoch\",\n    learning_rate=4e-4,\n    per_device_train_batch_size=BATCH_SIZE,\n    per_device_eval_batch_size=BATCH_SIZE,\n    gradient_accumulation_steps=4, # مهم جداً لتوفير الذاكرة\n    num_train_epochs=3,\n    weight_decay=0.01,\n    save_total_limit=1,\n    predict_with_generate=True,\n    fp16=torch.cuda.is_available(),\n    logging_steps=50,\n    report_to=\"none\"\n)\n\ntrainer = Seq2SeqTrainer(\n    model=model,\n    args=args,\n    train_dataset=tokenized_train,\n    eval_dataset=tokenized_val,\n    data_collator=DataCollatorForSeq2Seq(tokenizer, model=model),\n    tokenizer=tokenizer,\n    compute_metrics=compute_metrics,\n)\n\nprint(\"🚀 انطلاق التدريب (ByT5)...\")\ntrainer.train()\n\n# حفظ النموذج النهائي\ntrainer.save_model(\"/kaggle/working/byt5-final\")\ntokenizer.save_pretrained(\"/kaggle/working/byt5-final\")\nprint(\"💾 تم حفظ النموذج بنجاح!\")\n\n# 6. إنشاء ملف التسليم (Submission)\n# =================================\nif TEST_FILE and os.path.exists(TEST_FILE):\n    print(\"🔮 جاري الترجمة لملف المسابقة...\")\n    test_df = pd.read_csv(TEST_FILE)\n    test_df['transliteration'] = test_df['transliteration'].apply(clean_and_normalize)\n    test_dataset = Dataset.from_pandas(test_df)\n\n    def generate_translation(batch):\n        inputs = tokenizer(\n            [\"translate Akkadian to English: \" + t for t in batch[\"transliteration\"]], \n            padding=\"max_length\", truncation=True, max_length=MAX_INPUT_LENGTH, return_tensors=\"pt\"\n        ).input_ids.to(model.device)\n        \n        outputs = model.generate(inputs, max_length=MAX_TARGET_LENGTH, num_beams=4, early_stopping=True)\n        return {\"translation\": tokenizer.batch_decode(outputs, skip_special_tokens=True)}\n\n    results = test_dataset.map(lambda x: generate_translation(x), batched=True, batch_size=8)\n    \n    submission = pd.DataFrame({\n        \"id\": test_df['id'] if 'id' in test_df else range(len(results)),\n        \"translation\": results['translation']\n    })\n    submission.to_csv(\"submission.csv\", index=False)\n    print(\"✅✅ تم إنشاء ملف submission.csv جاهز للإرسال!\")\nelse:\n    print(\"⚠️ لم يتم العثور على ملف test.csv، تم الاكتفاء بتدريب وحفظ النموذج.\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}