{"cells":[{"metadata":{},"cell_type":"markdown","source":"This notebook is a demonstration of how someone could use cosine similarity to find similar images within the trainset. \n\nI have seen a couple of discussions talking about how people were able to find \"potatoes\" within the trainset, which they expected to be filled with leaves only. \n\nIn this notebook we want to identify how many of these \"potatoes\" are within our trainset by using cosine similarity."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import pandas as pd\nfrom PIL import Image\nimport torch\nimport numpy as np\nimport cv2\nfrom albumentations.pytorch.transforms import ToTensorV2\nimport albumentations as A","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"train_csv = pd.read_csv(\"../input/cassava-leaf-disease-classification/train.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class CassavaDataset(torch.utils.data.Dataset):\n    def __init__(self, img_path, df,transforms=None):\n        self.path = img_path\n        self.df = df\n        self.transforms = transforms\n        \n    def __getitem__(self, index):\n        img_name = self.df.image_id.values[index]\n        img_arr = cv2.imread(self.path+img_name)\n        img_arr_rgb = cv2.cvtColor(img_arr, cv2.COLOR_BGR2RGB)\n        \n        if self.transforms:\n            sample = {'image':img_arr_rgb}\n            sample = self.transforms(**sample)\n            img_tens = sample['image']\n        else:\n            img_tens = torchvision.transforms.ToTensor()(img_arr_rgb)\n            \n        return img_tens\n    \n    def __len__(self):\n        return len(self.df)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"valid_transform = A.Compose(\n    [A.Resize(256,256),\n     A.Normalize(),\n     ToTensorV2()])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install timm","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import timm","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def create_model_ef():\n    model = timm.create_model(\"tf_efficientnet_b1\", pretrained=False)\n    # five classes only\n    num_classes = 5\n    model.classifier = torch.nn.Linear(model.classifier.in_features, num_classes)\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# create model and load pretrained weights\nmodel = create_model_ef()\nmodel_weights = torch.load(\"../input/cassava-leaf-disease-classification-training/trained_weights_1\", torch.device('cpu'))\nmodel.load_state_dict(model_weights)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# \"remove\" last classifier layer by setting it to identity passing the last layer completly through\nmodel.classifier = torch.nn.Identity()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_ds = CassavaDataset(\"../input/cassava-leaf-disease-classification/train_images/\", train_csv, transforms=valid_transform)\ntrain_dl = torch.utils.data.DataLoader(train_ds, batch_size=32, num_workers=2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"features = []\nfor images in train_dl:\n    with torch.no_grad():\n        feature = model(images)\n        features.append(feature)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# manually checked if its a potatoe\npotatoe = features[1][10]\n\n# the corresponding image we want to check all other similarities to (our input/identity image)\nImage.open(\"../input/cassava-leaf-disease-classification/train_images/\" + train_csv.iloc[42][\"image_id\"])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# flatten the arrays\nfeature_vec = []\nfor x in features:\n    for k in x:\n        feature_vec.append(k)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# we will store all relevant indices here\nrelevant = []\n# random threshold score (-> higher is more similar)\nthreshold = 0.65\n\nfor i, feat in enumerate(feature_vec):\n    if float(torch.nn.CosineSimilarity(dim=0)(potatoe,feat)) > threshold:\n        relevant.append(i)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# indices of similar images\n# using np.array for easier visuals\nnp.array(relevant)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# how many images with a similarity score over 0.65 are in our trainset\nlen(relevant)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# example 1\n# random sample from the relevant list, you can check them in your notebook \nImage.open(\"../input/cassava-leaf-disease-classification/train_images/\" + train_csv.iloc[relevant[22]][\"image_id\"])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# example 2\n# random sample from the relevant list, you can check them in your notebook \nImage.open(\"../input/cassava-leaf-disease-classification/train_images/\" + train_csv.iloc[relevant[50]][\"image_id\"])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# example 3\n# random sample from the relevant list, you can check them in your notebook \nImage.open(\"../input/cassava-leaf-disease-classification/train_images/\" + train_csv.iloc[relevant[0]][\"image_id\"])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# example 4\n# random sample from the relevant list, you can check them in your notebook \nImage.open(\"../input/cassava-leaf-disease-classification/train_images/\" + train_csv.iloc[relevant[140]][\"image_id\"])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# example 5\n# random sample from the relevant list, you can check them in your notebook \nImage.open(\"../input/cassava-leaf-disease-classification/train_images/\" + train_csv.iloc[relevant[146]][\"image_id\"])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We have checked the whole trainset and there are **147 images** with a cosine similarity higher than **0.65**, thats around **0.6%** of the whole trainset and should therefore only affect our training a little bit. \n\nKeeping them in our training process should not have a big effect on the model, we also dont know if the testset includes such images or not. \n\nSomeone could try to see if they achieve a higher LB-Score by excluding these images."}],"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}