{"cells":[{"metadata":{"id":"ElTO5OUYFhYe"},"cell_type":"markdown","source":"# Importing Libraries","execution_count":null},{"metadata":{"_uuid":"61d54aff-e4d6-4878-90ac-ff1467a1d469","_cell_guid":"26a7cdd3-66ac-4014-b45e-67263b7f1b53","trusted":true,"id":"R9lb1AzC-xFP","outputId":"cc95927b-f635-4542-898d-f967584003b2"},"cell_type":"code","source":"from keras.preprocessing.image import ImageDataGenerator\nfrom keras.utils.np_utils import to_categorical\nfrom keras.layers.normalization import BatchNormalization\nfrom keras.applications import inception_v3,vgg16\nfrom keras.layers import Lambda, merge\nfrom keras.layers import AveragePooling2D,Conv2D,MaxPooling2D\nfrom keras.layers import Dropout\nfrom keras.layers import Flatten\nfrom keras.layers import Dense\nfrom keras.layers import Input\nfrom keras.models import Model, Sequential\nfrom keras.regularizers import l2\nfrom keras.optimizers import Adam\nfrom keras.utils import to_categorical\nfrom keras.losses import binary_crossentropy\nfrom keras import backend as K\nfrom sklearn.preprocessing import LabelBinarizer\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import classification_report\nfrom sklearn.metrics import confusion_matrix,accuracy_score,f1_score\nfrom sklearn.utils import shuffle\nfrom sklearn import preprocessing\nfrom statistics import mean\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport numpy.random as rng\nimport numpy as np\nimport pickle\nimport random\nimport time\nimport cv2\nimport os","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# # Defining data path\n# IMAGE_PATH = \"../input/siim-isic-melanoma-classification/\"\n\n# train_df = pd.read_csv('../input/siim-isic-melanoma-classification/train.csv')\n# test_df = pd.read_csv('../input/siim-isic-melanoma-classification/test.csv')\n\n# images = [\n#     train_df[(train_df['sex'].isin(['female'])) & (train_df['target']==0)]['image_name'].values,\n#     train_df[(train_df['sex'].isin(['male'])) & (train_df['target']==0)]['image_name'].values,\n#     train_df[(train_df['sex'].isin(['female'])) & (train_df['target']==1)]['image_name'].values,\n#     train_df[(train_df['sex'].isin(['male'])) & (train_df['target']==1)]['image_name'].values\n# ]\n\n# # Extract 75 random images from every sex\n# dataset = [\n#     rng.choice(images[0]+'.jpg',size=(75,),replace=False), #random 75 female image for benign (50 for train,25 for test)\n#     rng.choice(images[1]+'.jpg',size=(75,),replace=False), #random 75 male image for benign (50 for train,25 for test)\n#     rng.choice(images[2]+'.jpg',size=(75,),replace=False), #random 75 female image for malignant (50 for train,25 for test)\n#     rng.choice(images[3]+'.jpg',size=(75,),replace=False) #random 75 male image for malignant (50 for train,25 for test)\n# ]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# def imgreadconvert(path):\n#     img = cv2.imread(path)\n#     img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n#     img = cv2.resize(img,(224,224))\n#     return img\n# # Location of the image dir\n# img_dir = IMAGE_PATH+'/jpeg/train'\n# x_train1 = []\n# x_train2 = []\n# x_test1 = []\n# x_test2 = []\n# for i in range(75):\n#     if i <50:\n#         img = imgreadconvert(os.path.join(img_dir,dataset[0][i])) #female benign train\n#         x_train1.append(img)\n#         img = imgreadconvert(os.path.join(img_dir,dataset[1][i])) #male benign train\n#         x_train1.append(img)\n#         img = imgreadconvert(os.path.join(img_dir,dataset[2][i])) #female malignant train\n#         x_train2.append(img)\n#         img = imgreadconvert(os.path.join(img_dir,dataset[3][i])) #male malignant train\n#         x_train2.append(img)\n#     else:\n#         img = imgreadconvert(os.path.join(img_dir,dataset[0][i])) #female benign test\n#         x_test1.append(img)\n#         img = imgreadconvert(os.path.join(img_dir,dataset[1][i])) #male benign test\n#         x_test1.append(img)\n#         img = imgreadconvert(os.path.join(img_dir,dataset[2][i])) #female malignant test\n#         x_test2.append(img)\n#         img = imgreadconvert(os.path.join(img_dir,dataset[3][i])) #male malignant test\n#         x_test2.append(img)\n\n# x_train1 = np.array(x_train1)\n# x_train2 = np.array(x_train2)\n# x_test1 = np.array(x_test1)\n# x_test2 = np.array(x_test2)\n\n# x_train1,x_train2 = shuffle(x_train1,x_train2)\n# x_test1,x_test2 = shuffle(x_test1,x_test2)\n\n# train_groups = [x_train1,x_train2]\n# test_groups = [x_test1,x_test2]\n\n# import pickle\n# with open(\"melanoma.pickle\",\"wb\") as f:\n#     pickle.dump((train_groups,test_groups),f)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"accde73f-8996-440f-a9ce-56f1ade3c63a","_cell_guid":"a498845b-ae5c-4fca-a6e2-3816e9e0addc","trusted":true,"id":"TrHCvQtL-xFX"},"cell_type":"markdown","source":"# Load Data and Create dataset","execution_count":null},{"metadata":{"_uuid":"143b1544-4248-4f6e-b814-94da52274443","_cell_guid":"b31d99f5-5190-4847-a872-796df72ab35d","trusted":true,"id":"D2X2aH9l-xFe"},"cell_type":"code","source":"import pickle\nwith open(\"../input/melanoma/melanoma.pickle\", \"rb\") as f:\n    (train_groups,test_groups) = pickle.load(f,encoding='latin1')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1ea4b1d1-0c52-4543-9c74-af1ca72c50eb","_cell_guid":"51c9b1ef-0721-4cd4-af80-92296cf99fdf","trusted":true,"id":"apJcH-Xp-xFj"},"cell_type":"markdown","source":"# Building Siamese Neural Architecture","execution_count":null},{"metadata":{"_uuid":"2dc6a57e-1e19-4dcd-b7e1-54e35accded7","_cell_guid":"006b9b0d-11d5-4f00-b547-ec870eef6a70","trusted":true,"id":"7EzJqsjg-xFl"},"cell_type":"code","source":"%matplotlib inline\ndef W_init(shape,name=None,dtype=None):\n    \"\"\"Initialize weights as in paper\"\"\"\n    values = rng.normal(loc=0,scale=1e-2,size=shape)\n    return K.variable(values,name=name)\n#//TODO: figure out how to initialize layer biases in keras.\ndef b_init(shape,name=None,dtype=None):\n    \"\"\"Initialize bias as in paper\"\"\"\n    values=rng.normal(loc=0.5,scale=1e-2,size=shape)\n    return K.variable(values,name=name)\n\ndef buildmodel(input_shape,pretrain=None):\n  left_input = Input(input_shape)\n  right_input = Input(input_shape)\n  #build convnet to use in each siamese 'leg'\n  convnet = Sequential()\n  if pretrain is None:\n    convnet.add(Conv2D(32,(10,10),activation='relu'))\n    convnet.add(MaxPooling2D())\n    convnet.add(Conv2D(64,(7,7),activation='relu',\n                      kernel_regularizer=l2(2e-4),kernel_initializer=W_init, bias_initializer=b_init))\n    convnet.add(MaxPooling2D())\n    convnet.add(Conv2D(64,(4,4),activation='relu',kernel_initializer=W_init,kernel_regularizer=l2(2e-4),\n                      bias_initializer=b_init))\n    convnet.add(MaxPooling2D())\n    convnet.add(Conv2D(128,(4,4),activation='relu',kernel_initializer=W_init,kernel_regularizer=l2(2e-4),\n                      bias_initializer=b_init))\n  else:\n    pretrained = pretrain(input_shape=input_shape,include_top=False,weights=None,pooling=max)\n    pretrained.trainable=False\n    convnet.add(pretrained)\n\n  convnet.add(Flatten())\n  convnet.add(Dense(2048,activation=\"sigmoid\",kernel_regularizer=l2(1e-3)))\n\n\n  #call the convnet Sequential model on each of the input tensors so params will be shared\n  encoded_l = convnet(left_input)\n  encoded_r = convnet(right_input)\n  #layer to merge two encoded inputs with the l1 distance between them\n  L1_layer = Lambda(lambda tensors:K.abs(tensors[0] - tensors[1]))\n  #call this layer on list of two input tensors.\n  L1_distance = L1_layer([encoded_l, encoded_r])\n  prediction = Dense(3,activation='sigmoid')(L1_distance)\n  siamese_net = Model(inputs=[left_input,right_input],outputs=prediction)\n  optimizer = Adam(0.00006)\n  #//TODO: get layerwise learning rates and momentum annealing scheme described in paperworking\n\n  siamese_net.compile(loss=\"binary_crossentropy\",optimizer=optimizer)\n\n  siamese_net.count_params()\n  siamese_net.summary()\n  return siamese_net","execution_count":null,"outputs":[]},{"metadata":{"id":"IxjnAtZKFqQb"},"cell_type":"markdown","source":"# Data Loader\n","execution_count":null},{"metadata":{"_uuid":"c7731f11-6d9b-412b-9e80-f5b534bb69d5","_cell_guid":"1b45c6b2-ccc9-4cbb-bee4-690ee0412a57","trusted":true,"scrolled":false,"id":"uz49vWHp-xFq"},"cell_type":"code","source":"class Siamese_Loader:\n  \"\"\"For loading batches and testing tasks to a siamese net\"\"\"\n  def __init__(self,input):\n    print(\"Siamese Loaded\")\n    self.input_shape = input\n    print(self.input_shape)\n      \n  def get_batch(self,batch_size):\n    \"\"\"Create batch of n pairs, half same class, half different class\"\"\"\n\n    h,w,c = self.input_shape\n\n    #initialize 2 empty arrays for the input image batch\n    pairs=[np.zeros((batch_size, h, w,c)) for i in range(2)]\n    #initialize vector for the targets, and make one half of it '1's, so 2nd half of batch has same class\n    targets=np.zeros((batch_size,))\n    X1 = train_groups[0]\n    X2 = train_groups[1]\n    n_examples1= X1.shape[0]\n    n_examples2= X2.shape[0]\n    for i in range(batch_size):\n      if i<(batch_size // 3):\n        idx_1 = rng.choice(n_examples1,size=(2,),replace=False)\n        pairs[0][i,:,:,:] = X1[idx_1[0]].reshape(h,w,c)\n        pairs[1][i,:,:,:] = X1[idx_1[1]].reshape(h,w,c)\n        targets[i] = 0\n      elif i>=(batch_size // 3) and i < (batch_size // 3)+(batch_size // 3):\n        idx_2 = rng.choice(n_examples2,size=(2,),replace=False)\n        pairs[0][i,:,:,:] = X2[idx_2[0]].reshape(h,w,c)\n        pairs[1][i,:,:,:] = X2[idx_2[1]].reshape(h,w,c)\n        targets[i] = 1\n      else:\n        idx_1 = rng.randint(0, n_examples1)\n        idx_2 = rng.randint(0, n_examples2)\n        pairs[0][i,:,:,:] = X1[idx_1].reshape(h,w,c)\n        pairs[1][i,:,:,:] = X2[idx_2].reshape(h,w,c)\n        targets[i] = 2\n    pairs[0],pairs[1],targets = shuffle(pairs[0],pairs[1],targets)\n    return pairs, targets\n\n  def make_oneshot_task(self,N,i):\n    \"\"\"Create pairs of test image, support set for testing N way one-shot learning. \"\"\"\n    h,w,c = self.input_shape\n    X1 = test_groups[0]\n    X2 = test_groups[1]\n    n_examples1= X1.shape[0]\n    n_examples2= X2.shape[0]\n    if i%2==0:\n      ex = rng.choice(n_examples1,replace=False,size=(int(N/2),))\n      test_image = np.asarray([X1[ex[0],:,:]]*N).reshape(N,h,w,c)\n      support_set = X1[ex].reshape(int(N/2),h,w,c)\n      targets = np.zeros((N,))\n      idx = rng.choice(n_examples2,replace=False,size=(int(N/2),))\n      support_set = np.append(support_set,X2[idx].reshape(int(N/2),h,w,c),axis=0)\n      targets[int(N/2):] = 2\n      targets,test_image, support_set = shuffle(targets, test_image, support_set)\n      pairs = [test_image,support_set]\n    else:\n      ex = rng.choice(n_examples2,replace=False,size=(int(N/2),))\n      test_image = np.asarray([X2[ex[0]]]*N).reshape(N,h,w,c)\n      support_set= X2[ex].reshape(int(N/2),h,w,c)\n      targets = np.ones((N,))\n      idx = rng.choice(n_examples1,replace=False,size=(int(N/2),))\n      support_set = np.append(support_set,X1[idx].reshape(int(N/2),h,w,c),axis=0)\n      targets[int(N/2):] = 2\n      targets, test_image, support_set = shuffle(targets, test_image, support_set)\n      pairs = [test_image,support_set]\n    \n    return pairs, targets\n  \n  def test_oneshot(self,model,N,k):\n    \"\"\"Test average N way oneshot learning accuracy of a siamese neural net over k one-shot tasks\"\"\"\n    n_correct = 0\n    sum = 0.0\n    sum1=0.0\n    for i in range(k):\n      inputs, targets = self.make_oneshot_task(N,i)\n      probs = model.predict(inputs)\n      probs = probs.argmax(axis=-1)\n      sum+= accuracy_score(targets,probs)\n      sum1+= f1_score(targets,probs,average='micro')\n    percent = (sum / k)*100.0\n    F1_score = sum1/k\n    print(\"ACCURACY-{}% and F1-SCORE-{} in {} random {} way one-shot learning\".format(round(percent,2),round(F1_score,2),k,N))\n    return percent,F1_score","execution_count":null,"outputs":[]},{"metadata":{"id":"xy6IHU2sFv7M"},"cell_type":"markdown","source":"# Test Data Plot\n","execution_count":null},{"metadata":{"_uuid":"0e009a8b-b133-4602-9af9-7af09809ece7","_cell_guid":"1751552a-b6c6-443d-abb7-308569e1b366","trusted":true,"id":"FADa9cL3-xFw"},"cell_type":"code","source":"def plot_oneshot_task(pairs):\n  \"\"\"Takes a one-shot task given to a siamese net and  \"\"\"\n  plt.figure(1)\n  plt.imshow(pairs[0][0])\n  plt.title(\"Test Image\")\n  plt.axis('off')\n  plt.figure(2)\n  for i in range(pairs[1].shape[0]):\n    plt.subplot(pairs[1].shape[0]//5,5,i+1)\n    plt.imshow(pairs[1][i])\n    plt.axis('off')\n  plt.suptitle(str(pairs[1].shape[0])+\" way one shot Support Image Set\")\n#example of a one-shot learning task\n","execution_count":null,"outputs":[]},{"metadata":{"id":"opRD9bflF0wG"},"cell_type":"markdown","source":"# Train the model","execution_count":null},{"metadata":{"_uuid":"7743f3c4-d528-4439-a22f-7149b1dc16fd","_cell_guid":"2741a340-d62c-4baf-8a66-aecc83798760","trusted":true,"id":"SXihczwP-xF1"},"cell_type":"code","source":"def train_model(siamese_net,ptm_name):\n  #Training loop\n  print(\"!\")\n  # evaluate_every = 1 # interval for evaluating on one-shot tasks\n  # loss_every=50 # interval for printing loss (iterations)\n  batch_size = 24\n  n_iter = 10000\n  N_way = 10 # how many classes for testing one-shot tasks>\n  n_val = 25 #how mahy one-shot tasks to validate on?\n  best = -1\n  s=-1\n  # weights_path = os.path.join(PATH, \"weights\")\n  LOSS = [];ACC=[];F1SCORE=[]\n  t=0.0\n  print(\"training\")\n  for i in range(1, n_iter+1):\n    print(\"----------------------------------------------------------------------------------\")\n    print(\"Iteration no-\",i,\"   (\",int(t/3600),\"hr,\",int((t%3600)/60),\"min,\",int((t%3600)%60),\"sec left)\")\n    start = time.time()\n    (inputs,targets)=loader.get_batch(batch_size)\n    targets = to_categorical(targets,num_classes=3)\n    loss=siamese_net.train_on_batch(inputs,targets)\n    print(\"Loss= \",loss)\n    val_acc,score = loader.test_oneshot(siamese_net,N_way,n_val)\n    if i%100==0 or i==1:\n      LOSS.append(loss)\n      ACC.append(val_acc)\n      F1SCORE.append(score)\n    end = time.time()\n    if best < val_acc or s< score:\n      if best < val_acc:\n        best = val_acc\n      if s< score:\n        s = score\n      print(\"saving\")\n      siamese_net.save(r'MelanomaWeights_'+ptm_name)\n    t = (10000-i)*(end-start)\n  return LOSS,ACC,F1SCORE\n","execution_count":null,"outputs":[]},{"metadata":{"id":"ZEbSkxN2F4CR"},"cell_type":"markdown","source":"# Train Performance plotting","execution_count":null},{"metadata":{"_uuid":"0ab9decc-0bb7-4feb-a8a3-3f619b32d799","_cell_guid":"b3d30dba-69a7-4a0e-b7f1-266e61ab7e8a","trusted":true,"id":"uKvWVYgz-xF7"},"cell_type":"code","source":"def train_performane(LOSS,ACC,F1SCORE,title):\n    performance = {\"loss\":LOSS,\"val_accuracy\":ACC,\"val_f1-score\":F1SCORE}\n    plt.figure(figsize=(15,4))\n    x = np.arange(100,10001,100)\n    x = np.insert(x, 0, 1)\n    for i,j in zip(performance,range(1,4)):\n        plt.subplot(1,3,j)\n        plt.plot(x,performance[i])\n        plt.xlabel(\"Iterations\")\n        plt.ylabel(i)\n        plt.title(i+title)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"id":"-83AZxnRF8lE"},"cell_type":"markdown","source":"# Test the data in N-ways ","execution_count":null},{"metadata":{"_uuid":"83d56645-6c4b-443d-aa13-ee7fa3f7af70","_cell_guid":"2a91bda8-bbbb-4d18-8185-2e96e5ee1f65","trusted":true,"id":"Fp3Ri7HX-xGC"},"cell_type":"code","source":"def testing(siamese_net):\n  ways = np.arange(2,51,2)\n  resume =  False\n  val_accs, train_accs, valscore, trainscore = [], [], [], []\n  trials = 100\n  i=0\n  for N in ways:\n      train,trains = loader.test_oneshot(siamese_net, N,trials)\n      val,vals = loader.test_oneshot(siamese_net, N,trials)\n      val_accs.append(val)\n      train_accs.append(train)\n      valscore.append(vals)\n      trainscore.append(trains)\n      i+=1\n  return val_accs, train_accs, valscore, trainscore","execution_count":null,"outputs":[]},{"metadata":{"id":"1IIjzT8_GBzp"},"cell_type":"markdown","source":"# N-way Test Performance","execution_count":null},{"metadata":{"_uuid":"dad47880-7bb9-453d-ac49-80061d3d101a","_cell_guid":"ee8a3bd8-1564-4ff9-82fa-1afd853f89c1","trusted":true,"id":"D-JWeJIq-xGI"},"cell_type":"code","source":"def test_result(val_accs, train_accs, valscore, trainscore,title):\n  print(\"The Average testing Accuracy is {}%\".format(round(mean(val_accs),2)))\n  print(\"The Average testing F1-Score is {}\".format(round(mean(valscore),2)))\n\n  plt.figure(figsize=(15,4))\n  plt.subplot(1,2,1)\n  plt.plot(np.arange(2,51,2),train_accs,\"b\",label=\"Siamese(train set)\")\n  plt.plot(np.arange(2,51,2),val_accs,\"r\",label=\"Siamese(val set)\")\n\n  plt.xlabel(\"Number of possible classes in one-shot tasks\")\n  plt.ylabel(\"% Accuracy\")\n  plt.title(title+\"Melanoma One-Shot Learning performace of a Siamese Network\")\n  # box = plt.get_position()\n  # plt.set_position([box.x0, box.y0, box.width * 0.8, box.height])\n  plt.legend(loc='upper right', bbox_to_anchor=(1, 0.5))\n  # inputs,targets = loader.make_oneshot_task(10,\"val\")\n\n  plt.subplot(1,2,2)\n  plt.plot(np.arange(2,51,2),trainscore,\"g\",label=\"Siamese(train set)\")\n  plt.plot(np.arange(2,51,2),valscore,\"r\",label=\"Siamese(val set)\")\n  plt.xlabel(\"Number of possible classes in one-shot tasks\")\n  plt.ylabel(\"F1-Score\")\n  plt.title(title+\"Melanoma One-Shot Learning F1 Score of a Siamese Network\")\n  # box = plt.get_position()\n  # plt.set_position([box.x0, box.y0, box.width * 0.8, box.height])\n  plt.legend(loc='upper right', bbox_to_anchor=(1, 0.5))\n  plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Plotting Data","execution_count":null},{"metadata":{"id":"qU9zXBOZEgYq","outputId":"480c511b-df20-4bd9-821d-3354e22c74a3","trusted":true},"cell_type":"code","source":"input = (224,224,3)\nloader = Siamese_Loader(input)\npairs, targets = loader.make_oneshot_task(10,1)\nplot_oneshot_task(pairs)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# InceptionV3 Model Train and Test","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"model = buildmodel(input,inception_v3.InceptionV3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"LOSS,ACC,F1SCORE = train_model(model,\"InceptionV3\")\ntrain_performane(LOSS,ACC,F1SCORE,' of InceptionV3 Siamease Net')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"val_accs, train_accs, valscore, trainscore = testing(model)\ntest_result(val_accs, train_accs, valscore, trainscore,\"InceptionV3 \")","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}