| import torch |
| import torch.nn as nn |
| import torch.optim as optim |
| import numpy as np |
|
|
| class TabTransformer(nn.Module): |
| def __init__(self, categorical_cardinalities, num_continuous, embed_dim=32, num_heads=4, num_transformer_layers=2, hidden_dim=128, output_dim=1, dropout=0.3): |
| super(TabTransformer, self).__init__() |
|
|
| |
| self.embeddings = nn.ModuleList([ |
| nn.Embedding(num_categories, embed_dim) for num_categories in categorical_cardinalities |
| ]) |
| |
| self.num_categorical = len(categorical_cardinalities) |
| self.embed_dim = embed_dim |
|
|
| |
| encoder_layers = nn.TransformerEncoderLayer( |
| d_model=embed_dim, |
| nhead=num_heads, |
| dim_feedforward=hidden_dim, |
| activation="relu", |
| dropout=dropout, |
| batch_first=True |
| ) |
| self.transformer_encoder = nn.TransformerEncoder(encoder_layers, num_layers=num_transformer_layers) |
|
|
| |
| self.numeric_projection = nn.Linear(num_continuous, embed_dim) if num_continuous > 0 else None |
|
|
| |
| self.fc = nn.Sequential( |
| nn.Linear(self.num_categorical * embed_dim + (embed_dim if num_continuous > 0 else 0), hidden_dim), |
| nn.ReLU(), |
| nn.Dropout(dropout), |
| nn.Linear(hidden_dim, output_dim) |
| ) |
|
|
| def forward(self, x_categorical, x_numerical): |
| |
| categorical_embeds = [embed(x_categorical[:, i]) for i, embed in enumerate(self.embeddings)] |
| categorical_embeds = torch.stack(categorical_embeds, dim=1) |
| |
| |
| categorical_features = self.transformer_encoder(categorical_embeds) |
| categorical_features = categorical_features.flatten(start_dim=1) |
|
|
| |
| if self.numeric_projection: |
| numerical_features = self.numeric_projection(x_numerical) |
| else: |
| numerical_features = torch.zeros((x_categorical.shape[0], 0), device=x_categorical.device) |
|
|
| |
| features = torch.cat([categorical_features, numerical_features], dim=1) |
|
|
| |
| output = self.fc(features) |
| return output |
|
|