{"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":38760,"databundleVersionId":4493939,"sourceType":"competition"},{"sourceId":4461402,"sourceType":"datasetVersion","datasetId":2611514},{"sourceId":4474043,"sourceType":"datasetVersion","datasetId":2601572}],"dockerImageVersionId":31154,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install recbole","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-09T17:19:16.597133Z","iopub.execute_input":"2026-01-09T17:19:16.597341Z","iopub.status.idle":"2026-01-09T17:20:40.186716Z","shell.execute_reply.started":"2026-01-09T17:19:16.597325Z","shell.execute_reply":"2026-01-09T17:20:40.185977Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tqdm\nimport polars as pl\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport random\nimport os \nimport h5py\nimport sys\nimport gc\n\nfrom matplotlib import pyplot as plt\nimport pyarrow.parquet as pq","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-01-09T17:20:55.952064Z","iopub.execute_input":"2026-01-09T17:20:55.952384Z","iopub.status.idle":"2026-01-09T17:20:57.843156Z","shell.execute_reply.started":"2026-01-09T17:20:55.952356Z","shell.execute_reply":"2026-01-09T17:20:57.842586Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Chuẩn bị dữ liệu huấn luyện\n#Dữ liệu 1 tuần cuối của tập train\ntrain = pl.read_parquet('/kaggle/input/otto-train-and-test-data-for-local-validation/test.parquet')\n#Dữ liệu của tập test\ntest = pl.read_parquet('/kaggle/input/otto-full-optimized-memory-footprint/test.parquet')\n\n#Ghép thành 1 dataframe\ndf = pl.concat([train, test])\n\n#Sắp xếp theo session và timestamp\ndf = df.sort(['session', 'ts'])\ndf = df.with_columns((pl.col('ts') * 1e9).alias('ts'))\n#Định dạng đầu vào chuẩn của Recbole\ndf = df.rename({'session': 'session:token', 'aid': 'aid:token', 'ts': 'ts:float'})","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-09T17:21:11.405124Z","iopub.execute_input":"2026-01-09T17:21:11.406Z","iopub.status.idle":"2026-01-09T17:21:13.111437Z","shell.execute_reply.started":"2026-01-09T17:21:11.405962Z","shell.execute_reply":"2026-01-09T17:21:13.110856Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(df.columns)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-27T14:59:57.24414Z","iopub.execute_input":"2025-11-27T14:59:57.244701Z","iopub.status.idle":"2025-11-27T14:59:57.248963Z","shell.execute_reply.started":"2025-11-27T14:59:57.24468Z","shell.execute_reply":"2025-11-27T14:59:57.248246Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!mkdir -p /kaggle/working/recbox_data\n#Ghi file inter để huấn luyện\ndf[['session:token', 'aid:token', 'ts:float']].write_csv('/kaggle/working/recbox_data/recbox_data.inter', separator='\\t')\n\ndel df, train, test\ngc.collect()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-09T17:21:27.136863Z","iopub.execute_input":"2026-01-09T17:21:27.137428Z","iopub.status.idle":"2026-01-09T17:21:29.660806Z","shell.execute_reply.started":"2026-01-09T17:21:27.137407Z","shell.execute_reply":"2026-01-09T17:21:29.66008Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import logging\nfrom logging import getLogger\nimport typing\nfrom typing_extensions import Literal\ntyping.Literal = Literal\nfrom recbole.config import Config\nfrom recbole.data import create_dataset, data_preparation\nfrom recbole.model.sequential_recommender import SASRec\nfrom recbole.trainer import Trainer\nfrom recbole.utils import init_seed, init_logger\n\nfrom recbole.utils.case_study import full_sort_topk","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-09T17:21:37.07363Z","iopub.execute_input":"2026-01-09T17:21:37.074223Z","iopub.status.idle":"2026-01-09T17:21:54.100001Z","shell.execute_reply.started":"2026-01-09T17:21:37.0742Z","shell.execute_reply":"2026-01-09T17:21:54.099381Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Độ dài chuỗi tối đa cho SASRec\nMAX_ITEM = 30  \n\nparameter_dict = {\n    # === Data ===\n    'data_path': '/kaggle/working/',\n    'USER_ID_FIELD': 'session',\n    'ITEM_ID_FIELD': 'aid',\n    'TIME_FIELD': 'ts',\n    'user_inter_num_interval': \"[5,Inf)\",\n    'item_inter_num_interval': \"[5,Inf)\",\n    'load_col': {'inter': ['session', 'ts']},\n\n    # === Tham số huấn luyện ===\n    'epochs': 20,                     \n    'stopping_step': 5,\n    'train_batch_size': 512,         \n    'eval_batch_size': 1024,\n    'train_neg_sample_args': None,\n    'learning_rate': 5e-4,\n\n    # === Sequence handling ===\n    'MAX_ITEM_LIST_LENGTH': MAX_ITEM,\n    'MAX_SEQ_LENGTH': MAX_ITEM,       \n    'hidden_size': 128,               # embedding dimension\n    'num_heads': 4,                   # số head trong self-attention\n    'num_layers': 2,                  # số layer Transformer\n    'hidden_dropout_prob': 0.2,       # dropout cho feed-forward\n    'attn_dropout_prob': 0.2,         # dropout cho attention\n\n    # === Evaluation Metrics ===\n    'metrics': ['Recall', 'MRR', 'NDCG', 'Hit', 'Precision'],\n    'topk': [20],                \n    'valid_metric': 'Recall@20', \n\n    # === Evaluation ===\n    'eval_args': {\n        'split': {'LS': 'valid_and_test'},\n        'group_by': 'user',\n        'order': 'TO',\n        'mode': 'full'\n    },\n\n    # === Optimization ===\n    'loss_type': 'CE',              \n\n    # === Save model to Kaggle working directory ===\n    'checkpoint_dir': '/kaggle/working/',   \n    'save_best': True,                      \n}\n\n# === Khởi tạo config ===\nconfig = Config(model='SASRec', dataset='recbox_data', config_dict=parameter_dict)\n\n# === Khởi tạo random seed và logger ===\ninit_seed(config['seed'], config['reproducibility'])\ninit_logger(config)\nlogger = getLogger()\n\n# === Tạo handler để log ra màn hình ===\nc_handler = logging.StreamHandler()\nc_handler.setLevel(logging.INFO)\nlogger.addHandler(c_handler)\n\n# === In config để kiểm tra ===\nlogger.info(config)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-09T19:01:40.510062Z","iopub.execute_input":"2026-01-09T19:01:40.510742Z","iopub.status.idle":"2026-01-09T19:01:42.153225Z","shell.execute_reply.started":"2026-01-09T19:01:40.510712Z","shell.execute_reply":"2026-01-09T19:01:42.152445Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataset = create_dataset(config)\nlogger.info(dataset)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-09T19:02:17.529551Z","iopub.execute_input":"2026-01-09T19:02:17.52983Z","iopub.status.idle":"2026-01-09T19:04:49.181027Z","shell.execute_reply.started":"2026-01-09T19:02:17.529811Z","shell.execute_reply":"2026-01-09T19:04:49.18016Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tách dữ liệu\ntrain_data, valid_data, test_data = data_preparation(config, dataset)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-09T19:04:49.182289Z","iopub.execute_input":"2026-01-09T19:04:49.182547Z","iopub.status.idle":"2026-01-09T19:07:35.094182Z","shell.execute_reply.started":"2026-01-09T19:04:49.182529Z","shell.execute_reply":"2026-01-09T19:07:35.093411Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = SASRec(config, train_data.dataset).to(config['device'])\nlogger.info(model)\n\ntrainer = Trainer(config, model)\n\nbest_valid_score, best_valid_result = trainer.fit(train_data, valid_data)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-09T19:08:02.863025Z","iopub.execute_input":"2026-01-09T19:08:02.86331Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"del trainer, train_data, valid_data, test_data","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-28T00:41:51.459923Z","iopub.execute_input":"2025-11-28T00:41:51.460816Z","iopub.status.idle":"2025-11-28T00:41:51.465099Z","shell.execute_reply.started":"2025-11-28T00:41:51.460795Z","shell.execute_reply":"2025-11-28T00:41:51.464601Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"gc.collect()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-28T00:41:51.466588Z","iopub.execute_input":"2025-11-28T00:41:51.466768Z","iopub.status.idle":"2025-11-28T00:41:52.471381Z","shell.execute_reply.started":"2025-11-28T00:41:51.466753Z","shell.execute_reply":"2025-11-28T00:41:52.470708Z"}},"outputs":[],"execution_count":null}]}