{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Dogs vs Cats","metadata":{}},{"cell_type":"markdown","source":"https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition","metadata":{}},{"cell_type":"code","source":"import cv2\nimport numpy as np\nimport tensorflow as tf\nfrom tensorflow.keras.applications import vgg16\n\nprint(tf.__version__)\nprint(tf.executing_eagerly())","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:40:31.558879Z","iopub.execute_input":"2022-05-16T18:40:31.559232Z","iopub.status.idle":"2022-05-16T18:40:37.245201Z","shell.execute_reply.started":"2022-05-16T18:40:31.559147Z","shell.execute_reply":"2022-05-16T18:40:37.243633Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# разархивируем трейн- и тест-датасеты\nimport os\nprint(os.listdir(\"../input\"))\n\nimport zipfile\n\nwith zipfile.ZipFile(\"../input/dogs-vs-cats-redux-kernels-edition/train.zip\",\"r\") as z:\n    z.extractall(\".\")\n    \nwith zipfile.ZipFile(\"../input/dogs-vs-cats-redux-kernels-edition/test.zip\",\"r\") as z:\n    z.extractall(\".\")","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:40:53.154422Z","iopub.execute_input":"2022-05-16T18:40:53.155118Z","iopub.status.idle":"2022-05-16T18:41:11.046725Z","shell.execute_reply.started":"2022-05-16T18:40:53.155079Z","shell.execute_reply":"2022-05-16T18:41:11.045975Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# убедимся, что датасеты разархивировались в рабочую папку на Kaggle (/working)\nprint(os.listdir(\"../working\"))","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:41:16.319156Z","iopub.execute_input":"2022-05-16T18:41:16.319411Z","iopub.status.idle":"2022-05-16T18:41:16.324188Z","shell.execute_reply.started":"2022-05-16T18:41:16.31938Z","shell.execute_reply":"2022-05-16T18:41:16.323314Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Функции загрузки данных","metadata":{}},{"cell_type":"code","source":"from random import shuffle\nfrom glob import glob\n\nIMG_SIZE = (224, 224)  # размер входного изображения сети\n\ntrain_files = glob('../working/train/*.jpg')\ntest_files = glob('../working/test/*.jpg')\n\n# загружаем входное изображение и предобрабатываем\ndef load_image(path, target_size=IMG_SIZE):\n    img = cv2.imread(path)[...,::-1]\n    img = cv2.resize(img, target_size)\n    return vgg16.preprocess_input(img)  # предобработка для VGG16\n\n# функция-генератор загрузки обучающих данных с диска\ndef fit_generator(files, batch_size=32):\n    batch_size = min(batch_size, len(files))\n    while True:\n        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(path) for path in files[i:j]])\n            y = np.array([1. if os.path.basename(path).startswith('dog') else 0.\n                          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)])","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:41:20.36801Z","iopub.execute_input":"2022-05-16T18:41:20.368284Z","iopub.status.idle":"2022-05-16T18:41:20.519613Z","shell.execute_reply.started":"2022-05-16T18:41:20.368253Z","shell.execute_reply":"2022-05-16T18:41:20.518904Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Визуализируем примеры для обучения","metadata":{}},{"cell_type":"code","source":"%matplotlib inline\nfrom matplotlib import pyplot as plt\nfig = plt.figure(figsize=(16, 8))\nfor i, path in enumerate(train_files[:10], 1):\n    subplot = fig.add_subplot(2, 5, i)\n    subplot.set_title('%s' % path.split('/')[-1])\n    img = cv2.imread(path)[...,::-1]\n    img = cv2.resize(img, IMG_SIZE)\n    plt.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:41:25.641536Z","iopub.execute_input":"2022-05-16T18:41:25.64228Z","iopub.status.idle":"2022-05-16T18:41:26.906957Z","shell.execute_reply.started":"2022-05-16T18:41:25.642242Z","shell.execute_reply":"2022-05-16T18:41:26.904622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Загружаем предобученную модель","metadata":{}},{"cell_type":"code","source":"# base_model - объект класса keras.models.Model (Functional Model)\nbase_model = vgg16.VGG16(weights='imagenet',\n                         include_top=False,\n                         input_shape=(IMG_SIZE[0], IMG_SIZE[1], 3))","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:41:34.43129Z","iopub.execute_input":"2022-05-16T18:41:34.431573Z","iopub.status.idle":"2022-05-16T18:41:37.652346Z","shell.execute_reply.started":"2022-05-16T18:41:34.431523Z","shell.execute_reply":"2022-05-16T18:41:37.651599Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"base_model.summary()","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:41:47.004885Z","iopub.execute_input":"2022-05-16T18:41:47.005174Z","iopub.status.idle":"2022-05-16T18:41:47.02026Z","shell.execute_reply.started":"2022-05-16T18:41:47.005134Z","shell.execute_reply":"2022-05-16T18:41:47.019467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Фиксируем веса предобученной НС и добавляем слои, дроп-аут для дообучения модели","metadata":{}},{"cell_type":"code","source":"# фиксируем все веса предобученной сети\nfor layer in base_model.layers:\n    layer.trainable = False\n\n# x = base_model.layers[-1].output\n# x = tf.keras.layers.Flatten()(x)\n# x = tf.keras.layers.Dropout(0.5)(x)\n# x = tf.keras.layers.Dense(128, activation='relu')(x)\n# x = tf.keras.layers.Dense(128, activation='relu')(x)\n# x = tf.keras.layers.Dropout(0.3)(x)\n\nx = base_model.layers[-1].output\nx = tf.keras.layers.Flatten()(x)\nx = tf.keras.layers.Dropout(0.3)(x)\n\nx = tf.keras.layers.Dense(128, activation='ReLU')(x)\nx = tf.keras.layers.BatchNormalization()(x)\n\nx = tf.keras.layers.Dense(16, activation='ReLU')(x)\nx = tf.keras.layers.BatchNormalization()(x)\n\nx = tf.keras.layers.Dense(1,  # один выход (бинарная классификация)\n                          activation='sigmoid',  # функция активации  \n                          kernel_regularizer=tf.keras.regularizers.l1(1e-4))(x)\n\nmodel = tf.keras.Model(inputs=base_model.input, outputs=x, name='dogs_vs_cats')","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:42:59.975742Z","iopub.execute_input":"2022-05-16T18:42:59.97605Z","iopub.status.idle":"2022-05-16T18:43:00.20354Z","shell.execute_reply.started":"2022-05-16T18:42:59.976017Z","shell.execute_reply":"2022-05-16T18:43:00.202781Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Выводим архитектуру модели","metadata":{}},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:43:03.575572Z","iopub.execute_input":"2022-05-16T18:43:03.576092Z","iopub.status.idle":"2022-05-16T18:43:03.596508Z","shell.execute_reply.started":"2022-05-16T18:43:03.576054Z","shell.execute_reply":"2022-05-16T18:43:03.595411Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Компилируем модель и запускаем обучение","metadata":{}},{"cell_type":"code","source":"model.compile(optimizer='adam', \n              loss='binary_crossentropy',  # функция потерь binary_crossentropy (log loss\n              metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:43:18.302882Z","iopub.execute_input":"2022-05-16T18:43:18.303142Z","iopub.status.idle":"2022-05-16T18:43:18.317359Z","shell.execute_reply.started":"2022-05-16T18:43:18.303112Z","shell.execute_reply":"2022-05-16T18:43:18.316594Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_samples = 1000  # число изображений в валидационной выборке\n\nshuffle(train_files)  # перемешиваем обучающую выборку\nvalidation_data = next(fit_generator(train_files[:val_samples], val_samples))\ntrain_data = fit_generator(train_files[val_samples:])  # данные читаем функцией-генератором\n\ncheckpoint = tf.keras.callbacks.ModelCheckpoint(\n    'cats-dogs-vgg16.hdf5',\n    monitor='loss',\n    verbose=1,  \n    save_best_only=True, \n    save_weights_only=False,\n    mode='auto',\n    save_freq=10)\n\n# запускаем процесс обучения\nmodel.fit(train_data,\n          steps_per_epoch=10,  # число вызовов генератора за эпоху\n          epochs=100,  # число эпох обучения\n          validation_data=validation_data,\n          callbacks=[checkpoint])","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:43:27.214338Z","iopub.execute_input":"2022-05-16T18:43:27.214632Z","iopub.status.idle":"2022-05-16T18:49:35.178117Z","shell.execute_reply.started":"2022-05-16T18:43:27.214598Z","shell.execute_reply":"2022-05-16T18:49:35.177449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# загружаем модель с наилучшими  весами, полученными на этапе обучения \nmodel.load_weights('cats-dogs-vgg16.hdf5')","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:51:13.985408Z","iopub.execute_input":"2022-05-16T18:51:13.98895Z","iopub.status.idle":"2022-05-16T18:51:14.067319Z","shell.execute_reply.started":"2022-05-16T18:51:13.988913Z","shell.execute_reply":"2022-05-16T18:51:14.066606Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Предсказания на проверочной выборке","metadata":{}},{"cell_type":"code","source":"test_pred = model.predict(\n    predict_generator(test_files), steps=len(test_files))","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:51:21.459905Z","iopub.execute_input":"2022-05-16T18:51:21.460159Z","iopub.status.idle":"2022-05-16T18:52:31.548151Z","shell.execute_reply.started":"2022-05-16T18:51:21.46013Z","shell.execute_reply":"2022-05-16T18:52:31.547403Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig = plt.figure(figsize=(16, 8))\nfor i, (path, score) in enumerate(zip(test_files[:10], test_pred[:10]), 1):\n    subplot = fig.add_subplot(2, 5, i)\n    subplot.set_title('%.1f %s' % (score, os.path.basename(path)))\n    img = cv2.imread(path)[...,::-1]\n    img = cv2.resize(img, IMG_SIZE)\n    subplot.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:52:41.760684Z","iopub.execute_input":"2022-05-16T18:52:41.760951Z","iopub.status.idle":"2022-05-16T18:52:43.121195Z","shell.execute_reply.started":"2022-05-16T18:52:41.760922Z","shell.execute_reply":"2022-05-16T18:52:43.120493Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Готовим данные для отправки","metadata":{}},{"cell_type":"code","source":"import re\n\nwith open('submit.csv', 'w') as dst:\n    dst.write('id,label\\n')\n    for path, score in zip(test_files, test_pred):\n        dst.write('%s,%.1f\\n' % (re.search('(\\d+).jpg$', path).group(1), score))","metadata":{"execution":{"iopub.status.busy":"2022-05-16T18:52:51.302426Z","iopub.execute_input":"2022-05-16T18:52:51.302975Z","iopub.status.idle":"2022-05-16T18:52:51.352542Z","shell.execute_reply.started":"2022-05-16T18:52:51.302937Z","shell.execute_reply":"2022-05-16T18:52:51.351778Z"},"trusted":true},"execution_count":null,"outputs":[]}]}