angusfung's picture
Initial setup with Longformer embedding feature
7812756
raw
history blame contribute delete
5.33 kB
import torch
import torch.nn as nn
import torch.nn.functional as F
from typing import Dict, Tuple
class KickstarterModel(nn.Module):
"""Kickstarter Project Success Prediction Model"""
def __init__(
self,
desc_embedding_dim=768,
blurb_embedding_dim=384,
risk_embedding_dim=384,
subcategory_embedding_dim=100,
category_embedding_dim=15,
country_embedding_dim=100,
numerical_features_dim=9,
hidden_dim=512,
dropout_rate=0.3
):
"""
Initialize the model
Args:
desc_embedding_dim: Description embedding vector dimension
blurb_embedding_dim: Blurb embedding vector dimension
risk_embedding_dim: Risk embedding vector dimension
subcategory_embedding_dim: Subcategory embedding vector dimension
category_embedding_dim: Category embedding vector dimension
country_embedding_dim: Country embedding vector dimension
numerical_features_dim: Numerical features dimension
hidden_dim: Hidden layer dimension
dropout_rate: Dropout rate
"""
super(KickstarterModel, self).__init__()
# Helper function to create feature processing layers
def create_fc_block(input_dim, output_dim):
return nn.Sequential(
nn.Linear(input_dim, output_dim),
nn.BatchNorm1d(output_dim),
nn.ReLU(),
nn.Dropout(dropout_rate)
)
# Feature processing layers
self.desc_fc = create_fc_block(desc_embedding_dim, hidden_dim)
self.blurb_fc = create_fc_block(blurb_embedding_dim, hidden_dim // 2)
self.risk_fc = create_fc_block(risk_embedding_dim, hidden_dim // 2)
self.subcategory_fc = create_fc_block(subcategory_embedding_dim, hidden_dim // 4)
self.category_fc = create_fc_block(category_embedding_dim, hidden_dim // 8)
self.country_fc = create_fc_block(country_embedding_dim, hidden_dim // 8)
self.numerical_fc = create_fc_block(numerical_features_dim, hidden_dim // 4)
# Combined features dimension
concat_dim = (hidden_dim +
hidden_dim // 2 +
hidden_dim // 2 +
hidden_dim // 4 +
hidden_dim // 8 +
hidden_dim // 8 +
hidden_dim // 4)
# Fully connected layers
self.fc1 = create_fc_block(concat_dim, hidden_dim)
self.fc2 = create_fc_block(hidden_dim, hidden_dim // 2)
# Output layer
self.output = nn.Linear(hidden_dim // 2, 1)
# Input names for SHAP explanation
self.input_names = [
'description_embedding',
'blurb_embedding',
'risk_embedding',
'subcategory_embedding',
'category_embedding',
'country_embedding',
'numerical_features'
]
def forward(self, inputs: Dict[str, torch.Tensor]) -> Tuple[torch.Tensor, Dict[str, torch.Tensor]]:
"""
Forward propagation
Args:
inputs: Dictionary containing all input features
Returns:
Prediction probability and intermediate feature representations
"""
# Process embeddings
desc_out = self.desc_fc(inputs['description_embedding'])
blurb_out = self.blurb_fc(inputs['blurb_embedding'])
risk_out = self.risk_fc(inputs['risk_embedding'])
subcategory_out = self.subcategory_fc(inputs['subcategory_embedding'])
category_out = self.category_fc(inputs['category_embedding'])
country_out = self.country_fc(inputs['country_embedding'])
numerical_out = self.numerical_fc(inputs['numerical_features'])
# Concatenate all features
combined = torch.cat([
desc_out,
blurb_out,
risk_out,
subcategory_out,
category_out,
country_out,
numerical_out
], dim=1)
# Fully connected layers
x = self.fc1(combined)
x = self.fc2(x)
# Output layer
logits = self.output(x)
probs = torch.sigmoid(logits)
# Store intermediate features for SHAP explanation
intermediate_features = {
'description_embedding': desc_out,
'blurb_embedding': blurb_out,
'risk_embedding': risk_out,
'subcategory_embedding': subcategory_out,
'category_embedding': category_out,
'country_embedding': country_out,
'numerical_features': numerical_out,
'combined': combined,
'fc1': x
}
return probs.squeeze(1), intermediate_features
def predict(self, inputs: Dict[str, torch.Tensor]) -> torch.Tensor:
"""
Prediction function
Args:
inputs: Dictionary containing all input features
Returns:
Prediction probability
"""
self.eval()
with torch.no_grad():
probs, _ = self.forward(inputs)
return probs