{"cells":[{"metadata":{},"cell_type":"markdown","source":"# load data and dataset preprocessing\n1. pip tez and put it into sys path\n2. import necessary packages\n3. split train and valid set, then build new image path(because shuffled)\n4. do augmentations to train and valid set using tez\n# build model with resnet18 and train \n5. create model using resnet in pytorch\n6. train the model with small size dataset(in pd.read_csv())\n7. do the same preprocessing for testset(only one image),and predict\n\n**Original Author by Abhishek Thakur, Youtube video here[https://www.youtube.com/watch?v=hBvUrj0FUiw]**"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"#!pip install tez # must with internet access","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"tez_path = \"../input/tez-lib/\"\nimport sys\nsys.path.append(tez_path)\nfor path in sys.path: #search for path\n    print(path)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport albumentations\nimport matplotlib.pyplot as plt\nimport pandas as pd\n\nimport tez\nfrom tez.datasets import ImageDataset\nfrom tez.callbacks import EarlyStopping\n\nimport torch\nimport torch.nn as nn\nimport torchvision\n\nfrom sklearn import metrics, model_selection\n\n%matplotlib inline\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"read the input file: train.csv, for small size dataset to train first"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_map = pd.read_csv(\"../input/cassava-leaf-disease-classification/train.csv\",nrows =2000)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_map.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_map.label.value_counts()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"split the datset"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_set,valid_set = model_selection.train_test_split(\n    train_map,\n    test_size = 0.1,\n    random_state=42,#经验值\n    stratify = train_map.label.values #将数据用作类标签以分层方式拆分\n)\n#When we reset the index, the old index is added as a column, and a new sequential index is used:\n#use drop parameter to avoid the old index being added as a column:\ntrain_set= train_set.reset_index(drop=True)\nvalid_set= valid_set.reset_index(drop=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_set.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"valid_set.shape","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**make new image path**\n* os.path.join(path1[, path2[, ...]]) 把目录和文件名合成一个路径\n* print( os.path.join('root','test','runoob.txt') ) \n* root/test/runoob.txt"},{"metadata":{"trusted":true},"cell_type":"code","source":"image_paths= \"../input/cassava-leaf-disease-classification/train_images/\"\ntrain_image_paths =[\n    os.path.join(image_paths,x) for x in train_set.image_id.values\n]\n\nvalid_image_paths =[\n    os.path.join(image_paths,x) for x in valid_set.image_id.values\n]\ntrain_image_paths[:5]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_targets = train_set.label.values\nvalid_targets = valid_set.label.values","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\"usual steps for image classification, capsuled in tez\n class LeafImageDataset:\n     def __init__(self,image_paths, targets, .........):\n         pass\n     def __len__(self):\n         return len(image_paths)\n     def __getitem__(self,item_index):\n         .\n         .\n         .\n         return{\n             \"image\": torch.tensor(...,dtype = torch.float)\n             \"target\":torch.tensor(......)\n         }\"\"\"\n        ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataset = ImageDataset(\n    image_paths = train_image_paths,\n    targets= train_targets,\n    resize = (256,256),\n    augmentations=None\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataset[1]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_img(img_dict):\n    img_tensor = img_dict[\"image\"]\n    target = img_dict[\"targets\"]\n    print(target)\n    plt.figure(figsize=(5,5))\n    image = img_tensor.permute(1,2,0)/255  # 换维，转置\n    plt.imshow(image) #imshow:(0-1 float or 0-255 int)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_img(train_dataset[10])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"augmentation"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_aug = albumentations.Compose(\n[\n    albumentations.RandomResizedCrop(256,256), #修剪crop\n    albumentations.Transpose(p=0.5), #透明度\n    albumentations.HorizontalFlip(p=0.6),\n    albumentations.VerticalFlip(p=0.6)   \n])\nvalid_aug = albumentations.Compose(\n[\n    albumentations.RandomResizedCrop(256,256,p=1.0), #修剪crop\n    albumentations.Resize(256,256),\n    albumentations.Transpose(p=0.5), #透明度\n    albumentations.HorizontalFlip(p=0.6),\n    albumentations.VerticalFlip(p=0.6)   \n])\n# copy paste from up, no need to resize because of argumentation\ntrain_dataset = ImageDataset(\n    image_paths = train_image_paths,\n    targets= train_targets,\n    resize = None,\n    augmentations=train_aug\n)\nvalid_dataset = ImageDataset(\n    image_paths = valid_image_paths,\n    targets= valid_targets,\n    resize = None,\n    augmentations=valid_aug\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_img(train_dataset[10])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"create model:\n* first pseudo code for forward, then specify loss and monitor_metrics ,and call them in forward"},{"metadata":{"trusted":true},"cell_type":"code","source":"class LeafModel(tez.Model):\n    def __init__(self,num_classes,pretrained=True):\n        super().__init__()\n        self.convnet = torchvision.models.resnet18(pretrained=pretrained) \n        self.convnet.fc = nn.Linear(512,num_classes)\n        self.step_scheduler_after = \"epoch\"\n        \n    def loss(self,outputs,targets):\n        if targets is None:\n            return None\n        return nn.CrossEntropyLoss()(outputs,targets)\n    \n    def monitor_metrics(self,outputs,targets):\n        outputs = torch.argmax(outputs,dim=1).cpu().detach().numpy() #largest dim in each row\n        targets = targets.cpu().detach().numpy()\n        acc = metrics.accuracy_score(targets,outputs)\n        # add more metrics here\n        return {\n            \"accuracy\":acc\n        }\n    \n    def fetch_optimizer(self):\n        opt = torch.optim.Adam(self.parameters(),lr=1e-3) # experience\n        return opt\n    \n    def fetch_scheduler(self): # after every epoch/batch\n        sch = torch.optim.lr_scheduler.StepLR(self.optimizer, step_size=0.7) # experience\n        return sch\n    \n    def forward(self, image, targets=None): # here always should be image and targets with tez\n        outputs = self.convnet(image)\n        if targets is not None:\n            loss = self.loss(outputs,targets)\n            mon_metrics = self.monitor_metrics(outputs,targets)\n            return outputs, loss, mon_metrics\n        return outputs,None,None","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#torchvision.models.resnet18(pretrained = False)# first run this cell to see the fc values(512,1000)\n# give 512 back to the last cell __init__,1000 is what we need to change","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = LeafModel(num_classes = train_map.label.nunique(),pretrained = True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"run model again find fc output change to 5"},{"metadata":{"trusted":true},"cell_type":"code","source":"img = train_dataset[0][\"image\"]\ny= train_dataset[0][\"targets\"]\nmodel(img.unsqueeze(0),y.unsqueeze(0))# returns outputs and loss","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"es=EarlyStopping(\n    monitor = \"valid_accuracy\",\n    model_path= \"model.bin\",\n    patience=2,\n    mode=\"max\"\n)\nmodel.fit(\n    train_dataset,\n    valid_dataset=valid_dataset,\n    train_bs=32,\n    valid_bs=64,\n    #device=\"cuda\",\n    callbacks=[es],\n    fp16=True,\n    epochs=10\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#model.save(\"model.bin\")\n# next time: model.load(\"model.bin\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_map = pd.read_csv(\"../input/cassava-leaf-disease-classification/sample_submission.csv\")\nimage_paths= \"../input/cassava-leaf-disease-classification/test_images/\"\ntest_targets = test_map.label.values\ntest_image_paths =[\n    os.path.join(image_paths,x) for x in test_map.image_id.values\n]\ntest_aug = albumentations.Compose(\n[\n    albumentations.RandomResizedCrop(256,256,p=1.0), #修剪crop\n    albumentations.Resize(256,256),\n    albumentations.Transpose(p=0.5), #透明度\n    albumentations.HorizontalFlip(p=0.6),\n    albumentations.VerticalFlip(p=0.6)   \n])\n# copy paste from up, no need to resize because of argumentation\ntest_dataset = ImageDataset(\n    image_paths = test_image_paths,\n    targets= test_targets,\n    resize = None,\n    augmentations=test_aug\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"1. change argumentation in testset and predict final_preds 5-10 times, get mean of argmax"},{"metadata":{"trusted":true},"cell_type":"code","source":"preds = model.predict(test_dataset,batch_size=64,n_jobs=-1,device=\"cuda\")\nfinal_preds=None\nfor p in preds:\n    if final_preds is None:\n        final_preds = p\n    else:\n        final_preds = np.vstack((final_preds,p))\nfinal_preds = final_preds.argmax(axis=1)\ntest_map.label = final_preds\ntest_map.to_csv(\"submission.csv\",index=False)\nprint(final_preds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}