{"cells":[{"metadata":{"trusted":true,"_uuid":"7a8e5a86c18ec7b67665a853fd4cbae218aa2587"},"cell_type":"code","source":"!pip install keras==2.1.6","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"46f8506222a9e1a8514daf4d83a7c2293f863310"},"cell_type":"code","source":"from collections import defaultdict\nfrom sklearn.model_selection import train_test_split\nimport pandas as pd\nimport numpy as np\nimport os\nimport glob\nfrom sklearn.neighbors import NearestNeighbors\nfrom PIL import Image\n\nimport keras\nfrom keras import backend as K\nfrom keras.optimizers import Adam\nfrom keras.models import Model\nfrom keras.callbacks import ModelCheckpoint, LearningRateScheduler, EarlyStopping, ReduceLROnPlateau, TensorBoard\nfrom keras import optimizers, losses, activations, models\nfrom keras.layers import Embedding, merge, Conv2D, Convolution2D, Dense, Input, Flatten, Dropout, MaxPooling2D, BatchNormalization, \\\n    GlobalMaxPool2D, Concatenate, GlobalMaxPooling2D, GlobalAveragePooling2D, Lambda\nfrom keras.applications.resnet50 import ResNet50","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5d30c8bdd22bda1d343b58153c399e1549dbabd8"},"cell_type":"code","source":"keras.__version__","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"334cea0c6b7a8721662610c4b34b0a898aa2ec32"},"cell_type":"code","source":"class sample_gen(object):\n    def __init__(self, file_class_mapping, other_class = \"new_whale\"):\n        self.file_class_mapping= file_class_mapping\n        self.class_to_list_files = defaultdict(list)\n        self.list_other_class = []\n        self.list_all_files = list(file_class_mapping.keys())\n        self.range_all_files = list(range(len(self.list_all_files)))\n\n        for file, class_ in file_class_mapping.items():\n            if class_ == other_class:\n                self.list_other_class.append(file)\n            else:\n                self.class_to_list_files[class_].append(file)\n\n        self.list_classes = list(set(self.file_class_mapping.values()))\n        self.range_list_classes= range(len(self.list_classes))\n        self.class_weight = np.array([len(self.class_to_list_files[class_]) for class_ in self.list_classes])\n        self.class_weight = self.class_weight/np.sum(self.class_weight)\n\n    def get_sample(self):\n        class_idx = np.random.choice(self.range_list_classes, 1, p=self.class_weight)[0]\n        examples_class_idx = np.random.choice(range(len(self.class_to_list_files[self.list_classes[class_idx]])), 2)\n        positive_example_1, positive_example_2 = \\\n            self.class_to_list_files[self.list_classes[class_idx]][examples_class_idx[0]],\\\n            self.class_to_list_files[self.list_classes[class_idx]][examples_class_idx[1]]\n\n\n        negative_example = None\n        while negative_example is None or self.file_class_mapping[negative_example] == \\\n                self.file_class_mapping[positive_example_1]:\n            negative_example_idx = np.random.choice(self.range_all_files, 1)[0]\n            negative_example = self.list_all_files[negative_example_idx]\n        return positive_example_1, negative_example, positive_example_2\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1084d6bd4aabb75d4fd1f8ae45f8bdb189f022c0"},"cell_type":"code","source":"batch_size = 8\ninput_shape = (256, 256)\nbase_path = \"../input/train/\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cd380640ac1f886d89d7c5f9f0ea935c4c6cbf65"},"cell_type":"code","source":"def identity_loss(y_true, y_pred):\n    return K.mean(y_pred - 0 * y_true)\n\ndef bpr_triplet_loss(X):\n\n    positive_item_latent, negative_item_latent, user_latent = X\n\n    # BPR loss\n    loss = 1.0 - K.sigmoid(\n        K.sum(user_latent * positive_item_latent, axis=-1, keepdims=True) -\n        K.sum(user_latent * negative_item_latent, axis=-1, keepdims=True))\n\n    return loss\n\ndef get_base_model():\n    latent_dim = 50\n    base_model = ResNet50(include_top=False, weights='imagenet')  # use weights='imagenet' locally\n\n    # for layer in base_model.layers:\n    #     layer.trainable = False\n\n    x = base_model.output\n    x = GlobalMaxPooling2D()(x)\n    x = Dropout(0.5)(x)\n    dense_1 = Dense(latent_dim)(x)\n    normalized = Lambda(lambda  x: K.l2_normalize(x,axis=1))(dense_1)\n    base_model = Model(base_model.input, normalized, name=\"base_model\")\n    return base_model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5a86056d71a0cffdea97c24ad9f21e26d718dea5"},"cell_type":"code","source":"def build_model():\n    base_model = get_base_model()\n\n    positive_example_1 = Input(input_shape+(3,) , name='positive_example_1')\n    negative_example = Input(input_shape+(3,), name='negative_example')\n    positive_example_2 = Input(input_shape+(3,), name='positive_example_2')\n\n    positive_example_1_out = base_model(positive_example_1)\n    negative_example_out = base_model(negative_example)\n    positive_example_2_out = base_model(positive_example_2)\n\n    loss = merge(\n        [positive_example_1_out, negative_example_out, positive_example_2_out],\n        mode=bpr_triplet_loss,\n        name='loss',\n        output_shape=(1, ))\n\n    model = Model(\n        input=[positive_example_1, negative_example, positive_example_2],\n        output=loss)\n    model.compile(loss=identity_loss, optimizer=Adam(0.000001))\n\n    print(model.summary())\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"98ccc068c8d138b7378a0f10ae72fca2b5be9cdd"},"cell_type":"code","source":"model_name = \"triplet_model\"\n\nfile_path = model_name + \"weights.best.hdf5\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"81e8e50c3156c77ff9fff74e42a75ad1f26f492c"},"cell_type":"code","source":"def build_inference_model(weight_path=file_path):\n    base_model = get_base_model()\n\n    positive_example_1 = Input(input_shape+(3,) , name='positive_example_1')\n    negative_example = Input(input_shape+(3,), name='negative_example')\n    positive_example_2 = Input(input_shape+(3,), name='positive_example_2')\n\n    positive_example_1_out = base_model(positive_example_1)\n    negative_example_out = base_model(negative_example)\n    positive_example_2_out = base_model(positive_example_2)\n\n    loss = merge(\n        [positive_example_1_out, negative_example_out, positive_example_2_out],\n        mode=bpr_triplet_loss,\n        name='loss',\n        output_shape=(1, ))\n\n    model = Model(\n        input=[positive_example_1, negative_example, positive_example_2],\n        output=loss)\n    model.compile(loss=identity_loss, optimizer=Adam(0.000001))\n\n    model.load_weights(weight_path)\n\n    inference_model = Model(base_model.get_input_at(0), output=base_model.get_output_at(0))\n    inference_model.compile(loss=\"mse\", optimizer=Adam(0.000001))\n    print(inference_model.summary())\n\n    return inference_model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f9a31cd9a71159882287fd90d698fe9582000a0d"},"cell_type":"code","source":"def read_and_resize(filepath):\n    im = Image.open((filepath)).convert('RGB')\n    im = im.resize(input_shape)\n    im_array = np.array(im, dtype=\"uint8\")[..., ::-1]\n    return np.array(im_array / (np.max(im_array)+ 0.001), dtype=\"float32\")\n\ndef augment(im_array):\n    if np.random.uniform(0, 1) > 0.9:\n        im_array = np.fliplr(im_array)\n    return im_array","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6ab45fcf5cbe4b1f9369e70d1c7054463551d151"},"cell_type":"code","source":"def gen(triplet_gen):\n    while True:\n        list_positive_examples_1 = []\n        list_negative_examples = []\n        list_positive_examples_2 = []\n\n        for i in range(batch_size):\n            positive_example_1, negative_example, positive_example_2 = triplet_gen.get_sample()\n            positive_example_1_img, negative_example_img, positive_example_2_img = read_and_resize(base_path+positive_example_1), \\\n                                                                       read_and_resize(base_path+negative_example), \\\n                                                                       read_and_resize(base_path+positive_example_2)\n\n            positive_example_1_img, negative_example_img, positive_example_2_img = augment(positive_example_1_img), \\\n                                                                                   augment(negative_example_img), \\\n                                                                                   augment(positive_example_2_img)\n\n            list_positive_examples_1.append(positive_example_1_img)\n            list_negative_examples.append(negative_example_img)\n            list_positive_examples_2.append(positive_example_2_img)\n\n        list_positive_examples_1 = np.array(list_positive_examples_1)\n        list_negative_examples = np.array(list_negative_examples)\n        list_positive_examples_2 = np.array(list_positive_examples_2)\n        yield [list_positive_examples_1, list_negative_examples, list_positive_examples_2], np.ones(batch_size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"be34c43cac73ff60cd38027bac956749cbbd6e52"},"cell_type":"code","source":"# Read data\ndata = pd.read_csv('../input/train.csv')\ntrain, test = train_test_split(data, test_size=0.3, shuffle=True, random_state=1337)\nfile_id_mapping_train = {k: v for k, v in zip(train.Image.values, train.Id.values)}\nfile_id_mapping_test = {k: v for k, v in zip(test.Image.values, test.Id.values)}\ntrain_gen = sample_gen(file_id_mapping_train)\ntest_gen = sample_gen(file_id_mapping_test)","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"# Prepare the test triplets\n\nmodel = build_model()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a44d1fcc2130781d93734f130c13864bee413679"},"cell_type":"code","source":"# Было\n#model.load_weights(file_path)\n\ncheckpoint = ModelCheckpoint(file_path, monitor='val_loss', verbose=1, save_best_only=True, mode='min')\n\nearly = EarlyStopping(monitor=\"val_loss\", mode=\"min\", patience=2)\n\n# callbacks_list = [checkpoint, early]  # early\ncallbacks_list = [checkpoint]\n\nhistory = model.fit_generator(gen(train_gen), validation_data=gen(test_gen), epochs=20,\n                              verbose=1, workers=4, use_multiprocessing=True,\n                              callbacks=callbacks_list, steps_per_epoch=300, \n                              validation_steps=30)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"575e1360011a784cdca090ed5854f53b51f15b9c"},"cell_type":"code","source":"model_name = \"triplet_loss\"\ndef data_generator(fpaths, batch=16):\n    i = 0\n    for path in fpaths:\n        if i == 0:\n            imgs = []\n            fnames = []\n        i += 1\n        img = read_and_resize(path)\n        imgs.append(img)\n        fnames.append(os.path.basename(path))\n        if i == batch:\n            i = 0\n            imgs = np.array(imgs)\n            yield fnames, imgs\n    if i < batch:\n        imgs = np.array(imgs)\n        yield fnames, imgs\n    raise StopIteration()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"58320a961fde37d6a75deafa65fd51245ff4e984"},"cell_type":"code","source":"data = pd.read_csv('../input/train.csv')\n\nfile_id_mapping = {k: v for k, v in zip(data.Image.values, data.Id.values)}\n\ninference_model = build_inference_model()\n\ntrain_files = glob.glob(\"../input/train/*.jpg\")\ntest_files = glob.glob(\"../input/test/*.jpg\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"60b848c50fcc25eb371016b655476e08c66b7499"},"cell_type":"code","source":"train_preds = []\ntrain_file_names = []\ni = 1\nfor fnames, imgs in data_generator(train_files, batch=32):\n    print(i*32/len(train_files)*100)\n    i += 1\n    predicts = inference_model.predict(imgs)\n    predicts = predicts.tolist()\n    train_preds += predicts\n    train_file_names += fnames","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"eb2b0d96314f8d5fcf7a77486b0e8f2059c8e3f1"},"cell_type":"code","source":"train_preds = np.array(train_preds)\n\ntest_preds = []\ntest_file_names = []\ni = 1\nfor fnames, imgs in data_generator(test_files, batch=32):\n    print(i * 32 / len(test_files) * 100)\n    i += 1\n    predicts = inference_model.predict(imgs)\n    predicts = predicts.tolist()\n    test_preds += predicts\n    test_file_names += fnames","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c5cb1c1be2a90cbda06d8ae6ef787b0b5e30c732"},"cell_type":"code","source":"test_preds = np.array(test_preds)\n\nneigh = NearestNeighbors(n_neighbors=6)\nneigh.fit(train_preds)\n\n# Было\n#distances, neighbors = neigh.kneighbors(train_preds)\n#print(distances, neighbors)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3ddff78a2ea1bd77dd6ab8313ba8df496a562767"},"cell_type":"code","source":"distances_test, neighbors_test = neigh.kneighbors(test_preds)\n\ndistances_test, neighbors_test = distances_test.tolist(), neighbors_test.tolist()\n\npreds_str = []\n\nfor filepath, distance, neighbour_ in zip(test_file_names, distances_test, neighbors_test):\n    sample_result = []\n    sample_classes = []\n    for d, n in zip(distance, neighbour_):\n        train_file = train_files[n].split(os.sep)[-1]\n        class_train = file_id_mapping[train_file]\n        sample_classes.append(class_train)\n        sample_result.append((class_train, d))\n\n    if \"new_whale\" not in sample_classes:\n        sample_result.append((\"new_whale\", 0.1))\n    sample_result.sort(key=lambda x: x[1])\n    sample_result = sample_result[:5]\n    preds_str.append(\" \".join([x[0] for x in sample_result]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"96db40e7770f64a7aaa2bd9631560278871ad32d"},"cell_type":"code","source":"df = pd.DataFrame(preds_str, columns=[\"Id\"])\ndf['Image'] = [x.split(os.sep)[-1] for x in test_file_names]\ndf.to_csv(\"sub_%s.csv\"%model_name, index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"69d4a0d50edd5b41f0efa3789d58f4717396b48b"},"cell_type":"code","source":"# pd.read_csv('sub_triplet_loss.csv')","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}