{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Dogs vs. Cats"},{"metadata":{},"cell_type":"markdown","source":"https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition"},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nimport keras\nfrom keras.models import Model\nfrom keras.applications.vgg16 import VGG16\nfrom keras.applications.vgg16 import preprocess_input\nfrom keras.applications.resnet50 import ResNet50, preprocess_input\nfrom keras.preprocessing.image import load_img, img_to_array, array_to_img, ImageDataGenerator\nimport cv2\nfrom keras.applications.inception_resnet_v2 import InceptionResNetV2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_SIZE = (224, 224)  # размер входного изображения сети","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Функции загрузки данных"},{"metadata":{"trusted":true},"cell_type":"code","source":"import pandas as pd\nmy_submission = pd.DataFrame(columns=['id', 'label'])\nmy_submission.id = np.arange(1,12501).astype(int)\nmy_submission.label = np.zeros(12500)\nmy_submission.head(3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from numpy import random","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"random.seed(12412)\n'''функция для небольшого изменения цвета'''\ndef change_value(img):\n    img_hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)\n    img_hsv[...,0] = img_hsv[...,0] + random.randint(-40, 40)\n    img_rgb = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2RGB)\n    img_new = array_to_img(img_rgb) # для того что бы изображение не выходило за границы (0, 255)\n    array = img_to_array(img_new)\n    return array","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import re\nfrom glob import glob\n\ntrain_files = glob('../input/train/*.jpg')\ntest_files = glob('../input/test/*.jpg')\n\nrandom.seed(29)\n# загружаем входное изображение и предобрабатываем\ndef load_image_with_augmentation(path, target_size=IMG_SIZE):\n    images = [] # создадим лист для аугментированных изображений\n    img = load_img(path, target_size=target_size)  # загрузка и масштабирование изображения\n    array_1 = img_to_array(img)\n    images.append(array_1) # добавим оригинальное изображение\n    array_2 = cv2.flip(array_1, flipCode=1)\n    images.append(array_2) # добавим зеркальное изображение\n    M = cv2.getRotationMatrix2D(center=(112, 112), angle=random.normal(loc=0.0, scale=10.0), scale=1.3)\n    array_3 = cv2.warpAffine(array_1, M, (224, 224))\n    images.append(array_3) # добавим повернутое изображение\n    array_4 = change_value(array_1)\n    images.append(array_4) # добавим изображение с измененным цветом\n    a = random.choice((0, 1, 2, 3))\n    array = images[a]\n    return preprocess_input(array)  # предобработка для VGG16\n\ndef load_image(path, target_size=IMG_SIZE):\n    img = load_img(path, target_size=target_size)  # загрузка и масштабирование изображения\n    array = img_to_array(img)\n    return preprocess_input(array)  # предобработка для VGG16\n\n# генератор для последовательного чтения обучающих данных с диска\ndef fit_generator(files, batch_size=32):\n    while True:\n        random.shuffle(files)\n        for k in range(len(files) // batch_size):\n            i = k * batch_size\n            j = i + batch_size\n            if j > len(files):\n                j = - j % len(files)\n            x = np.array([load_image_with_augmentation(path) for path in files[i:j]])\n            y = np.array([1. if re.search('.*/dog\\.\\d', path) else 0. for path in files[i:j]])\n            yield (x, y)\n\n# генератор последовательного чтения тестовых данных с диска\ndef predict_generator(files):\n    while True:\n        for path in files:\n            yield np.array([load_image(path)])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(train_files)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Визуализируем примеры для обучения"},{"metadata":{"trusted":true},"cell_type":"code","source":"%matplotlib inline\nfrom matplotlib import pyplot as plt\nfig = plt.figure(figsize=(20, 20))\nfor i, path in enumerate(test_files[:5], 1):\n    subplot = fig.add_subplot(i // 5 + 1, 5, i)\n    plt.imshow(plt.imread(path));\n    subplot.set_title('%s' % path.split('/')[-1]);","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Загружаем предобученную модель"},{"metadata":{"trusted":true},"cell_type":"code","source":"# base_model -  объект класса keras.models.Model (Functional Model)\n# base_model = VGG16(include_top = False,\n#                    weights = 'imagenet',\n#                    input_shape = (IMG_SIZE[0], IMG_SIZE[1], 3))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"base_model = ResNet50(include_top = False,\n                      weights = 'imagenet',\n                      input_shape = (IMG_SIZE[0], IMG_SIZE[1], 3))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# base_model = InceptionResNetV2(include_top = False,\n#                                weights = 'imagenet',\n#                                input_shape = (IMG_SIZE[0], IMG_SIZE[1], 3))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(base_model.layers)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for layer in base_model.layers[:-25]:\n    layer.trainable = False","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# фиксируем веса до 6-ого слоя\n# for num, layer in enumerate(base_model.layers):\n#     if num <= 6:\n#         layer.trainable = False\n#     else:\n#         layer.trainable = True","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# base_model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Добавляем полносвязный слой"},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.layers.normalization import BatchNormalization","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"seed = 1854241\nkernek_initializer = keras.initializers.glorot_normal(seed=seed)\nbias_initializer = keras.initializers.normal(stddev=1., seed=seed)\nact = keras.layers.PReLU()\n\nx = base_model.layers[-5].output\nx = keras.layers.Flatten()(x)\nx = keras.layers.Dense(24, activation=act, kernel_regularizer=keras.regularizers.l1(1e-4),\n                       bias_initializer=bias_initializer, kernel_initializer=kernek_initializer)(x)\nx = BatchNormalization()(x)\nx = keras.layers.Dropout(0.5)(x)\nx = keras.layers.Dense(24, activation=act, kernel_regularizer=keras.regularizers.l1(1e-4), \n                       bias_initializer=bias_initializer, kernel_initializer=kernek_initializer)(x)\nx = BatchNormalization()(x)\nx = keras.layers.Dropout(0.5)(x)\nx = keras.layers.Dense(1, activation='sigmoid', kernel_regularizer=keras.regularizers.l1(1e-4), \n                       bias_initializer=bias_initializer, kernel_initializer=kernek_initializer)(x)\nmodel = Model(inputs=base_model.input, outputs=x)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Выводим архитектуру модели"},{"metadata":{"trusted":true},"cell_type":"code","source":"# model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Компилируем модель и запускаем обучение"},{"metadata":{"trusted":true},"cell_type":"code","source":"model.evaluate\n\noptimizer_ = keras.optimizers.adam(lr=3e-4)\nmodel.compile(optimizer=optimizer_, \n              loss='binary_crossentropy',  # функция потерь binary_crossentropy (log loss)\n              metrics=['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def scheduler(epoch):\n    if epoch < 180:\n        return 3e-4\n    elif 180 <= epoch < 250:\n        return 1e-4\n    elif 250 <= epoch < 330:\n        return 5e-5\n    else:\n        return 1e-5\n\ncallback = keras.callbacks.LearningRateScheduler(scheduler)","execution_count":null,"outputs":[]},{"metadata":{"scrolled":false,"trusted":true},"cell_type":"code","source":"random.seed(29)\nrandom.shuffle(train_files)  # перемешиваем обучающую выборку\n\ntrain_val_split = 100  # число изображений в валидационной выборке\n\nvalidation_data = next(fit_generator(train_files[:train_val_split], train_val_split))\n\n# запускаем процесс обучения\nmodel.fit_generator(fit_generator(train_files[train_val_split:]),  # данные читаем функцией-генератором\n        steps_per_epoch=30,  # число вызовов генератора за эпоху\n        epochs=450,  # число эпох обучения\n        validation_data=validation_data)#, callbacks=[callback])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"\n## Предсказания на проверочной выборке"},{"metadata":{"trusted":true},"cell_type":"code","source":"pred = model.predict_generator(predict_generator(test_files), len(test_files), max_queue_size=500)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%matplotlib inline\nfrom matplotlib import pyplot as plt\nfig = plt.figure(figsize=(20, 20))\nfor i, (path, score) in enumerate(zip(test_files[160:][:10], pred[160:][:10]), 1):\n    subplot = fig.add_subplot(i // 5 + 1, 5, i)\n    plt.imshow(plt.imread(path));\n    subplot.set_title('%.3f' % score);","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Готовим данные для сабмита"},{"metadata":{"trusted":true},"cell_type":"code","source":"with open('submit_2.csv', 'w') as dst:\n    dst.write('id,label\\n')\n    for path, score in zip(test_files, pred):\n        dst.write('%s,%f\\n' % (re.search('(\\d+)', path).group(0), score))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"my_submission.label = pred\nmy_submission.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# my_submission.to_csv('submit.csv', index=False)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.7.3"},"widgets":{"state":{},"version":"1.1.2"}},"nbformat":4,"nbformat_minor":1}