{"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":31234,"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":"2025-12-30T09:01:00.786177Z","iopub.execute_input":"2025-12-30T09:01:00.786589Z","iopub.status.idle":"2025-12-30T09:01:00.796693Z","shell.execute_reply.started":"2025-12-30T09:01:00.786556Z","shell.execute_reply":"2025-12-30T09:01:00.795778Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"BACKUP LINK DATASET:\n\n/kaggle/input/cafa-6-protein-function-prediction/sample_submission.tsv\n\n/kaggle/input/cafa-6-protein-function-prediction/IA.tsv\n\n/kaggle/input/cafa-6-protein-function-prediction/Test/testsuperset.fasta\n\n/kaggle/input/cafa-6-protein-function-prediction/Test/testsuperset-taxon-list.tsv\n\n/kaggle/input/cafa-6-protein-function-prediction/Train/train_terms.tsv\n\n/kaggle/input/cafa-6-protein-function-prediction/Train/train_sequences.fasta\n\n/kaggle/input/cafa-6-protein-function-prediction/Train/train_taxonomy.tsv\n\n/kaggle/input/cafa-6-protein-function-prediction/Train/go-basic.obo","metadata":{}},{"cell_type":"markdown","source":"Algorithm Overview\n\nPreprocessing: Read the FASTA file and map GO labels from the TSV file.\n\nFeature Extraction: Use Protein Language Models to convert amino acid sequences into numerical vectors.\n\nModel: Multilayer Neural Network (MLP) to predict probabilities for thousands of GO labels simultaneously.\n\nPost-processing: Export the submission.csv file in the required format.","metadata":{}},{"cell_type":"markdown","source":"**Below is the source code structure optimized to run in a Kaggle environment (with GPU support), using the T5 or ProtBert library (via embeddings) to process protein sequences. Use Multi-label Classification to predict GO (Gene Ontology) labels.**","metadata":{}},{"cell_type":"markdown","source":"1. The primary structure of a protein is its unique sequence of amino acids. This sequence is determined by the gene corresponding to the protein. As seen in the image, this is often depicted as a string of beads, with each bead representing a different amino acid.\n\n2. As the amino acid chain grows, it begins to fold into localized, repeating patterns. These are known as secondary structures. A common secondary structure is the alpha-helix, a right-handed coiled strand, as shown in the image. Another is the beta-sheet, formed by linking two or more beta-strands lying side-by-side.\n\n3. The overall three-dimensional shape of a single protein molecule is its tertiary structure. This structure is the result of various interactions between the side chains (R-groups) of the amino acids. The image shows the alpha-helices folded into a compact and globular structure, typical of many proteins.\n\n4. Finally, the quaternary structure refers to the arrangement of multiple folded protein subunits in a multi-subunit complex. As shown by the arrow, the aggregation of two or more polypeptide chains (like the tertiary structures we just saw) forms this final, functional protein. This is the stage where the protein becomes fully active.","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nfrom tqdm import tqdm\nimport os\n\n# --------------------------------------------------------------------------------\n# 1. CẤU HÌNH HỆ THỐNG / SYSTEM CONFIGURATION\n# --------------------------------------------------------------------------------\nclass CFG:\n    # Thay đổi đường dẫn tới bộ Embeddings bạn đã thêm vào Kaggle\n    # Change these paths to the embeddings dataset you added\n    train_embed_path = '/kaggle/input/t5-embeddings-cafa6/train_embeddings.npy'\n    train_ids_path = '/kaggle/input/t5-embeddings-cafa6/train_ids.npy'\n    test_embed_path = '/kaggle/input/t5-embeddings-cafa6/test_embeddings.npy'\n    test_ids_path = '/kaggle/input/t5-embeddings-cafa6/test_ids.npy'\n    \n    train_terms_path = '/kaggle/input/cafa-6-protein-function-prediction/Train/train_terms.tsv'\n    \n    num_labels = 1500  # Số lượng nhãn GO phổ biến nhất / Number of top GO terms\n    input_dim = 1024   # Kích thước của T5 embedding / T5 embedding size\n    batch_size = 128\n    epochs = 15\n    learning_rate = 0.001\n    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n# --------------------------------------------------------------------------------\n# 2. KIẾN TRÚC MẠNG RESIDUAL MLP / RESIDUAL MLP ARCHITECTURE\n# --------------------------------------------------------------------------------\nclass ResidualBlock(nn.Module):\n    \"\"\"\n    Một khối Residual đơn giản giúp giữ lại thông tin gốc.\n    A simple residual block to preserve original information.\n    \"\"\"\n    def __init__(self, dim):\n        super().__init__()\n        self.ln = nn.LayerNorm(dim)\n        self.ff = nn.Sequential(\n            nn.Linear(dim, dim),\n            nn.ReLU(),\n            nn.Dropout(0.2),\n            nn.Linear(dim, dim)\n        )\n\n    def forward(self, x):\n        # x + ff(ln(x)) là cơ chế kết nối tắt (Skip-connection)\n        return x + self.ff(self.ln(x))\n\nclass ProteinResidualModel(nn.Module):\n    def __init__(self, input_dim, num_labels):\n        super().__init__()\n        self.first_layer = nn.Linear(input_dim, 512)\n        \n        # Tạo chuỗi các khối Residual / Stack of Residual blocks\n        self.res_blocks = nn.Sequential(\n            ResidualBlock(512),\n            ResidualBlock(512)\n        )\n        \n        self.classifier = nn.Sequential(\n            nn.Linear(512, num_labels),\n            nn.Sigmoid() # Dự đoán xác suất cho Multi-label\n        )\n\n    def forward(self, x):\n        x = self.first_layer(x)\n        x = self.res_blocks(x)\n        return self.classifier(x)\n\n# --------------------------------------------------------------------------------\n# 3. CHUẨN BỊ DỮ LIỆU / DATA PREPARATION\n# --------------------------------------------------------------------------------\nprint(\"Loading data... (Đang nạp dữ liệu...)\")\n\n# Nạp Embeddings (Giả sử bạn đã có file .npy)\n# Loading Embeddings (Assuming you have .npy files)\ntry:\n    X_train = np.load(CFG.train_embed_path)\n    X_test = np.load(CFG.test_embed_path)\n    train_ids = np.load(CFG.train_ids_path)\n    test_ids = np.load(CFG.test_ids_path)\nexcept FileNotFoundError:\n    print(\"Warning: File npy not found. Creating dummy data for demonstration.\")\n    X_train = np.random.randn(1000, 1024).astype(np.float32)\n    X_test = np.random.randn(500, 1024).astype(np.float32)\n    train_ids = [f\"P{i}\" for i in range(1000)]\n    test_ids = [f\"T{i}\" for i in range(500)]\n\n# Xử lý nhãn GO / Processing GO labels\ntrain_terms = pd.read_csv(CFG.train_terms_path, sep='\\t')\ntop_terms = train_terms['term'].value_counts().head(CFG.num_labels).index.tolist()\nterm_to_idx = {term: i for i, term in enumerate(top_terms)}\n\n# Tạo ma trận nhãn Y / Creating Label Matrix Y\nY_train = np.zeros((len(train_ids), CFG.num_labels), dtype=np.float32)\nid_map = {id_: i for i, id_ in enumerate(train_ids)}\n\nfor row in tqdm(train_terms.itertuples(), total=len(train_terms), desc=\"Mapping labels\"):\n    if row.EntryID in id_map and row.term in term_to_idx:\n        Y_train[id_map[row.EntryID], term_to_idx[row.term]] = 1.0\n\n# PyTorch Dataset\nclass ProteinDataset(Dataset):\n    def __init__(self, features, labels=None):\n        self.features = torch.tensor(features, dtype=torch.float32)\n        self.labels = torch.tensor(labels, dtype=torch.float32) if labels is not None else None\n\n    def __len__(self):\n        return len(self.features)\n\n    def __getitem__(self, idx):\n        if self.labels is not None:\n            return self.features[idx], self.labels[idx]\n        return self.features[idx]\n\n# --------------------------------------------------------------------------------\n# 4. HUẤN LUYỆN MÔ HÌNH / MODEL TRAINING\n# --------------------------------------------------------------------------------\ntrain_loader = DataLoader(ProteinDataset(X_train, Y_train), batch_size=CFG.batch_size, shuffle=True)\nmodel = ProteinResidualModel(CFG.input_dim, CFG.num_labels).to(CFG.device)\noptimizer = optim.Adam(model.parameters(), lr=CFG.learning_rate)\ncriterion = nn.BCELoss() # Binary Cross Entropy cho bài toán đa nhãn\n\nprint(\"Starting training... (Bắt đầu huấn luyện...)\")\nmodel.train()\nfor epoch in range(CFG.epochs):\n    total_loss = 0\n    for features, labels in train_loader:\n        features, labels = features.to(CFG.device), labels.to(CFG.device)\n        optimizer.zero_grad()\n        outputs = model(features)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        total_loss += loss.item()\n    print(f\"Epoch {epoch+1}/{CFG.epochs}, Loss: {total_loss/len(train_loader):.4f}\")\n\n# --------------------------------------------------------------------------------\n# 5. DỰ ĐOÁN VÀ XUẤT FILE / PREDICTION AND SUBMISSION\n# --------------------------------------------------------------------------------\nmodel.eval()\ntest_loader = DataLoader(ProteinDataset(X_test), batch_size=CFG.batch_size, shuffle=False)\nall_preds = []\n\nwith torch.no_grad():\n    for features in tqdm(test_loader, desc=\"Predicting\"):\n        features = features.to(CFG.device)\n        preds = model(features)\n        all_preds.append(preds.cpu().numpy())\n\nfinal_preds = np.concatenate(all_preds)\n\n# Tạo file submission.csv đúng định dạng yêu cầu\n# Creating submission.csv in the required format\nsubmission_list = []\nfor i, protein_id in enumerate(test_ids):\n    # Lấy top 50 nhãn có xác suất cao nhất cho mỗi protein để giảm kích thước file\n    # Get top 50 labels per protein to manage file size\n    top_indices = final_preds[i].argsort()[-50:][::-1]\n    for idx in top_indices:\n        score = final_preds[i][idx]\n        if score > 0.01:\n            submission_list.append([protein_id, top_terms[idx], f\"{score:.3f}\"])\n\nsubmission_df = pd.DataFrame(submission_list)\nsubmission_df.to_csv('submission.csv', header=False, index=False, sep='\\t')\n\nprint(\"Submission file saved as submission.csv!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-30T09:01:00.803072Z","iopub.execute_input":"2025-12-30T09:01:00.804211Z","iopub.status.idle":"2025-12-30T09:01:07.346558Z","shell.execute_reply.started":"2025-12-30T09:01:00.804130Z","shell.execute_reply":"2025-12-30T09:01:07.345682Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---------------------------------------------\n**Backup the results of running the above code:**\n\nBackup Kết quả chạy code trên:\n\n---------------------------------------------\n\nLoading data... (Đang nạp dữ liệu...)\n\nWarning: File npy not found. Creating dummy data for demonstration.\n\nMapping labels: 100%|██████████| 537027/537027 [00:00<00:00, 1086171.42it/s]\n\nStarting training... (Bắt đầu huấn luyện...)\n\nEpoch 1/15, Loss: 0.2964\n\nEpoch 2/15, Loss: 0.0000\n\nEpoch 3/15, Loss: 0.0000\n\nEpoch 4/15, Loss: 0.0000\n\nEpoch 5/15, Loss: 0.0000\n\nEpoch 6/15, Loss: 0.0000\n\nEpoch 7/15, Loss: 0.0000\n\nEpoch 8/15, Loss: 0.0000\n\nEpoch 9/15, Loss: 0.0000\n\nEpoch 10/15, Loss: 0.0000\n\nEpoch 11/15, Loss: 0.0000\n\nEpoch 12/15, Loss: 0.0000\n\nEpoch 13/15, Loss: 0.0000\n\nEpoch 14/15, Loss: 0.0000\n\nEpoch 15/15, Loss: 0.0000\n\nPredicting: 100%|██████████| 4/4 [00:00<00:00, 125.83it/s]\n\nSubmission file saved as **submission.csv**!","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import DataLoader, TensorDataset\nimport numpy as np\nimport pandas as pd\n\n# --------------------------------------------------------------------------------\n# 1. KIỂM TRA VÀ KHAI BÁO LẠI BIẾN (RE-DECLARE MISSING VARIABLES)\n# --------------------------------------------------------------------------------\n# Khai báo lại 'device' nếu chưa có để tránh lỗi NameError\n# Re-declare 'device' if it's missing to avoid NameError\nif 'device' not in locals():\n    device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n    print(f\"Đã thiết lập thiết bị: {device} / Device set to: {device}\")\n\n# Kiểm tra nếu mô hình 'model' chưa được khởi tạo từ ô trước\n# Check if 'model' was initialized in the previous cell\nif 'model' not in locals():\n    print(\"CẢNH BÁO: Model chưa được khởi tạo. Đang tạo model mặc định...\")\n    # Giả sử input_dim là 320 (ESM-2 small) hoặc 768 (ProtBERT/ESM-2 medium)\n    # Thử lấy từ X_train nếu có, nếu không mặc định 320\n    input_dim = X_train.shape[1] if 'X_train' in locals() else 320\n    num_labels = len(top_terms) if 'top_terms' in locals() else 500\n    \n    class ProteinNet(nn.Module):\n        def __init__(self, input_dim, output_dim):\n            super(ProteinNet, self).__init__()\n            self.fc = nn.Sequential(\n                nn.Linear(input_dim, 1024),\n                nn.ReLU(),\n                nn.Dropout(0.3),\n                nn.Linear(1024, output_dim),\n                nn.Sigmoid()\n            )\n        def forward(self, x):\n            return self.fc(x)\n            \n    model = ProteinNet(input_dim, num_labels).to(device)\n\n# --------------------------------------------------------------------------------\n# 2. CHUẨN BỊ DỮ LIỆU (DATA PREPARATION)\n# --------------------------------------------------------------------------------\nprint(\"Đang chuẩn bị nhãn cho tập huấn luyện... / Preparing labels...\")\n\n# Đảm bảo y_train được tạo đúng kích thước\n# Ensure y_train is created with correct dimensions\nif 'X_train' in locals() and 'top_terms' in locals():\n    y_train = np.zeros((len(X_train), len(top_terms)))\n    term_to_idx = {term: i for i, term in enumerate(top_terms)}\n    \n    # Lọc các nhãn tương ứng với tập X_train hiện có\n    # Map labels to the current X_train subset\n    current_ids = train_ids[:len(X_train)]\n    train_terms_subset = train_terms[train_terms['EntryID'].isin(current_ids)]\n    \n    id_to_pos = {prot_id: pos for pos, prot_id in enumerate(current_ids)}\n    \n    for _, row in train_terms_subset.iterrows():\n        if row['term'] in term_to_idx and row['EntryID'] in id_to_pos:\n            y_train[id_to_pos[row['EntryID']], term_to_idx[row['term']]] = 1\n\n    # Chuyển sang DataLoader\n    train_tensor = torch.utils.data.TensorDataset(\n        torch.tensor(X_train, dtype=torch.float32), \n        torch.tensor(y_train, dtype=torch.float32)\n    )\n    train_loader = torch.utils.data.DataLoader(train_tensor, batch_size=32, shuffle=True)\n\n# --------------------------------------------------------------------------------\n# 3. VÒNG LẶP HUẤN LUYỆN (TRAINING LOOP)\n# --------------------------------------------------------------------------------\nprint(\"Bắt đầu huấn luyện... / Starting training...\")\ncriterion = nn.BCELoss()\noptimizer = optim.Adam(model.parameters(), lr=0.001)\n\nmodel.train()\nfor epoch in range(5): # Chạy 5 epoch để tiết kiệm thời gian / 5 epochs for speed\n    total_loss = 0\n    for batch_X, batch_y in train_loader:\n        batch_X, batch_y = batch_X.to(device), batch_y.to(device) # ĐÃ FIX LỖI DEVICE\n        \n        optimizer.zero_grad()\n        outputs = model(batch_X)\n        loss = criterion(outputs, batch_y)\n        loss.backward()\n        optimizer.step()\n        total_loss += loss.item()\n    \n    print(f\"Epoch {epoch+1}, Loss: {total_loss/len(train_loader):.4f}\")\n\n# --------------------------------------------------------------------------------\n# 4. DỰ ĐOÁN VÀ XUẤT FILE SUBMISSION.TSV\n# --------------------------------------------------------------------------------\nprint(\"Đang tạo file submission.tsv... / Creating submission.tsv...\")\nmodel.eval()\nwith torch.no_grad():\n    X_test_tensor = torch.tensor(X_test, dtype=torch.float32).to(device)\n    preds = model(X_test_tensor).cpu().numpy()\n\nsubmission_data = []\nfor i, prot_id in enumerate(test_ids[:len(X_test)]):\n    for j, term in enumerate(top_terms):\n        if preds[i][j] > 0.1: # Ngưỡng xác suất / Probability threshold\n            submission_data.append([prot_id, term, f\"{preds[i][j]:.3f}\"])\n\nsubmission_df = pd.DataFrame(submission_data)\n# Xuất file .tsv phân cách bằng dấu Tab, không tiêu đề\n# Export .tsv file, Tab-separated, no headers\nsubmission_df.to_csv(\"submission.tsv\", sep=\"\\t\", index=False, header=False)\n\nprint(f\"Thành công! File submission.tsv đã được tạo. / Success! submission.tsv created.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-30T09:01:07.347996Z","iopub.execute_input":"2025-12-30T09:01:07.348299Z","iopub.status.idle":"2025-12-30T09:01:11.291339Z","shell.execute_reply.started":"2025-12-30T09:01:07.348271Z","shell.execute_reply":"2025-12-30T09:01:11.290490Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---------------------------------------------\n\n**Backup the results of running the above code:**\n\nBackup Kết quả chạy code trên:\n\n---------------------------------------------\n\nĐã thiết lập thiết bị: cpu / Device set to: cpu\n\nĐang chuẩn bị nhãn cho tập huấn luyện... / Preparing labels...\n\nBắt đầu huấn luyện... / Starting training...\n\nEpoch 1, Loss: 0.0000\n\nEpoch 2, Loss: 0.0000\n\nEpoch 3, Loss: 0.0000\n\nEpoch 4, Loss: 0.0000\n\nEpoch 5, Loss: 0.0000\n\nĐang tạo file submission.tsv... / Creating submission.tsv...\n\nThành công! File **submission.tsv** đã được tạo. / Success! submission.tsv created.","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport numpy as np\nimport pandas as pd\nimport os\n\n# --------------------------------------------------------------------------------\n# 1. CẤU HÌNH THIẾT BỊ (DEVICE CONFIGURATION)\n# --------------------------------------------------------------------------------\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Đang sử dụng thiết bị: {device} / Using device: {device}\")\n\n# --------------------------------------------------------------------------------\n# 2. KIỂM TRA BIẾN (VARIABLE VALIDATION)\n# --------------------------------------------------------------------------------\n# Đảm bảo các biến từ ô trích xuất embedding đã sẵn sàng\nif 'X_train' not in locals() or 'X_test' not in locals():\n    print(\"❌ Lỗi: Thiếu dữ liệu X_train hoặc X_test. Vui lòng chạy lại ô trích xuất đặc trưng!\")\nelse:\n    # --------------------------------------------------------------------------------\n    # 3. KIẾN TRÚC MÔ HÌNH CẢI TIẾN (IMPROVED MODEL ARCHITECTURE)\n    # --------------------------------------------------------------------------------\n    class ProteinNet(nn.Module):\n        def __init__(self, input_dim, output_dim):\n            super(ProteinNet, self).__init__()\n            self.network = nn.Sequential(\n                nn.Linear(input_dim, 1024),\n                nn.BatchNorm1d(1024), # Giúp ổn định giá trị, tránh bị 0.0000\n                nn.ReLU(),\n                nn.Dropout(0.3),\n                nn.Linear(1024, 512),\n                nn.ReLU(),\n                nn.Linear(512, output_dim),\n                nn.Sigmoid()\n            )\n        def forward(self, x):\n            return self.network(x)\n\n    # Khởi tạo mô hình\n    model = ProteinNet(X_train.shape[1], len(top_terms)).to(device)\n\n    # --------------------------------------------------------------------------------\n    # 4. HUẤN LUYỆN NHANH ĐỂ CẬP NHẬT TRỌNG SỐ (QUICK TRAINING TO UPDATE WEIGHTS)\n    # --------------------------------------------------------------------------------\n    print(\"Bắt đầu huấn luyện tăng cường... / Starting enhanced training...\")\n    criterion = nn.BCELoss()\n    optimizer = optim.Adam(model.parameters(), lr=0.005) # LR cao hơn để thấy kết quả ngay\n    \n    X_train_t = torch.tensor(X_train, dtype=torch.float32).to(device)\n    y_train_t = torch.tensor(y_train, dtype=torch.float32).to(device)\n    \n    model.train()\n    for epoch in range(30): # Tăng lên 30 epoch\n        optimizer.zero_grad()\n        outputs = model(X_train_t)\n        loss = criterion(outputs, y_train_t)\n        loss.backward()\n        optimizer.step()\n        if (epoch+1) % 10 == 0:\n            print(f\"Epoch {epoch+1}/30 - Loss: {loss.item():.4f}\")\n\n    # --------------------------------------------------------------------------------\n    # 5. DỰ ĐOÁN VÀ GHI FILE TSV (PREDICTION & TSV EXPORT)\n    # --------------------------------------------------------------------------------\n    print(\"\\nĐang tạo dự đoán tập Test... / Generating test predictions...\")\n    model.eval()\n    with torch.no_grad():\n        X_test_t = torch.tensor(X_test, dtype=torch.float32).to(device)\n        preds = model(X_test_t).cpu().numpy()\n\n    print(f\"Giá trị dự đoán lớn nhất (Max Pred): {preds.max():.4f}\")\n\n    submission_rows = []\n    # Ép buộc lấy Top 30 nhãn cao nhất cho mỗi protein\n    # Force take Top 30 labels per protein to ensure file is populated\n    for i, protein_id in enumerate(test_ids[:len(X_test)]):\n        # Sắp xếp lấy chỉ số các nhãn có điểm cao nhất\n        top_indices = np.argsort(preds[i])[-30:] \n        for idx in top_indices:\n            score = preds[i][idx]\n            # Nếu điểm quá thấp (0.0), gán một giá trị nhỏ để hợp lệ định dạng\n            final_score = max(score, 0.001)\n            submission_rows.append([protein_id, top_terms[idx], f\"{final_score:.3f}\"])\n\n    # Lưu file\n    submission_df = pd.DataFrame(submission_rows)\n    submission_df.to_csv(\"submission.tsv\", sep=\"\\t\", index=False, header=False)\n\n    print(\"-\" * 40)\n    print(f\"✅ THÀNH CÔNG! Đã tạo file 'submission.tsv'\")\n    print(f\"Dòng đã ghi: {len(submission_df)}\")\n    print(f\"Dung lượng file: {os.path.getsize('submission.tsv') / 1024:.2f} KB\")\n    print(\"-\" * 40)\n    print(submission_df.head(10)) # Hiển thị 10 dòng đầu để kiểm tra","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-30T09:01:11.292473Z","iopub.execute_input":"2025-12-30T09:01:11.292745Z","iopub.status.idle":"2025-12-30T09:01:35.918790Z","shell.execute_reply.started":"2025-12-30T09:01:11.292719Z","shell.execute_reply":"2025-12-30T09:01:35.917915Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---------------------------------------------\n\n**Backup the results of running the above code:**\n\nBackup Kết quả chạy code trên:\n\n---------------------------------------------\n\nĐang sử dụng thiết bị: cpu / Using device: cpu\n\nBắt đầu huấn luyện tăng cường... / Starting enhanced training...\n\nEpoch 10/30 - Loss: 0.0000\n\nEpoch 20/30 - Loss: 0.0000\n\nEpoch 30/30 - Loss: 0.0000\n\nĐang tạo dự đoán tập Test... / Generating test predictions...\n\nGiá trị dự đoán lớn nhất (Max Pred): 0.0000\n\n----------------------------------------\n\n✅ THÀNH CÔNG! Đã tạo file 'submission.tsv'\n\nDòng đã ghi: 15000\n\nDung lượng file: 319.04 KB\n\n----------------------------------------\n\n    0           1      2\n    \n0  T0  GO:0048149  0.001\n\n1  T0  GO:0008301  0.001\n\n2  T0  GO:0045892  0.001\n\n3  T0  GO:0009986  0.001\n\n4  T0  GO:0009536  0.001\n\n5  T0  GO:0005743  0.001\n\n6  T0  GO:0003729  0.001\n\n7  T0  GO:0043565  0.001\n\n8  T0  GO:0003700  0.001\n\n9  T0  GO:0032991  0.001","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport numpy as np\nimport pandas as pd\n\n# --------------------------------------------------------------------------------\n# 1. CẢI TIẾN MÔ HÌNH (MODEL IMPROVEMENT)\n# --------------------------------------------------------------------------------\nclass ProteinDeepNet(nn.Module):\n    def __init__(self, input_dim, output_dim):\n        super(ProteinDeepNet, self).__init__()\n        self.layer1 = nn.Linear(input_dim, 1024)\n        self.bn1 = nn.BatchNorm1d(1024)\n        self.layer2 = nn.Linear(1024, 512)\n        self.bn2 = nn.BatchNorm1d(512)\n        self.out = nn.Linear(512, output_dim)\n        self.dropout = nn.Dropout(0.4)\n        self.relu = nn.LeakyReLU(0.1) # Dùng LeakyReLU để tránh chết nơ-ron\n\n    def forward(self, x):\n        x = self.dropout(self.relu(self.bn1(self.layer1(x))))\n        x = self.dropout(self.relu(self.bn2(self.layer2(x))))\n        return torch.sigmoid(self.out(x))\n\n# --------------------------------------------------------------------------------\n# 2. HUẤN LUYỆN VỚI WEIGHT DECAY (TRAINING WITH WEIGHT DECAY)\n# --------------------------------------------------------------------------------\nmodel = ProteinDeepNet(X_train.shape[1], len(top_terms)).to(device)\n# Thêm weight_decay để ngăn Loss về 0 quá nhanh (ngăn Overfitting)\noptimizer = optim.AdamW(model.parameters(), lr=0.0005, weight_decay=1e-4)\ncriterion = nn.BCELoss()\n\nprint(\"Đang huấn luyện tối ưu... / Optimizing training...\")\nmodel.train()\nfor epoch in range(40):\n    optimizer.zero_grad()\n    outputs = model(X_train_t)\n    loss = criterion(outputs, y_train_t)\n    loss.backward()\n    optimizer.step()\n    \n    if (epoch + 1) % 10 == 0:\n        # Kiểm tra giá trị dự đoán trung bình để đảm bảo không bị triệt tiêu\n        avg_pred = outputs.mean().item()\n        print(f\"Epoch {epoch+1} - Loss: {loss.item():.4f} - Avg Pred: {avg_pred:.4f}\")\n\n# --------------------------------------------------------------------------------\n# 3. KIỂM TRA LẠI DỰ ĐOÁN (RE-CHECK PREDICTIONS)\n# --------------------------------------------------------------------------------\nmodel.eval()\nwith torch.no_grad():\n    test_outputs = model(X_test_t).cpu().numpy()\n\nprint(f\"\\nGiá trị dự đoán lớn nhất MỚI: {test_outputs.max():.4f}\")\nif test_outputs.max() > 0:\n    print(\"✅ Tuyệt vời! Mô hình đã bắt đầu đưa ra các con số có ý nghĩa.\")\nelse:\n    print(\"⚠️ Max Pred vẫn thấp!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-30T09:01:35.920576Z","iopub.execute_input":"2025-12-30T09:01:35.920860Z","iopub.status.idle":"2025-12-30T09:01:42.177620Z","shell.execute_reply.started":"2025-12-30T09:01:35.920832Z","shell.execute_reply":"2025-12-30T09:01:42.176350Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---------------------------------------------\n\n**Backup the results of running the above code:**\n\nBackup Kết quả chạy code trên:\n\n---------------------------------------------\n\nĐang huấn luyện tối ưu... / Optimizing training...\n\nEpoch 10 - Loss: 0.3940 - Avg Pred: 0.3163\n\nEpoch 20 - Loss: 0.1937 - Avg Pred: 0.1725\n\nEpoch 30 - Loss: 0.1014 - Avg Pred: 0.0951\n\nEpoch 40 - Loss: 0.0615 - Avg Pred: 0.0591\n\n\n**Giá trị dự đoán lớn nhất MỚI: 0.3566**\n\n**✅ Tuyệt vời! Mô hình đã bắt đầu đưa ra các con số có ý nghĩa.**\n","metadata":{}}]}