Open SalvatoreRa opened 11 months ago
Any model can use the CoxPHLoss. The loss will be:
criterion = CoxPHLoss()
loss = criterion(model(X_train[batch]), y_train[batch])
To transform the data, please look at this example: https://github.com/lasso-net/lassonet/blob/master/examples/cox_experiments.py
Thank you for your reply,
If I have understood correctly, for a dataset one should do:
X = np.genfromtxt(path_x, delimiter=",", skip_header=1)
y = np.genfromtxt(path_y, delimiter=",", skip_header=1)
X = preprocessing.StandardScaler().fit(X).transform(X)
For instance, this should work if the dataset is save as the provided data: hnscc
Once done that, you can split in training and test set:
''' X_train, X_test, y_train, y_test = train_test_split( X, y, random_state=random_state, stratify=y[:, 1], test_size=0.20 ) '''
Should I do anything for the data loader? and for the NN architecture (like which should be the last layer)?
For y you should have both a duration and a boolean column for events. For the data loader, just use mini batches. The last layer should just output a real number, so a Linear layer is good.
Thank you,
I have done so:
from pathlib import Path
import numpy as np
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
from lassonet import LassoNetCoxRegressor
from lassonet import plot_path
res_dir = './survival/'
X = np.genfromtxt(res_dir + "hnscc_x.csv", delimiter=",", skip_header=1)
y = np.genfromtxt(res_dir + "hnscc_y.csv", delimiter=",", skip_header=1)
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import TensorDataset, random_split, SubsetRandomSampler, ConcatDataset, Dataset
import pandas as pd
import seaborn as sns
class FCNNC(nn.Module):
def __init__(self, input_size, constraint_size, hidden_size, num_classes):
super(FCNNC, self).__init__()
self.fc1 = nn.Linear(input_size, constraint_size)
self.fc2 = nn.Linear(constraint_size, hidden_size)
self.fc3 = nn.Linear(hidden_size, num_classes)
def forward(self, x):
x = torch.tanh(self.fc1(x))
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
class DataClassifier(Dataset):
def __init__(self, X_train, y_train):
self.X = torch.from_numpy(X_train.astype(np.float32))
self.y = torch.from_numpy(y_train.astype(np.float32))
self.len = self.X.shape[0]
def __getitem__(self, index):
return self.X[index], self.y[index]
def __len__(self):
return self.len
batch_size = 200
X_train, X_test, Y_train, Y_test = train_test_split(X, y, random_state=0)
traindata = DataClassifier(X_train, Y_train)
trainloader = torch.utils.data.DataLoader(traindata, batch_size=batch_size, shuffle=True)
valdata = DataClassifier(X_test,Y_test)
valloader = torch.utils.data.DataLoader(valdata, batch_size=X_test.shape[0], shuffle=False)
n_epochs =1000
%matplotlib inline
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
criterion = CoxPHLoss(method="breslow")
model = FCNNC(X.shape[1],20,20,1)
optimizer = torch.optim.SGD(model.parameters(), lr=0.0001)
loss_stats = {
'train': [],
"val": []
}
for epoch in range(n_epochs):
running_loss = 0.0
train_epoch_acc = 0
for i, data in enumerate(trainloader):
inputs, labels = data
inputs = inputs.to(device)
labels = labels.to(device)
model.to(device)
# set optimizer to zero grad to remove previous epoch gradients
optimizer.zero_grad()
# forward propagation
outputs = model(inputs)
#loss = criterion(outputs, labels)
loss =criterion(model(inputs), labels)
# backward propagation
loss.backward()
# optimize
optimizer.step()
running_loss += loss.item()
with torch.no_grad():
val_epoch_loss = 0
model.eval()
for X_val_batch, y_val_batch in valloader:
X_val_batch = X_val_batch.to(device)
y_val_batch = y_val_batch.to(device)
y_val_pred = model(X_val_batch)
val_loss =criterion(model(X_val_batch), y_val_batch)
val_epoch_loss += val_loss.item()
loss_stats['train'].append(running_loss/len(trainloader))
loss_stats['val'].append(val_epoch_loss/len(valloader))
if epoch % 50 == True:
print(f'Epoch {epoch+0:03}: | Train Loss: {running_loss/len(trainloader):.5f} | Val Loss: {val_epoch_loss/len(valloader):.5f}')
train_val_loss_df = pd.DataFrame.from_dict(loss_stats).reset_index().melt(id_vars=['index']).rename(columns={"index":"epochs"})
# Plot the dataframes
sns.lineplot(data=train_val_loss_df, x = "epochs", y="value", hue="variable").set_title('Train-Val Loss/Epoch')
It worked and loss is diminishing. As last question how you evaluate? How you should use with CI index? do you have some suggestions for evaluation?
This is the most basically implementation of neural network with PyTorch, but I think it could work with any custom network (and it is using the data you provide). Do you want I will organize the script as tutorial? could be useful?
You might want to look at the new Interval models, see the spinet example.
Great work,
I found your approach very interesting and I was trying to generalize it to different pytorch architectures
I wanted to test your approach with custom models and other pytorch model. The idea is to basically take a pytorch model (arbitrary architecture) and test the ability to predict survival.
for example, I wanted to test with a simple pytorch model.
let' s say:
now, to better explain there is below:
What I am trying to understand is, considering this case:
taking this dataset and starting from your example:
this is a simple version of the approach modelling the survival as a simple binary classification approach:
The idea starting from very simple example to transform a model in able to handle censored data
I was highlighting this code from your repository:
Thank you very much
Salvatore