{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.12.12"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":121150,"databundleVersionId":15061024,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":297919550,"sourceType":"kernelVersion"}],"dockerImageVersionId":31236,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true},"papermill":{"default_parameters":{},"duration":66.275322,"end_time":"2026-02-01T09:33:27.325509","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2026-02-01T09:32:21.050187","version":"2.6.0"},"widgets":{"application/vnd.jupyter.widget-state+json":{"state":{"0c589241f8a245fcbe2f3b5f40bf6bd4":{"model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"2.0.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"2.0.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border_bottom":null,"border_left":null,"border_right":null,"border_top":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2651f374400f4aa294fb8cc9d89064ab":{"model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","model_name":"HTMLStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"2.0.0","_model_name":"HTMLStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"2.0.0","_view_name":"StyleView","background":null,"description_width":"","font_size":null,"text_color":null}},"3874555319fc4525b2d5fe290a242db2":{"model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"2.0.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"2.0.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"41622ec6b670421caf9ff5e8d9105555":{"model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"2.0.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"2.0.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border_bottom":null,"border_left":null,"border_right":null,"border_top":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"570358390ee34c899cc1ae0cf9f246ef":{"model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"2.0.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"2.0.0","_view_name":"ProgressView","bar_style":"success","description":"","description_allow_html":false,"layout":"IPY_MODEL_88ce92fec44a467b97104aac4a6fde26","max":4,"min":0,"orientation":"horizontal","style":"IPY_MODEL_3874555319fc4525b2d5fe290a242db2","tabbable":null,"tooltip":null,"value":4}},"599394fec3324640b710f92dcf4f4fe9":{"model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","model_name":"HTMLStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"2.0.0","_model_name":"HTMLStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"2.0.0","_view_name":"StyleView","background":null,"description_width":"","font_size":null,"text_color":null}},"651e24378af3436d9f68a542db3aa169":{"model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"2.0.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"2.0.0","_view_name":"HTMLView","description":"","description_allow_html":false,"layout":"IPY_MODEL_0c589241f8a245fcbe2f3b5f40bf6bd4","placeholder":"​","style":"IPY_MODEL_2651f374400f4aa294fb8cc9d89064ab","tabbable":null,"tooltip":null,"value":"🚀 Translating: 100%"}},"88ce92fec44a467b97104aac4a6fde26":{"model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"2.0.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"2.0.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border_bottom":null,"border_left":null,"border_right":null,"border_top":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"8ecd180e767d402c967e611e0b6a82a9":{"model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"2.0.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"2.0.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border_bottom":null,"border_left":null,"border_right":null,"border_top":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"aa9ace3da80e443ab645bc812e448a17":{"model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"2.0.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"2.0.0","_view_name":"HTMLView","description":"","description_allow_html":false,"layout":"IPY_MODEL_41622ec6b670421caf9ff5e8d9105555","placeholder":"​","style":"IPY_MODEL_599394fec3324640b710f92dcf4f4fe9","tabbable":null,"tooltip":null,"value":" 4/4 [00:11&lt;00:00,  2.87s/it]"}},"d5d045ebeb2e4fa7806e185f499d668d":{"model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"2.0.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"2.0.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_651e24378af3436d9f68a542db3aa169","IPY_MODEL_570358390ee34c899cc1ae0cf9f246ef","IPY_MODEL_aa9ace3da80e443ab645bc812e448a17"],"layout":"IPY_MODEL_8ecd180e767d402c967e611e0b6a82a9","tabbable":null,"tooltip":null}}},"version_major":2,"version_minor":0}}},"nbformat_minor":4,"nbformat":4,"cells":[{"id":"fa0bee1a","cell_type":"code","source":"# Verify optimum is installed\ntry:\n    from optimum.bettertransformer import BetterTransformer\n    print(\"✅ BetterTransformer available!\")\nexcept ImportError:\n    print(\"❌ BetterTransformer NOT available\")","metadata":{"execution":{"iopub.status.busy":"2026-02-16T14:02:34.610388Z","iopub.execute_input":"2026-02-16T14:02:34.611074Z","iopub.status.idle":"2026-02-16T14:02:34.621318Z","shell.execute_reply.started":"2026-02-16T14:02:34.611040Z","shell.execute_reply":"2026-02-16T14:02:34.620438Z"},"papermill":{"duration":0.014189,"end_time":"2026-02-01T09:32:23.152337","exception":false,"start_time":"2026-02-01T09:32:23.138148","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"0e6f18e5","cell_type":"code","source":"import os\n\n# Optimize PyTorch/CUDA performance\nos.environ['OMP_NUM_THREADS'] = '4'\nos.environ['MKL_NUM_THREADS'] = '4'\nos.environ['CUDA_LAUNCH_BLOCKING'] = '0'\nos.environ['TORCH_CUDNN_V8_API_ENABLED'] = '1'\nos.environ['TOKENIZERS_PARALLELISM'] = 'true'\n\nprint(\"✅ Environment variables optimized\")","metadata":{"execution":{"iopub.status.busy":"2026-02-16T14:02:34.622957Z","iopub.execute_input":"2026-02-16T14:02:34.623282Z","iopub.status.idle":"2026-02-16T14:02:34.638798Z","shell.execute_reply.started":"2026-02-16T14:02:34.623258Z","shell.execute_reply":"2026-02-16T14:02:34.637615Z"},"papermill":{"duration":0.010936,"end_time":"2026-02-01T09:32:23.166401","exception":false,"start_time":"2026-02-01T09:32:23.155465","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"9e888339","cell_type":"code","source":"import re\nimport logging\nimport warnings\nfrom pathlib import Path\nfrom typing import Dict, List, Tuple, Optional\nfrom dataclasses import dataclass\nimport pandas as pd\nimport numpy as np\nimport torch\nfrom torch.utils.data import Dataset, DataLoader, Sampler\nfrom torch.cuda.amp import autocast\nfrom transformers import AutoTokenizer, AutoModelForSeq2SeqLM\nfrom tqdm.auto import tqdm\nimport json\nimport random\n\nwarnings.filterwarnings('ignore')\n\n# Check GPU\nprint(f\"PyTorch version: {torch.__version__}\")\nprint(f\"CUDA available: {torch.cuda.is_available()}\")\nif torch.cuda.is_available():\n    print(f\"GPU: {torch.cuda.get_device_name(0)}\")\n    print(f\"GPU Memory: {torch.cuda.get_device_properties(0).total_memory / 1e9:.2f} GB\")","metadata":{"execution":{"iopub.status.busy":"2026-02-16T14:02:34.639911Z","iopub.execute_input":"2026-02-16T14:02:34.640227Z","iopub.status.idle":"2026-02-16T14:02:47.442066Z","shell.execute_reply.started":"2026-02-16T14:02:34.640195Z","shell.execute_reply":"2026-02-16T14:02:47.441136Z"},"papermill":{"duration":14.3217,"end_time":"2026-02-01T09:32:37.490918","exception":false,"start_time":"2026-02-01T09:32:23.169218","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"96a86a70","cell_type":"code","source":"@dataclass\nclass UltraConfig:\n    \"\"\"Ultra-optimized configuration\"\"\"\n    \n    # ============ PATHS - EDIT THESE ============\n    test_data_path: str = \"/kaggle/input/deep-past-initiative-machine-translation/test.csv\"\n    model_path: str = \"/kaggle/input/notebooks/antonyjoseph2121/deep-past-baseline-akkadian-1353d5b9404/model2/\"\n    output_dir: str = \"/kaggle/working/\"\n    \n    # ============ PROCESSING ============\n    max_length: int = 1024\n    batch_size: int = 8  # Will auto-tune if use_auto_batch_size=True\n    num_workers: int = 5  # Increased for better throughput\n    \n    # ============ GENERATION ============\n    num_beams: int = 8\n    max_new_tokens: int = 1024\n    length_penalty: float = 1.3\n    early_stopping: bool = True\n    no_repeat_ngram_size: int = 0  # Set to 3 if you see repetition\n    \n    # ============ OPTIMIZATIONS ============\n    use_mixed_precision: bool = True      # FP16 for 2x speedup\n    use_better_transformer: bool = True   # 20-50% speedup\n    use_bucket_batching: bool = True      # 20-40% less padding\n    use_vectorized_postproc: bool = True  # 3-5x faster postproc\n    use_adaptive_beams: bool = True       # Smart beam allocation\n    use_auto_batch_size: bool = False     # Auto-find optimal batch size\n    \n    # ============ OTHER ============\n    aggressive_postprocessing: bool = True\n    checkpoint_freq: int = 100\n    num_buckets: int = 4  # For bucket batching\n    \n    def __post_init__(self):\n        self.device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n        Path(self.output_dir).mkdir(exist_ok=True, parents=True)\n        \n        if not torch.cuda.is_available():\n            self.use_mixed_precision = False\n            self.use_better_transformer = False\n\n# Create config\nconfig = UltraConfig()\n\nprint(\"\\n📋 Configuration:\")\nprint(f\"  Device: {config.device}\")\nprint(f\"  Batch size: {config.batch_size}\")\nprint(f\"  Beams: {config.num_beams}\")\nprint(f\"\\n🚀 Optimizations:\")\nprint(f\"  Mixed Precision: {config.use_mixed_precision}\")\nprint(f\"  BetterTransformer: {config.use_better_transformer}\")\nprint(f\"  Bucket Batching: {config.use_bucket_batching}\")\nprint(f\"  Vectorized Postproc: {config.use_vectorized_postproc}\")\nprint(f\"  Adaptive Beams: {config.use_adaptive_beams}\")","metadata":{"execution":{"iopub.status.busy":"2026-02-16T14:02:47.443332Z","iopub.execute_input":"2026-02-16T14:02:47.443790Z","iopub.status.idle":"2026-02-16T14:02:47.455047Z","shell.execute_reply.started":"2026-02-16T14:02:47.443763Z","shell.execute_reply":"2026-02-16T14:02:47.454250Z"},"papermill":{"duration":0.01533,"end_time":"2026-02-01T09:32:37.509269","exception":false,"start_time":"2026-02-01T09:32:37.493939","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"2969a93f","cell_type":"code","source":"def setup_logging(output_dir: str = './outputs'):\n    \"\"\"Setup logging\"\"\"\n    Path(output_dir).mkdir(exist_ok=True, parents=True)\n    log_file = Path(output_dir) / 'inference_ultra.log'\n    \n    for handler in logging.root.handlers[:]:\n        logging.root.removeHandler(handler)\n    \n    logging.basicConfig(\n        level=logging.INFO,\n        format='%(asctime)s - %(levelname)s - %(message)s',\n        handlers=[\n            logging.StreamHandler(),\n            logging.FileHandler(log_file)\n        ]\n    )\n    return logging.getLogger(__name__)\n\nlogger = setup_logging(config.output_dir)\nlogger.info(\"Logging initialized\")","metadata":{"execution":{"iopub.status.busy":"2026-02-16T14:02:47.457327Z","iopub.execute_input":"2026-02-16T14:02:47.458101Z","iopub.status.idle":"2026-02-16T14:02:47.595339Z","shell.execute_reply.started":"2026-02-16T14:02:47.458062Z","shell.execute_reply":"2026-02-16T14:02:47.594417Z"},"papermill":{"duration":0.012025,"end_time":"2026-02-01T09:32:37.524325","exception":false,"start_time":"2026-02-01T09:32:37.512300","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"cd383eff","cell_type":"code","source":"class OptimizedPreprocessor:\n    \"\"\"Preprocessor with pre-compiled patterns\"\"\"\n    \n    def __init__(self):\n        # Pre-compile regex patterns (20-30% faster)\n        self.patterns = {\n            'big_gap': re.compile(r'(\\.{3,}|…+|……)'),\n            'small_gap': re.compile(r'(xx+|\\s+x\\s+)'),\n        }\n    \n    def preprocess_input_text(self, text: str) -> str:\n        \"\"\"Single text preprocessing\"\"\"\n        if pd.isna(text):\n            return \"\"\n        \n        text = str(text)\n        text = self.patterns['big_gap'].sub('<big_gap>', text)\n        text = self.patterns['small_gap'].sub('<gap>', text)\n        \n        return text\n    \n    def preprocess_batch(self, texts: List[str]) -> List[str]:\n        \"\"\"Vectorized batch preprocessing (faster)\"\"\"\n        s = pd.Series(texts).fillna(\"\")\n        s = s.astype(str)\n        s = s.str.replace(self.patterns['big_gap'], '<big_gap>', regex=True)\n        s = s.str.replace(self.patterns['small_gap'], '<gap>', regex=True)\n        return s.tolist()\n\n# Test\npreprocessor = OptimizedPreprocessor()\ntest = \"lugal ... xxx mu.2.kam\"\nprint(f\"Test input:  {test}\")\nprint(f\"Preprocessed: {preprocessor.preprocess_input_text(test)}\")","metadata":{"execution":{"iopub.status.busy":"2026-02-16T14:02:47.596392Z","iopub.execute_input":"2026-02-16T14:02:47.597171Z","iopub.status.idle":"2026-02-16T14:02:47.611326Z","shell.execute_reply.started":"2026-02-16T14:02:47.597139Z","shell.execute_reply":"2026-02-16T14:02:47.610441Z"},"papermill":{"duration":0.01366,"end_time":"2026-02-01T09:32:37.541055","exception":false,"start_time":"2026-02-01T09:32:37.527395","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"1311026b","cell_type":"code","source":"class VectorizedPostprocessor:\n    \"\"\"Ultra-fast vectorized postprocessing\"\"\"\n    \n    def __init__(self, aggressive: bool = True):\n        self.aggressive = aggressive\n        \n        # Pre-compile ALL patterns\n        self.patterns = {\n            'gap': re.compile(r'(\\[x\\]|\\(x\\)|\\bx\\b)', re.I),\n            'big_gap': re.compile(r'(\\.{3,}|…|\\[\\.+\\])'),\n            'annotations': re.compile(r'\\((fem|plur|pl|sing|singular|plural|\\?|!)\\..\\s*\\w*\\)', re.I),\n            'repeated_words': re.compile(r'\\b(\\w+)(?:\\s+\\1\\b)+'),\n            'whitespace': re.compile(r'\\s+'),\n            'punct_space': re.compile(r'\\s+([.,:])'),\n            'repeated_punct': re.compile(r'([.,])\\1+'),\n        }\n        \n        # Character translation tables\n        self.subscript_trans = str.maketrans(\"₀₁₂₃₄₅₆₇₈₉\", \"0123456789\")\n        self.special_chars_trans = str.maketrans('ḫḪ', 'hH')\n        self.forbidden_chars = '!?()\"——<>⌈⌋⌊[]+ʾ/;'\n        self.forbidden_trans = str.maketrans('', '', self.forbidden_chars)\n    \n    def postprocess_batch(self, translations: List[str]) -> List[str]:\n        \"\"\"Vectorized batch postprocessing - 3-5x faster than loop\"\"\"\n        \n        # Convert to Series for vectorized operations\n        s = pd.Series(translations)\n        \n        # Filter invalid entries\n        valid_mask = s.apply(lambda x: isinstance(x, str) and x.strip())\n        if not valid_mask.all():\n            s[~valid_mask] = \"\"\n        \n        # Basic cleaning (always applied)\n        s = s.str.translate(self.special_chars_trans)\n        s = s.str.translate(self.subscript_trans)\n        s = s.str.replace(self.patterns['whitespace'], ' ', regex=True)\n        s = s.str.strip()\n        \n        if self.aggressive:\n            # Normalize gaps\n            s = s.str.replace(self.patterns['gap'], '<gap>', regex=True)\n            s = s.str.replace(self.patterns['big_gap'], '<big_gap>', regex=True)\n            \n            # Merge adjacent gaps\n            s = s.str.replace('<gap> <gap>', '<big_gap>', regex=False)\n            s = s.str.replace('<big_gap> <big_gap>', '<big_gap>', regex=False)\n            \n            # Remove annotations\n            s = s.str.replace(self.patterns['annotations'], '', regex=True)\n            \n            # Protect gaps during char removal\n            s = s.str.replace('<gap>', '\\x00GAP\\x00', regex=False)\n            s = s.str.replace('<big_gap>', '\\x00BIG\\x00', regex=False)\n            \n            # Remove forbidden characters\n            s = s.str.translate(self.forbidden_trans)\n            \n            # Restore gaps\n            s = s.str.replace('\\x00GAP\\x00', ' <gap> ', regex=False)\n            s = s.str.replace('\\x00BIG\\x00', ' <big_gap> ', regex=False)\n            \n            # Fractions (vectorized)\n            s = s.str.replace(r'(\\d+)\\.5\\b', r'\\1½', regex=True)\n            s = s.str.replace(r'\\b0\\.5\\b', '½', regex=True)\n            s = s.str.replace(r'(\\d+)\\.25\\b', r'\\1¼', regex=True)\n            s = s.str.replace(r'\\b0\\.25\\b', '¼', regex=True)\n            s = s.str.replace(r'(\\d+)\\.75\\b', r'\\1¾', regex=True)\n            s = s.str.replace(r'\\b0\\.75\\b', '¾', regex=True)\n            \n            # Remove repeated words\n            s = s.str.replace(self.patterns['repeated_words'], r'\\1', regex=True)\n            \n            # Remove repeated n-grams\n            for n in range(4, 1, -1):\n                pattern = r'\\b((?:\\w+\\s+){' + str(n-1) + r'}\\w+)(?:\\s+\\1\\b)+'\n                s = s.str.replace(pattern, r'\\1', regex=True)\n            \n            # Fix punctuation\n            s = s.str.replace(self.patterns['punct_space'], r'\\1', regex=True)\n            s = s.str.replace(self.patterns['repeated_punct'], r'\\1', regex=True)\n            \n            # Final cleanup\n            s = s.str.replace(self.patterns['whitespace'], ' ', regex=True)\n            s = s.str.strip().str.strip('-').str.strip()\n        \n        return s.tolist()\n\n# Test\npostprocessor = VectorizedPostprocessor(aggressive=config.aggressive_postprocessing)\ntest_outputs = [\n    \"The king (plur.) took the city... [x] [x]\",\n    \"He spoke spoke to the assembly\"\n]\ncleaned = postprocessor.postprocess_batch(test_outputs)\nprint(\"Test postprocessing:\")\nfor orig, clean in zip(test_outputs, cleaned):\n    print(f\"  {orig}\")\n    print(f\"  → {clean}\")","metadata":{"execution":{"iopub.status.busy":"2026-02-16T14:02:47.612176Z","iopub.execute_input":"2026-02-16T14:02:47.612484Z","iopub.status.idle":"2026-02-16T14:02:47.642457Z","shell.execute_reply.started":"2026-02-16T14:02:47.612463Z","shell.execute_reply":"2026-02-16T14:02:47.641789Z"},"papermill":{"duration":0.027099,"end_time":"2026-02-01T09:32:37.571172","exception":false,"start_time":"2026-02-01T09:32:37.544073","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"e1d59cb6","cell_type":"code","source":"class BucketBatchSampler(Sampler):\n    \"\"\"Batch samples by similar length to minimize padding\"\"\"\n    \n    def __init__(self, dataset, batch_size: int, num_buckets: int = 4, shuffle: bool = False):\n        self.dataset = dataset\n        self.batch_size = batch_size\n        self.shuffle = shuffle\n        \n        # Calculate lengths\n        lengths = [len(text.split()) for _, text in dataset]\n        \n        # Sort indices by length\n        sorted_indices = sorted(range(len(lengths)), key=lambda i: lengths[i])\n        \n        # Create buckets\n        bucket_size = len(sorted_indices) // num_buckets\n        self.buckets = []\n        for i in range(num_buckets):\n            start = i * bucket_size\n            end = None if i == num_buckets - 1 else (i + 1) * bucket_size\n            self.buckets.append(sorted_indices[start:end])\n        \n        # Log bucket info\n        logger.info(f\"Created {num_buckets} buckets:\")\n        for i, bucket in enumerate(self.buckets):\n            bucket_lengths = [lengths[idx] for idx in bucket]\n            logger.info(f\"  Bucket {i}: {len(bucket)} samples, \"\n                       f\"length range [{min(bucket_lengths)}, {max(bucket_lengths)}]\")\n    \n    def __iter__(self):\n        for bucket in self.buckets:\n            if self.shuffle:\n                random.shuffle(bucket)\n            \n            for i in range(0, len(bucket), self.batch_size):\n                yield bucket[i:i+self.batch_size]\n    \n    def __len__(self):\n        return sum((len(b) + self.batch_size - 1) // self.batch_size for b in self.buckets)","metadata":{"execution":{"iopub.status.busy":"2026-02-16T14:02:47.643449Z","iopub.execute_input":"2026-02-16T14:02:47.643765Z","iopub.status.idle":"2026-02-16T14:02:47.653062Z","shell.execute_reply.started":"2026-02-16T14:02:47.643742Z","shell.execute_reply":"2026-02-16T14:02:47.652031Z"},"papermill":{"duration":0.012194,"end_time":"2026-02-01T09:32:37.586514","exception":false,"start_time":"2026-02-01T09:32:37.574320","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"120f1155","cell_type":"code","source":"class AkkadianDataset(Dataset):\n    \"\"\"Optimized dataset with batch preprocessing\"\"\"\n    \n    def __init__(self, dataframe: pd.DataFrame, preprocessor: OptimizedPreprocessor):\n        self.sample_ids = dataframe['id'].tolist()\n        \n        # Batch preprocess (faster than loop)\n        raw_texts = dataframe['transliteration'].tolist()\n        preprocessed = preprocessor.preprocess_batch(raw_texts)\n        \n        # Add task prefix\n        self.input_texts = [\n            \"translate Akkadian to English: \" + text\n            for text in preprocessed\n        ]\n        \n        logger.info(f\"Dataset created with {len(self.sample_ids)} samples\")\n    \n    def __len__(self):\n        return len(self.sample_ids)\n    \n    def __getitem__(self, index: int):\n        return self.sample_ids[index], self.input_texts[index]","metadata":{"execution":{"iopub.status.busy":"2026-02-16T14:02:47.654241Z","iopub.execute_input":"2026-02-16T14:02:47.654601Z","iopub.status.idle":"2026-02-16T14:02:47.665292Z","shell.execute_reply.started":"2026-02-16T14:02:47.654579Z","shell.execute_reply":"2026-02-16T14:02:47.664257Z"},"papermill":{"duration":0.009925,"end_time":"2026-02-01T09:32:37.599506","exception":false,"start_time":"2026-02-01T09:32:37.589581","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"a6385f4c","cell_type":"code","source":"class UltraInferenceEngine:\n    \"\"\"Ultra-optimized inference engine\"\"\"\n    \n    def __init__(self, config: UltraConfig):\n        self.config = config\n        self.preprocessor = OptimizedPreprocessor()\n        self.postprocessor = VectorizedPostprocessor(aggressive=config.aggressive_postprocessing)\n        self.results = []\n        \n        # Load model\n        self._load_model()\n    \n    def _load_model(self):\n        \"\"\"Load and optimize model\"\"\"\n        logger.info(f\"Loading model from {self.config.model_path}\")\n        \n        try:\n            self.model = AutoModelForSeq2SeqLM.from_pretrained(\n                self.config.model_path\n            ).to(self.config.device).eval()\n            \n            self.tokenizer = AutoTokenizer.from_pretrained(self.config.model_path)\n            \n            num_params = sum(p.numel() for p in self.model.parameters())\n            logger.info(f\"Model loaded: {num_params:,} parameters\")\n            \n            # Apply BetterTransformer\n            if self.config.use_better_transformer and torch.cuda.is_available():\n                try:\n                    from optimum.bettertransformer import BetterTransformer\n                    logger.info(\"Applying BetterTransformer...\")\n                    self.model = BetterTransformer.transform(self.model)\n                    logger.info(\"✅ BetterTransformer applied (20-50% speedup)\")\n                except ImportError:\n                    logger.warning(\"⚠️  'optimum' not installed, skipping BetterTransformer\")\n                    logger.warning(\"   Install with: !pip install optimum\")\n                except Exception as e:\n                    logger.warning(f\"⚠️  BetterTransformer failed: {e}\")\n            \n        except Exception as e:\n            logger.error(f\"Failed to load model: {e}\")\n            raise\n    \n    def _collate_fn(self, batch_samples):\n        \"\"\"Collate function\"\"\"\n        batch_ids = [s[0] for s in batch_samples]\n        batch_texts = [s[1] for s in batch_samples]\n        \n        tokenized = self.tokenizer(\n            batch_texts,\n            max_length=self.config.max_length,\n            padding=True,\n            truncation=True,\n            return_tensors=\"pt\"\n        )\n        \n        return batch_ids, tokenized\n    \n    def find_optimal_batch_size(self, dataset, start_bs: int = 32):\n        \"\"\"Binary search for optimal batch size\"\"\"\n        logger.info(\"🔍 Finding optimal batch size...\")\n        \n        max_bs = start_bs\n        min_bs = 1\n        \n        while max_bs - min_bs > 1:\n            test_bs = (max_bs + min_bs) // 2\n            \n            try:\n                test_batch = [dataset[i] for i in range(min(test_bs, len(dataset)))]\n                ids, inputs = self._collate_fn(test_batch)\n                \n                with torch.inference_mode():\n                    if self.config.use_mixed_precision:\n                        with autocast():\n                            outputs = self.model.generate(\n                                input_ids=inputs.input_ids.to(self.config.device),\n                                attention_mask=inputs.attention_mask.to(self.config.device),\n                                num_beams=self.config.num_beams,\n                                max_new_tokens=64,\n                                use_cache=True\n                            )\n                    else:\n                        outputs = self.model.generate(\n                            input_ids=inputs.input_ids.to(self.config.device),\n                            attention_mask=inputs.attention_mask.to(self.config.device),\n                            num_beams=self.config.num_beams,\n                            max_new_tokens=64,\n                            use_cache=True\n                        )\n                \n                min_bs = test_bs\n                logger.info(f\"  ✅ Batch size {test_bs} works\")\n                \n                del outputs, inputs\n                if torch.cuda.is_available():\n                    torch.cuda.empty_cache()\n                \n            except RuntimeError as e:\n                if \"out of memory\" in str(e):\n                    max_bs = test_bs\n                    logger.info(f\"  ❌ Batch size {test_bs} OOM\")\n                    if torch.cuda.is_available():\n                        torch.cuda.empty_cache()\n                else:\n                    raise\n        \n        optimal = min_bs\n        logger.info(f\"🎯 Optimal batch size: {optimal}\")\n        return optimal\n    \n    def _get_adaptive_beam_size(self, input_ids, attention_mask):\n        \"\"\"Adaptive beam size based on complexity\"\"\"\n        if not self.config.use_adaptive_beams:\n            return self.config.num_beams\n        \n        lengths = attention_mask.sum(dim=1)\n        \n        # Short → fewer beams, Long → more beams\n        beam_sizes = torch.where(\n            lengths < 100,\n            torch.tensor(max(4, self.config.num_beams // 2)),\n            torch.tensor(self.config.num_beams)\n        )\n        \n        return beam_sizes[0].item()\n    \n    def _save_checkpoint(self):\n        \"\"\"Save checkpoint\"\"\"\n        if len(self.results) > 0 and len(self.results) % self.config.checkpoint_freq == 0:\n            path = Path(self.config.output_dir) / f\"checkpoint_{len(self.results)}.csv\"\n            df = pd.DataFrame(self.results, columns=['id', 'translation'])\n            df.to_csv(path, index=False)\n            logger.info(f\"💾 Checkpoint: {len(self.results)} translations\")\n    \n    def run_inference(self, test_df: pd.DataFrame) -> pd.DataFrame:\n        \"\"\"Run ultra-optimized inference\"\"\"\n        logger.info(\"🚀 Starting ULTRA-OPTIMIZED inference\")\n        \n        # Create dataset\n        dataset = AkkadianDataset(test_df, self.preprocessor)\n        \n        # Auto-find batch size\n        if self.config.use_auto_batch_size:\n            optimal_bs = self.find_optimal_batch_size(dataset)\n            self.config.batch_size = optimal_bs\n        \n        # Create dataloader\n        if self.config.use_bucket_batching:\n            batch_sampler = BucketBatchSampler(\n                dataset, \n                self.config.batch_size,\n                num_buckets=self.config.num_buckets\n            )\n            dataloader = DataLoader(\n                dataset,\n                batch_sampler=batch_sampler,\n                num_workers=self.config.num_workers,\n                collate_fn=self._collate_fn,\n                pin_memory=True,\n                prefetch_factor=2,\n                persistent_workers=True if self.config.num_workers > 0 else False\n            )\n        else:\n            dataloader = DataLoader(\n                dataset,\n                batch_size=self.config.batch_size,\n                shuffle=False,\n                num_workers=self.config.num_workers,\n                collate_fn=self._collate_fn,\n                pin_memory=True,\n                prefetch_factor=2,\n                persistent_workers=True if self.config.num_workers > 0 else False\n            )\n        \n        logger.info(f\"DataLoader created: {len(dataloader)} batches\")\n        logger.info(f\"Active optimizations:\")\n        logger.info(f\"  ✅ Mixed Precision: {self.config.use_mixed_precision}\")\n        logger.info(f\"  ✅ BetterTransformer: {self.config.use_better_transformer}\")\n        logger.info(f\"  ✅ Bucket Batching: {self.config.use_bucket_batching}\")\n        logger.info(f\"  ✅ Vectorized Postproc: {self.config.use_vectorized_postproc}\")\n        logger.info(f\"  ✅ Adaptive Beams: {self.config.use_adaptive_beams}\")\n        \n        # Generation config\n        base_gen_config = {\n            \"max_new_tokens\": self.config.max_new_tokens,\n            \"length_penalty\": self.config.length_penalty,\n            \"early_stopping\": self.config.early_stopping,\n            \"use_cache\": True,  # Critical for speed!\n        }\n        if self.config.no_repeat_ngram_size > 0:\n            base_gen_config[\"no_repeat_ngram_size\"] = self.config.no_repeat_ngram_size\n        \n        # Run inference\n        self.results = []\n        \n        with torch.inference_mode():\n            for batch_idx, (batch_ids, tokenized) in enumerate(tqdm(dataloader, desc=\"🚀 Translating\")):\n                try:\n                    input_ids = tokenized.input_ids.to(self.config.device)\n                    attention_mask = tokenized.attention_mask.to(self.config.device)\n                    \n                    # Adaptive beam size\n                    beam_size = self._get_adaptive_beam_size(input_ids, attention_mask)\n                    gen_config = {**base_gen_config, \"num_beams\": beam_size}\n                    \n                    # Generate\n                    if self.config.use_mixed_precision:\n                        with autocast():\n                            outputs = self.model.generate(\n                                input_ids=input_ids,\n                                attention_mask=attention_mask,\n                                **gen_config\n                            )\n                    else:\n                        outputs = self.model.generate(\n                            input_ids=input_ids,\n                            attention_mask=attention_mask,\n                            **gen_config\n                        )\n                    \n                    # Decode\n                    translations = self.tokenizer.batch_decode(outputs, skip_special_tokens=True)\n                    \n                    # Postprocess (vectorized)\n                    if self.config.use_vectorized_postproc:\n                        cleaned = self.postprocessor.postprocess_batch(translations)\n                    else:\n                        # Fallback to single processing\n                        cleaned = [self.postprocessor.postprocess_batch([t])[0] for t in translations]\n                    \n                    # Store\n                    self.results.extend(zip(batch_ids, cleaned))\n                    \n                    # Checkpoint\n                    self._save_checkpoint()\n                    \n                    # Memory cleanup\n                    if torch.cuda.is_available() and batch_idx % 10 == 0:\n                        torch.cuda.empty_cache()\n                    \n                except Exception as e:\n                    logger.error(f\"❌ Batch {batch_idx} error: {e}\")\n                    self.results.extend([(bid, \"\") for bid in batch_ids])\n                    continue\n        \n        logger.info(\"✅ Inference completed\")\n        \n        # Create results\n        results_df = pd.DataFrame(self.results, columns=['id', 'translation'])\n        self._validate_results(results_df)\n        \n        return results_df\n    \n    def _validate_results(self, df: pd.DataFrame):\n        \"\"\"Validation report\"\"\"\n        print(\"\\n\" + \"=\"*60)\n        print(\"📊 VALIDATION REPORT\")\n        print(\"=\"*60)\n        \n        empty = df['translation'].str.strip().eq('').sum()\n        print(f\"\\nEmpty: {empty} ({empty/len(df)*100:.2f}%)\")\n        \n        lengths = df['translation'].str.len()\n        print(f\"\\n📏 Length stats:\")\n        print(f\"   Mean: {lengths.mean():.1f}, Median: {lengths.median():.1f}\")\n        print(f\"   Min: {lengths.min()}, Max: {lengths.max()}\")\n        \n        short = ((lengths < 5) & (lengths > 0)).sum()\n        if short > 0:\n            print(f\"   ⚠️  {short} very short translations\")\n        \n        print(f\"\\n📝 Sample translations:\")\n        for idx in [0, len(df)//2, -1]:\n            s = df.iloc[idx]\n            preview = s['translation'][:70] + \"...\" if len(s['translation']) > 70 else s['translation']\n            print(f\"   ID {s['id']:4d}: {preview}\")\n        \n        print(\"\\n\" + \"=\"*60 + \"\\n\")\n\nprint(\"✅ Inference engine defined\")","metadata":{"execution":{"iopub.status.busy":"2026-02-16T14:02:47.666397Z","iopub.execute_input":"2026-02-16T14:02:47.666729Z","iopub.status.idle":"2026-02-16T14:02:47.698809Z","shell.execute_reply.started":"2026-02-16T14:02:47.666684Z","shell.execute_reply":"2026-02-16T14:02:47.698094Z"},"papermill":{"duration":0.031312,"end_time":"2026-02-01T09:32:37.633747","exception":false,"start_time":"2026-02-01T09:32:37.602435","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"54c5d131","cell_type":"code","source":"logger.info(f\"Loading test data from {config.test_data_path}\")\n\ntest_df = pd.read_csv(config.test_data_path, encoding='utf-8')\nlogger.info(f\"✅ Loaded {len(test_df)} test samples\")\n\nprint(\"\\nFirst 5 samples:\")\nprint(test_df.head())","metadata":{"execution":{"iopub.status.busy":"2026-02-16T14:02:47.699925Z","iopub.execute_input":"2026-02-16T14:02:47.700269Z","iopub.status.idle":"2026-02-16T14:02:47.737858Z","shell.execute_reply.started":"2026-02-16T14:02:47.700237Z","shell.execute_reply":"2026-02-16T14:02:47.736942Z"},"papermill":{"duration":0.032371,"end_time":"2026-02-01T09:32:37.669450","exception":false,"start_time":"2026-02-01T09:32:37.637079","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"58f87ec8","cell_type":"code","source":"# Create engine\nengine = UltraInferenceEngine(config)\n\n# Run inference\nresults_df = engine.run_inference(test_df)","metadata":{"execution":{"iopub.status.busy":"2026-02-16T14:02:47.739097Z","iopub.execute_input":"2026-02-16T14:02:47.739707Z","iopub.status.idle":"2026-02-16T14:03:29.621835Z","shell.execute_reply.started":"2026-02-16T14:02:47.739679Z","shell.execute_reply":"2026-02-16T14:03:29.620954Z"},"papermill":{"duration":46.867091,"end_time":"2026-02-01T09:33:24.539867","exception":false,"start_time":"2026-02-01T09:32:37.672776","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"c7156597","cell_type":"code","source":"# Save submission\noutput_path = Path(config.output_dir) / 'submission.csv'\nresults_df.to_csv(output_path, index=False)\nlogger.info(f\"\\n✅ Submission saved to {output_path}\")\n\n# Save config\nconfig_dict = {\n    \"batch_size\": config.batch_size,\n    \"num_beams\": config.num_beams,\n    \"length_penalty\": config.length_penalty,\n    \"no_repeat_ngram_size\": config.no_repeat_ngram_size,\n    \"optimizations\": {\n        \"mixed_precision\": config.use_mixed_precision,\n        \"better_transformer\": config.use_better_transformer,\n        \"bucket_batching\": config.use_bucket_batching,\n        \"vectorized_postproc\": config.use_vectorized_postproc,\n        \"adaptive_beams\": config.use_adaptive_beams,\n    }\n}\n\nconfig_path = Path(config.output_dir) / 'ultra_config.json'\nwith open(config_path, 'w') as f:\n    json.dump(config_dict, f, indent=2)\n\nprint(\"\\n\" + \"=\"*60)\nprint(\"🎉 ULTRA-OPTIMIZED INFERENCE COMPLETE!\")\nprint(\"=\"*60)\nprint(f\"Submission file: {output_path}\")\nprint(f\"Config file: {config_path}\")\nprint(f\"Log file: {Path(config.output_dir) / 'inference_ultra.log'}\")\nprint(f\"Total translations: {len(results_df)}\")\nprint(\"=\"*60)","metadata":{"execution":{"iopub.status.busy":"2026-02-16T14:03:29.626032Z","iopub.execute_input":"2026-02-16T14:03:29.626666Z","iopub.status.idle":"2026-02-16T14:03:29.646238Z","shell.execute_reply.started":"2026-02-16T14:03:29.626630Z","shell.execute_reply":"2026-02-16T14:03:29.645558Z"},"papermill":{"duration":0.026833,"end_time":"2026-02-01T09:33:24.571438","exception":false,"start_time":"2026-02-01T09:33:24.544605","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"5fb529c4","cell_type":"code","source":"# Load submission\nsubmission = pd.read_csv(output_path)\n\nprint(f\"Submission shape: {submission.shape}\")\nprint(f\"\\nFirst 10 translations:\")\nprint(submission.head(10))\n\nprint(f\"\\nLast 10 translations:\")\nprint(submission.tail(10))\n\n# Statistics\nlengths = submission['translation'].str.len()\nprint(f\"\\nLength distribution:\")\nprint(lengths.describe())\n\n# Check for issues\nempty = submission['translation'].str.strip().eq('').sum()\nprint(f\"\\nEmpty translations: {empty}\")\n\nif empty > 0:\n    print(\"\\nEmpty translation IDs:\")\n    print(submission[submission['translation'].str.strip().eq('')]['id'].tolist())","metadata":{"execution":{"iopub.status.busy":"2026-02-16T14:03:29.647160Z","iopub.execute_input":"2026-02-16T14:03:29.647822Z","iopub.status.idle":"2026-02-16T14:03:29.673774Z","shell.execute_reply.started":"2026-02-16T14:03:29.647796Z","shell.execute_reply":"2026-02-16T14:03:29.672966Z"},"papermill":{"duration":0.026908,"end_time":"2026-02-01T09:33:24.603088","exception":false,"start_time":"2026-02-01T09:33:24.576180","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null}]}