Kaggle competition: Restaurant Revenue Prediction
!pip install /kaggle/input/iterative-stratification/iterative-stratification-master/ 
<set_options>
%matplotlib inline
SEED_VALUE = 42
def seed_everything(seed=42):
random.seed(seed)
 os.environ['PYTHONHASHSEED'] = str(seed)
 np.random.seed(seed)
 torch.manual_seed(seed)
 torch.cuda.manual_seed(seed)
 torch.backends.cudnn.deterministic = True
seed_everything(seed=SEED_VALUE )<define_variables>
train = pd.read_csv('/kaggle/input/restaurant-revenue-prediction/train.csv')
 test = pd.read_csv('/kaggle/input/restaurant-revenue-prediction/test.csv' )
MDL_NAME = 'trans_learn_drop_zero_target'
MDL_DIR = '.. /input/pytorch-transfer-learn-dropping-zero-targets'<load_from_csv>
train['Open Date'] = pd.to_datetime(train['Open Date'])
 test['Open Date'] = pd.to_datetime(test['Open Date'] )
data_dir = '.. /input/lish-moa/'
train_features = pd.read_csv(data_dir + 'train_features.csv')
 train_targets_scored = pd.read_csv(data_dir + 'train_targets_scored.csv')
 train_targets_nonscored = pd.read_csv(data_dir + 'train_targets_nonscored.csv')
 train_drug = pd.read_csv(data_dir + 'train_drug.csv')
 test_features = pd.read_csv(data_dir + 'test_features.csv')
 sample_submission = pd.read_csv(data_dir + 'sample_submission.csv')
 print('train_features: {}'.format(train_features.shape))
print('train_targets_scored: {}'.format(train_targets_scored.shape))
print('train_targets_nonscored: {}'.format(train_targets_nonscored.shape))
print('train_drug: {}'.format(train_drug.shape))
print('test_features: {}'.format(test_features.shape))
print('sample_submission: {}'.format(sample_submission.shape))<drop_column>
test.columns[test.isna().any() ].tolist()
tmp = train_targets_nonscored.iloc[:, 1:].sum()
drop_cols = list(tmp[tmp==0].index)
 train_targets_nonscored.drop(drop_cols, axis=1, inplace=True)
 print(f'{len(drop_cols)} targets are dropped' )<define_variables>
train[train['revenue'] > 10000000 ]
train_genes = train_features[GENES].copy()
train_cells = train_features[CELLS].copy()
test_genes = test_features[GENES].copy()
test_cells = test_features[CELLS].copy()<categorify>
from sklearn import preprocessing
for col in(GENES + CELLS):
transformer = QuantileTransformer(n_quantiles=100,random_state=0, output_distribution="normal")
 vec_len = len(train_features[col].values)
 vec_len_test = len(test_features[col].values)
 raw_vec = train_features[col].values.reshape(vec_len, 1)
 transformer.fit(raw_vec)
 train_features[col] = transformer.transform(raw_vec ).reshape(1, vec_len)[0]
test_features[col] = transformer.transform(test_features[col].values.reshape(vec_len_test, 1)).reshape(1, vec_len_test)[0]<categorify>
num_train = train.shape[0]
num_test = test.shape[0]
print(num_train, num_test)
 data = pd.concat(( train.loc[:, "Id" : "P37"],
test.loc[:, "Id" : "P37"]), ignore_index=True )
n_comp = 157
pca = PCA(n_components=n_comp, random_state=SEED_VALUE)
 train2 = pca.fit_transform(train_features[GENES])
 test2 = pca.transform(test_features[GENES])
 train2 = pd.DataFrame(train2, columns=[f'pca_G-{i}' for i in range(n_comp)])
 test2 = pd.DataFrame(test2, columns=[f'pca_G-{i}' for i in range(n_comp)])
 train_features = pd.concat(( train_features, train2), axis=1)
 test_features = pd.concat(( test_features, test2), axis=1)
 print('train_features: {}'.format(train_features.shape))
print('test_features: {}'.format(test_features.shape))<categorify>
distinct_cities = train.loc[:, "City"].unique()
means = []
for col in train.columns[5:42]:
temp = []
for city in distinct_cities:
temp.append(train.loc[train.City == city, col].mean())
 means.append(temp)
 city_pvars = pd.DataFrame(columns=["city_var", "means"])
 for i in range(37):
for j in range(len(distinct_cities)) :
city_pvars.loc[i+37*j] = ["P"+str(i+1), means[i][j]]
plt.rcParams['figure.figsize'] =(18.0, 6.0)
 sns.boxplot(x="city_var", y="means", data=city_pvars )
n_comp = 7
pca = PCA(n_components=n_comp, random_state=SEED_VALUE)
 train2 = pca.fit_transform(train_features[CELLS])
 test2 = pca.transform(test_features[CELLS])
 train2 = pd.DataFrame(train2, columns=[f'pca_C-{i}' for i in range(n_comp)])
 test2 = pd.DataFrame(test2, columns=[f'pca_C-{i}' for i in range(n_comp)])
 train_features = pd.concat(( train_features, train2), axis=1)
 test_features = pd.concat(( test_features, test2), axis=1)
 print('train_features: {}'.format(train_features.shape))
print('test_features: {}'.format(test_features.shape))<feature_engineering>
def adjust_cities(data, train, k):
relevant_pvars = ["P1", "P2", "P11", "P19", "P20", "P23", "P30"]
train = train.loc[:, relevant_pvars]
kmeans = cluster.KMeans(n_clusters=k)
 kmeans.fit(train)
 data['City Cluster'] = kmeans.predict(data.loc[:, relevant_pvars])
 del data["City"]
return data
def one_hot_ecoding(data,col,pref):
data = data.join(pd.get_dummies(data[col], prefix=pref))
data = data.drop([col], axis=1)
 return data
def fe_stats(train, test):
GENES = [col for col in train.columns if col.startswith('g-')]
CELLS = [col for col in train.columns if col.startswith('c-')]
for df in train, test:
df['g_mean'] = df[GENES].mean(axis = 1)
 df['g_std'] = df[GENES].std(axis = 1)
 df['g_kurt'] = df[GENES].kurtosis(axis = 1)
 df['g_skew'] = df[GENES].skew(axis = 1)
 df['c_mean'] = df[CELLS].mean(axis = 1)
 df['c_std'] = df[CELLS].std(axis = 1)
 df['c_kurt'] = df[CELLS].kurtosis(axis = 1)
 df['c_skew'] = df[CELLS].skew(axis = 1)
 return train, test
train_features, test_features = fe_stats(train_features, test_features )<merge>
data = adjust_cities(data, train, 20)
 data = one_hot_ecoding(data,'City Group',"CG")
 data = one_hot_ecoding(data,'Type',"T" )
train = train_features.merge(train_targets_scored, on='sig_id', how='left')
 train = train.merge(train_targets_nonscored, on='sig_id', how='left')
 train = train.merge(train_drug, on='sig_id', how='left')
 train_genes = train_genes[train['cp_type'] != 'ctl_vehicle'].reset_index(drop=True)
 train_cells = train_cells[train['cp_type'] != 'ctl_vehicle'].reset_index(drop=True)
 test_genes = test_genes[test_features['cp_type'] != 'ctl_vehicle'].reset_index(drop=True)
 test_cells = test_cells[test_features['cp_type'] != 'ctl_vehicle'].reset_index(drop=True)
 train = train[train['cp_type'] != 'ctl_vehicle'].reset_index(drop=True)
 test = test_features[test_features['cp_type'] != 'ctl_vehicle'].reset_index(drop=True)
 train = train.drop('cp_type', axis=1)
 test = test.drop('cp_type', axis=1 )<define_variables>
train_processed = data[:num_train]
test_processed = data[num_train:]
print("Train :",train.shape)
 print("Test:",test.shape )
target_cols = [x for x in train_targets_scored.columns if x != 'sig_id']
aux_target_cols = [x for x in train_targets_nonscored.columns if x != 'sig_id']
all_target_cols = target_cols + aux_target_cols
num_targets = len(target_cols)
 num_aux_targets = len(aux_target_cols)
 num_all_targets = len(all_target_cols)
 print('num_targets: {}'.format(num_targets))
print('num_aux_targets: {}'.format(num_aux_targets))
print('num_all_targets: {}'.format(num_all_targets))<categorify>
train["revenue"] = [np.log(num)for num in train["revenue"]]
len(train["revenue"] )
class MoADataset:
def __init__(self, features, genes, cells, targets):
self.features = features
self.genes = genes
self.cells = cells
self.targets = targets
def __len__(self):
return(self.features.shape[0])
 def __getitem__(self, idx):
dct = {
'x1' : torch.tensor(self.features[idx, :], dtype=torch.float),
'x2' : torch.tensor(self.genes[idx, :], dtype=torch.float),
'x3' : torch.tensor(self.cells[idx, :], dtype=torch.float),
'y' : torch.tensor(self.targets[idx, :], dtype=torch.float)
 }
return dct
class TestDataset:
def __init__(self, features, genes, cells):
self.features = features
self.genes = genes
self.cells = cells
def __len__(self):
return(self.features.shape[0])
 def __getitem__(self, idx):
dct = {
'x1' : torch.tensor(self.features[idx, :], dtype=torch.float),
'x2' : torch.tensor(self.genes[idx, :], dtype=torch.float),
'x3' : torch.tensor(self.cells[idx, :], dtype=torch.float)
 }
return dct<train_model>
train_processed["revenue"] = train["revenue"].values
train = train_processed
test = test_processed
def train_fn(model, optimizer, scheduler, loss_fn, dataloader, device):
model.train()
final_loss = 0
for data in dataloader:
optimizer.zero_grad()
x1, x2, x3, targets = data['x1'].to(device), data['x2'].to(device), \
data['x3'].to(device), data['y'].to(device)
 outputs = model(x1, x2, x3)
 loss = loss_fn(outputs, targets)
 loss.backward()
optimizer.step()
scheduler.step()
final_loss += loss.item()
final_loss /= len(dataloader)
 return final_loss
def valid_fn(model, loss_fn, dataloader, device):
model.eval()
final_loss = 0
valid_preds = []
for data in dataloader:
x1, x2, x3, targets = data['x1'].to(device), data['x2'].to(device), \
data['x3'].to(device), data['y'].to(device)
 outputs = model(x1, x2, x3)
 loss = loss_fn(outputs, targets)
 final_loss += loss.item()
valid_preds.append(outputs.sigmoid().detach().cpu().numpy())
 final_loss /= len(dataloader)
 valid_preds = np.concatenate(valid_preds)
 return final_loss, valid_preds
def inference_fn(model, dataloader, device):
model.eval()
preds = []
for data in dataloader:
x1, x2, x3 = data['x1'].to(device), data['x2'].to(device), data['x3'].to(device)
 with torch.no_grad() :
outputs = model(x1, x2, x3)
 preds.append(outputs.sigmoid().detach().cpu().numpy())
 preds = np.concatenate(preds)
 return preds<normalization>
def prepare_data_frame(dataframe, target):
df = dataframe.copy()
df['Open Date Year'] = df['Open Date'].dt.year
df['Open Date Month'] = df['Open Date'].dt.month
df['Open Date Day'] = df['Open Date'].dt.day
all_diff = []
for date in df["Open Date"]:
diff = dt.now() - date
all_diff.append(int(diff.days/1000))
df['Days_from_open'] = pd.Series(all_diff)
 df = df.drop(['Open Date'], axis=1)
 if target in df.columns:
tar = df[target]
df = df.drop([target], axis=1)
 else:
tar = None
num_vars = df.select_dtypes([np.number] ).columns.tolist()
cat_vars = df.select_dtypes(include='object' ).columns.tolist()
df[cat_vars] = df[cat_vars].apply(preprocessing.LabelEncoder().fit_transform)
 return(df,tar )
class SmoothBCEwLogits(_WeightedLoss):
def __init__(self, weight=None, reduction='mean', smoothing=0.0):
super().__init__(weight=weight, reduction=reduction)
 self.smoothing = smoothing
self.weight = weight
self.reduction = reduction
@staticmethod
def _smooth(targets:torch.Tensor, n_labels:int, smoothing=0.0):
assert 0 <= smoothing < 1
with torch.no_grad() :
targets = targets *(1.0 - smoothing)+ 0.5 * smoothing
return targets
def forward(self, inputs, targets):
targets = SmoothBCEwLogits._smooth(targets, inputs.size(-1),
self.smoothing)
 loss = F.binary_cross_entropy_with_logits(inputs, targets,self.weight)
 if self.reduction == 'sum':
loss = loss.sum()
elif self.reduction == 'mean':
loss = loss.mean()
return loss<choose_model_class>
X_train,y_train = prepare_data_frame(train,'revenue')
 X_test,y_test = prepare_data_frame(test,'revenue' )
class Model(nn.Module):
def __init__(self, num_features, num_genes, num_cells, num_targets):
super(Model, self ).__init__()
self.hidden_size = [1500, 1250, 1000, 750]
self.dropout_value = [0.5, 0.35, 0.3, 0.25]
self.batch_norm1 = nn.BatchNorm1d(num_features)
 self.dense1 = nn.Linear(num_features, self.hidden_size[0])
 self.layer_norm1_2 = nn.LayerNorm(num_genes)
 self.dense1_2 = nn.Linear(num_genes, self.hidden_size[0])
 self.layer_norm1_3 = nn.LayerNorm(num_cells)
 self.dense1_3 = nn.Linear(num_cells, self.hidden_size[0]//2)
 self.batch_norm2 = nn.BatchNorm1d(self.hidden_size[0]*2+self.hidden_size[0]//2)
 self.dropout2 = nn.Dropout(self.dropout_value[0])
 self.dense2 = nn.Linear(self.hidden_size[0]*2+self.hidden_size[0]//2, self.hidden_size[1])
 self.batch_norm3 = nn.BatchNorm1d(self.hidden_size[1])
 self.dropout3 = nn.Dropout(self.dropout_value[1])
 self.dense3 = nn.Linear(self.hidden_size[1], self.hidden_size[2])
 self.batch_norm4 = nn.BatchNorm1d(self.hidden_size[2])
 self.dropout4 = nn.Dropout(self.dropout_value[2])
 self.dense4 = nn.Linear(self.hidden_size[2], self.hidden_size[3])
 self.batch_norm5 = nn.BatchNorm1d(self.hidden_size[3])
 self.dropout5 = nn.Dropout(self.dropout_value[3])
 self.dense5 = nn.utils.weight_norm(nn.Linear(self.hidden_size[3], num_targets))
def forward(self, x1, x2, x3):
x1 = self.batch_norm1(x1)
 x1 = F.leaky_relu(self.dense1(x1))
x2 = self.layer_norm1_2(x2)
 x2 = F.leaky_relu(self.dense1_2(x2))
x3 = self.layer_norm1_3(x3)
 x3 = F.leaky_relu(self.dense1_3(x3))
x = torch.cat(( x1, x2, x3), 1)
 x = self.batch_norm2(x)
 x = self.dropout2(x)
 x = F.leaky_relu(self.dense2(x))
x = self.batch_norm3(x)
 x = self.dropout3(x)
 x = F.leaky_relu(self.dense3(x))
x = self.batch_norm4(x)
 x = self.dropout4(x)
 x = F.leaky_relu(self.dense4(x))
x = self.batch_norm5(x)
 x = self.dropout5(x)
 x = self.dense5(x)
 return x<choose_model_class>
warnings.filterwarnings('ignore' )
class FineTuneScheduler:
def __init__(self, epochs):
self.epochs = epochs
self.epochs_per_step = 0
self.frozen_layers = []
def copy_without_top(self, model, num_features, num_targets, num_targets_new):
self.frozen_layers = []
model_new = Model(num_features, len(GENES), len(CELLS), num_targets)
 model_new.load_state_dict(model.state_dict())
 for name, param in model_new.named_parameters() :
layer_index = name.split('.')[0][-1]
if layer_index == 5:
continue
param.requires_grad = False
if layer_index not in self.frozen_layers:
self.frozen_layers.append(layer_index)
 self.epochs_per_step = self.epochs // len(self.frozen_layers)
 model_new.batch_norm5 = nn.BatchNorm1d(model_new.hidden_size[3])
 model_new.dropout5 = nn.Dropout(model_new.dropout_value[3])
 model_new.dense5 = nn.utils.weight_norm(nn.Linear(model_new.hidden_size[-1], num_targets_new))
model_new.to(DEVICE)
 return model_new
def step(self, epoch, model):
if len(self.frozen_layers)== 0:
return
if epoch % self.epochs_per_step == 0:
last_frozen_index = self.frozen_layers[-1]
for name, param in model.named_parameters() :
layer_index = name.split('.')[0][-1]
if layer_index == last_frozen_index:
param.requires_grad = True
del self.frozen_layers[-1]<categorify>
def get_reg_mse(model,in_parameters):
my_model_1 = model
clf = GridSearchCV(my_model_1, in_parameters, cv=2, scoring='neg_mean_squared_error')
 clf.fit(X_train, y_train)
 print('best_params_',clf.best_params_)
 mae_1 = clf.best_score_ * -1
return mae_1
def process_data(data):
data = pd.get_dummies(data, columns=['cp_time','cp_dose'])
 return data<define_variables>
def baseline_model() :
dim = len(X_train.columns.tolist())
 if not isinstance(dim, int):
return 0
model = tf.keras.Sequential([
layers.Dense(dim, input_dim=dim, kernel_initializer='normal', activation='relu'),
layers.Dense(int(round(dim/2)) , kernel_initializer='normal', activation='relu'),
layers.Dense(int(round(dim/4)) , kernel_initializer='normal', activation='relu'),
layers.Dense(int(round(dim/8)) , kernel_initializer='normal', activation='relu'),
layers.Dense(1, kernel_initializer='normal')
 ])
 model.compile(optimizer='adam',
loss='mse',
metrics=['mse'])
 return model
feature_cols = [c for c in process_data(train ).columns if c not in all_target_cols]
feature_cols = [c for c in feature_cols if c not in ['kfold', 'sig_id', 'drug_id']]
num_features = len(feature_cols)
 num_features<define_variables>
def get_reg_keras_mse(in_parameters):
my_model_1 = tf.keras.wrappers.scikit_learn.KerasRegressor(build_fn=baseline_model, verbose=1)
 reg = GridSearchCV(my_model_1, in_parameters, cv=2, scoring='neg_mean_squared_error')
 X_ktrain = StandardScaler().fit_transform(X_train.values)
 arr = sav_train['rev_save'].values
y_ktrain = StandardScaler().fit_transform(arr[:, np.newaxis])
 reg.fit(X_ktrain, y_train.values)
 print('best_params_',reg.best_params_)
 mse_1 = reg.best_score_ * -1
return mse_1
def df_to_dataset(dataframe, shuffle=True, batch_size=32, target_name='target'):
dataframe = dataframe.copy()
labels = dataframe.pop(target_name)
 ds = tf.data.Dataset.from_tensor_slices(( dict(dataframe), labels))
if shuffle:
ds = ds.shuffle(buffer_size=len(dataframe))
ds = ds.batch(batch_size)
 return ds
def input_fn(features, labels, training=True, batch_size=32):

 dataset = tf.data.Dataset.from_tensor_slices(( dict(features), labels))
if training:
dataset = dataset.shuffle(buffer_size=len(features))
return dataset.batch(batch_size )
DEVICE =('cuda' if torch.cuda.is_available() else 'cpu')
 EPOCHS = 24
BATCH_SIZE = 128
WEIGHT_DECAY = {'ALL_TARGETS': 1e-5, 'SCORED_ONLY': 3e-6}
MAX_LR = {'ALL_TARGETS': 1e-2, 'SCORED_ONLY': 3e-3}
DIV_FACTOR = {'ALL_TARGETS': 1e3, 'SCORED_ONLY': 1e2}
PCT_START = 0.1<choose_model_class>
samp = pd.read_csv('/kaggle/input/restaurant-revenue-prediction/sampleSubmission.csv')
 samp.head()
model = Model(num_features, len(GENES), len(CELLS), num_all_targets)
 model<define_search_model>
def make_cv_folds(train, SEEDS, NFOLDS, DRUG_THRESH):
vc = train.drug_id.value_counts()
vc1 = vc.loc[vc <= DRUG_THRESH].index.sort_values()
vc2 = vc.loc[vc > DRUG_THRESH].index.sort_values()
for seed_id in range(SEEDS):
kfold_col = 'kfold_{}'.format(seed_id)
 dct1 = {}
dct2 = {}
skf = MultilabelStratifiedKFold(n_splits=NFOLDS, shuffle=True, random_state=seed_id)
 tmp = train.groupby('drug_id')[target_cols].mean().loc[vc1]
for fold,(idxT, idxV)in enumerate(skf.split(tmp, tmp[target_cols])) :
dd = {k: fold for k in tmp.index[idxV].values}
dct1.update(dd)
 skf = MultilabelStratifiedKFold(n_splits=NFOLDS, shuffle=True, random_state=seed_id)
 tmp = train.loc[train.drug_id.isin(vc2)].reset_index(drop=True)
 for fold,(idxT, idxV)in enumerate(skf.split(tmp, tmp[target_cols])) :
dd = {k: fold for k in tmp.sig_id[idxV].values}
dct2.update(dd)
 train[kfold_col] = train.drug_id.map(dct1)
 train.loc[train[kfold_col].isna() , kfold_col] = train.loc[train[kfold_col].isna() , 'sig_id'].map(dct2)
 train[kfold_col] = train[kfold_col].astype('int8')
 return train
SEEDS = 7
NFOLDS = 7
DRUG_THRESH = 18
train = make_cv_folds(train, SEEDS, NFOLDS, DRUG_THRESH)
<split>
def run_training(fold_id, seed_id):
seed_everything(seed_id)
 train_ = process_data(train)
 test_ = process_data(test)
 kfold_col = f'kfold_{seed_id}'
trn_idx = train_[train_[kfold_col] != fold_id].index
val_idx = train_[train_[kfold_col] == fold_id].index
train_df = train_[train_[kfold_col] != fold_id].reset_index(drop=True)
 valid_df = train_[train_[kfold_col] == fold_id].reset_index(drop=True)
 train_genes_df = train_genes[train_[kfold_col] != fold_id].reset_index(drop=True)
 valid_genes_df = train_genes[train_[kfold_col] == fold_id].reset_index(drop=True)
 train_cells_df = train_cells[train_[kfold_col] != fold_id].reset_index(drop=True)
 valid_cells_df = train_cells[train_[kfold_col] == fold_id].reset_index(drop=True)
 def train_model(model, tag_name, target_cols_now, fine_tune_scheduler=None):
x_train, y_train = train_df[feature_cols], train_df[target_cols_now]
x_valid, y_valid = valid_df[feature_cols], valid_df[target_cols_now]
train_dataset = MoADataset(x_train.values, train_genes_df.values, train_cells_df.values, y_train.values)
 valid_dataset = MoADataset(x_valid.values, valid_genes_df.values, valid_cells_df.values, y_valid.values)
 trainloader = torch.utils.data.DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)
 validloader = torch.utils.data.DataLoader(valid_dataset, batch_size=BATCH_SIZE, shuffle=False)
 loss_fn = nn.BCEWithLogitsLoss()
loss_tr = SmoothBCEwLogits(smoothing=0.001)
 oof = np.zeros(( len(train), len(target_cols_now)))
 if TRAINING:
optimizer = torch.optim.Adam(model.parameters() , lr=1e-3, weight_decay=WEIGHT_DECAY[tag_name])
 scheduler = optim.lr_scheduler.OneCycleLR(optimizer=optimizer,
steps_per_epoch=len(trainloader),
pct_start=PCT_START,
div_factor=DIV_FACTOR[tag_name],
max_lr=MAX_LR[tag_name],
epochs=EPOCHS)
 best_loss = np.inf
best_epoch = None
for epoch in range(EPOCHS):
if fine_tune_scheduler is not None:
fine_tune_scheduler.step(epoch, model)
 train_loss = train_fn(model, optimizer, scheduler, loss_tr, trainloader, DEVICE)
 valid_loss, valid_preds = valid_fn(model, loss_fn, validloader, DEVICE)
 print(f"SEED: {seed_id}, FOLD: {fold_id}, {tag_name}, EPOCH: {epoch}, train_loss: {train_loss:.6f}, valid_loss: {valid_loss:.6f}")
 if np.isnan(valid_loss):
break
if valid_loss < best_loss:
best_loss = valid_loss
best_epoch = epoch
oof[val_idx] = valid_preds
torch.save(model.state_dict() , f"./{MDL_NAME}_{tag_name}_SEED{seed_id}_FOLD{fold_id}_.pth")
 print(f'
else:
valid_loss, valid_preds = valid_fn(model, loss_fn, validloader, DEVICE)
 oof[val_idx] = valid_preds
print(f'
return oof
if TRAINING:
fine_tune_scheduler = FineTuneScheduler(EPOCHS)
 pretrained_model = Model(num_features, len(GENES), len(CELLS), num_all_targets)
 pretrained_model.to(DEVICE)
 train_model(pretrained_model, 'ALL_TARGETS', all_target_cols)
 pretrained_model = Model(num_features, len(GENES), len(CELLS), num_all_targets)
 pretrained_model.load_state_dict(torch.load(f"./{MDL_NAME}_ALL_TARGETS_SEED{seed_id}_FOLD{fold_id}_.pth"))
pretrained_model.to(DEVICE)
 final_model = fine_tune_scheduler.copy_without_top(pretrained_model, num_features, num_all_targets, num_targets)
 oof = train_model(final_model, 'SCORED_ONLY', target_cols, fine_tune_scheduler)
 model = Model(num_features, len(GENES), len(CELLS), num_targets)
 model.load_state_dict(torch.load(f"./{MDL_NAME}_SCORED_ONLY_SEED{seed_id}_FOLD{fold_id}_.pth"))
model.to(DEVICE)
 else:
model = Model(num_features, len(GENES), len(CELLS), num_targets)
 model.load_state_dict(torch.load(f"{MDL_DIR}/{MDL_NAME}_SCORED_ONLY_SEED{seed_id}_FOLD{fold_id}_.pth"))
model.to(DEVICE)
 oof = train_model(model, 'SCORED_ONLY', target_cols)
 x_test = test_[feature_cols]
testdataset = TestDataset(x_test.values, test_genes.values, test_cells.values)
 testloader = torch.utils.data.DataLoader(testdataset, batch_size=BATCH_SIZE, shuffle=False)
 predictions = np.zeros(( len(test_), num_targets))
predictions = inference_fn(model, testloader, DEVICE)
 return oof, predictions<compute_test_metric>