From ec3b8f9ba2834db407f4520d8cbdfc99f6a3168f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Oct 2025 03:44:37 +0000 Subject: [PATCH 1/5] Initial plan From 99fb31ffbacbfc7d5b07a3a65e592cb95ab9f7d3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Oct 2025 03:50:50 +0000 Subject: [PATCH 2/5] Add Kaggle-ready Jupyter notebook for TabFormer training Co-authored-by: ZhulongNT <191720247+ZhulongNT@users.noreply.github.com> --- tabformer_kaggle_notebook.ipynb | 1064 +++++++++++++++++++++++++++++++ 1 file changed, 1064 insertions(+) create mode 100644 tabformer_kaggle_notebook.ipynb diff --git a/tabformer_kaggle_notebook.ipynb b/tabformer_kaggle_notebook.ipynb new file mode 100644 index 0000000..ed1261a --- /dev/null +++ b/tabformer_kaggle_notebook.ipynb @@ -0,0 +1,1064 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# TabFormer: Tabular BERT for Credit Card Transaction Modeling\n", + "\n", + "This notebook trains a hierarchical BERT model on credit card transaction data using the TabFormer architecture.\n", + "Designed to run in Kaggle environment with GPU acceleration.\n", + "\n", + "## Overview\n", + "- **Model**: Hierarchical Tabular BERT with field-wise cross-entropy\n", + "- **Task**: Masked Language Modeling on transaction sequences\n", + "- **Data**: Synthetic credit card transactions (24M records)\n", + "- **Hardware**: GPU-accelerated training" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Install Required Packages" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Install required packages for Kaggle environment\n", + "!pip install -q torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118\n", + "!pip install -q transformers>=4.30.0 scikit-learn>=1.0.0 pandas>=1.3.0 numpy>=1.21.0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Import Libraries and Setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import random\n", + "import math\n", + "import pickle\n", + "import logging\n", + "from collections import OrderedDict\n", + "from typing import Dict, List, Tuple, Union\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "from tqdm.auto import tqdm\n", + "\n", + "import torch\n", + "import torch.nn as nn\n", + "from torch.utils.data import Dataset\n", + "\n", + "from sklearn.preprocessing import LabelEncoder, MinMaxScaler\n", + "\n", + "from transformers import (\n", + " BertTokenizer,\n", + " BertConfig,\n", + " BertModel,\n", + " BertForMaskedLM,\n", + " PreTrainedModel,\n", + " Trainer,\n", + " TrainingArguments,\n", + " DataCollatorForLanguageModeling\n", + ")\n", + "\n", + "from IPython.display import display, HTML, Markdown\n", + "\n", + "# Setup logging\n", + "logging.basicConfig(\n", + " format=\"%(asctime)s - %(levelname)s - %(name)s - %(message)s\",\n", + " datefmt=\"%m/%d/%Y %H:%M:%S\",\n", + " level=logging.INFO\n", + ")\n", + "logger = logging.getLogger(__name__)\n", + "\n", + "# Display GPU availability\n", + "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n", + "print(f\"\\n{'='*60}\")\n", + "print(f\"Device: {device}\")\n", + "if torch.cuda.is_available():\n", + " print(f\"GPU: {torch.cuda.get_device_name(0)}\")\n", + " print(f\"GPU Memory: {torch.cuda.get_device_properties(0).total_memory / 1024**3:.2f} GB\")\n", + "print(f\"{'='*60}\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Configuration" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Training configuration\n", + "CONFIG = {\n", + " 'seed': 42,\n", + " 'data_root': './data/credit_card/',\n", + " 'data_fname': 'card_transaction.v1',\n", + " 'output_dir': './output',\n", + " 'vocab_dir': './output',\n", + " \n", + " # Model hyperparameters\n", + " 'field_hidden_size': 64, # Reduced for faster training\n", + " 'mlm_prob': 0.15,\n", + " \n", + " # Data parameters\n", + " 'seq_len': 10, # Sequence length (number of transactions)\n", + " 'stride': 5, # Stride for sliding window\n", + " 'num_bins': 10, # Number of bins for quantization\n", + " 'nrows': 100000, # Number of rows to use (None for all data)\n", + " 'user_ids': None, # Filter by user IDs (None for all users)\n", + " \n", + " # Training parameters\n", + " 'num_train_epochs': 3,\n", + " 'batch_size': 32,\n", + " 'save_steps': 500,\n", + " 'logging_steps': 100,\n", + "}\n", + "\n", + "# Create output directory\n", + "os.makedirs(CONFIG['output_dir'], exist_ok=True)\n", + "os.makedirs(CONFIG['vocab_dir'], exist_ok=True)\n", + "\n", + "# Set random seeds for reproducibility\n", + "def set_seed(seed):\n", + " random.seed(seed)\n", + " np.random.seed(seed)\n", + " torch.manual_seed(seed)\n", + " if torch.cuda.is_available():\n", + " torch.cuda.manual_seed_all(seed)\n", + "\n", + "set_seed(CONFIG['seed'])\n", + "\n", + "display(HTML(f\"
Using {CONFIG['nrows']} rows for training
\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Vocabulary Class\n", + "\n", + "Manages the vocabulary for tabular data with field-aware tokenization." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class AttrDict(dict):\n", + " \"\"\"Dictionary that allows attribute-style access\"\"\"\n", + " def __init__(self, *args, **kwargs):\n", + " super(AttrDict, self).__init__(*args, **kwargs)\n", + " self.__dict__ = self\n", + "\n", + "\n", + "class Vocabulary:\n", + " \"\"\"Vocabulary for tabular data with field-aware tokenization\"\"\"\n", + " \n", + " def __init__(self, adap_thres=10000, target_column_name=\"Is Fraud?\"):\n", + " # Special tokens\n", + " self.unk_token = \"[UNK]\"\n", + " self.sep_token = \"[SEP]\"\n", + " self.pad_token = \"[PAD]\"\n", + " self.cls_token = \"[CLS]\"\n", + " self.mask_token = \"[MASK]\"\n", + " self.bos_token = \"[BOS]\"\n", + " self.eos_token = \"[EOS]\"\n", + " \n", + " self.adap_thres = adap_thres\n", + " self.adap_sm_cols = set()\n", + " \n", + " self.target_column_name = target_column_name\n", + " self.special_field_tag = \"SPECIAL\"\n", + " \n", + " self.special_tokens = [self.unk_token, self.sep_token, self.pad_token,\n", + " self.cls_token, self.mask_token, self.bos_token, self.eos_token]\n", + " \n", + " self.token2id = OrderedDict() # {field: {token: [global_id, local_id]}, ...}\n", + " self.id2token = OrderedDict() # {global_id: [token, field, local_id]}\n", + " self.field_keys = OrderedDict()\n", + " self.token2id[self.special_field_tag] = OrderedDict()\n", + " \n", + " self.filename = ''\n", + " \n", + " # Initialize special tokens\n", + " for token in self.special_tokens:\n", + " global_id = len(self.id2token)\n", + " local_id = len(self.token2id[self.special_field_tag])\n", + " self.token2id[self.special_field_tag][token] = [global_id, local_id]\n", + " self.id2token[global_id] = [token, self.special_field_tag, local_id]\n", + " \n", + " def set_field_keys(self, keys):\n", + " \"\"\"Initialize field keys\"\"\"\n", + " for key in keys:\n", + " self.token2id[key] = OrderedDict()\n", + " global_id = len(self.id2token)\n", + " local_id = len(self.token2id[key])\n", + " self.token2id[key][self.sep_token] = [global_id, local_id]\n", + " self.id2token[global_id] = [self.sep_token, key, local_id]\n", + " self.field_keys[key] = global_id\n", + " \n", + " def set_id(self, token, field_name, return_local=False):\n", + " \"\"\"Set token ID for a field\"\"\"\n", + " if token not in self.token2id[field_name]:\n", + " global_id = len(self.id2token)\n", + " local_id = len(self.token2id[field_name])\n", + " self.token2id[field_name][token] = [global_id, local_id]\n", + " self.id2token[global_id] = [token, field_name, local_id]\n", + " else:\n", + " global_id, local_id = self.token2id[field_name][token]\n", + " \n", + " return local_id if return_local else global_id\n", + " \n", + " def get_id(self, token, field_name=\"\", special_token=False, return_local=False):\n", + " \"\"\"Get token ID\"\"\"\n", + " if special_token:\n", + " field_name = self.special_field_tag\n", + " \n", + " if token in self.token2id[field_name]:\n", + " global_id, local_id = self.token2id[field_name][token]\n", + " else:\n", + " raise Exception(f\"Token {token} not found in field: {field_name}\")\n", + " \n", + " return local_id if return_local else global_id\n", + " \n", + " def get_special_tokens(self):\n", + " \"\"\"Return special tokens as AttrDict\"\"\"\n", + " return AttrDict(\n", + " unk_token=self.unk_token,\n", + " sep_token=self.sep_token,\n", + " pad_token=self.pad_token,\n", + " cls_token=self.cls_token,\n", + " mask_token=self.mask_token,\n", + " bos_token=self.bos_token,\n", + " eos_token=self.eos_token\n", + " )\n", + " \n", + " def get_from_local_ids(self, field, local_ids):\n", + " \"\"\"Convert local IDs to global IDs\"\"\"\n", + " return [self.token2id[field][token][0] for token, ids in self.token2id[field].items() if ids[1] in local_ids]\n", + " \n", + " def save_vocab(self, file_name):\n", + " \"\"\"Save vocabulary to file\"\"\"\n", + " self.filename = file_name\n", + " with open(file_name, 'wb') as f:\n", + " pickle.dump(self, f)\n", + " logger.info(f\"Vocabulary saved to {file_name}\")\n", + " \n", + " def __len__(self):\n", + " return len(self.id2token)\n", + "\n", + "print(\"✓ Vocabulary class defined\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Transaction Dataset Class\n", + "\n", + "Processes credit card transaction data into sequences for training." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class TransactionDataset(Dataset):\n", + " \"\"\"Credit card transaction dataset for sequence modeling\"\"\"\n", + " \n", + " def __init__(self,\n", + " mlm=True,\n", + " user_ids=None,\n", + " seq_len=10,\n", + " num_bins=10,\n", + " cached=False,\n", + " root=\"./data/card/\",\n", + " fname=\"card_trans\",\n", + " vocab_dir=\"checkpoints\",\n", + " fextension=\"\",\n", + " nrows=None,\n", + " flatten=False,\n", + " stride=5,\n", + " adap_thres=10**8,\n", + " return_labels=False,\n", + " skip_user=False):\n", + " \n", + " self.root = root\n", + " self.fname = fname\n", + " self.nrows = nrows\n", + " self.fextension = f'_{fextension}' if fextension else ''\n", + " self.cached = cached\n", + " self.user_ids = user_ids\n", + " self.return_labels = return_labels\n", + " self.skip_user = skip_user\n", + " \n", + " self.mlm = mlm\n", + " self.trans_stride = stride\n", + " self.flatten = flatten\n", + " \n", + " self.vocab = Vocabulary(adap_thres)\n", + " self.seq_len = seq_len\n", + " self.encoder_fit = {}\n", + " \n", + " self.trans_table = None\n", + " self.data = []\n", + " self.labels = []\n", + " self.window_label = []\n", + " \n", + " self.ncols = None\n", + " self.num_bins = num_bins\n", + " \n", + " # Process data\n", + " self.encode_data()\n", + " self.init_vocab()\n", + " self.prepare_samples()\n", + " self.save_vocab(vocab_dir)\n", + " \n", + " def __getitem__(self, index):\n", + " if self.flatten:\n", + " return_data = torch.tensor(self.data[index], dtype=torch.long)\n", + " else:\n", + " return_data = torch.tensor(self.data[index], dtype=torch.long).reshape(self.seq_len, -1)\n", + " \n", + " if self.return_labels:\n", + " return_data = (return_data, torch.tensor(self.labels[index], dtype=torch.long))\n", + " \n", + " return return_data\n", + " \n", + " def __len__(self):\n", + " return len(self.data)\n", + " \n", + " def save_vocab(self, vocab_dir):\n", + " \"\"\"Save vocabulary\"\"\"\n", + " file_name = os.path.join(vocab_dir, f'vocab{self.fextension}.nb')\n", + " self.vocab.save_vocab(file_name)\n", + " \n", + " @staticmethod\n", + " def label_fit_transform(column, enc_type=\"label\"):\n", + " \"\"\"Fit and transform column using encoder\"\"\"\n", + " if enc_type == \"label\":\n", + " mfit = LabelEncoder()\n", + " else:\n", + " mfit = MinMaxScaler()\n", + " mfit.fit(column)\n", + " return mfit, mfit.transform(column)\n", + " \n", + " @staticmethod\n", + " def nanNone(x):\n", + " \"\"\"Replace NaN with 'None'\"\"\"\n", + " return x.fillna('None')\n", + " \n", + " @staticmethod\n", + " def nanZero(x):\n", + " \"\"\"Replace NaN with 0\"\"\"\n", + " return x.fillna(0)\n", + " \n", + " @staticmethod\n", + " def fraudEncoder(x):\n", + " \"\"\"Encode fraud labels\"\"\"\n", + " return x.map(lambda val: 1 if val == 'Yes' else 0)\n", + " \n", + " def _quantize(self, inputs, bin_edges):\n", + " \"\"\"Quantize continuous values\"\"\"\n", + " out_tokens = []\n", + " for val in inputs:\n", + " out_tokens.append(np.abs(bin_edges - val).argmin())\n", + " return out_tokens\n", + " \n", + " def encode_data(self):\n", + " \"\"\"Encode transaction data\"\"\"\n", + " data_file = os.path.join(self.root, f\"{self.fname}.csv\")\n", + " \n", + " logger.info(f\"Reading data from {data_file}\")\n", + " data = pd.read_csv(data_file, nrows=self.nrows)\n", + " logger.info(f\"Loaded {len(data)} transactions\")\n", + " \n", + " # Handle NaN values\n", + " data['Errors?'] = self.nanNone(data['Errors?'])\n", + " data['Is Fraud?'] = self.fraudEncoder(data['Is Fraud?'])\n", + " data['Zip'] = self.nanZero(data['Zip'])\n", + " data['Merchant State'] = self.nanNone(data['Merchant State'])\n", + " \n", + " # Remove dollar sign from Amount\n", + " data['Amount'] = data['Amount'].apply(lambda x: float(x.replace('$', '')))\n", + " \n", + " # Encode categorical columns\n", + " cat_cols = ['Merchant Name', 'Merchant City', 'Merchant State', 'Zip', \n", + " 'MCC', 'Errors?', 'Use Chip', 'Year', 'Month', 'Day']\n", + " \n", + " for col in cat_cols:\n", + " self.encoder_fit[col], data[col] = self.label_fit_transform(data[col].astype(str))\n", + " \n", + " # Quantize Amount\n", + " min_val, max_val = data['Amount'].min(), data['Amount'].max()\n", + " bin_edges = np.linspace(min_val, max_val, self.num_bins)\n", + " data['Amount'] = self._quantize(data['Amount'].values, bin_edges)\n", + " \n", + " # Convert Time to numeric\n", + " data['Time'] = data['Time'].apply(lambda x: int(x.split(':')[0]) * 60 + int(x.split(':')[1]))\n", + " self.encoder_fit['Time'], data['Time'] = self.label_fit_transform(data['Time'])\n", + " \n", + " if not self.skip_user:\n", + " self.encoder_fit['User'], data['User'] = self.label_fit_transform(data['User'])\n", + " \n", + " self.encoder_fit['Card'], data['Card'] = self.label_fit_transform(data['Card'])\n", + " \n", + " self.trans_table = data\n", + " logger.info(\"Data encoding completed\")\n", + " \n", + " def init_vocab(self):\n", + " \"\"\"Initialize vocabulary from encoded data\"\"\"\n", + " columns = list(self.trans_table.columns)\n", + " \n", + " # Remove label column\n", + " columns.remove('Is Fraud?')\n", + " \n", + " if self.skip_user:\n", + " columns.remove('User')\n", + " \n", + " self.vocab.set_field_keys(columns)\n", + " \n", + " # Build vocabulary\n", + " for column in tqdm(columns, desc=\"Building vocabulary\"):\n", + " for val in self.trans_table[column].unique():\n", + " token = str(val)\n", + " self.vocab.set_id(token, column)\n", + " \n", + " logger.info(f\"Vocabulary size: {len(self.vocab)}\")\n", + " \n", + " def user_level_data(self):\n", + " \"\"\"Organize data by user\"\"\"\n", + " if self.user_ids:\n", + " user_ids = [int(u) for u in self.user_ids]\n", + " else:\n", + " user_ids = self.trans_table['User'].unique()\n", + " \n", + " user_data = {}\n", + " for user_id in user_ids:\n", + " user_data[user_id] = self.trans_table[self.trans_table['User'] == user_id]\n", + " \n", + " return user_data\n", + " \n", + " def prepare_samples(self):\n", + " \"\"\"Prepare training samples from transactions\"\"\"\n", + " logger.info(\"Preparing samples...\")\n", + " \n", + " columns = list(self.trans_table.columns)\n", + " columns.remove('Is Fraud?')\n", + " if self.skip_user:\n", + " columns.remove('User')\n", + " \n", + " user_data = self.user_level_data()\n", + " \n", + " cls_token = self.vocab.get_id(self.vocab.cls_token, special_token=True)\n", + " sep_token = self.vocab.get_id(self.vocab.sep_token, special_token=True)\n", + " \n", + " for user_id, user_trans in tqdm(user_data.items(), desc=\"Processing users\"):\n", + " user_vocab_ids = []\n", + " user_labels = []\n", + " \n", + " for _, trans in user_trans.iterrows():\n", + " trans_ids = []\n", + " \n", + " if not self.flatten:\n", + " trans_ids.append(cls_token)\n", + " \n", + " for column in columns:\n", + " token = str(trans[column])\n", + " token_id = self.vocab.get_id(token, column)\n", + " trans_ids.append(token_id)\n", + " \n", + " if not self.flatten:\n", + " trans_ids.append(sep_token)\n", + " \n", + " user_vocab_ids.append(trans_ids)\n", + " user_labels.append(trans['Is Fraud?'])\n", + " \n", + " # Create sliding windows\n", + " for idx in range(0, len(user_vocab_ids) - self.seq_len + 1, self.trans_stride):\n", + " ids = user_vocab_ids[idx:(idx + self.seq_len)]\n", + " ids = [item for sublist in ids for item in sublist] # Flatten\n", + " self.data.append(ids)\n", + " \n", + " for jdx in range(0, len(user_labels) - self.seq_len + 1, self.trans_stride):\n", + " ids = user_labels[jdx:(jdx + self.seq_len)]\n", + " self.labels.append(ids)\n", + " \n", + " fraud = 1 if sum(ids) > 0 else 0\n", + " self.window_label.append(fraud)\n", + " \n", + " assert len(self.data) == len(self.labels)\n", + " \n", + " # Calculate ncols (number of columns)\n", + " self.ncols = len(self.vocab.field_keys) - 2 + (1 if self.mlm else 0)\n", + " \n", + " logger.info(f\"Prepared {len(self.data)} samples\")\n", + " logger.info(f\"Number of columns: {self.ncols}\")\n", + "\n", + "print(\"✓ TransactionDataset class defined\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Load and Prepare Data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create dataset\n", + "display(HTML(\"Location: {final_model_path}
\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 15. Training Summary" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display training summary\n", + "print(f\"\\n{'='*60}\")\n", + "print(f\"TRAINING SUMMARY\")\n", + "print(f\"{'='*60}\")\n", + "print(f\"Dataset: Credit Card Transactions\")\n", + "print(f\"Model: Hierarchical TabFormer BERT\")\n", + "print(f\"Training samples: {trainN:,}\")\n", + "print(f\"Validation samples: {valN:,}\")\n", + "print(f\"Epochs: {CONFIG['num_train_epochs']}\")\n", + "print(f\"Batch size: {CONFIG['batch_size']}\")\n", + "print(f\"Field hidden size: {CONFIG['field_hidden_size']}\")\n", + "print(f\"Total parameters: {total_params:,}\")\n", + "print(f\"Device: {device}\")\n", + "print(f\"{'='*60}\\n\")\n", + "\n", + "display(Markdown(\"\"\"\n", + "## Next Steps\n", + "\n", + "1. **Evaluate the model**: Use the trained model for inference on test data\n", + "2. **Fine-tune**: Adjust hyperparameters for better performance\n", + "3. **Deploy**: Export the model for production use\n", + "4. **Analyze**: Examine attention patterns and learned representations\n", + "\"\"\"))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.0" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 662299a5fd8fb6620678e2bef70801b6e0a32af5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Oct 2025 03:52:19 +0000 Subject: [PATCH 3/5] Add comprehensive README for Kaggle notebook usage Co-authored-by: ZhulongNT <191720247+ZhulongNT@users.noreply.github.com> --- KAGGLE_NOTEBOOK_README.md | 193 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 KAGGLE_NOTEBOOK_README.md diff --git a/KAGGLE_NOTEBOOK_README.md b/KAGGLE_NOTEBOOK_README.md new file mode 100644 index 0000000..7454904 --- /dev/null +++ b/KAGGLE_NOTEBOOK_README.md @@ -0,0 +1,193 @@ +# TabFormer Kaggle Notebook Guide + +## Overview + +`tabformer_kaggle_notebook.ipynb` is a self-contained Jupyter notebook that trains a hierarchical TabFormer BERT model on credit card transaction data. It's designed to run in Kaggle's environment with GPU acceleration. + +## Features + +✅ **Single File**: All code merged into one notebook - no external dependencies +✅ **Kaggle Ready**: Installs required packages automatically +✅ **GPU Accelerated**: Uses CUDA when available with FP16 mixed precision +✅ **IPython Display**: Rich output with HTML/Markdown displays +✅ **Well Documented**: Comprehensive comments and explanations +✅ **Production Ready**: Complete pipeline from data loading to model saving + +## What's Included + +The notebook includes all necessary components: + +1. **Package Installation** - Automatically installs PyTorch, Transformers, and dependencies +2. **Vocabulary System** - Field-aware tokenization for tabular data +3. **Dataset Processing** - Credit card transaction encoding and sequence preparation +4. **Model Architecture** - Complete TabFormer BERT implementation: + - Hierarchical field embeddings + - Custom BERT configuration + - Field-wise cross-entropy support +5. **Data Collator** - Masked language modeling for tabular data +6. **Training Pipeline** - Hugging Face Trainer with GPU optimization +7. **Progress Tracking** - Visual feedback with IPython display + +## Quick Start + +### Running in Kaggle + +1. **Upload to Kaggle**: + - Go to [Kaggle Notebooks](https://www.kaggle.com/code) + - Click "New Notebook" → "Upload Notebook" + - Select `tabformer_kaggle_notebook.ipynb` + +2. **Upload Data**: + - Add the credit card dataset as input data + - Place `card_transaction.v1.csv` in `/kaggle/input/credit-card/data/credit_card/` + - Or upload the `transactions.tgz` file and extract it + +3. **Configure GPU**: + - In notebook settings, enable GPU accelerator + - Recommended: GPU P100 or T4 + +4. **Run All Cells**: + - Click "Run All" or run cells sequentially + - Training will start automatically + +### Configuration Options + +Edit the `CONFIG` dictionary in cell 3 to customize: + +```python +CONFIG = { + 'seed': 42, # Random seed for reproducibility + 'field_hidden_size': 64, # Model hidden size (64 for faster, 768 for better quality) + 'seq_len': 10, # Number of transactions per sequence + 'stride': 5, # Sliding window stride + 'nrows': 100000, # Number of data rows (None for all) + 'num_train_epochs': 3, # Training epochs + 'batch_size': 32, # Batch size (adjust based on GPU memory) +} +``` + +## Hardware Requirements + +### Minimum +- **GPU**: Any CUDA-compatible GPU +- **RAM**: 8 GB +- **Storage**: 5 GB + +### Recommended (for faster training) +- **GPU**: NVIDIA P100, V100, or T4 +- **RAM**: 16 GB +- **Storage**: 10 GB + +## Expected Runtime + +With default configuration (`nrows=100000`, `epochs=3`, `batch_size=32`): + +| Hardware | Approximate Time | +|----------|-----------------| +| GPU P100 | ~15-20 minutes | +| GPU T4 | ~20-30 minutes | +| CPU | ~2-3 hours (not recommended) | + +For full dataset (~24M rows): 4-8 hours on GPU + +## Output + +The notebook produces: + +1. **Model Checkpoints**: Saved in `./output/checkpoint-*` +2. **Final Model**: Saved in `./output/final_model/` +3. **Vocabulary**: Saved as `./output/vocab.nb` +4. **Training Logs**: Console output with loss and metrics +5. **Summary Statistics**: Dataset info, model parameters, training config + +## Model Architecture + +**Hierarchical TabFormer BERT**: +- Field-level embeddings for tabular structure +- Multi-head attention across transactions +- Masked language modeling objective +- Field-wise cross-entropy loss + +**Key Differences from Standard BERT**: +- Preserves tabular structure (fields) +- Custom tokenization per column +- Hierarchical attention mechanism + +## Data Format + +The notebook expects credit card transaction CSV with columns: +- `User`, `Card`, `Year`, `Month`, `Day`, `Time` +- `Amount`, `Use Chip`, `Merchant Name`, `Merchant City`, `Merchant State` +- `Zip`, `MCC`, `Errors?`, `Is Fraud?` + +## Troubleshooting + +### Out of Memory Error +- Reduce `batch_size` in CONFIG (try 16 or 8) +- Reduce `field_hidden_size` (try 32) +- Reduce `nrows` to train on less data + +### Slow Training +- Enable GPU in Kaggle notebook settings +- Increase `batch_size` if GPU memory allows +- Reduce `nrows` for faster iteration + +### Data Not Found +- Check data path in CONFIG['data_root'] +- Ensure CSV file exists at the correct location +- Verify file name matches CONFIG['data_fname'] + +### Import Errors +- Restart kernel and run cell 1 (package installation) +- Check internet connectivity for package downloads + +## Advanced Usage + +### Custom Dataset + +To use your own tabular data: + +1. Format CSV with transaction sequences +2. Update `TransactionDataset.encode_data()` for your columns +3. Adjust `CONFIG` parameters for your data size +4. Modify preprocessing in data encoding section + +### Hyperparameter Tuning + +Key parameters to tune: +- `field_hidden_size`: Model capacity (32-768) +- `num_train_epochs`: Training duration (1-10) +- `mlm_prob`: Masking probability (0.10-0.20) +- `batch_size`: Training batch size (8-64) +- `seq_len`: Sequence length (5-20) + +### Export for Inference + +After training, load the model: + +```python +from transformers import BertForMaskedLM + +model = BertForMaskedLM.from_pretrained('./output/final_model/') +``` + +## References + +- **Paper**: [Tabular Transformers for Modeling Multivariate Time Series](http://arxiv.org/abs/2011.01843) +- **Original Repo**: [IBM/TabFormer](https://github.com/IBM/TabFormer) +- **Hugging Face**: [Transformers Documentation](https://huggingface.co/docs/transformers) + +## License + +This notebook follows the same license as the TabFormer repository. + +## Questions? + +For issues or questions: +1. Check the troubleshooting section above +2. Review the inline comments in the notebook +3. Open an issue in the GitHub repository + +--- + +**Note**: This notebook is self-contained and includes all necessary code. You don't need to install or import anything from the repository - just upload the notebook and data to Kaggle! From f759b29ea1e566ff96856facb941f438c7a5b0e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Oct 2025 05:12:34 +0000 Subject: [PATCH 4/5] Fix CUDA version mismatch and add transformers[torch] dependency Co-authored-by: ZhulongNT <191720247+ZhulongNT@users.noreply.github.com> --- KAGGLE_NOTEBOOK_README.md | 2 +- tabformer_kaggle_notebook.ipynb | 23 +++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/KAGGLE_NOTEBOOK_README.md b/KAGGLE_NOTEBOOK_README.md index 7454904..843ccd3 100644 --- a/KAGGLE_NOTEBOOK_README.md +++ b/KAGGLE_NOTEBOOK_README.md @@ -17,7 +17,7 @@ The notebook includes all necessary components: -1. **Package Installation** - Automatically installs PyTorch, Transformers, and dependencies +1. **Package Installation** - Automatically installs PyTorch (CUDA 11.8), Transformers with torch extras, and dependencies 2. **Vocabulary System** - Field-aware tokenization for tabular data 3. **Dataset Processing** - Credit card transaction encoding and sequence preparation 4. **Model Architecture** - Complete TabFormer BERT implementation: diff --git a/tabformer_kaggle_notebook.ipynb b/tabformer_kaggle_notebook.ipynb index ed1261a..a983235 100644 --- a/tabformer_kaggle_notebook.ipynb +++ b/tabformer_kaggle_notebook.ipynb @@ -30,8 +30,11 @@ "outputs": [], "source": [ "# Install required packages for Kaggle environment\n", + "# Install PyTorch with CUDA 11.8 support (all from same index to avoid CUDA version mismatch)\n", "!pip install -q torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118\n", - "!pip install -q transformers>=4.30.0 scikit-learn>=1.0.0 pandas>=1.3.0 numpy>=1.21.0" + "\n", + "# Install transformers with torch extras and other dependencies\n", + "!pip install -q transformers[torch]>=4.30.0 scikit-learn>=1.0.0 pandas>=1.3.0 numpy>=1.21.0" ] }, { @@ -271,7 +274,7 @@ " def __len__(self):\n", " return len(self.id2token)\n", "\n", - "print(\"✓ Vocabulary class defined\")" + "print(\"\u2713 Vocabulary class defined\")" ] }, { @@ -521,7 +524,7 @@ " logger.info(f\"Prepared {len(self.data)} samples\")\n", " logger.info(f\"Number of columns: {self.ncols}\")\n", "\n", - "print(\"✓ TransactionDataset class defined\")" + "print(\"\u2713 TransactionDataset class defined\")" ] }, { @@ -765,7 +768,7 @@ " \n", " return model\n", "\n", - "print(\"✓ TabFormer model architecture defined\")" + "print(\"\u2713 TabFormer model architecture defined\")" ] }, { @@ -884,7 +887,7 @@ " mlm_probability=CONFIG['mlm_prob']\n", ")\n", "\n", - "print(\"✓ Data collator initialized\")" + "print(\"\u2713 Data collator initialized\")" ] }, { @@ -950,7 +953,7 @@ " eval_dataset=eval_dataset,\n", ")\n", "\n", - "print(\"✓ Trainer initialized\")\n", + "print(\"\u2713 Trainer initialized\")\n", "display(HTML(\"Location: {final_model_path}
\"))" + "display(HTML(f\"Location: {final_model_path}
\"))" ] }, { @@ -1061,4 +1064,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file From cb4c9010e2d67df3892c4d3f9e6c04ff4b965525 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Oct 2025 05:33:06 +0000 Subject: [PATCH 5/5] Fix CUDA version conflict by uninstalling packages before reinstall Co-authored-by: ZhulongNT <191720247+ZhulongNT@users.noreply.github.com> --- KAGGLE_NOTEBOOK_README.md | 2 +- tabformer_kaggle_notebook.ipynb | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/KAGGLE_NOTEBOOK_README.md b/KAGGLE_NOTEBOOK_README.md index 843ccd3..0fa0608 100644 --- a/KAGGLE_NOTEBOOK_README.md +++ b/KAGGLE_NOTEBOOK_README.md @@ -17,7 +17,7 @@ The notebook includes all necessary components: -1. **Package Installation** - Automatically installs PyTorch (CUDA 11.8), Transformers with torch extras, and dependencies +1. **Package Installation** - Uninstalls conflicting packages, then installs PyTorch (CUDA 11.8), Transformers with torch extras, and dependencies 2. **Vocabulary System** - Field-aware tokenization for tabular data 3. **Dataset Processing** - Credit card transaction encoding and sequence preparation 4. **Model Architecture** - Complete TabFormer BERT implementation: diff --git a/tabformer_kaggle_notebook.ipynb b/tabformer_kaggle_notebook.ipynb index a983235..4727b3a 100644 --- a/tabformer_kaggle_notebook.ipynb +++ b/tabformer_kaggle_notebook.ipynb @@ -30,11 +30,14 @@ "outputs": [], "source": [ "# Install required packages for Kaggle environment\n", - "# Install PyTorch with CUDA 11.8 support (all from same index to avoid CUDA version mismatch)\n", + "# Uninstall existing torch packages to avoid CUDA version conflicts\n", + "!pip uninstall -y torch torchvision torchaudio\n", + "\n", + "# Install PyTorch with CUDA 11.8 support (all from same index)\n", "!pip install -q torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118\n", "\n", "# Install transformers with torch extras and other dependencies\n", - "!pip install -q transformers[torch]>=4.30.0 scikit-learn>=1.0.0 pandas>=1.3.0 numpy>=1.21.0" + "!pip install -q \"transformers[torch]>=4.30.0\" scikit-learn>=1.0.0 pandas>=1.3.0 numpy>=1.21.0" ] }, {