{"cells":[{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport shutil\nimport re\nimport math\n\nimport pandas as pd\nimport numpy as np\n\nimport PIL.Image\nimport cv2\n\nfrom random import shuffle\nfrom glob import glob\n\nfrom sklearn.model_selection import train_test_split\n\n#from tensorflow.python.keras.applications import VGG16\n\nfrom keras.applications import VGG16\n\nfrom tensorflow.python.keras.preprocessing.image import ImageDataGenerator\n\nfrom tensorflow import keras\nfrom tensorflow.keras.models import Model\n#from tensorflow.keras.applications.vgg16 import VGG16\nfrom tensorflow.keras.applications.vgg16 import preprocess_input\nfrom tensorflow.keras.preprocessing.image import load_img, img_to_array\n\nfrom keras import models\nfrom keras import layers\nfrom keras.callbacks import EarlyStopping, ModelCheckpoint\n\nfrom keras.optimizers import Adam","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"base_image_dir = os.path.join('..', 'input/aptos2019-blindness-detection/')\ntrain_dir = os.path.join(base_image_dir,'train_images/')\ndf = pd.read_csv(os.path.join(base_image_dir, 'train.csv'))\ndf['path'] = df['id_code'].map(lambda x: os.path.join(train_dir,'{}.png'.format(x)))\ndf = df.drop(columns=['id_code'])\ndf = df.sample(frac=1).reset_index(drop=True) #shuffle dataframe\ndf.head(10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df.diagnosis.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image_train, image_test, y_train, y_test = train_test_split(np.array(df.path), \n                                                            np.array(df.diagnosis), \n                                                            test_size=0.3,\n                                                            random_state=123, \n                                                            stratify=df.diagnosis)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image_train.shape","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Создадим словарь вида {имя_картинки : класс, ...} для быстрого доступа к метке класса по имени картинки"},{"metadata":{"trusted":true},"cell_type":"code","source":"image_and_class_train = dict(zip(image_train, y_train))\nimage_and_class_test = dict(zip(image_test, y_test))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Предобработка данных:**"},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_SIZE = (224, 224)  # размер входного изображения сети\nNUM_CLASSES = 5        # число классов","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def crop_image_from_gray(img,tol=7):\n    if img.ndim ==2:\n        mask = img>tol\n        return img[np.ix_(mask.any(1),mask.any(0))]\n    elif img.ndim==3:\n        gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n        mask = gray_img>tol\n        \n        check_shape = img[:,:,0][np.ix_(mask.any(1),mask.any(0))].shape[0]\n        if (check_shape == 0): # image is too dark so that we crop out everything,\n            return img # return original image\n        else:\n            img1=img[:,:,0][np.ix_(mask.any(1),mask.any(0))]\n            img2=img[:,:,1][np.ix_(mask.any(1),mask.any(0))]\n            img3=img[:,:,2][np.ix_(mask.any(1),mask.any(0))]\n    #         print(img1.shape,img2.shape,img3.shape)\n            img = np.stack([img1,img2,img3],axis=-1)\n    #         print(img.shape)\n        return img","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def circle_crop(path, img_size=(224,224), sigmaX=10):   \n    \"\"\"\n    Create circular crop around image centre    \n    \"\"\"    \n    \n    img = cv2.imread(path)\n    img = crop_image_from_gray(img)    \n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    \n    height, width, depth = img.shape    \n    \n    x = int(width/2)\n    y = int(height/2)\n    r = np.amin((x,y))\n    \n    circle_img = np.zeros((height, width), np.uint8)\n    cv2.circle(circle_img, (x,y), int(r), 1, thickness=-1)\n    img = cv2.bitwise_and(img, img, mask=circle_img)\n    img = crop_image_from_gray(img)\n    img = cv2.addWeighted ( img,4, cv2.GaussianBlur( img , (0,0) , sigmaX) ,-4 ,128)\n    img = cv2.resize(img, img_size)\n    return preprocess_input(img) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# загружаем входное изображение и предобрабатываем\n# ИСХОДНАЯ ПРЕДОБРАБОТКА ДАННЫХ\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","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# генератор для последовательного чтения обучающих данных с диска\ndef fit_generator(files, batch_size=32):\n    while True:\n        shuffle(files)\n        for k in range(math.ceil(len(files) / batch_size)):   # округляем до ближайшего целого вверх\n            i = k * batch_size                                # k -- номер батча в проходе                      \n            j = i + batch_size\n            if j > len(files):\n                j = len(files)\n                \n            # если оставить функцию load_image, то будут исходные изображения\n            #x = np.array([load_image(path)/255 for path in files[i:j]])         # картинки в виде матрицы\n            \n            # а это с предобработкой \n            x = np.array([circle_crop(path) for path in files[i:j]]) \n            \n            label = np.array([image_and_class_train[path] for path in files[i:j]])   # метки классов\n            y = keras.utils.to_categorical(label, num_classes=NUM_CLASSES)      # one hot кодирование\n            yield (x, y)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# генератор последовательного чтения тестовых данных с диска\ndef predict_generator(files):\n    while True:\n        for path in files:\n            \n            # с предобработкой\n            yield np.array([circle_crop(path)])\n            \n            # исходные\n            #yield np.array([load_image(path)])\n            ","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, 10))\nfor i, path in enumerate(image_train[:10], 1):\n    subplot = fig.add_subplot(2, 5, i)\n    \n    # исходная картинка\n    plt.imshow(plt.imread(path));\n    \n\n    subplot.set_title('{} \\n label: {}'.format(os.path.basename(path), image_and_class_train[path]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%matplotlib inline\nfrom matplotlib import pyplot as plt\nfig = plt.figure(figsize=(20, 10))\nfor i, path in enumerate(image_train[:10], 1):\n    subplot = fig.add_subplot(2, 5, i)\n    \n    # исходная картинка\n    #plt.imshow(plt.imread(path));\n    \n    # новая предобработка\n    image = circle_crop(path,sigmaX=10)\n    plt.imshow(image)\n\n    subplot.set_title('{} \\n label: {}'.format(os.path.basename(path), image_and_class_train[path]))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Строим модель**\n\nЗагружаем преобученную на датасете 'ImagNet' модель VGG16 "},{"metadata":{"trusted":true},"cell_type":"code","source":"conv_base = VGG16(include_top=False, weights='imagenet', input_shape=(IMG_SIZE[0], IMG_SIZE[1], 3))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# фиксируем все веса предобученной сети кроме последнего блока \nset_trainable = False\nfor layer in conv_base.layers:\n    if layer.name == 'block5_conv3':\n        set_trainable = True\n    if set_trainable:\n        layer.trainable = True\n    else:\n        layer.trainable = False","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"conv_base.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_2 = models.Sequential()\nmodel_2.add(conv_base)  # кусок VGG-16 добавлен в модель\nmodel_2.add(layers.BatchNormalization())\nmodel_2.add(layers.Flatten())\n#model_1.add(layers.Dense(512, activation='relu'))\nmodel_2.add(layers.Dense(NUM_CLASSES, activation='softmax'))\nmodel_2.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras import metrics","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_2.compile(optimizer=Adam(lr=0.001), \n              loss='categorical_crossentropy',  # функция потерь 'categorical_crossentropy' (log loss\n              metrics=['accuracy', 'categorical_accuracy', metrics.Precision(), metrics.Recall(), metrics.AUC()])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"shuffle(image_train)  # перемешиваем обучающую выборку\n\ntrain_val_split = 100  # число изображений в валидационной выборке\n\nvalidation_data = next(fit_generator(image_train[:train_val_split], train_val_split))\n\n# запускаем процесс обучения\nhistory = model_2.fit_generator(fit_generator(image_train[train_val_split:]),  # данные читаем функцией-генератором\n        steps_per_epoch=10,  # число вызовов генератора за эпоху\n        epochs=100,  # число эпох обучения\n        validation_data=validation_data,\n        callbacks=[ #EarlyStopping(patience = 5),\n                   ModelCheckpoint(filepath='the_least_loss_new_preproc_gpu.h5',\n                                  verbose=1,\n                                  save_best_only=True)]\n                               )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"start = 0\nplt.plot(history.history['loss'][start:])\nplt.plot(history.history['val_loss'][start:])\nplt.legend(['Train loss', 'Validation loss'])\nplt.savefig('loss_preproc.png')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"f1 = open('train_loss_preproc.txt', 'w')\nf1.writelines('%s\\n' % i for i in history.history['loss'][start:])\nf1.close()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"f2 = open('vall_loss_preproc.txt', 'w')\nf2.writelines('%s\\n' % i for i in history.history['val_loss'][start:])\nf2.close()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(history.history['accuracy'][start:])\nplt.plot(history.history['val_accuracy'][start:])\nplt.legend(['Train acc', 'Validation acc'])\nplt.savefig('accuracy_preproc.png')\n\nf3 = open('train_acc_preproc.txt', 'w')\nf3.writelines('%s\\n' % i for i in history.history['accuracy'][start:])\nf3.close()\n\nf4 = open('vall_acc_preproc.txt', 'w')\nf4.writelines('%s\\n' % i for i in history.history['val_accuracy'][start:])\nf4.close()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(history.history['precision_2'][start:])\nplt.plot(history.history['val_precision_2'][start:])\nplt.legend(['Train precision', 'Validation precision'])\nplt.savefig('precision_preproc.png')\n\nf5 = open('train_precision_preproc.txt', 'w')\nf5.writelines('%s\\n' % i for i in history.history['precision_2'][start:])\nf5.close()\n\nf6 = open('vall_precision_preproc.txt', 'w')\nf6.writelines('%s\\n' % i for i in history.history['val_precision_2'][start:])\nf6.close()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(history.history['recall_2'][start:])\nplt.plot(history.history['val_recall_2'][start:])\nplt.legend(['Train recall', 'Validation recall'])\nplt.savefig('recall_preproc.png')\n\nf7 = open('train_recall_preproc.txt', 'w')\nf7.writelines('%s\\n' % i for i in history.history['recall_2'][start:])\nf7.close()\n\nf8 = open('vall_recall_preproc.txt', 'w')\nf8.writelines('%s\\n' % i for i in history.history['val_recall_2'][start:])\nf8.close()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(history.history['auc_2'][start:])\nplt.plot(history.history['val_auc_2'][start:])\nplt.legend(['Train auc', 'Validation auc'])\nplt.savefig('auc_preproc.png')\n\nf9 = open('train_auc_preproc.txt', 'w')\nf9.writelines('%s\\n' % i for i in history.history['auc_2'][start:])\nf9.close()\n\nf10 = open('vall_auc_preproc.txt', 'w')\nf10.writelines('%s\\n' % i for i in history.history['val_auc_2'][start:])\nf10.close()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_2.save('preproc_100_epoch.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# загружаем веса модели для наименьшего loss \nmodel_2.load_weights('the_least_loss_new_preproc_gpu.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pred = model_2.predict_generator(predict_generator(image_test), len(image_test), 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(image_test[80:][:10], pred[80:][:10]), 1):\n    subplot = fig.add_subplot(math.ceil(i / 5), 5, i)\n    plt.imshow(plt.imread(path))\n    subplot.set_title('label: {} \\n prediction: {} \\n model confidence: {:.3f}'\\\n                      .format(image_and_class_test[path],\n                              int(np.argmax(score)),\n                             np.max(score)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from IPython.display import HTML","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"create_download_link('/kaggle/output/project_3_model_2-vgg16.hdf5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_2.save('model_2.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_2.save_weights('my_model_weights.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from IPython.display import FileLink, FileLinks\nFileLinks('.')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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.1"}},"nbformat":4,"nbformat_minor":1}