text: from collections import defaultdict
  from glob import glob
  from random import choice, sample
  
  import cv2
  import numpy as np
  import pandas as pd
  from keras.applications.resnet50 import ResNet50, preprocess_input
  from keras.callbacks import ModelCheckpoint, ReduceLROnPlateau
  from keras.layers import Input, Dense, GlobalMaxPool2D, GlobalAvgPool2D, Concatenate, Multiply, Dropout, Subtract
  from keras.models import Model
  from keras.optimizers import Adam
  
  basestr = ''
  train_file_path = "../input/train_relationships.csv"
  train_folders_path = "../input/train/"
  val_famillies = "F09"
  
  all_images = glob(train_folders_path + "*/*/*.jpg")
  
  train_images = [x for x in all_images if val_famillies not in x]
  val_images = [x for x in all_images if val_famillies in x]
  
  train_person_to_images_map = defaultdict(list)
  
  ppl = [x.split("/")[-3] + "/" + x.split("/")[-2] for x in all_images]
  
  for x in train_images:
      train_person_to_images_map[x.split("/")[-3] + "/" + x.split("/")[-2]].append(x)
  
  val_person_to_images_map = defaultdict(list)
  
  for x in val_images:
      val_person_to_images_map[x.split("/")[-3] + "/" + x.split("/")[-2]].append(x)
  
  relationships = pd.read_csv(train_file_path)
  relationships = list(zip(relationships.p1.values, relationships.p2.values))
  relationships = [x for x in relationships if x[0] in ppl and x[1] in ppl]
  
  train = [x for x in relationships if val_famillies not in x[0]]
  val = [x for x in relationships if val_famillies in x[0]]
  
  
  def read_img(path):
      img = cv2.imread(path)
      return preprocess_input(img)
  
  
  def gen(list_tuples, person_to_images_map, batch_size=16):
      ppl = list(person_to_images_map.keys())
      while True:
          batch_tuples = sample(list_tuples, batch_size // 2)
          labels = [1] * len(batch_tuples)
          while len(batch_tuples) < batch_size:
              p1 = choice(ppl)
              p2 = choice(ppl)
  
              if p1 != p2 and (p1, p2) not in list_tuples and (p2, p1) not in list_tuples:
                  batch_tuples.append((p1, p2))
                  labels.append(0)
  
          for x in batch_tuples:
              if not len(person_to_images_map[x[0]]):
                  print(x[0])
  
          X1 = [choice(person_to_images_map[x[0]]) for x in batch_tuples]
          X1 = np.array([read_img(x) for x in X1])
  
          X2 = [choice(person_to_images_map[x[1]]) for x in batch_tuples]
          X2 = np.array([read_img(x) for x in X2])
  
          yield [X1, X2], labels
  
  
  def baseline_model():
      input_1 = Input(shape=(224, 224, 3))
      input_2 = Input(shape=(224, 224, 3))
  
      base_model = ResNet50(weights='imagenet', include_top=False)
  
      for x in base_model.layers[:-3]:
          x.trainable = True
  
      x1 = base_model(input_1)
      x2 = base_model(input_2)
  
      # x1_ = Reshape(target_shape=(7*7, 2048))(x1)
      # x2_ = Reshape(target_shape=(7*7, 2048))(x2)
      #
      # x_dot = Dot(axes=[2, 2], normalize=True)([x1_, x2_])
      # x_dot = Flatten()(x_dot)
  
      x1 = Concatenate(axis=-1)([GlobalMaxPool2D()(x1), GlobalAvgPool2D()(x1)])
      x2 = Concatenate(axis=-1)([GlobalMaxPool2D()(x2), GlobalAvgPool2D()(x2)])
  
      x3 = Subtract()([x1, x2])
      x3 = Multiply()([x3, x3])
  
      x = Multiply()([x1, x2])
  
      x = Concatenate(axis=-1)([x, x3])
  
      x = Dense(100, activation="relu")(x)
      x = Dropout(0.01)(x)
      out = Dense(1, activation="sigmoid")(x)
  
      model = Model([input_1, input_2], out)
  
      model.compile(loss="binary_crossentropy", metrics=['acc'], optimizer=Adam(0.00001))
  
      model.summary()
  
      return model
  
  
  file_path = "baseline_"+basestr+".h5"
  
  checkpoint = ModelCheckpoint(file_path, monitor='val_acc', verbose=1, save_best_only=True, mode='max')
  
  reduce_on_plateau = ReduceLROnPlateau(monitor="val_acc", mode="max", factor=0.1, patience=20, verbose=1)
  
  from keras.callbacks import TensorBoard
  tbCallBack = TensorBoard(log_dir='./logs/'+basestr,
                           histogram_freq=0,
                           write_graph=True,
                           write_images=True)
  
  callbacks_list = [checkpoint, reduce_on_plateau, tbCallBack]
  
  model = baseline_model()
  # model.load_weights(file_path)
  model.fit_generator(gen(train, train_person_to_images_map, batch_size=16), use_multiprocessing=True,
                      validation_data=gen(val, val_person_to_images_map, batch_size=16), epochs=50, verbose=2,
                      workers=4, callbacks=callbacks_list, steps_per_epoch=200, validation_steps=100)
  
  test_path = "../input/test/"
  
  
  def chunker(seq, size=32):
      return (seq[pos:pos + size] for pos in range(0, len(seq), size))
  
  
  from tqdm import tqdm
  
  submission = pd.read_csv('../input/sample_submission.csv')
  
  predictions = []
  
  for batch in tqdm(chunker(submission.img_pair.values)):
      X1 = [x.split("-")[0] for x in batch]
      X1 = np.array([read_img(test_path + x) for x in X1])
  
      X2 = [x.split("-")[1] for x in batch]
      X2 = np.array([read_img(test_path + x) for x in X2])
  
      pred = model.predict([X1, X2]).ravel().tolist()
      predictions += pred
  
  submission['is_related'] = predictions
  
  submission.to_csv("baseline_"+basestr+".csv", index=False)
  