{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "%reload_ext autoreload\n", "%autoreload 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from fastai.conv_learner import *\n", "from fastai.dataset import *\n", "from fastai.models.resnet import vgg_resnet50\n", "\n", "import json" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "torch.cuda.set_device(2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "torch.backends.cudnn.benchmark=True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Data" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "PATH = Path('data/carvana')\n", "MASKS_FN = 'train_masks.csv'\n", "META_FN = 'metadata.csv'\n", "masks_csv = pd.read_csv(PATH/MASKS_FN)\n", "meta_csv = pd.read_csv(PATH/META_FN)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def show_img(im, figsize=None, ax=None, alpha=None):\n", " if not ax: fig,ax = plt.subplots(figsize=figsize)\n", " ax.imshow(im, alpha=alpha)\n", " ax.set_axis_off()\n", " return ax" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "TRAIN_DN = 'train-128'\n", "MASKS_DN = 'train_masks-128'\n", "sz = 128\n", "bs = 64\n", "nw = 16" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "TRAIN_DN = 'train'\n", "MASKS_DN = 'train_masks_png'\n", "sz = 128\n", "bs = 64\n", "nw = 16" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class MatchedFilesDataset(FilesDataset):\n", " def __init__(self, fnames, y, transform, path):\n", " self.y=y\n", " assert(len(fnames)==len(y))\n", " super().__init__(fnames, transform, path)\n", " def get_y(self, i): return open_image(os.path.join(self.path, self.y[i]))\n", " def get_c(self): return 0" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x_names = np.array([Path(TRAIN_DN)/o for o in masks_csv['img']])\n", "y_names = np.array([Path(MASKS_DN)/f'{o[:-4]}_mask.png' for o in masks_csv['img']])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "val_idxs = list(range(1008))\n", "((val_x,trn_x),(val_y,trn_y)) = split_by_idx(val_idxs, x_names, y_names)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "aug_tfms = [RandomRotate(4, tfm_y=TfmType.CLASS),\n", " RandomFlip(tfm_y=TfmType.CLASS),\n", " RandomLighting(0.05, 0.05, tfm_y=TfmType.CLASS)]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tfms = tfms_from_model(resnet34, sz, crop_type=CropType.NO, tfm_y=TfmType.CLASS, aug_tfms=aug_tfms)\n", "datasets = ImageData.get_ds(MatchedFilesDataset, (trn_x,trn_y), (val_x,val_y), tfms, path=PATH)\n", "md = ImageData(PATH, datasets, bs, num_workers=16, classes=None)\n", "denorm = md.trn_ds.denorm" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x,y = next(iter(md.trn_dl))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(torch.Size([64, 3, 128, 128]), torch.Size([64, 128, 128]))" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.shape,y.shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Simple upsample" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f = resnet34\n", "cut,lr_cut = model_meta[f]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def get_base():\n", " layers = cut_model(f(True), cut)\n", " return nn.Sequential(*layers)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def dice(pred, targs):\n", " pred = (pred>0).float()\n", " return 2. * (pred*targs).sum() / (pred+targs).sum()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class StdUpsample(nn.Module):\n", " def __init__(self, nin, nout):\n", " super().__init__()\n", " self.conv = nn.ConvTranspose2d(nin, nout, 2, stride=2)\n", " self.bn = nn.BatchNorm2d(nout)\n", " \n", " def forward(self, x): return self.bn(F.relu(self.conv(x)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Upsample34(nn.Module):\n", " def __init__(self, rn):\n", " super().__init__()\n", " self.rn = rn\n", " self.features = nn.Sequential(\n", " rn, nn.ReLU(),\n", " StdUpsample(512,256),\n", " StdUpsample(256,256),\n", " StdUpsample(256,256),\n", " StdUpsample(256,256),\n", " nn.ConvTranspose2d(256, 1, 2, stride=2))\n", " \n", " def forward(self,x): return self.features(x)[:,0]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class UpsampleModel():\n", " def __init__(self,model,name='upsample'):\n", " self.model,self.name = model,name\n", "\n", " def get_layer_groups(self, precompute):\n", " lgs = list(split_by_idxs(children(self.model.rn), [lr_cut]))\n", " return lgs + [children(self.model.features)[1:]]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m_base = get_base()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m = to_gpu(Upsample34(m_base))\n", "models = UpsampleModel(m)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = ConvLearner(md, models)\n", "learn.opt_fn=optim.Adam\n", "learn.crit=nn.BCEWithLogitsLoss()\n", "learn.metrics=[accuracy_thresh(0.5),dice]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn.freeze_to(1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "e4667e9fa899453da7cbf0a0524fb426", "version_major": 2, "version_minor": 0 }, "text/html": [ "
Failed to display Jupyter Widget of type HBox
.
\n", " If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean\n", " that the widgets JavaScript is still loading. If this message persists, it\n", " likely means that the widgets JavaScript library is either not installed or\n", " not enabled. See the Jupyter\n", " Widgets Documentation for setup instructions.\n", "
\n", "\n", " If you're reading this message in another frontend (for example, a static\n", " rendering on GitHub or NBViewer),\n", " it may mean that your frontend doesn't currently support widgets.\n", "
\n" ], "text/plain": [ "HBox(children=(IntProgress(value=0, description='Epoch', max=1), HTML(value='')))" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " 86%|█████████████████████████████████████████████████████████████ | 55/64 [00:22<00:03, 2.46it/s, loss=3.21]" ] }, { "data": { "image/png": "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\n", "text/plain": [ "