{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":87793,"databundleVersionId":12276181,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":11811012,"sourceType":"datasetVersion","datasetId":7418041},{"sourceId":391350,"sourceType":"modelInstanceVersion","isSourceIdPinned":false,"modelInstanceId":322234,"modelId":342922}],"dockerImageVersionId":31041,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"**This is my little attempt with LLM. The Qwen3_1.7B_16-bit_original here was fine-tuned using SFT based on training and training_v2 dataset for 10000 steps each. And was fine-tuned using GRPO for only 500 steps with training dataset.** ","metadata":{}},{"cell_type":"markdown","source":"*Before using the LLM, since there is no VLLM in the Kaggle environment. You should install VLLM first.*","metadata":{}},{"cell_type":"code","source":"!pip install --no-index --find-links=/kaggle/input/vllm-offline-install blake3 msgspec py-cpuinfo tqdm requests transformers","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-14T14:36:06.325971Z","iopub.execute_input":"2025-05-14T14:36:06.326194Z","iopub.status.idle":"2025-05-14T14:36:10.619221Z","shell.execute_reply.started":"2025-05-14T14:36:06.326172Z","shell.execute_reply":"2025-05-14T14:36:10.618432Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install --no-index --find-links=/kaggle/input/vllm-offline-install vllm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-14T14:36:27.641028Z","iopub.execute_input":"2025-05-14T14:36:27.641493Z","iopub.status.idle":"2025-05-14T14:37:57.034098Z","shell.execute_reply.started":"2025-05-14T14:36:27.641462Z","shell.execute_reply":"2025-05-14T14:37:57.033398Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nos.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0,1\"\nos.environ[\"TOKENIZERS_PARALLELISM\"] = \"false\"\nos.environ[\"TRITON_PTXAS_PATH\"] = \"/usr/local/cuda/bin/ptxas\"\nimport re\nimport time\nimport random\nimport warnings\nfrom collections import Counter\nimport polars as pl\nimport pandas as pd, numpy as np, json, math, re, gc, time, tqdm, torch, os, textwrap\n\nimport torch\nimport vllm\nfrom vllm import LLM, SamplingParams\n\n# import kaggle_evaluation.aimo_2_inference_server\n\nwarnings.simplefilter('ignore')\nprint('PyTorch version:', torch.__version__)\nprint('vLLM:', vllm.__version__)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-14T14:47:47.287007Z","iopub.execute_input":"2025-05-14T14:47:47.287694Z","execution_failed":"2025-05-14T14:53:17.629Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ------------------------------------------------------------------\n#   Imports & checkpoint paths\n# ------------------------------------------------------------------\n\n\nCKPT   = \"/kaggle/input/qwen-3-rna-grope-250/transformers/default/1\"   # <-- your .safetensors or HF repo\nTEST_CSV = \"/kaggle/input/stanford-rna-3d-folding/test_sequences.csv\"\nOUT_CSV  = \"/kaggle/working/submission.csv\"\n\nBATCH_SIZE    = 8      # prompts per vLLM batch\nTEMPERATURE   = 0.9     # sampling settings for diversity\nTOP_P         = 0.9\nMAX_NEW_TOK   = 4096\n\n# ------------------------------------------------------------------\n#   vLLM engine\n# ------------------------------------------------------------------\nllm = LLM(\n    model=CKPT, \n    tensor_parallel_size=2,\n    max_model_len = 8192,\n    dtype='float16',\n\n)\nsampling = SamplingParams(\n    n             = 1,        # we call .generate() 5×\n    temperature   = TEMPERATURE,\n    top_p         = TOP_P,\n    max_tokens    = MAX_NEW_TOK,\n    # stop=['### Input:','### Response:'],  # never cross into next prompt\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-14T14:50:03.461277Z","iopub.execute_input":"2025-05-14T14:50:03.462175Z","iopub.status.idle":"2025-05-14T14:52:51.724888Z","shell.execute_reply.started":"2025-05-14T14:50:03.462147Z","shell.execute_reply":"2025-05-14T14:52:51.724272Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"CHUNK = 100     # whatever you used in training\n\nINSTR = (\n    \"You are given an RNA primary sequence of length **{L}**. \"\n    \"This slice covers positions **{s}-{e}**.\\n\\n\"\n    \"Return **exactly {n} lines**, one per nucleotide in the slice, \"\n    \"with 5 TAB‑separated columns: global_index res x y z.\\n\\n\"\n    \"Print nothing else.\"\n)\n\nALPACA_TMPL = (\n    \"Below is an instruction that describes a task, paired with an input that \"\n    \"provides further context. Write a response that appropriately completes \"\n    \"the request.\\n\\n\"\n    \"### Instruction:\\n{instruction}\\n\\n\"\n    \"### Input:\\n{input}\\n\\n\"\n    \"### Response:\\n\"\n)\n\ndef spaced(seq:str)->str: return \" \".join(seq)\n\n# regex: capture last 3 floats on each line (handles Unicode minus)\n_FLOAT3 = re.compile(\n    r\"(?:\\S+\\s+\\S+\\s+)?\" r\"(-?\\d+(?:\\.\\d+)?)\\s+\" r\"(-?\\d+(?:\\.\\d+)?)\\s+\" r\"(-?\\d+(?:\\.\\d+)?)\"\n)\n\ndef rows_to_xyz(block:str)->np.ndarray:\n    block = block.replace(\"\\u2212\",\"-\").replace(\"\\\\t\",\"\\t\")\n    rows  = [list(map(float,t)) for t in _FLOAT3.findall(block)]\n    return np.asarray(rows,dtype=np.float32) if rows else np.empty((0,3))\n\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df  = pd.read_csv(TEST_CSV).rename(columns={\"sequence\":\"seq\"})\nrecords  = []\n\nfor tid, grp in test_df.groupby(\"target_id\", sort=False):\n    seq, desc = grp[\"seq\"].iloc[0], grp[\"description\"].iloc[0]\n    L = len(seq)\n    for s in range(1, L+1, CHUNK):\n        e   = min(s+CHUNK-1, L)\n        sub = seq[s-1:e]\n        prompt = ALPACA_TMPL.format(\n            instruction = INSTR.format(L=L, s=s, e=e, n=len(sub)),\n            input = textwrap.dedent(f\"\"\"\\\n                target_id: {tid}\n                full_sequence: {spaced(seq)}\n                slice_start: {s}\n                slice_end: {e}\n                slice_seq: {spaced(sub)}\n                full_length: {L}\n                description: {desc}\"\"\")\n        )\n        records.append({\n            \"prompt\":      prompt,\n            \"target_id\":   tid,\n            \"slice_start\": s,\n            \"n\":           len(sub),\n            \"slice_seq\":   sub,          # ← keep the plain 5′‑to‑3′ letters\n        })\nprint(\"Total slices:\", len(records))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================================================================\n# 4   Generate 5 predictions per slice\n# ================================================================\ndef vllm_generate(batch): return [o.outputs[0].text for o in llm.generate(batch, sampling)]\n\nall_xyz = {k: [] for k in range(5)}\nfor k in range(5):\n    for i in tqdm.trange(0, len(records), BATCH_SIZE, desc=f\"pass{k+1}/5\"):\n        batch_prompts = [r[\"prompt\"] for r in records[i:i+BATCH_SIZE]]\n        outs = vllm_generate(batch_prompts)\n        all_xyz[k].extend(outs)\n    gc.collect()\n\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# all_xyz[4]","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"SAMPLE_CSV = \"/kaggle/input/stanford-rna-3d-folding/sample_submission.csv\"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================================================================\n# 5   Assemble submission rows\n# ================================================================\n\nsub_rows = []\nfor idx, rec in enumerate(records):\n    n     = rec[\"n\"]\n    tid   = rec[\"target_id\"]\n    off   = rec[\"slice_start\"]\n    seq   = rec[\"slice_seq\"]          # ← fetch stored slice letters\n\n    # pad / truncate xyz blocks exactly as before\n    blocks = []\n    for k in range(5):\n        arr = rows_to_xyz(all_xyz[k][idx])\n        m   = len(arr)\n        if   m == n: blocks.append(arr)\n        elif m > n: blocks.append(arr[:n])\n        else:\n            pad = np.zeros((n,3), dtype=np.float32); pad[:m] = arr\n            blocks.append(pad)\n\n    # one row per nucleotide\n    for r in range(n):\n        row = {\n            \"ID\":      f\"{tid}_{off + r}\",\n            \"resname\": seq[r],        # ← true A/C/G/U letter\n            \"resid\":   r + 1,\n        }\n        for k, arr in enumerate(blocks, 1):\n            x, y, z = arr[r]\n            row[f\"x_{k}\"], row[f\"y_{k}\"], row[f\"z_{k}\"] = x, y, z\n        sub_rows.append(row)\n\n\nsubmission = pd.DataFrame(sub_rows)\nsubmission = submission[pd.read_csv(SAMPLE_CSV, nrows=0).columns]  # align col order\nsubmission.to_csv(OUT_CSV, index=False)\nprint(\"✓ submission.csv written with shape:\", submission.shape)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}