<jupyter_start><jupyter_text>Load, join, filter the data<jupyter_code>survival_info = pd.read_csv('/dataSRI/DataSets/BrATS/MICCAI_BraTS2020_TrainingData/survival_info.csv')
survival_info = survival_info.rename(columns={'Brats20ID': 'subj_id'})
with open('split_preprocessing/saved_ids.json', 'r') as f:
    split_data = json.load(f)
data = []
for train_id in split_data['train_ids']:
    data.append({
        'subj_id': train_id,
        'split': 'train',
    })
for val_id in split_data['val_ids']:
    data.append({
        'subj_id': val_id,
        'split': 'val',
    })
split_df = pd.DataFrame(data)
survival_info = survival_info.join(split_df.set_index('subj_id'), on='subj_id')
survival_features = []
survival_feature_files = glob.glob('data/models/unet_resize2/survival_features/result_dataset/survival_features_*.pt')
for fname in survival_feature_files:
    features = torch.load(fname, map_location='cpu')
    survival_features.append({
        'subj_id': features['subj_id'],
        'et_ratio': float(features['et_pred_size'] / features['whole_brain_size']),
        'tc_ratio': float(features['tc_pred_size'] / features['whole_brain_size']),
        'wt_ratio': float(features['wt_pred_size'] / features['whole_brain_size']),
        'et_ratio_gt': float(features['et_gt_size'] / features['whole_brain_size']),
        'tc_ratio_gt': float(features['tc_gt_size'] / features['whole_brain_size']),
        'wt_ratio_gt': float(features['wt_gt_size'] / features['whole_brain_size']),
    })
survival_feature_df = pd.DataFrame(survival_features)
features.keys()
survival_info = survival_info.join(survival_feature_df.set_index('subj_id'), on='subj_id')
# There's only one subject which didn't have an integer for Survival_days
# Not sure what's best, so I just removed this subject
survival_info = survival_info[~survival_info.Survival_days.str.startswith('ALIVE')]
survival_info
survival_info.groupby('split').agg('count')
survival_info.corr().style.background_gradient()<jupyter_output><empty_output><jupyter_text>Train and Evaluate a model<jupyter_code>import torch
import torch.nn as nn
import torch.nn.functional as F
import skorch
import skorch.dataset
from skorch import NeuralNetClassifier, NeuralNetRegressor
from skorch.helper import predefined_split

from sklearn.preprocessing import StandardScaler
import sklearn.metrics as metrics
import scipy.stats
train_mask = (survival_info.split == 'train')
val_mask = (survival_info.split == 'val')
X = np.stack([survival_info.Age, survival_info.et_ratio_gt, survival_info.tc_ratio_gt, survival_info.wt_ratio_gt]).T
X = X.astype(np.float32)
X_train = X[train_mask]
X_val = X[val_mask]
scaler = StandardScaler()
scaler.fit(X_train)
X_train = scaler.transform(X_train)
X_val = scaler.transform(X_val)
y = np.stack([survival_info.Survival_days.map(int)]).T
y = y.astype(np.float32)
y_train = y[train_mask]
y_val = y[val_mask]
num_inputs = X.shape[1]
class LogRMSE(nn.Module):
    def __init__(self):
        super(LogRMSE, self).__init__()
    
    def forward(self, y_pred, y):
        log_pred = torch.log(y_pred + 1)
        log_gt   = torch.log(y + 1)
        return torch.sqrt(torch.pow(log_pred - log_gt, 2).mean(dim=0))
class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        
        self.slope = 0.0
        self.act_f = nn.LeakyReLU(self.slope)
        self.layers = nn.Sequential(
            nn.Linear(num_inputs, 64),
            self.act_f,
            nn.Linear(64, 64),
            self.act_f,
            nn.Linear(64,1),
        )
        self.init()
    
    def init(self):
        for layer in self.layers:
            if isinstance(layer, nn.Linear):
                nn.init.xavier_normal_(layer.weight)
                nn.init.constant_(layer.bias, 500.)
        #nn.init.constant_(self.layers[-1].bias, 500.)
        
    def forward(self, X, **kwargs):
        return self.layers(X)

torch.manual_seed(2)
net = NeuralNetRegressor(
    SimpleModel,
    max_epochs=30,
    criterion=LogRMSE,
    lr=0.0003,
    optimizer=torch.optim.Adam,
    train_split=predefined_split(skorch.dataset.Dataset(X_val, y_val)),
    # Shuffle training data on each epoch
    iterator_train__shuffle=True,
)
net.initialize()
_ = net.fit(X_train, y_train)
train_loss = [h['train_loss'] for h in net.history]
val_loss = [h['valid_loss'] for h in net.history]
epochs = [h['epoch'] for h in net.history]
plt.plot(epochs, train_loss, label='train')
plt.plot(epochs, val_loss, label='val')
plt.legend()
y_train_pred = net.predict(X_train)
y_val_pred = net.predict(X_val)
sns.distplot(convert(y_train_pred))
sns.distplot(convert(y_val_pred))
def convert(days, month_length=30.): 
    months = days / month_length
    classes = np.zeros_like(days, dtype=int)
    # 0 - short term (less than 10 months)
    classes[months < 10.] = 0
    # 1 - mid term (between 10 and 15 months)
    classes[(10. <= months) & (months <= 15.)] = 1
    # 2 - long term (more than 15 months)
    classes[months > 15.] = 2
    return classes
    
def compute_accuracy(pred_days, gt_days):
    # based on the quantization from the BraTS paper (https://arxiv.org/pdf/1811.02629.pdf)
    pred_classes = convert(pred_days)
    gt_classes = convert(gt_days)
    acc = (pred_classes == gt_classes).mean()
    return acc
compute_accuracy(y_train_pred, y_train)
for ytp, pci in zip(y_train, gtc):
    print('{:.2f}, {}'.format(float(ytp) / 30, pci))
for ytp, pci in zip(y_train_pred, pc):
    print(ytp / 30, pci)
SE_train = (y_train_pred - y_train)**2
SE_val = (y_val_pred - y_val)**2

measures = [
{
    'split': 'train',
    'accuracy': compute_accuracy(y_train_pred, y_train),
    'MSE': SE_train.mean(),
    'RMSE': np.sqrt(SE_train.mean()),
    'medianSE': np.median(SE_train),
    'MSLE': metrics.mean_squared_log_error(y_train_pred, y_train),
    'SpearmanR': scipy.stats.spearmanr(y_train_pred, y_train)
},
{
    'split': 'val',
    'accuracy': compute_accuracy(y_val_pred, y_val),
    'MSE': SE_val.mean(),
    'RMSE': np.sqrt(SE_val.mean()),
    'medianSE': np.median(SE_val),
    'MSLE': metrics.mean_squared_log_error(y_val_pred, y_val),
    'SpearmanR': scipy.stats.spearmanr(y_val_pred, y_val)
}, 
]
measures = pd.DataFrame(measures)
measures<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1383878691141261, 'fraction_numerical': 0.013088587390263367, 'mean_word_length': 4.148726376335251, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 10, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '553308', 'license': 'Apache-2.0', 'n_tokens_mistral': 2411, 'n_tokens_neox': 2280, 'n_words': 414, 'path': 'monai_model/survival.ipynb', 'repo_name': 'mcogswellsri/dare_brain_demo', 'size': '6265'}