--- title: Title keywords: fastai sidebar: home_sidebar ---
%reload_ext autoreload
%autoreload 2
%matplotlib inline
from fastai.vision import *
from fastai.tabular import *
from image_tabular.core import *
from image_tabular.dataset import *
from image_tabular.model import *
from image_tabular.metric import *
# use gpu by default if available
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
import warnings
warnings.filterwarnings("ignore", category=UserWarning, module="torch.nn.functional")
data_path = Path("./data/siim-isic-melanoma-classification/")
train_df = pd.read_csv(data_path/"train.csv")
test_df = pd.read_csv(data_path/"test.csv")
print(len(train_df), len(test_df))
train_df.head()
# extremely unbalanced dataset, most of the images are benign
train_df["target"].value_counts(normalize=True)
tfms = get_transforms(flip_vert=True)
size = 128
# idx for validation, shared by image and tabular data
val_idx = get_valid_index(train_df)
len(val_idx)
# load image data using train_df and prepare fastai LabelLists
image_data = (ImageList.from_df(train_df, path=data_path, cols="image_name",
folder="train_128", suffix=".jpg")
.split_by_idx(val_idx)
.label_from_df(cols="target")
.transform(tfms, size=size))
# add test data so that we can make predictions
test_image_data = ImageList.from_df(test_df, path=data_path, cols="image_name",
folder="test_128", suffix=".jpg")
image_data.add_test(test_image_data)
# show one example image
print(image_data.train[0][1])
image_data.train[0][0]
dep_var = 'target'
cat_names = ['sex', 'anatom_site_general_challenge']
cont_names = ['age_approx']
procs = [FillMissing, Categorify, Normalize]
tab_data = (TabularList.from_df(train_df, path=data_path, cat_names=cat_names, cont_names=cont_names, procs=procs)
.split_by_idx(val_idx)
.label_from_df(cols=dep_var))
# add test
tab_data.add_test(TabularList.from_df(test_df, cat_names=cat_names, cont_names=cont_names,
processor = tab_data.train.x.processor))
# one example
tab_data.train[0]
integrate_train, integrate_valid, integrate_test = get_imagetabdatasets(image_data, tab_data)
# package train, valid, and test datasets into a fastai databunch
bs = 64
db = DataBunch.create(integrate_train, integrate_valid, integrate_test,
path=data_path, bs=bs)
db
# image normalization with imagenet_stats
db.norm, db.denorm = normalize_funcs_image_tab(*imagenet_stats)
db.add_tfm(db.norm)
# check the shape of one batch
x, y = next(iter(db.train_dl))
len(x)
# images
x[0].shape
# categorical and continuous tabular data
x[1][0].shape, x[1][1].shape
# targets
y.shape
# cnn model for images, use Resnet50 as an example
cnn_arch = models.resnet50
# cnn_out_sz is the output size of the cnn model that will be concatenated with tabular model output
cnn_out_sz = 256
# use fastai functions to get a cnn model
image_data_db = image_data.databunch()
image_data_db.c = cnn_out_sz
cnn_learn = cnn_learner(image_data_db, cnn_arch, ps=0.2)
cnn_model = cnn_learn.model
# get embedding sizes of categorical data
emb_szs = tab_data.train.get_emb_szs()
# output size of the tabular model that will be concatenated with cnn model output
tab_out_sz = 8
# use fastai functions to get a tabular model
tabular_model = TabularModel(emb_szs, len(cont_names), out_sz=tab_out_sz, layers=[8], ps=0.2)
tabular_model
# get an integrated model that combines the two components and concatenate their outputs
# which will pass through additional fully connected layers
integrate_model = CNNTabularModel(cnn_model,
tabular_model,
layers = [cnn_out_sz + tab_out_sz, 32],
ps=0.2,
out_sz=2).to(device)
# check model output dimension, should be (bs, 2)
integrate_model(*x).shape
# adjust loss function weight because the dataset is extremely unbalanced
weights = [1/(1-train_df["target"].mean()), 1/train_df["target"].mean()]
loss_func = CrossEntropyFlat(weight=torch.FloatTensor(weights).to(device))
# package everything in a fastai learner, add auc roc score as a metric
learn = Learner(db, integrate_model, metrics=[accuracy, ROCAUC()], loss_func=loss_func)
# organize layer groups in order to use differential learning rates provided by fastai
# the first two layer groups are earlier layers of resnet
# the last layer group consists of the fully connected layers of cnn model, tabular model,
# and final fully connected layers for the concatenated data
learn.layer_groups = [nn.Sequential(*flatten_model(cnn_learn.layer_groups[0])),
nn.Sequential(*flatten_model(cnn_learn.layer_groups[1])),
nn.Sequential(*(flatten_model(cnn_learn.layer_groups[2]) +
flatten_model(integrate_model.tabular_model) +
flatten_model(integrate_model.layers)))]
# find learning rate to train the last layer group first
learn.freeze()
learn.lr_find()
learn.recorder.plot()
# train
learn.fit_one_cycle(10, 1e-4)
# unfreeze all layer groups to train the entire model using differential learning rates
learn.unfreeze()
learn.fit_one_cycle(5, slice(1e-6, 1e-4))
The model achieved an ROC AUC score of about 0.87 on the validation set.
# make predictions for the test set
preds, y = learn.get_preds(DatasetType.Test)
# submit predictions to kaggle
submit = pd.read_csv(data_path/"sample_submission.csv")
submit["target"] = preds[:, 1]
submit.to_csv(data_path/"image_tab.csv", index=False)