In [1]:
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0"

In [2]:
import os
import glob
import tensorflow as tf
import numpy as np
from keras import layers, models, optimizers, losses, metrics, regularizers
from keras.callbacks import Callback, EarlyStopping, ReduceLROnPlateau, ModelCheckpoint, TensorBoard
from keras.preprocessing.sequence import pad_sequences
import keras.backend as K


/home/duke/.conda/envs/heads/lib/python3.6/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  from ._conv import register_converters as _register_converters
Using TensorFlow backend.

In [3]:
from sklearn.model_selection import train_test_split

In [4]:
import matplotlib.pyplot as plt
plt.style.use('ggplot')
%matplotlib inline
plt.rcParams['figure.figsize'] = (15, 12) # set default size of plots

In [6]:
from keras.datasets import mnist

In [7]:
(x_train, y_train), (x_test, y_test) = mnist.load_data()

In [8]:
y_train = np.squeeze(y_train)
y_test = np.squeeze(y_test)

In [9]:
classes = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
num_classes = len(classes)
samples_per_class = 10
for y, cls in enumerate(classes):
    idxs = np.flatnonzero(y_train == y)
    idxs = np.random.choice(idxs, samples_per_class, replace=False)
    for i, idx in enumerate(idxs):
        plt_idx = i * num_classes + y + 1
        plt.subplot(samples_per_class, num_classes, plt_idx)
        plt.imshow(x_train[idx].astype('uint8'), cmap='gray')
        plt.axis('off')
        if i == 0:
            plt.title(cls)
plt.show()



In [10]:
# Preprocessing: вычитаем среднее
# 1: Находим среднее изображение
mean_image = np.mean(x_train, axis=0)
plt.figure(figsize=(4,4))
plt.imshow(mean_image.reshape((28,28)).astype('uint8'), cmap='gray') # визуализируем полученное среднее
plt.show()



In [11]:
# 2: вычитаем среднее из изображений обучающей и тестовых выборок
x_train = x_train - mean_image
x_test = x_test - mean_image

In [13]:
x_train, x_val, y_train, y_val = train_test_split(x_train, y_train, test_size=1000)

In [24]:
def build_encoder():
    img_input = layers.Input(shape=(28, 28, 1))
    
    x = layers.Conv2D(32, kernel_size=4, strides=2, padding='same')(img_input)
    x = layers.ELU()(x)
    x = layers.Conv2D(32, kernel_size=4, strides=1, padding='same')(x)
    x = layers.ELU()(x)
    
    x = layers.Conv2D(64, kernel_size=4, strides=2, padding='same')(x)
    x = layers.ELU()(x)
    x = layers.Conv2D(64, kernel_size=4, strides=1, padding='same')(x)
    x = layers.ELU()(x)
    
    x = layers.Conv2D(128, kernel_size=4, strides=2, padding='same')(x)
    x = layers.ELU()(x)
    x = layers.Conv2D(128, kernel_size=4, strides=1, padding='same')(x)
    x = layers.ELU()(x)
    
    x = layers.Conv2D(128, kernel_size=3, strides=2, padding='same')(x)
    x = layers.ELU()(x)
    x = layers.Conv2D(128, kernel_size=3, strides=1, padding='same')(x)
    
    output = layers.GlobalAvgPool2D()(x)
    
    return models.Model(img_input, output, 
                        name='encoder')

In [25]:
def build_siamese():
    img_input = layers.Input(shape=(28, 28, 1))
    img_input_pair = layers.Input(shape=(28, 28, 1))
    encoder = build_encoder()
    
    embedding = encoder(img_input)
    embedding_pair = encoder(img_input_pair)
    
    output = layers.dot([embedding, embedding_pair], axes=-1, normalize=True)
    
    
    return models.Model([img_input, img_input_pair], output, 
                        name='siamese')

In [26]:
K.clear_session()
model = build_siamese()

In [27]:
model.summary()


__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_1 (InputLayer)            (None, 28, 28, 1)    0                                            
__________________________________________________________________________________________________
input_2 (InputLayer)            (None, 28, 28, 1)    0                                            
__________________________________________________________________________________________________
encoder (Model)                 (None, 128)          787616      input_1[0][0]                    
                                                                 input_2[0][0]                    
__________________________________________________________________________________________________
dot_1 (Dot)                     (None, 1)            0           encoder[1][0]                    
                                                                 encoder[2][0]                    
==================================================================================================
Total params: 787,616
Trainable params: 787,616
Non-trainable params: 0
__________________________________________________________________________________________________

Тренировочный цикл


In [28]:
def generate_batch(data, labels, batch_size):
    indexes = np.arange(len(data))
    
    while True:
        batch_obj = []
        batch_pair_obj = []
        batch_label = []
        for _ in range(batch_size // 2):
            class_index = np.random.choice(labels, 1, replace=False)

            class_objects_indexes = indexes[labels == class_index]
            object_index, positive_index = np.random.choice(class_objects_indexes, 2, replace=False)
            

            batch_obj.append(data[object_index])
            batch_pair_obj.append(data[positive_index])
            batch_label.append(1)

            other_objects_indexes = indexes[labels != class_index]
            negative_index = np.random.choice(other_objects_indexes, 1, replace=False)

            batch_obj.append(data[object_index])
            batch_pair_obj.append(data[negative_index[0]])
            batch_label.append(-1)

        yield [np.expand_dims(batch_obj, -1), np.expand_dims(batch_pair_obj, -1)], np.array(batch_label)

In [29]:
generator = generate_batch(x_train, y_train, 128)
generator_val = generate_batch(x_val, y_val, 128)

In [30]:
# for item in generator:
#     print (item[0][1].shape)

In [31]:
adam = optimizers.Adam(lr=0.0001,amsgrad=True)
model.compile('adam', 'mse', metrics=['acc'])

In [32]:
model.fit_generator(generator=generator, 
                    steps_per_epoch= 1024, 
                    epochs=256, 
                    validation_steps= 32, 
                    validation_data=generator_val, 
                    callbacks= [ReduceLROnPlateau(patience=6, monitor='loss', epsilon=0.01, verbose=1)])


Epoch 1/256
1024/1024 [==============================] - 133s 130ms/step - loss: 0.4983 - acc: 0.4834 - val_loss: 0.4205 - val_acc: 0.4922
Epoch 2/256
1024/1024 [==============================] - 134s 131ms/step - loss: 0.4115 - acc: 0.4917 - val_loss: 0.4108 - val_acc: 0.4900
Epoch 3/256
1024/1024 [==============================] - 134s 131ms/step - loss: 0.4072 - acc: 0.4939 - val_loss: 0.4094 - val_acc: 0.4907
Epoch 4/256
1024/1024 [==============================] - 136s 133ms/step - loss: 0.4043 - acc: 0.4954 - val_loss: 0.4118 - val_acc: 0.4910
Epoch 5/256
1024/1024 [==============================] - 134s 130ms/step - loss: 0.4039 - acc: 0.4960 - val_loss: 0.4059 - val_acc: 0.4932
Epoch 6/256
1024/1024 [==============================] - 143s 140ms/step - loss: 0.4026 - acc: 0.4969 - val_loss: 0.4129 - val_acc: 0.4905
Epoch 7/256
1024/1024 [==============================] - 137s 134ms/step - loss: 0.4002 - acc: 0.4976 - val_loss: 0.4185 - val_acc: 0.4885
Epoch 8/256
1024/1024 [==============================] - 129s 126ms/step - loss: 0.4002 - acc: 0.4974 - val_loss: 0.4144 - val_acc: 0.4878
Epoch 9/256
1024/1024 [==============================] - 127s 124ms/step - loss: 0.3993 - acc: 0.4981 - val_loss: 0.4031 - val_acc: 0.4924
Epoch 10/256
1024/1024 [==============================] - 130s 127ms/step - loss: 0.3998 - acc: 0.4980 - val_loss: 0.4083 - val_acc: 0.4900
Epoch 11/256
1024/1024 [==============================] - 132s 129ms/step - loss: 0.3989 - acc: 0.4985 - val_loss: 0.4103 - val_acc: 0.4915
Epoch 12/256
1024/1024 [==============================] - 126s 123ms/step - loss: 0.3979 - acc: 0.4989 - val_loss: 0.4086 - val_acc: 0.4915
Epoch 13/256
1024/1024 [==============================] - 128s 125ms/step - loss: 0.3982 - acc: 0.4988 - val_loss: 0.4057 - val_acc: 0.4939
Epoch 14/256
1023/1024 [============================>.] - ETA: 0s - loss: 0.3979 - acc: 0.4988
Epoch 00014: ReduceLROnPlateau reducing learning rate to 0.00010000000474974513.
1024/1024 [==============================] - 129s 126ms/step - loss: 0.3979 - acc: 0.4988 - val_loss: 0.4148 - val_acc: 0.4858
Epoch 15/256
1024/1024 [==============================] - 130s 127ms/step - loss: 0.3960 - acc: 0.4996 - val_loss: 0.4063 - val_acc: 0.4895
Epoch 16/256
 249/1024 [======>.......................] - ETA: 1:37 - loss: 0.3960 - acc: 0.4997
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
<ipython-input-32-c34409db7ced> in <module>()
      4                     validation_steps= 32,
      5                     validation_data=generator_val,
----> 6                     callbacks= [ReduceLROnPlateau(patience=6, monitor='loss', epsilon=0.01, verbose=1)])

~/.conda/envs/heads/lib/python3.6/site-packages/keras/legacy/interfaces.py in wrapper(*args, **kwargs)
     89                 warnings.warn('Update your `' + object_name +
     90                               '` call to the Keras 2 API: ' + signature, stacklevel=2)
---> 91             return func(*args, **kwargs)
     92         wrapper._original_function = func
     93         return wrapper

~/.conda/envs/heads/lib/python3.6/site-packages/keras/engine/training.py in fit_generator(self, generator, steps_per_epoch, epochs, verbose, callbacks, validation_data, validation_steps, class_weight, max_queue_size, workers, use_multiprocessing, shuffle, initial_epoch)
   2175                     outs = self.train_on_batch(x, y,
   2176                                                sample_weight=sample_weight,
-> 2177                                                class_weight=class_weight)
   2178 
   2179                     if not isinstance(outs, list):

~/.conda/envs/heads/lib/python3.6/site-packages/keras/engine/training.py in train_on_batch(self, x, y, sample_weight, class_weight)
   1847             ins = x + y + sample_weights
   1848         self._make_train_function()
-> 1849         outputs = self.train_function(ins)
   1850         if len(outputs) == 1:
   1851             return outputs[0]

~/.conda/envs/heads/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py in __call__(self, inputs)
   2473         session = get_session()
   2474         updated = session.run(fetches=fetches, feed_dict=feed_dict,
-> 2475                               **self.session_kwargs)
   2476         return updated[:len(self.outputs)]
   2477 

~/.conda/envs/heads/lib/python3.6/site-packages/tensorflow/python/client/session.py in run(self, fetches, feed_dict, options, run_metadata)
    887     try:
    888       result = self._run(None, fetches, feed_dict, options_ptr,
--> 889                          run_metadata_ptr)
    890       if run_metadata:
    891         proto_data = tf_session.TF_GetBuffer(run_metadata_ptr)

~/.conda/envs/heads/lib/python3.6/site-packages/tensorflow/python/client/session.py in _run(self, handle, fetches, feed_dict, options, run_metadata)
   1118     if final_fetches or final_targets or (handle and feed_dict_tensor):
   1119       results = self._do_run(handle, final_targets, final_fetches,
-> 1120                              feed_dict_tensor, options, run_metadata)
   1121     else:
   1122       results = []

~/.conda/envs/heads/lib/python3.6/site-packages/tensorflow/python/client/session.py in _do_run(self, handle, target_list, fetch_list, feed_dict, options, run_metadata)
   1315     if handle is None:
   1316       return self._do_call(_run_fn, self._session, feeds, fetches, targets,
-> 1317                            options, run_metadata)
   1318     else:
   1319       return self._do_call(_prun_fn, self._session, handle, feeds, fetches)

~/.conda/envs/heads/lib/python3.6/site-packages/tensorflow/python/client/session.py in _do_call(self, fn, *args)
   1321   def _do_call(self, fn, *args):
   1322     try:
-> 1323       return fn(*args)
   1324     except errors.OpError as e:
   1325       message = compat.as_text(e.message)

~/.conda/envs/heads/lib/python3.6/site-packages/tensorflow/python/client/session.py in _run_fn(session, feed_dict, fetch_list, target_list, options, run_metadata)
   1300           return tf_session.TF_Run(session, options,
   1301                                    feed_dict, fetch_list, target_list,
-> 1302                                    status, run_metadata)
   1303 
   1304     def _prun_fn(session, handle, feed_dict, fetch_list):

KeyboardInterrupt: 

In [72]:
def retrieve(index):
    request = x_test[index]
    data = np.expand_dims(x_test, -1)
    
    scores = model.predict([data, np.array([data[index]] * len(data))], batch_size=128)
    scores = np.squeeze(scores)
    scores[index] = -100
    
    sort = np.argsort(scores * -1)
    
#     return sort
    
    fig = plt.figure()
    a=fig.add_subplot(1,3,1)
    imgplot = plt.imshow(x_test[index] + mean_image, cmap='gray')
    a.set_title('Request')
    a=fig.add_subplot(1,3,2)
    imgplot = plt.imshow(x_test[sort[0]] + mean_image, cmap='gray')
    a.set_title(f'Result. Label {y_test[sort[0]]}')
    a=fig.add_subplot(1,3,3)
    imgplot = plt.imshow(x_test[sort[1]] + mean_image, cmap='gray')
    a.set_title(f'Result. Label {y_test[sort[1]]}')
    plt.show()

In [74]:
a = retrieve(777)



In [ ]: