-
Notifications
You must be signed in to change notification settings - Fork 541
Description
❓ Questions and Help
import torch
import torch.nn as nn
import pandas as pd
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.model_selection import train_test_split
class TitanicDNNModel(nn.Module):
def init(self, num_sex, num_embarked, num_pclass, embedding_dim=4):
super(TitanicDNNModel, self).init()
# Embedding layers
self.sex_embedding = nn.Embedding(num_sex, embedding_dim)
self.embarked_embedding = nn.Embedding(num_embarked, embedding_dim)
self.pclass_embedding = nn.Embedding(num_pclass, embedding_dim)
# FC layers
self.fc_input_dim = embedding_dim * 3 + 3 # 3 embedded features + 3 numerical
self.fc1 = nn.Linear(self.fc_input_dim, 64)
self.relu1 = nn.ReLU()
self.fc2 = nn.Linear(64, 32)
self.relu2 = nn.ReLU()
self.fc3 = nn.Linear(32, 2) # Output logits for 2 classes
self.softmax = nn.Softmax(dim=1)
def forward(self, sex, embarked, pclass, age, parch, fare):
# Embed categorical features
sex_emb = self.sex_embedding(sex.long()).view(sex.size(0), -1)
embarked_emb = self.embarked_embedding(embarked.long()).view(embarked.size(0), -1)
pclass_emb = self.pclass_embedding(pclass.long()).view(pclass.size(0), -1)
# Concatenate all features
x = torch.cat([
sex_emb,
embarked_emb,
pclass_emb,
age.unsqueeze(1),
parch.unsqueeze(1),
fare.unsqueeze(1)
], dim=1)
# Forward pass
x = self.relu1(self.fc1(x))
x = self.relu2(self.fc2(x))
return self.softmax(self.fc3(x)) # Return logits
Load and preprocess data
train_df = pd.read_csv("/data/usershare/work/code/FuxiCTR/data/tiny_csv/titanic_train.csv")
features = ['sex', 'embarked', 'pclass', 'age', 'parch', 'fare']
X = train_df[features]
y = train_df['survived']
Encode categorical features
le = LabelEncoder()
X['sex'] = le.fit_transform(X['sex'].fillna('missing'))
X['embarked'] = le.fit_transform(X['embarked'].fillna('missing'))
X['pclass'] = le.fit_transform(X['pclass'].fillna('missing'))
Scale numerical features
scaler = StandardScaler()
num_features = ['age', 'parch', 'fare']
X[num_features] = scaler.fit_transform(X[num_features].fillna(0))
X = X.astype(float)
Split data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
Convert to tensors
def df_to_tensors(df):
return (
torch.tensor(df['sex'].values),
torch.tensor(df['embarked'].values),
torch.tensor(df['pclass'].values, dtype=torch.long),
torch.tensor(df['age'].values, dtype=torch.float32),
torch.tensor(df['parch'].values, dtype=torch.float32),
torch.tensor(df['fare'].values, dtype=torch.float32)
)
X_train_tensors = df_to_tensors(X_train)
X_test_tensors = df_to_tensors(X_test)
y_train_tensor = torch.tensor(y_train.values, dtype=torch.long)
y_test_tensor = torch.tensor(y_test.values, dtype=torch.long)
Initialize model, loss, optimizer
model = TitanicDNNModel(
num_sex=X['sex'].nunique(),
num_embarked=X['embarked'].nunique(),
num_pclass=X['pclass'].nunique()
)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
Training loop
epochs = 100
for epoch in range(epochs):
model.train()
optimizer.zero_grad()
outputs = model(*X_train_tensors)
loss = criterion(outputs, y_train_tensor)
loss.backward()
optimizer.step()
if (epoch + 1) % 10 == 0:
with torch.no_grad():
model.eval()
test_outputs = model(*X_test_tensors)
test_loss = criterion(test_outputs, y_test_tensor)
_, predicted = torch.max(test_outputs, 1)
correct = (predicted == y_test_tensor).sum().item()
accuracy = correct / len(y_test_tensor)
print(f"Epoch [{epoch+1}/{epochs}], "
f"Train Loss: {loss.item():.4f}, "
f"Test Loss: {test_loss.item():.4f}, "
f"Test Acc: {accuracy:.4f}")
from captum.attr import IntegratedGradients
import matplotlib.pyplot as plt
import numpy as np
使用测试集的一个batch进行分析
batch_size = 32
test_indices = torch.randperm(len(X_test_tensors[0]))[:batch_size]
batch_data = [tensor[test_indices] for tensor in X_test_tensors]
def model_forward(sex, embarked, pclass, age, parch, fare):
# 将类别变量从 float 转回 long
sex = sex.long()
embarked = embarked.long()
pclass = pclass.long()
# 数值变量保持 float
age = age.float()
parch = parch.float()
fare = fare.float()
# 调用模型
logits = model(sex, embarked, pclass, age, parch, fare)
return logits
初始化 IntegratedGradients
ig = IntegratedGradients(model_forward)
准备输入数据(确保是 float 类型)
batch_data = [t.float().requires_grad_() for t in batch_data]
计算归因
attr_ig, delta = ig.attribute(
inputs=tuple(batch_data),
target=1,
return_convergence_delta=True
)
how to fix this problem? thanks