{"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":"none","dataSources":[{"sourceId":116062,"databundleVersionId":14875579,"sourceType":"competition"}],"dockerImageVersionId":31259,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"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-19T15:01:18.418517Z","iopub.execute_input":"2026-01-19T15:01:18.418801Z","iopub.status.idle":"2026-01-19T15:01:20.666378Z","shell.execute_reply.started":"2026-01-19T15:01:18.418766Z","shell.execute_reply":"2026-01-19T15:01:20.665371Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n#  baseline (ESM2-35M + Logistic + hierarchy)\n\nimport os, torch, numpy as np, pandas as pd\nfrom transformers import EsmTokenizer, EsmModel\nfrom sklearn.preprocessing import MultiLabelBinarizer\nfrom sklearn.linear_model import LogisticRegression\nimport networkx as nx\nfrom tqdm import tqdm\n\n# ------------------ PATHS ------------------\nBASE = \"/kaggle/input/cafa-6-protein-function-prediction\"\nTRAIN_FASTA = f\"{BASE}/Train/train_sequences.fasta\"\nTRAIN_TERMS = f\"{BASE}/Train/train_terms.tsv\"\nTEST_FASTA  = f\"{BASE}/Test/testsuperset.fasta\"\nGO_OBO      = f\"{BASE}/Train/go-basic.obo\"\nSUB_PATH    = \"submission.tsv\"\n\n# ===============================\n# IGNORE WARNINGS (KAGGLE SAFE)\n# ===============================\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\n# TensorFlow warnings (if loaded indirectly)\nimport os\nos.environ[\"TF_CPP_MIN_LOG_LEVEL\"] = \"3\"\n\n# Transformers warnings\nos.environ[\"TRANSFORMERS_NO_ADVISORY_WARNINGS\"] = \"1\"\n\n# HuggingFace tokenizer parallelism warning\nos.environ[\"TOKENIZERS_PARALLELISM\"] = \"false\"\n\nprint(\"✅ All warnings suppressed\")\n\n\n# ------------------ FASTA READER (no Bio) ------------------\ndef read_fasta(path):\n    seqs, cur_id, cur_seq = {}, None, []\n    with open(path) as f:\n        for line in f:\n            line=line.strip()\n            if line.startswith(\">\"):\n                if cur_id: seqs[cur_id]=\"\".join(cur_seq)\n                cur_id=line[1:].split()[0]; cur_seq=[]\n            else:\n                cur_seq.append(line)\n        if cur_id: seqs[cur_id]=\"\".join(cur_seq)\n    return seqs\n\n# ------------------ LOAD DATA ------------------\ntrain_seqs = read_fasta(TRAIN_FASTA)\ntest_seqs  = read_fasta(TEST_FASTA)\nterms = pd.read_csv(TRAIN_TERMS, sep=\"\\t\")\n\n# ------------------ FILTER LABELS (HUGE BOOST) ------------------\nvalid_terms = terms[\"term\"].value_counts()\nvalid_terms = valid_terms[valid_terms >= 50].index\nterms = terms[terms[\"term\"].isin(valid_terms)]\n\n# ------------------ LOAD ESM ------------------\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\ntokenizer = EsmTokenizer.from_pretrained(\"facebook/esm2_t12_35M_UR50D\")\nmodel = EsmModel.from_pretrained(\"facebook/esm2_t12_35M_UR50D\").to(device)\nmodel.eval()\n\n@torch.no_grad()\ndef embed(seq):\n    inp = tokenizer(seq, return_tensors=\"pt\", truncation=True, max_length=1024)\n    out = model(**inp.to(device))\n    return out.last_hidden_state.mean(1).cpu().numpy()[0]\n\n# ------------------ EMBEDDINGS ------------------\nX_train = np.vstack([embed(train_seqs[k]) for k in tqdm(train_seqs)])\nX_test  = np.vstack([embed(test_seqs[k])  for k in tqdm(test_seqs)])\n\ntrain_ids = list(train_seqs.keys())\ntest_ids  = list(test_seqs.keys())\n\nfrom lightgbm import LGBMClassifier\n\nmodel = LGBMClassifier(\n    n_estimators=500,\n    learning_rate=0.05,\n    num_leaves=64,\n    subsample=0.8,\n    colsample_bytree=0.8,\n    device=\"gpu\"\n)\n\n# ------------------ GO HIERARCHY ------------------\nG = nx.DiGraph()\nwith open(GO_OBO) as f:\n    cur=None\n    for l in f:\n        if l.startswith(\"id:\"):\n            cur=l.strip().split()[1]\n        elif l.startswith(\"is_a:\"):\n            G.add_edge(cur, l.split()[1])\n\ndef propagate(scores):\n    for c,p in G.edges():\n        if c in scores:\n            scores[p]=max(scores.get(p,0), scores[c])\n    return scores\n\n# ------------------ TRAIN PER ASPECT ------------------\nthresholds = {\"F\":0.30, \"P\":0.15, \"C\":0.40}\nall_preds = {pid:{} for pid in test_ids}\n\nfor aspect in [\"F\",\"P\",\"C\"]:\n    sub = terms[terms[\"aspect\"]==aspect]\n    grouped = (\n        sub.groupby(\"EntryID\")[\"term\"]\n        .apply(list).reindex(train_ids)\n        .apply(lambda x: x if isinstance(x,list) else [])\n    )\n    mlb = MultiLabelBinarizer()\n    y = mlb.fit_transform(grouped)\n\n    clf = LogisticRegression(\n        max_iter=2000, solver=\"saga\", n_jobs=-1\n    )\n    clf.fit(X_train, y)\n\n    probs = clf.predict_proba(X_test)\n    for i,pid in enumerate(test_ids):\n        for j,go in enumerate(mlb.classes_):\n            if probs[i][j] >= thresholds[aspect]:\n                all_preds[pid][go] = probs[i][j]\n\n# ------------------ HIERARCHY + SUBMISSION ------------------\nrows=[]\nfor pid,scores in all_preds.items():\n    scores = propagate(scores)\n    for go,sc in scores.items():\n        rows.append([pid, go, sc])\n\npd.DataFrame(rows, columns=[\"EntryID\",\"term\",\"score\"])\\\n  .to_csv(SUB_PATH, sep=\"\\t\", index=False)\n\nprint(\"✅ submission.tsv created\")\n# ======================================================================\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-19T15:28:45.471165Z","iopub.execute_input":"2026-01-19T15:28:45.471459Z","iopub.status.idle":"2026-01-19T15:55:32.588458Z","shell.execute_reply.started":"2026-01-19T15:28:45.471436Z","shell.execute_reply":"2026-01-19T15:55:32.586983Z"}},"outputs":[],"execution_count":null}]}