{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":116062,"databundleVersionId":14084779,"sourceType":"competition"},{"sourceId":13719495,"sourceType":"datasetVersion","datasetId":8728609},{"sourceId":13962046,"sourceType":"datasetVersion","datasetId":8900209}],"dockerImageVersionId":31193,"isInternetEnabled":true,"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,"execution":{"iopub.status.busy":"2025-12-04T12:45:15.15269Z","iopub.execute_input":"2025-12-04T12:45:15.153052Z","iopub.status.idle":"2025-12-04T12:45:15.244934Z","shell.execute_reply.started":"2025-12-04T12:45:15.153023Z","shell.execute_reply":"2025-12-04T12:45:15.244099Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nimport pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T12:45:17.937069Z","iopub.execute_input":"2025-12-04T12:45:17.93738Z","iopub.status.idle":"2025-12-04T12:45:17.941705Z","shell.execute_reply.started":"2025-12-04T12:45:17.937342Z","shell.execute_reply":"2025-12-04T12:45:17.940962Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install -q biopython","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T12:46:05.150264Z","iopub.execute_input":"2025-12-04T12:46:05.150569Z","iopub.status.idle":"2025-12-04T12:46:10.629498Z","shell.execute_reply.started":"2025-12-04T12:46:05.150545Z","shell.execute_reply":"2025-12-04T12:46:10.628716Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Load dataset","metadata":{}},{"cell_type":"code","source":"train_terms = pd.read_csv(\"/kaggle/input/test-data/Train/train_terms.tsv\", delimiter=\"\\t\")\nprint(train_terms.shape)\ntrain_terms.head(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T12:46:10.630834Z","iopub.execute_input":"2025-12-04T12:46:10.631117Z","iopub.status.idle":"2025-12-04T12:46:11.194638Z","shell.execute_reply.started":"2025-12-04T12:46:10.631091Z","shell.execute_reply":"2025-12-04T12:46:11.193819Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from Bio import SeqIO\n\ntrain_id_df = pd.DataFrame([\n    {\"ID\": rec.id.split(\"|\")[1]}\n    for rec in SeqIO.parse(\"/kaggle/input/test-data/Train/train_sequences.fasta\", format='fasta')\n])\nprint(train_id_df.shape)\ntrain_id_df.head(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T12:46:18.240668Z","iopub.execute_input":"2025-12-04T12:46:18.240968Z","iopub.status.idle":"2025-12-04T12:46:20.027858Z","shell.execute_reply.started":"2025-12-04T12:46:18.240947Z","shell.execute_reply":"2025-12-04T12:46:20.027291Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_ids = np.load(\"/kaggle/input/t5-embedding-cafa-6/test_ids.npy\")\ntest_embs = np.load(\"/kaggle/input/t5-embedding-cafa-6/test_embeddings.npy\")\nprint(test_ids.shape)\nprint(test_embs.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T12:46:24.814777Z","iopub.execute_input":"2025-12-04T12:46:24.815105Z","iopub.status.idle":"2025-12-04T12:46:31.90056Z","shell.execute_reply.started":"2025-12-04T12:46:24.81508Z","shell.execute_reply":"2025-12-04T12:46:31.899907Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"embedding_map = dict(zip(test_ids, test_embs))\ntrain_embs = np.array([embedding_map[idx] for idx in train_id_df[\"ID\"].values])\n\ncolumn_num = train_embs.shape[1]\ntrain_df = pd.DataFrame(train_embs, columns = [\"Column_\" + str(i) for i in range(1, column_num+1)])\nprint(train_df.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T12:47:42.094837Z","iopub.execute_input":"2025-12-04T12:47:42.095472Z","iopub.status.idle":"2025-12-04T12:47:42.385309Z","shell.execute_reply.started":"2025-12-04T12:47:42.095447Z","shell.execute_reply":"2025-12-04T12:47:42.384631Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.head(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T12:47:43.39661Z","iopub.execute_input":"2025-12-04T12:47:43.3969Z","iopub.status.idle":"2025-12-04T12:47:43.416412Z","shell.execute_reply.started":"2025-12-04T12:47:43.396879Z","shell.execute_reply":"2025-12-04T12:47:43.415708Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Select first 1500 values for plotting\nplot_df = train_terms['term'].value_counts().iloc[:100]\n\nfigure, axis = plt.subplots(1, 1, figsize=(12, 6))\n\nbp = sns.barplot(ax=axis, x=np.array(plot_df.index), y=plot_df.values)\nbp.set_xticklabels(bp.get_xticklabels(), rotation=90, size = 6)\naxis.set_title('Top 100 frequent GO term IDs')\nbp.set_xlabel(\"GO term IDs\", fontsize = 12)\nbp.set_ylabel(\"Count\", fontsize = 12)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T12:47:47.893648Z","iopub.execute_input":"2025-12-04T12:47:47.89436Z","iopub.status.idle":"2025-12-04T12:47:49.082201Z","shell.execute_reply.started":"2025-12-04T12:47:47.894335Z","shell.execute_reply":"2025-12-04T12:47:49.081556Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Set the limit for label\nnum_of_labels = 1500\n\n# Take value counts in descending order and fetch first 1500 `GO term ID` as labels\nlabels = train_terms['term'].value_counts().index[:num_of_labels].tolist()\n\ntrain_terms_updated = train_terms.loc[train_terms['term'].isin(labels)]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T12:48:14.173554Z","iopub.execute_input":"2025-12-04T12:48:14.174283Z","iopub.status.idle":"2025-12-04T12:48:14.285137Z","shell.execute_reply.started":"2025-12-04T12:48:14.174258Z","shell.execute_reply":"2025-12-04T12:48:14.28422Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pie_df = train_terms_updated['aspect'].value_counts()\npalette_color = sns.color_palette('bright')\nplt.pie(pie_df.values, labels=np.array(pie_df.index), colors=palette_color, autopct='%.0f%%')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T12:48:15.243446Z","iopub.execute_input":"2025-12-04T12:48:15.244089Z","iopub.status.idle":"2025-12-04T12:48:15.363603Z","shell.execute_reply.started":"2025-12-04T12:48:15.244061Z","shell.execute_reply":"2025-12-04T12:48:15.362951Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_size = train_df.shape[0] # len(X)\ntrain_labels = np.zeros((train_size ,num_of_labels)) # 1500\n\n# Loop through each label\nfor i in range(num_of_labels):\n    # For each label, fetch the corresponding train_terms data\n    n_train_terms = train_terms_updated[train_terms_updated['term'] ==  labels[i]]\n    \n    # Fetch all the unique EntryId aka proteins related to the current label(GO term ID)\n    label_related_proteins = n_train_terms['EntryID'].unique()\n    \n    # In the series_train_protein_ids pandas series, if a protein is related\n    # to the current label, then mark it as 1, else 0.\n    # Replace the ith column of train_Y with with that pandas series.\n    train_labels[:,i] =  train_id_df[\"ID\"].isin(label_related_proteins).astype(float)\n    \n\n# Convert train_Y numpy into pandas dataframe\nlabels_df = pd.DataFrame(data = train_labels, columns = labels)\nprint(labels_df.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T12:49:23.197972Z","iopub.execute_input":"2025-12-04T12:49:23.198282Z","iopub.status.idle":"2025-12-04T12:50:11.379608Z","shell.execute_reply.started":"2025-12-04T12:49:23.198263Z","shell.execute_reply":"2025-12-04T12:50:11.378868Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T13:07:59.360859Z","iopub.execute_input":"2025-12-04T13:07:59.361693Z","iopub.status.idle":"2025-12-04T13:07:59.383125Z","shell.execute_reply.started":"2025-12-04T13:07:59.361664Z","shell.execute_reply":"2025-12-04T13:07:59.382436Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Training","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau \nINPUT_SHAPE = [train_df.shape[1]]\nBATCH_SIZE = 5120\nL2_REG = 0.0005 \n\nmodel = tf.keras.Sequential([\n    # Lớp chuẩn hóa là tốt, giữ nguyên\n    tf.keras.layers.BatchNormalization(input_shape=INPUT_SHAPE),\n    \n    # Layer 1: Thêm L2 Regularization để phạt trọng số lớn\n    tf.keras.layers.Dense(units=512, activation='relu', \n                          kernel_regularizer=tf.keras.regularizers.l2(L2_REG)),\n    tf.keras.layers.Dropout(0.25), \n\n    # Layer 2\n    tf.keras.layers.Dense(units=512, activation='relu',\n                          kernel_regularizer=tf.keras.regularizers.l2(L2_REG)),\n    tf.keras.layers.Dropout(0.25), \n\n    # Layer 3\n    tf.keras.layers.Dense(units=256, activation='relu',\n                          kernel_regularizer=tf.keras.regularizers.l2(L2_REG)),\n    tf.keras.layers.Dropout(0.25), \n\n    # Output Layer\n    tf.keras.layers.Dense(units=num_of_labels, activation='sigmoid')\n])\n\n\n\n# 1. Early Stopping: Dừng huấn luyện nếu AUC không cải thiện sau 3 epochs liên tiếp\nearly_stopping = EarlyStopping(\n    monitor='val_auc', # Giám sát chỉ số AUC trên tập validation\n    patience=3,   \n    restore_best_weights=True\n)\n\n# 2. ReduceLROnPlateau: Giảm Learning Rate nếu AUC không cải thiện sau 2 epochs\nlr_scheduler = ReduceLROnPlateau(\n    monitor='val_auc',\n    factor=0.5,        \n    patience=2,\n    min_lr=1e-6,\n    verbose=1\n)\n\nmodel.compile(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),\n    loss='binary_crossentropy',\n    metrics=['binary_accuracy', tf.keras.metrics.AUC()],\n)\n\n# Huấn luyện model (Sử dụng callbacks và tăng số epochs lên)\nhistory = model.fit(\n    train_df, labels_df,\n    batch_size=BATCH_SIZE,\n    epochs=50, \n    validation_split=0.15,\n    callbacks=[early_stopping, lr_scheduler]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T13:08:11.238906Z","iopub.execute_input":"2025-12-04T13:08:11.239579Z","iopub.status.idle":"2025-12-04T13:08:36.017679Z","shell.execute_reply.started":"2025-12-04T13:08:11.239542Z","shell.execute_reply":"2025-12-04T13:08:36.017104Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history_df = pd.DataFrame(history.history)\nhistory_df.loc[:, ['loss']].plot(title=\"Cross-entropy\")\nhistory_df.loc[:, ['binary_accuracy']].plot(title=\"Accuracy\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T13:09:24.762397Z","iopub.execute_input":"2025-12-04T13:09:24.762715Z","iopub.status.idle":"2025-12-04T13:09:25.161284Z","shell.execute_reply.started":"2025-12-04T13:09:24.762693Z","shell.execute_reply":"2025-12-04T13:09:25.160716Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"column_num = test_embs.shape[1]\ntest_df = pd.DataFrame(test_embs, columns = [\"Column_\" + str(i) for i in range(1, column_num+1)])\nprint(test_df.shape)\ntest_df.head(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T13:09:39.710311Z","iopub.execute_input":"2025-12-04T13:09:39.710827Z","iopub.status.idle":"2025-12-04T13:09:39.728337Z","shell.execute_reply.started":"2025-12-04T13:09:39.710804Z","shell.execute_reply":"2025-12-04T13:09:39.727506Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import gc\nfrom tqdm import tqdm\n\nPREDICT_BATCH_SIZE = 512\nTEMPERATURE = 1.5\nMAX_PREDS_PER_PROTEIN = 250\nMIN_CONFIDENCE = 0.2\n\n# test_protein_ids: list ID protein theo đúng thứ tự với test_df\n# Ví dụ nếu bạn có sẵn từ file test:\ntest_protein_ids = test_ids  # Đảm bảo len == len(test_df)\n\nassert len(test_protein_ids) == len(test_df), \"Số protein ID phải bằng số dòng trong test_df\"\n\nn_predictions = 0\n\nwith open('submission.tsv', 'w', newline='') as f:\n    # Duyệt theo batch để predict\n    for start in tqdm(range(0, len(test_protein_ids), PREDICT_BATCH_SIZE), desc=\"Predicting\"):\n        end = start + PREDICT_BATCH_SIZE\n        \n        batch_ids = test_protein_ids[start:end]\n        X_batch = test_df.iloc[start:end].values.astype(np.float32)\n\n        # model output hiện tại là sigmoid (probabilities)\n        # Nếu muốn áp dụng temperature scaling giống PyTorch (trên logits),\n        # ta chuyển prob -> logit -> scale -> prob lại.\n\n        # 1) Predict probabilities từ model\n        probs_batch = model.predict(X_batch, batch_size=5120, verbose=0)  # shape: (batch_size, num_of_labels)\n\n        # 2) Chuyển prob -> logits\n        eps = 1e-7\n        logits = np.log(probs_batch + eps) - np.log(1.0 - probs_batch + eps)\n\n        # 3) Temperature scaling trên logits, rồi sigmoid lại\n        scaled_logits = logits / TEMPERATURE\n        outputs = 1.0 / (1.0 + np.exp(-scaled_logits))   # sigmoid\n\n        # 4) Ghi ra file theo format: protein_id \\t term \\t prob\n        for i, pid in enumerate(batch_ids):\n            probs = outputs[i]\n            # Lấy top MAX_PREDS_PER_PROTEIN label\n            top_indices = np.argsort(probs)[::-1][:MAX_PREDS_PER_PROTEIN]\n\n            # Lọc các label có confidence > MIN_CONFIDENCE\n            confident_indices = [idx for idx in top_indices if probs[idx] > MIN_CONFIDENCE]\n\n            for idx in confident_indices:\n                line = f\"{pid}\\t{labels[idx]}\\t{min(probs[idx], 0.999):.3f}\\n\"\n                f.write(line)\n                n_predictions += 1\n\n        del X_batch, probs_batch, logits, scaled_logits, outputs\n        if start % (PREDICT_BATCH_SIZE * 10) == 0:\n            gc.collect()\n\nprint(f\"✓ Generated {n_predictions:,} predictions\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T14:12:01.84572Z","iopub.execute_input":"2025-12-04T14:12:01.846055Z","iopub.status.idle":"2025-12-04T14:17:54.849021Z","shell.execute_reply.started":"2025-12-04T14:12:01.846025Z","shell.execute_reply":"2025-12-04T14:17:54.848249Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# predictions =  model.predict(test_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T14:11:28.345408Z","iopub.execute_input":"2025-12-04T14:11:28.346128Z","iopub.status.idle":"2025-12-04T14:11:28.587303Z","shell.execute_reply.started":"2025-12-04T14:11:28.346105Z","shell.execute_reply":"2025-12-04T14:11:28.586472Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Giả sử predictions đã được tạo: predictions = model.predict(test_df)\n\n# # 1. Tính toán các chỉ số thống kê cho MỖI protein (trên trục Term, axis=1)\n# max_scores = predictions.max(axis=1)\n# min_scores = predictions.min(axis=1)\n# mean_scores = predictions.mean(axis=1)\n\n# # Phạm vi chênh lệch (kiểm tra mức độ khác biệt giữa điểm cao nhất và thấp nhất)\n# score_ranges = max_scores - min_scores\n\n# # 2. Tổng hợp thành DataFrame để dễ dàng phân tích\n# analysis_df = pd.DataFrame({\n#     'Max_Score': max_scores,    # Điểm tin cậy cao nhất cho protein\n#     'Min_Score': min_scores,    # Điểm tin cậy thấp nhất cho protein\n#     'Mean_Score': mean_scores,  # Điểm tin cậy trung bình cho protein\n#     'Score_Range': score_ranges # Chênh lệch Max - Min\n# })\n\n# # 3. Xuất bảng thống kê mô tả (Descriptive Statistics)\n# # Bảng này tóm tắt các chỉ số trên toàn bộ tập dữ liệu Protein\n# descriptive_stats = analysis_df.describe().T\n\n# print(\"--- BẢNG THỐNG KÊ CHÊNH LỆCH ĐIỂM TIN CẬY ---\")\n# print(descriptive_stats)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-03T01:08:18.410121Z","iopub.execute_input":"2025-12-03T01:08:18.410712Z","iopub.status.idle":"2025-12-03T01:08:19.258142Z","shell.execute_reply.started":"2025-12-03T01:08:18.410686Z","shell.execute_reply":"2025-12-03T01:08:19.257484Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# labels_arr = np.array(labels)\n# labels_arr","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-03T01:11:16.772164Z","iopub.execute_input":"2025-12-03T01:11:16.772822Z","iopub.status.idle":"2025-12-03T01:11:16.779155Z","shell.execute_reply.started":"2025-12-03T01:11:16.772792Z","shell.execute_reply":"2025-12-03T01:11:16.778166Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import numpy as np\n# import pandas as pd\n# from tqdm import tqdm\n\n# THRESHOLD = 0.3\n# # Giả sử các biến sau đã được định nghĩa:\n# test_protein_ids = np.load('/kaggle/input/t5-embedding-cafa-6/test_ids.npy')\n\n# CHUNK_SIZE = 10000\n# OUTPUT_FILE = \"submission.tsv\" # Đổi tên file để phân biệt\n\n# # 1. Khởi tạo container để lưu trữ các DataFrame nhỏ\n# total_predictions = 0\n# num_proteins = predictions.shape[0]\n\n# # 2. Lặp qua ma trận dự đoán theo từng lô (Protein)\n# for i in tqdm(range(0, num_proteins, CHUNK_SIZE), desc=\"Collecting Filtered Chunks\"):\n#     end_idx = min(i + CHUNK_SIZE, num_proteins)\n    \n#     # 2a. Cắt lát dữ liệu theo lô hiện tại\n#     pred_chunk = predictions[i:end_idx, :]\n#     id_chunk = test_protein_ids[i:end_idx]\n    \n#     # 2b. Lọc trong lô\n#     row_indices, col_indices = np.where(pred_chunk >= THRESHOLD)\n    \n#     # 2c. Tạo các mảng kết quả đã lọc\n#     filtered_protein_ids = id_chunk[row_indices]\n#     filtered_term_ids = labels_arr[col_indices]\n#     filtered_scores = pred_chunk[row_indices, col_indices]\n    \n#     # 2d. Tạo DataFrame nhỏ\n#     df_chunk = pd.DataFrame({\n#         'Protein_ID': filtered_protein_ids,\n#         'Term_ID': filtered_term_ids,\n#         'Confident_Score': filtered_scores\n#     })\n    \n#     # Ghi \n#     df_chunk.to_csv(OUTPUT_FILE, header=False, index=False, sep=\"\\t\", mode='a')\n    \n#     total_predictions += len(df_chunk)\n\n# # 4. Ghi file submission MỘT LẦN duy nhất\n# print(f\"\\nĐã lưu thành công file submission {OUTPUT_FILE} bằng phương pháp concat.\")\n# print(f\"Tổng số lượng dự đoán sau khi lọc: {total_predictions}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-03T01:13:08.921809Z","iopub.execute_input":"2025-12-03T01:13:08.922156Z","iopub.status.idle":"2025-12-03T01:14:14.13281Z","shell.execute_reply.started":"2025-12-03T01:13:08.922124Z","shell.execute_reply":"2025-12-03T01:14:14.132051Z"}},"outputs":[],"execution_count":null}]}