{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Hi, This is my first step into Image classification. Hope this notebook helps for any beginner like me. Please use the dataset from here. \nhttps://www.kaggle.com/cdeotte/jpeg-melanoma-384x384?select=train  \n\nI have managed to reach LB : 0.925. I have few more ideas that will push LB to atleast 0.935 / 0.94 without tabular data.\n\nToDos :\n1. Use 512x512 data for ensembling\n2. Use EfficientNet \n3. Hair removal from images : There is already an existing implementation for the same\n4. As many have suggested that external data reduces the LB score, however that can be used as an ensembling technique to improve score. Or better way analyse the malignant images and take the ones with which you feel confident (costs time). \n4. Think more ....\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"from tqdm.autonotebook import tqdm\nfrom sklearn.metrics import confusion_matrix\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset,DataLoader\nfrom torch.utils.data.sampler import SequentialSampler, RandomSampler\nfrom torchvision import transforms\nimport numpy as np\nimport albumentations as A\nfrom albumentations.pytorch.transforms import ToTensorV2\nimport cv2\nimport torchvision.transforms as T\nimport torch.nn.functional as F\nfrom PIL import Image, ImageEnhance, ImageFilter\nimport sys\nimport os\nfrom torch.optim.lr_scheduler import  StepLR\nfrom sklearn.model_selection import train_test_split\nimport torchvision.models as model;from sklearn.metrics import roc_auc_score,accuracy_score\nimport matplotlib.pyplot as plt\nimport pretrainedmodels\nimport efficientnet_pytorch\nimport cv2\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","collapsed":true,"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":false},"cell_type":"code","source":"DIR_INPUT = '../input/siim-isic-melanoma-classification/jpeg'\nDIR_TRAIN = f'{DIR_INPUT}/train'\nDIR_TEST = f'{DIR_INPUT}/test'\nFILE_CSV = '../input/siim-isic-melanoma-classification/train.csv'\nTEST_CSV = '../input/siim-isic-melanoma-classification/test.csv'\nSUBMISSION_CSV = '../input/siim-isic-melanoma-classification/sample_submission.csv'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def color_constancy(img, power=6, gamma=None):\n    img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)\n    img_dtype = img.dtype\n\n    if gamma is not None:\n        img = img.astype('uint8')\n        look_up_table = np.ones((256,1), dtype='uint8') * 0\n        for i in range(256):\n            look_up_table[i][0] = 255*pow(i/255, 1/gamma)\n        img = cv2.LUT(img, look_up_table)\n\n    img = img.astype('float32')\n    img_power = np.power(img, power)\n    rgb_vec = np.power(np.mean(img_power, (0,1)), 1/power)\n    rgb_norm = np.sqrt(np.sum(np.power(rgb_vec, 2.0)))\n    rgb_vec = rgb_vec/rgb_norm\n    rgb_vec = 1/(rgb_vec*np.sqrt(3))\n    img = np.multiply(img, rgb_vec)\n\n    img = cv2.cvtColor(np.array(img), cv2.COLOR_BGR2RGB)\n    return img.astype(img_dtype)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def split_data_v1(path,fold,random_state=42):\n    df = pd.read_csv(path) \n    df = df.sort_values('target') \n    df = df.reset_index(drop=True)\n    batch_ls = np.array([[0,2000],[2000,4000],[4000,6000],[6000,8000],[8000,10000],[10000,12000],[12000,14000],\n                        [14000,16000],[16000,18000],[18000,20000],[20000,22000],[22000,24000],[24000,26000],\n                        [26000,28000],[28000,30000],[30000,32540]])\n    v1 = 583\n    df_ls = []\n    for i in range(batch_ls.shape[0]):\n        temp = pd.concat([df[batch_ls[i][0]:batch_ls[i][1]].reset_index(drop=True),df[-v1:].reset_index(drop=True)], ignore_index=True)\n        df_ls.append(temp)\n    X = df_ls[fold].pop('image_name')\n    Y = df_ls[fold].pop('target')\n    X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=random_state)\n    return X_train, X_test, y_train, y_test","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class SEResnext50_32x4d(nn.Module):\n    def __init__(self, pretrained='imagenet'):\n        super(SEResnext50_32x4d, self).__init__()\n        \n        self.base_model = pretrainedmodels.__dict__[\n            \"se_resnext50_32x4d\"\n        ](pretrained=None)\n        if pretrained is not None:\n            self.base_model.load_state_dict(\n                torch.load(\n                    '../input/se-resnext-weight/se_resnext50_32x4d-a260b3a4.pth'\n            )\n        #self.l0 = nn.Linear(2048, 1)\n        self.l0 = nn.Sequential(nn.Linear(2048, 32),nn.Dropout(0.05),nn.ReLU(),nn.Linear(32,1))\n    def forward(self, image):\n        batch_size, _, _, _ = image.shape\n        \n        x = self.base_model.features(image)\n        x = F.adaptive_avg_pool2d(x, 1).reshape(batch_size, -1)\n        out = self.l0(x)\n        return out","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class MelanomaDataSet(torch.utils.data.Dataset):\n    def __init__(self,image_path,targets,mode):\n        self.image_path = image_path\n        self.targets = targets\n        self.mode = mode\n        \n        self.aug = A.Compose({\n        A.Cutout(num_holes=8, max_h_size=8, max_w_size=8, fill_value=0, p=0.5),\n        \n        A.HorizontalFlip(p=0.5),\n        A.Rotate(limit=(-20, 20)),\n        A.VerticalFlip(p=0.5),\n        A.augmentations.transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), max_pixel_value=255.0, always_apply=False, p=1.0),              \n        })\n        self.aug1 = A.Compose({\n        A.HorizontalFlip(p=0.5),\n        A.Rotate(limit=(-20, 20)),\n        A.VerticalFlip(p=0.5),    \n        A.augmentations.transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), max_pixel_value=255.0, always_apply=False, p=1.0),             \n        })\n    def __len__(self):\n        return len(self.image_path)\n    \n    def __getitem__(self, item):\n        image = self.image_path[item]\n        targets = self.targets[item]\n        \n        if self.mode == 'test':\n            image = DIR_TEST+'/'+image+'.jpg'\n        else:\n            image = DIR_TRAIN+'/'+image+'.jpg'\n        \n        img = plt.imread(image)\n        img = Image.fromarray(img).convert('RGB')\n        img = color_constancy(img)\n        if(self.mode == 'train' or self.mode=='validation'):\n            img = self.aug(image=np.array(img))['image']\n            img = np.transpose(img, (2,0,1))\n        else:\n            img = self.aug1(image=np.array(img))['image']\n            img = np.transpose(img, (2,0,1))\n        return torch.tensor(img,dtype=torch.float32), torch.tensor(targets,dtype=torch.float32)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def run_fold(fold,LR,EPOCHS=10,bs=256):\n    train_images, test_images, train_targets, test_targets = split_data_v1(FILE_CSV,fold)\n    class_sample_count = np.array([len(np.where(train_targets==t)[0]) for t in np.unique(train_targets)])\n    print(class_sample_count)\n    weight = 1. / class_sample_count\n    print(weight)\n    samples_weight = np.array([weight[t] for t in train_targets])\n\n    samples_weight = torch.from_numpy(samples_weight)\n\n    sampler = torch.utils.data.WeightedRandomSampler(samples_weight.type('torch.DoubleTensor'), len(samples_weight))\n\n    \n    train_dataset = MelanomaDataSet(train_images.values, train_targets.values, 'train')\n    valid_dataset = MelanomaDataSet(test_images.values, test_targets.values, 'validation')\n    \n    train_data_loader = DataLoader(\n    train_dataset,\n    sampler=sampler,\n    batch_size=bs,\n    num_workers=0\n    )\n\n    valid_data_loader = DataLoader(\n    valid_dataset,\n    batch_size=bs,\n    shuffle=False,\n    num_workers=0\n    )\n    \n    device = torch.device('cuda')\n    model = SEResnext50_32x4d()\n    fold_val = fold\n    if(os.path.isfile(f'melanoma_best___{fold_val}_384.pth')):\n        model.load_state_dict(torch.load(f'melanoma_best___{fold_val}_384.pth'))\n        print('Loaded ',f'melanoma_best___{fold_val}_384.pth')\n    model = model.to(device)\n    criterion = nn.BCEWithLogitsLoss()\n    optimizer = torch.optim.AdamW(model.parameters(), lr=LR)\n    best_score = 0\n    for epoch in range(EPOCHS):\n        print('Epoch:', epoch)\n        loss_arr = []\n        model.train()\n        for images, labels in tqdm(train_data_loader):\n            images, labels = images.to(device), labels.to(device)\n            optimizer.zero_grad()\n            output = model(images)\n            loss = criterion(output, labels.unsqueeze(1))\n            loss.backward()\n            optimizer.step()\n            loss_arr.append(loss.item())\n            del images, labels\n        print('-'*50)\n        print(\"epoch = {},   loss = {}\".format(epoch, sum(loss_arr)/len(loss_arr)))\n        print('-'*50)\n        model.eval()\n        final_predictions = []\n        for val_images, val_labels in tqdm(valid_data_loader):\n            val_images, val_labels = val_images.to(device), val_labels.to(device)\n            with torch.no_grad():\n                val_output = model(val_images)\n                val_output = torch.sigmoid(val_output)\n                pred = val_output.cpu()\n                final_predictions.append(pred)\n                del val_images, val_labels\n            \n        predictions = np.vstack(final_predictions).ravel()\n        k = roc_auc_score(test_targets, predictions)\n        print('CM : ',confusion_matrix(test_targets, np.round(predictions)))\n        \n        print('-'*50)\n        print('AUC Score = {}'.format(k))\n        print('-'*50)\n        if(k > best_score):\n            best_score = k\n            print('Best model found for Fold {} in Epoch {}........Saving Model'.format(fold,epoch+1))\n            torch.save(model.state_dict(), f'melanoma_best___{fold}_384.pth')\n    return model\ndef eval_test(test_path,test_csv,submission_csv,fname,bs=128,TTA_COUNT=2,fold=0):\n    model = SEResnext50_32x4d()\n    device = torch.device('cuda')\n    if(os.path.isfile(f'melanoma_best___{fold}_384.pth')):\n        model.load_state_dict(torch.load(f'melanoma_best___{fold}_384.pth'))\n        model = model.to(device)\n        print('Loaded ',f'melanoma_best___{fold}_384.pth')\n    else:\n        print('Error!! Model not found')\n    \n    ls_sample = []\n    for i in range(TTA_COUNT):\n        \n        df = pd.read_csv(test_csv)\n        targets = np.zeros(len(df))\n        print(df.image_name.values)\n        test_dataset = MelanomaDataSet(df.image_name.values, targets, 'test')\n        test_loader = DataLoader(\n        test_dataset,\n        batch_size=bs,\n        shuffle=False,\n        num_workers=0\n        )\n        model.eval()\n        final_predictions = []\n        for test_data in test_loader:\n            test_images,test_labels = test_data\n            test_images = test_images.to(device)\n            with torch.no_grad():\n                test_output = model(test_images)\n                test_output = torch.sigmoid(test_output)\n                pred = test_output.cpu()\n                final_predictions.append(pred)\n                del test_images,test_data\n        predictions = np.vstack(final_predictions).ravel()\n        sample = pd.read_csv(submission_csv)\n        sample.loc[:, \"target\"] = predictions\n        ls_sample.append(sample)\n        #sample.to_csv(fname, index=False)\n    return ls_sample","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"splits=16\nlr = 0.000002\nbs = 2\nep = 3\nls_model = []\nls_sample = []\nfor i in range(splits):\n    print(f'Modeling split : {i}')\n    ls_model.append(run_fold(i,lr,ep,bs))\n\nfor i in range(splits):\n    print(f'Evaluating split : {i}')\n    ls_sample.append(eval_test(DIR_TEST,TEST_CSV,SUBMISSION_CSV,f'sample_{i}.csv',bs=bs,fold=i))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Average the predictions from different fold and submit the result.\nHope it helps!!","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"pred = []\nfor i in range(splits):\n    pred.append((ls_sample[i][0].target.values + ls_sample[i][1].target.values) / 2.0) \n#####\n#Average out all pred and submit the csv","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}