{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# https://www.kaggle.com/qgh1223/inceptionv3-siamesenet\nfrom keras.applications.vgg16 import VGG16\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport cv2\nimport os\nfrom tqdm import tqdm\nimport time\nimport matplotlib.pyplot as plt\nimport random\n# Read or generate p2h, a dictionary of image name to image id (picture to hash)\nimport pickle\nimport platform\nimport random\n# Determine the size of each image\nfrom os.path import isfile","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"from keras.models import Model,Sequential\nfrom keras.layers import *\nfrom keras.optimizers import Adam\nfrom keras.callbacks import ModelCheckpoint,ReduceLROnPlateau\nfrom keras.applications.resnet50 import ResNet50\nfrom keras.applications.inception_v3 import InceptionV3\nfrom keras.applications.vgg16 import VGG16\nfrom keras.applications.mobilenetv2 import MobileNetV2\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f491b228f2e730b44fb834b1269681ba48fa66c1"},"cell_type":"code","source":"IMG_ROW=IMG_COL=144\nBASE_DIR='../input/humpback-whale-identification/train/'\nlabelpath='../input/humpback-whale-identification/train.csv'\ntraindata=pd.read_csv(labelpath)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"26993f474171bc4a5e591ab263b73942ca435be1"},"cell_type":"code","source":"# https://www.kaggle.com/khaled34/siamese-0-822\nTRAIN_DF = '../input/humpback-whale-identification/train.csv'\nSUB_Df = '../input/humpback-whale-identification/sample_submission.csv'\nTRAIN = '../input/humpback-whale-identification/train/'\nTEST = '../input/humpback-whale-identification/test/'\nP2H = '../input/humpbackwhaleidentificationmetadata/p2h.pickle'\nP2SIZE = '../input/humpbackwhaleidentificationmetadata/p2size.pickle'\nBB_DF = \"../input/humpbackwhaleidentificationmetadata/bounding_boxes.csv\"\ntagged = dict([(p, w) for _, p, w in pd.read_csv(TRAIN_DF).to_records()])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0ca552ab988c2d2f95c8d8504d7503483cc85a95"},"cell_type":"markdown","source":"Duplicate image identification\nThis part was from the original kernel, seems like in the playground competition dulicated images was a real issue. I don't know the case about this one but I took one for the team and generated the results anyway. I'm such a nice chap.\n"},{"metadata":{"trusted":true,"_uuid":"35a4917366d253b5e751587904c41af173963439"},"cell_type":"code","source":"if isfile(P2SIZE):\n    print(\"P2SIZE exists.\")\n    with open(P2SIZE, 'rb') as f:\n        p2size = pickle.load(f)\nelse:\n    p2size = {}\n    for p in tqdm(join):\n        size = pil_image.open(expand_path(p)).size\n        p2size[p] = size\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c6a6efb85a3dc75ec77c50b816ef56fff294a2a5"},"cell_type":"code","source":"\ndef match(h1, h2):\n    for p1 in h2ps[h1]:\n        for p2 in h2ps[h2]:\n            i1 = pil_image.open(expand_path(p1))\n            i2 = pil_image.open(expand_path(p2))\n            if i1.mode != i2.mode or i1.size != i2.size: return False\n            a1 = np.array(i1)\n            a1 = a1 - a1.mean()\n            a1 = a1 / sqrt((a1 ** 2).mean())\n            a2 = np.array(i2)\n            a2 = a2 - a2.mean()\n            a2 = a2 / sqrt((a2 ** 2).mean())\n            a = ((a1 - a2) ** 2).mean()\n            if a > 0.1: return False\n    return True\nif isfile(P2H):\n    print(\"P2H exists.\")\n    with open(P2H, 'rb') as f:\n        p2h = pickle.load(f)\n# For each image id, determine the list of pictures\nh2ps = {}\nfor p, h in p2h.items():\n    if h not in h2ps: h2ps[h] = []\n    if p not in h2ps[h]: h2ps[h].append(p)\n#len(p2h), list(p2h.items())[:5]\nprint(len(p2h))\nprint(len(h2ps))\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c155dfbd20acca18d42c041eb23a04b3be248903"},"cell_type":"code","source":"def build_siamese_model( img_shape,lr,branch_model,activation='sigmoid'):\n\n    optim  = Adam(lr=lr)\n    \n    \n    \n    mid        = 32\n    xa_inp     = Input(shape=branch_model.output_shape[1:])\n    xb_inp     = Input(shape=branch_model.output_shape[1:])\n    x1         = Lambda(lambda x : x[0]*x[1])([xa_inp, xb_inp])\n    x2         = Lambda(lambda x : x[0] + x[1])([xa_inp, xb_inp])\n    x3         = Lambda(lambda x : K.abs(x[0] - x[1]))([xa_inp, xb_inp])\n    x4         = Lambda(lambda x : K.square(x))(x3)\n    x          = Concatenate()([x1, x2, x3, x4])\n    x          = Reshape((4, branch_model.output_shape[1], 1), name='reshape1')(x)\n\n    # Per feature NN with shared weight is implemented using CONV2D with appropriate stride.\n    x          = Conv2D(mid, (4, 1), activation='relu', padding='valid')(x)\n    x          = Reshape((branch_model.output_shape[1], mid, 1))(x)\n    x          = Conv2D(1, (1, mid), activation='linear', padding='valid')(x)\n    x          = Flatten(name='flatten')(x)\n    x          = Dense(1, use_bias=True, activation=activation, name='weighted-average')(x)\n    head_model = Model([xa_inp, xb_inp], x, name='head')\n    img_a      = Input(shape=img_shape)\n    img_b      = Input(shape=img_shape)\n    xa         = branch_model(img_a)\n    xb         = branch_model(img_b)\n    x          = head_model([xa, xb])\n    model      = Model([img_a, img_b], x)\n    model.compile(optim, loss='binary_crossentropy', metrics=[ 'accuracy'])\n    return model,head_model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"57c387b9cbb6b3c6545ed624b717bd113ec4e484"},"cell_type":"code","source":"def kind_list(imgdata):\n    kindlist=imgdata.groupby('Id').size()\n    return kindlist.index\n\ndef fetch_all_kind_list(imgdata):\n    kindlist=kind_list(imgdata)\n    kindimgpathlist=[]\n    for kind in kindlist:\n        kindimgpathlist.append(list(imgdata['Image'][imgdata['Id']==kind]))\n    return kindimgpathlist,kindlist\n\ndef fetch_kind_list_split(kindimgpathlist,split_size=0.8):\n    trainkindimgpathlist=[]\n    validkindimgpathlist=[]\n    for pathlist in kindimgpathlist:\n        if(len(pathlist)<=3):\n            trainkindimgpathlist.append(pathlist)\n            validkindimgpathlist.append(pathlist)\n        else:\n            trainkindimgpathlist.append(pathlist[:int(len(pathlist)*split_size)])\n            validkindimgpathlist.append(pathlist[int(len(pathlist)*split_size):])\n    return trainkindimgpathlist,validkindimgpathlist","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e7914459b60d79731f4f83ae6e23955624d61747"},"cell_type":"code","source":"def imgarr(imgpath):\n    img=cv2.imread(imgpath)\n    return img","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"90597abab5faef531b602d0741be4a7606a771a4"},"cell_type":"code","source":"def siamese_img_gen(BASE_DIR,IMG_ROW,IMG_COL,kindimgpathlist,\n                    contrast_times=5,batch_size=50):\n    while(True):\n        imglist1=[]\n        imglist2=[]\n        labellist=[]\n        for i in range(batch_size):\n            for j in range(contrast_times):\n                rndid=random.randint(0,len(kindimgpathlist)-1)\n                if(i%2==0):\n                    #print(len(kindimgpathlist[rndid]))\n                    pair=np.random.randint(0,len(kindimgpathlist[rndid]),2)\n                    imgpath1=kindimgpathlist[rndid][pair[0]]\n                    imgpath2=kindimgpathlist[rndid][pair[1]]\n                    labellist.append(1)\n                else:\n                    rndid1=random.randint(0,len(kindimgpathlist[rndid])-1)\n                    imgpath1=kindimgpathlist[rndid][rndid1]\n                    index1=random.choice([num for num in range(len(kindimgpathlist)) if num not in [rndid]])\n                    rndid2=random.randint(0,len(kindimgpathlist[index1])-1)\n                    imgpath2=kindimgpathlist[index1][rndid2]\n                    labellist.append(0)\n                img1=imgarr(BASE_DIR+imgpath1)\n                img2=imgarr(BASE_DIR+imgpath2)\n                img1=cv2.resize(img1,(IMG_ROW,IMG_COL))\n                img2=cv2.resize(img2,(IMG_ROW,IMG_COL))\n                imglist1.append(img1)\n                imglist2.append(img2)\n        yield ([np.asarray(imglist1),np.asarray(imglist2)],np.asarray(labellist))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"42ae3e1d133dbe155db5019805930684a5544bc3"},"cell_type":"code","source":"img_shape=(IMG_ROW,IMG_COL,3)\nmodelfn=InceptionV3(weights=None,\n                   input_shape=img_shape,\n                   classes=300)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5fe711e21168a471b412a2806114029d5a1f6718"},"cell_type":"code","source":"model,head_model = build_siamese_model(img_shape,64e-5,modelfn)\nmodel.summary()\nmodel.summary()\nmodel.compile(optimizer=Adam(0.001),metrics=['accuracy'],\n              loss=['binary_crossentropy'])\ncallbacks=[\n    ReduceLROnPlateau(monitor='val_loss',patience=5,min_lr=1e-9,verbose=1,mode='min'),\n    ModelCheckpoint('siamese.h5',monitor='val_loss',save_best_only=True,verbose=1)\n]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e1302682ef08126051024ed339530a5b6b0aac57"},"cell_type":"code","source":"kindimgpathlist,kindlist=fetch_all_kind_list(traindata)\ntrainkindimgpathlist,validkindimgpathlist=fetch_kind_list_split(kindimgpathlist)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0ad5c50e22298e02d9ad201539ccb1d46d4e0b82"},"cell_type":"code","source":"history=model.fit_generator(siamese_img_gen(BASE_DIR,IMG_ROW,IMG_COL,\n                                            trainkindimgpathlist,batch_size=30),\n                            steps_per_epoch=2,\n                            epochs=1,\n                            validation_data=siamese_img_gen(BASE_DIR,IMG_ROW,IMG_COL,\n                                                            validkindimgpathlist,contrast_times=10,batch_size=5),\n                            validation_steps=2,\n                            callbacks=callbacks)\nplt.plot(history.history['loss'])\nplt.plot(history.history['val_loss'])\nplt.legend(['train','valid'])\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"833d3ec97f0cd50fe9cf2a5a7b68c7301bc32aaf"},"cell_type":"code","source":"# https://www.kaggle.com/khaled34/siamese-0-822\ndef prepare_submission(threshold, filename):\n    \"\"\"\n    Generate a Kaggle submission file.\n    @param threshold the score given to 'new_whale'\n    @param filename the submission file name\n    \"\"\"\n    vtop = 0\n    vhigh = 0\n    pos = [0, 0, 0, 0, 0, 0]\n    with open(filename, 'wt', newline='\\n') as f:\n        f.write('Image,Id\\n')\n        for i, p in enumerate(tqdm(submit)):\n            t = []\n            s = set()\n            a = score[i, :]\n            for j in list(reversed(np.argsort(a))):\n                h = known[j]\n                if a[j] < threshold and new_whale not in s:\n                    pos[len(t)] += 1\n                    s.add(new_whale)\n                    t.append(new_whale)\n                    if len(t) == 5: break;\n                for w in h2ws[h]:\n                    assert w != new_whale\n                    if w not in s:\n                        if a[j] > 1.0:\n                            vtop += 1\n                        elif a[j] >= threshold:\n                            vhigh += 1\n                        s.add(w)\n                        t.append(w)\n                        if len(t) == 5: break;\n                if len(t) == 5: break;\n            if new_whale not in s: pos[5] += 1\n            assert len(t) == 5 and len(s) == 5\n            f.write(p + ',' + ' '.join(t[:5]) + '\\n')\n    return vtop, vhigh, pos","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1006f3b1e11ca25d3d1bcb1f3fbd82e122bb6388"},"cell_type":"code","source":"# https://www.kaggle.com/khaled34/siamese-0-822\n# Find elements from training sets not 'new_whale'\ntic = time.time()\nnew_whale = 'new_whale'\nh2ws = {}\nfor p, w in tagged.items():\n    if w != new_whale:  # Use only identified whales\n        h = p2h[p]\n        if h not in h2ws: h2ws[h] = []\n        if w not in h2ws[h]: h2ws[h].append(w)\nknown = sorted(list(h2ws.keys()))\n\n# Dictionary of picture indices\nh2i = {}\nfor i, h in enumerate(known): h2i[h] = i\n\n# Evaluate the model.\nfknown = model.predict_generator(siamese_img_gen(BASE_DIR,IMG_ROW,IMG_COL,\n                                            trainkindimgpathlist,batch_size=30),                                                                                    \n                            steps=1,\n                            callbacks=callbacks,\n                            verbose=0)\n\"\"\"\nfsubmit = branch_model.predict_generator(FeatureGen(submit), max_queue_size=20, workers=10, verbose=0)\nscore = head_model.predict_generator(ScoreGen(fknown, fsubmit), max_queue_size=20, workers=10, verbose=0)\nscore = score_reshape(score, fknown, fsubmit)\n\"\"\"\n\n# Generate the subsmission file.\nprepare_submission(0.99, 'submission.csv')\ntoc = time.time()\nprint(\"Submission time: \", (toc - tic) / 60.)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8797e0d6acc589bba2d20e51e3e088c7c7f36d81"},"cell_type":"code","source":"modelfn.save('mobile_encoder.h5')","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}