{"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"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":6927,"databundleVersionId":45059,"sourceType":"competition"}],"dockerImageVersionId":30097,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-07-21T19:54:16.771889Z","iopub.execute_input":"2021-07-21T19:54:16.772326Z","iopub.status.idle":"2021-07-21T19:54:16.778557Z","shell.execute_reply.started":"2021-07-21T19:54:16.772255Z","shell.execute_reply":"2021-07-21T19:54:16.777796Z"}}},{"cell_type":"markdown","source":"# Автомобили – Carvana Image Masking Challenge","metadata":{}},{"cell_type":"markdown","source":"## Загрузим библиотеки","metadata":{}},{"cell_type":"code","source":"!pip install git+https://github.com/tensorflow/examples.git\n!pip install -U tfds-nightly","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:08.961908Z","iopub.execute_input":"2021-10-05T06:49:08.962495Z","iopub.status.idle":"2021-10-05T06:49:28.235599Z","shell.execute_reply.started":"2021-10-05T06:49:08.962367Z","shell.execute_reply":"2021-10-05T06:49:28.234641Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow_examples.models.pix2pix import pix2pix\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Dense, Flatten, Conv2D, MaxPooling2D\nfrom tensorflow.keras.optimizers import Adam\nimport numpy as np\nfrom tensorflow.keras.layers import Input, Conv2D,Dropout\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom IPython.display import clear_output\nimport random, re, math\nimport pandas as pd \nimport keras.backend as K\nfrom sklearn.model_selection import train_test_split\nimport matplotlib.pyplot as plt\nimport os\nimport zipfile","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:28.237481Z","iopub.execute_input":"2021-10-05T06:49:28.237893Z","iopub.status.idle":"2021-10-05T06:49:30.060184Z","shell.execute_reply.started":"2021-10-05T06:49:28.237852Z","shell.execute_reply":"2021-10-05T06:49:30.059342Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Извлечём данные из zip архивов","metadata":{}},{"cell_type":"code","source":"\ntrain_img_zip = '/kaggle/input/carvana-image-masking-challenge/train.zip'\ntrain_mask_zip='/kaggle/input/carvana-image-masking-challenge/train_masks.zip'\n\ntrain_img = zipfile.ZipFile(train_img_zip, 'r')\ntrain_img.extractall('/kaggle/working')\ntrain_img.close()\n\ntrain_mask = zipfile.ZipFile(train_mask_zip, 'r')\ntrain_mask.extractall('/kaggle/working')\ntrain_mask.close()","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:30.062008Z","iopub.execute_input":"2021-10-05T06:49:30.062337Z","iopub.status.idle":"2021-10-05T06:49:38.333006Z","shell.execute_reply.started":"2021-10-05T06:49:30.062309Z","shell.execute_reply":"2021-10-05T06:49:38.332055Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Создадим папки с тренировочными данными и масками.","metadata":{}},{"cell_type":"code","source":"\ntrain_dir = os.path.join('/kaggle/working/train')\ntrain_mask_dir = os.path.join('/kaggle/working/train_masks')\n","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:38.334588Z","iopub.execute_input":"2021-10-05T06:49:38.334929Z","iopub.status.idle":"2021-10-05T06:49:38.340291Z","shell.execute_reply.started":"2021-10-05T06:49:38.33489Z","shell.execute_reply":"2021-10-05T06:49:38.339314Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Отобразим несколько примернов изображений с их масками","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\n\nplt.subplots(2, 5, figsize=(30, 10))\npic_index = 0\n\n\npic_index += 1600\nnext_car_pix = [os.path.join(train_dir, fname) \n                for fname in sorted(os.listdir(train_dir))[pic_index-4:pic_index]]\nnext_mask_pix = [os.path.join(train_mask_dir, fname) \n                for fname in sorted(os.listdir(train_mask_dir))[pic_index-4:pic_index]]\n\nfor i, img_path in enumerate(next_car_pix+next_mask_pix):\n  # Set up subplot; subplot indices start at 1\n  sp = plt.subplot(2, 4, i + 1)\n  sp.axis('Off') # Don't show axes (or gridlines)\n\n  img = mpimg.imread(img_path)\n  plt.imshow(img)\n\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:38.341736Z","iopub.execute_input":"2021-10-05T06:49:38.342164Z","iopub.status.idle":"2021-10-05T06:49:40.747149Z","shell.execute_reply.started":"2021-10-05T06:49:38.342105Z","shell.execute_reply":"2021-10-05T06:49:40.746333Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Определим размер изображения","metadata":{}},{"cell_type":"code","source":"img = mpimg.imread(train_dir+'/28d9a149cb02_12.jpg')\n\nimg.shape","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:40.748193Z","iopub.execute_input":"2021-10-05T06:49:40.748501Z","iopub.status.idle":"2021-10-05T06:49:40.786413Z","shell.execute_reply.started":"2021-10-05T06:49:40.748467Z","shell.execute_reply":"2021-10-05T06:49:40.785399Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Сформируем набор данных","metadata":{}},{"cell_type":"markdown","source":"#### Картинка и её маска должны иметь одинаковый id:","metadata":{}},{"cell_type":"code","source":"def creat_dataframe(img_path,mask_path):\n\n    car_ids = []\n    car_paths = []\n    mask_ids=[]\n    mask_paths=[]\n    for p in (img_path,mask_path):\n        for dirname, _, filenames in os.walk(p):\n            for filename in filenames:\n                path = os.path.join(dirname, filename)  \n                if p==img_path:\n                    car_paths.append(path)\n                    car_id = filename.split(\".\")[0]\n                    car_ids.append(car_id)\n                    df=pd.DataFrame(data = {\"id\": car_ids, \"img_path\": car_paths}).set_index('id')\n                else:\n                    mask_paths.append(path)\n                    mask_id = filename.split(\".\")[0]\n                    mask_id = mask_id.split(\"_mask\")[0]\n                    mask_ids.append(mask_id)\n                    df_mask=pd.DataFrame(data = {\"id\": mask_ids, \"mask_path\": mask_paths}).set_index('id')\n                    \n    df[\"mask_path\"] = df_mask[\"mask_path\"]\n         \n    return df","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:40.787768Z","iopub.execute_input":"2021-10-05T06:49:40.78817Z","iopub.status.idle":"2021-10-05T06:49:40.796839Z","shell.execute_reply.started":"2021-10-05T06:49:40.788131Z","shell.execute_reply":"2021-10-05T06:49:40.795764Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Создадим датафрейм.","metadata":{}},{"cell_type":"code","source":"df=creat_dataframe('/kaggle/working/train','/kaggle/working/train_masks')\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:40.798365Z","iopub.execute_input":"2021-10-05T06:49:40.798733Z","iopub.status.idle":"2021-10-05T06:49:56.219088Z","shell.execute_reply.started":"2021-10-05T06:49:40.798696Z","shell.execute_reply":"2021-10-05T06:49:56.218274Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.info()","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:56.222121Z","iopub.execute_input":"2021-10-05T06:49:56.222385Z","iopub.status.idle":"2021-10-05T06:49:56.235067Z","shell.execute_reply.started":"2021-10-05T06:49:56.222359Z","shell.execute_reply":"2021-10-05T06:49:56.23395Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Конфигурация","metadata":{}},{"cell_type":"code","source":"AUTO = tf.data.experimental.AUTOTUNE\n\n# Configuration\nIMAGE_SIZE = [256, 256]\nEPOCHS = 30\nSEED = 931\nBATCH_SIZE = 12 ","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:56.237348Z","iopub.execute_input":"2021-10-05T06:49:56.237886Z","iopub.status.idle":"2021-10-05T06:49:56.242333Z","shell.execute_reply.started":"2021-10-05T06:49:56.237849Z","shell.execute_reply":"2021-10-05T06:49:56.241294Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Определим функции","metadata":{"execution":{"iopub.status.busy":"2021-07-22T20:33:33.271407Z","iopub.execute_input":"2021-07-22T20:33:33.27183Z","iopub.status.idle":"2021-07-22T20:33:33.276408Z","shell.execute_reply.started":"2021-07-22T20:33:33.271783Z","shell.execute_reply":"2021-07-22T20:33:33.275237Z"}}},{"cell_type":"markdown","source":"### Вращение маски и изображения","metadata":{}},{"cell_type":"code","source":"def flip(image,mask):\n    \n    image = tf.image.flip_left_right(image)\n    mask = tf.image.flip_left_right(mask)\n    \n    return image,mask","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:56.243868Z","iopub.execute_input":"2021-10-05T06:49:56.244261Z","iopub.status.idle":"2021-10-05T06:49:56.250305Z","shell.execute_reply.started":"2021-10-05T06:49:56.244209Z","shell.execute_reply":"2021-10-05T06:49:56.249018Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Поворот матрицы, приближение и сдвиг","metadata":{}},{"cell_type":"code","source":"def get_mat(rotation, shear, height_zoom, width_zoom, height_shift, width_shift):   \n    \n    rotation = math.pi * rotation / 180.\n    shear = math.pi * shear / 180.\n    # ROTATION MATRIX\n    c1 = tf.math.cos(rotation)\n    s1 = tf.math.sin(rotation)\n    one = tf.constant([1],dtype='float32')\n    zero = tf.constant([0],dtype='float32')\n    rotation_matrix = tf.reshape( tf.concat([c1,s1,zero, -s1,c1,zero, zero,zero,one],axis=0),[3,3] )\n        \n    # SHEAR MATRIX\n    c2 = tf.math.cos(shear)\n    s2 = tf.math.sin(shear)\n    shear_matrix = tf.reshape( tf.concat([one,s2,zero, zero,c2,zero, zero,zero,one],axis=0),[3,3] )    \n    \n    # ZOOM MATRIX\n    zoom_matrix = tf.reshape( tf.concat([one/height_zoom,zero,zero, zero,one/width_zoom,zero, zero,zero,one],axis=0),[3,3] )\n    \n    # SHIFT MATRIX\n    shift_matrix = tf.reshape( tf.concat([one,zero,height_shift, zero,one,width_shift, zero,zero,one],axis=0),[3,3] )\n    \n    return K.dot(K.dot(rotation_matrix, shear_matrix), K.dot(zoom_matrix, shift_matrix))\n  \n    \ndef transform(image,mask):\n    # is borrowed from https://www.kaggle.com/cdeotte/rotation-augmentation-gpu-tpu-0-96\n    DIM = IMAGE_SIZE[0]\n    XDIM = DIM%2 \n    \n    rot = 10. * tf.random.normal([1],dtype='float32')\n    shr = 2. * tf.random.normal([1],dtype='float32') \n    h_zoom = 1.0 + tf.random.normal([1],dtype='float32')/10.\n    w_zoom = 1.0 + tf.random.normal([1],dtype='float32')/10.\n    h_shift = 10. * tf.random.normal([1],dtype='float32') \n    w_shift = 10. * tf.random.normal([1],dtype='float32') \n  \n    m = get_mat(rot,shr,h_zoom,w_zoom,h_shift,w_shift) \n\n    x = tf.repeat( tf.range(DIM//2,-DIM//2,-1), DIM )\n    y = tf.tile( tf.range(-DIM//2,DIM//2),[DIM] )\n    z = tf.ones([DIM*DIM],dtype='int32')\n    idx = tf.stack( [x,y,z] )\n    \n    idx2 = K.dot(m,tf.cast(idx,dtype='float32'))\n    idx2 = K.cast(idx2,dtype='int32')\n    idx2 = K.clip(idx2,-DIM//2+XDIM+1,DIM//2)\n    \n    idx3 = tf.stack( [DIM//2-idx2[0,], DIM//2-1+idx2[1,]] )\n    d = tf.gather_nd(image,tf.transpose(idx3))\n    m = tf.gather_nd(mask,tf.transpose(idx3))\n        \n    return tf.reshape(d,[DIM,DIM,3]),tf.reshape(m,[DIM,DIM,1])\n\n","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:56.252136Z","iopub.execute_input":"2021-10-05T06:49:56.252584Z","iopub.status.idle":"2021-10-05T06:49:56.271546Z","shell.execute_reply.started":"2021-10-05T06:49:56.252502Z","shell.execute_reply":"2021-10-05T06:49:56.270421Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Чтение изображений и масок по пути","metadata":{}},{"cell_type":"code","source":"def read_image_and_mask(image_path, mask_path=None,resize=IMAGE_SIZE):\n    \n    image=tf.io.read_file(image_path)\n    image=tf.image.decode_jpeg(image, channels=3)\n    image=tf.image.resize(image, IMAGE_SIZE)\n    image = tf.cast(image, dtype=tf.float32)/255.\n    if not mask_path is None:\n        mask=tf.io.read_file(mask_path)\n        mask=tf.image.decode_jpeg(mask, channels=3)\n        mask=mask[:,:,:1]\n        mask=tf.image.resize(mask, IMAGE_SIZE)\n        mask = tf.cast(mask, dtype=tf.float32)/255.\n        return image, mask\n    return image\n\ndef get_training_dataset(df):\n    \n    training_dataset = tf.data.Dataset.from_tensor_slices((df[\"img_path\"].values, df[\"mask_path\"].values))\n    training_dataset = training_dataset.map(read_image_and_mask,num_parallel_calls=AUTO)\n    training_dataset = training_dataset.map(flip,num_parallel_calls=AUTO)\n    training_dataset = training_dataset.map(transform,num_parallel_calls=AUTO)\n    training_dataset = training_dataset.shuffle(512, reshuffle_each_iteration=True)\n    training_dataset = training_dataset.batch(BATCH_SIZE)\n    training_dataset = training_dataset.repeat()\n    training_dataset = training_dataset.prefetch(AUTO)\n\n    return training_dataset","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:56.27301Z","iopub.execute_input":"2021-10-05T06:49:56.273573Z","iopub.status.idle":"2021-10-05T06:49:56.285299Z","shell.execute_reply.started":"2021-10-05T06:49:56.273536Z","shell.execute_reply":"2021-10-05T06:49:56.284349Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Получение выборок для валидации и проверки","metadata":{}},{"cell_type":"code","source":"def get_validation_dataset(df):\n  \n  validation_dataset = tf.data.Dataset.from_tensor_slices((df[\"img_path\"].values, df[\"mask_path\"].values))\n  validation_dataset = validation_dataset.map(read_image_and_mask)\n  validation_dataset = validation_dataset.batch(BATCH_SIZE)\n    \n  return validation_dataset\n\n\ndef get_test_dataset(images):\n  \n  test_dataset = tf.data.Dataset.from_tensor_slices((images))\n  test_dataset = test_dataset.map(read_image_and_mask)\n  test_dataset = test_dataset.batch(10, drop_remainder=True)\n\n  return test_dataset","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:56.286516Z","iopub.execute_input":"2021-10-05T06:49:56.286956Z","iopub.status.idle":"2021-10-05T06:49:56.295448Z","shell.execute_reply.started":"2021-10-05T06:49:56.286918Z","shell.execute_reply":"2021-10-05T06:49:56.294473Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Сформируем выборки","metadata":{}},{"cell_type":"markdown","source":"#### тестовая выборка будет иметь размер 25%","metadata":{}},{"cell_type":"code","source":"tr_df, val_df = train_test_split(creat_dataframe('/kaggle/working/train','/kaggle/working/train_masks'), random_state=SEED, test_size=.25)\ntr_dataset = get_training_dataset(tr_df)\nval_dataset = get_validation_dataset(val_df)","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:49:56.298038Z","iopub.execute_input":"2021-10-05T06:49:56.298306Z","iopub.status.idle":"2021-10-05T06:50:14.047195Z","shell.execute_reply.started":"2021-10-05T06:49:56.298281Z","shell.execute_reply":"2021-10-05T06:50:14.046363Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Отображение изображений с их маской (синий цвет)\n","metadata":{}},{"cell_type":"code","source":"row = 2; col = 4;\nall_elements = tr_dataset.unbatch()\none_element = tf.data.Dataset.from_tensors( next(iter(all_elements)) )\naugmented_element = one_element.repeat().map(transform).batch(row*col)\n\nfor (img,mask) in augmented_element:\n    plt.figure(figsize=(15,int(15*row/col)))\n    for j in range(row*col):\n        plt.subplot(row,col,j+1)\n        plt.axis('off')\n        plt.imshow(img[j,])\n        plt.imshow(mask[j,:,:,0],alpha=.6,cmap='Blues')\n    plt.show()\n    break","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:50:14.048545Z","iopub.execute_input":"2021-10-05T06:50:14.048886Z","iopub.status.idle":"2021-10-05T06:50:28.676759Z","shell.execute_reply.started":"2021-10-05T06:50:14.04885Z","shell.execute_reply":"2021-10-05T06:50:28.675743Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Методы визуализации","metadata":{}},{"cell_type":"code","source":"def display(display_list):\n    plt.figure(figsize=(15, 15))\n\n    title = ['Input Image', 'True Mask', 'Predicted Mask']\n\n    for i in range(len(display_list)):\n        plt.subplot(1, len(display_list), i+1)\n        plt.title(title[i])\n        plt.imshow(tf.keras.preprocessing.image.array_to_img(display_list[i]))\n        plt.axis('off')\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:50:28.678332Z","iopub.execute_input":"2021-10-05T06:50:28.678712Z","iopub.status.idle":"2021-10-05T06:50:28.685134Z","shell.execute_reply.started":"2021-10-05T06:50:28.678672Z","shell.execute_reply":"2021-10-05T06:50:28.684087Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def batch_predict(image,model):\n    preds=model.predict(image)  \n    threshold = 0.5\n    preds[preds > threshold] = 1.0\n    preds[preds <= threshold] = 0.0 \n    return preds\n\ndef vis_compare(dataset=val_dataset,num_case=1):\n       \n    for sample in dataset.take(1):\n        image, label = sample[0].numpy(), sample[1].numpy()\n    preds=batch_predict(image,model)\n    if num_case>1:\n        cases=[j for j in np.random.choice(image.shape[0],size=num_case,replace=False)]    \n        for i in cases:\n            truth=(image[i],label[i])\n            pred=(image[i],preds[i])\n            print(f\"case_number_{i}\")\n            display([image,label,preds])\n            print('\\n')\n            print(464*'*')\n            print('\\n')\n    else:\n        truth=(image[0],label[0])\n        pred=(image[0],preds[0])\n        display([image[0],label[0],preds[0]])\n            \n    \n    \n    plt.show() ","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:50:28.686745Z","iopub.execute_input":"2021-10-05T06:50:28.687273Z","iopub.status.idle":"2021-10-05T06:50:28.698727Z","shell.execute_reply.started":"2021-10-05T06:50:28.687238Z","shell.execute_reply":"2021-10-05T06:50:28.697632Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Сформируем методы для обратной связи","metadata":{}},{"cell_type":"markdown","source":"#### Далее посмотрим, как модель совершенствуется во время обучения. Для выполнения этой задачи ниже определена функция обратного вызова.\n","metadata":{"execution":{"iopub.status.busy":"2021-07-22T19:54:24.08352Z","iopub.execute_input":"2021-07-22T19:54:24.08402Z","iopub.status.idle":"2021-07-22T19:54:24.11263Z","shell.execute_reply.started":"2021-07-22T19:54:24.083983Z","shell.execute_reply":"2021-07-22T19:54:24.110539Z"}}},{"cell_type":"code","source":"class DisplayCallback(tf.keras.callbacks.Callback):\n  def on_epoch_end(self, epoch, logs=None):\n    clear_output(wait=True)\n    vis_compare()\n    print ('\\nSample Prediction after epoch {}\\n'.format(epoch+1))\n","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:50:28.700167Z","iopub.execute_input":"2021-10-05T06:50:28.700735Z","iopub.status.idle":"2021-10-05T06:50:28.706963Z","shell.execute_reply.started":"2021-10-05T06:50:28.700698Z","shell.execute_reply":"2021-10-05T06:50:28.706066Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### Определим методы преждевременной остановки при достижении требуемой точности","metadata":{}},{"cell_type":"code","source":"class EarlyStoppingAtMinLoss(tf.keras.callbacks.Callback):\n\n    def __init__(self, patience=3):\n        super(EarlyStoppingAtMinLoss, self).__init__()\n        self.patience = patience\n        # best_weights to store the weights at which the minimum loss occurs.\n        self.best_weights = None\n\n    def on_train_begin(self, logs=None):\n        # The number of epoch it has waited when loss is no longer minimum.\n        self.wait = 0\n        # The epoch the training stops at.\n        self.stopped_epoch = 0\n        # Initialize the best as infinity.\n        self.best = np.Inf\n\n    def on_epoch_end(self, epoch, logs=None):\n        current = logs.get(\"val_loss\")\n        if np.less(current, self.best):\n            self.best = current\n            self.wait = 0\n            # Record the best weights if current results is better (less).\n            self.best_weights = self.model.get_weights()\n        else:\n            self.wait += 1\n            if self.wait >= self.patience:\n                self.stopped_epoch = epoch\n                self.model.stop_training = True\n                print(\"Restoring model weights from the end of the best epoch.\")\n                self.model.set_weights(self.best_weights)\n\n    def on_train_end(self, logs=None):\n        if self.stopped_epoch > 0:\n            print(\"Epoch %05d: early stopping\" % (self.stopped_epoch + 1))\n            \n","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:50:28.708291Z","iopub.execute_input":"2021-10-05T06:50:28.708652Z","iopub.status.idle":"2021-10-05T06:50:28.718412Z","shell.execute_reply.started":"2021-10-05T06:50:28.708617Z","shell.execute_reply":"2021-10-05T06:50:28.717374Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Определим функцию ошибки","metadata":{}},{"cell_type":"code","source":"def dice_coef(y_true, y_pred, smooth=1):\n    intersection = K.sum(y_true * y_pred, axis=[1,2,3])\n    union = K.sum(y_true, axis=[1,2,3]) + K.sum(y_pred, axis=[1,2,3])\n    return K.mean( (2. * intersection + smooth) / (union + smooth), axis=0)\n\ndef dice_loss(in_gt, in_pred):\n    return 1-dice_coef(in_gt, in_pred)","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:50:28.72001Z","iopub.execute_input":"2021-10-05T06:50:28.720564Z","iopub.status.idle":"2021-10-05T06:50:28.729639Z","shell.execute_reply.started":"2021-10-05T06:50:28.720491Z","shell.execute_reply":"2021-10-05T06:50:28.728843Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Модель","metadata":{"execution":{"iopub.status.busy":"2021-07-21T23:49:38.616018Z","iopub.execute_input":"2021-07-21T23:49:38.616426Z","iopub.status.idle":"2021-07-21T23:49:38.620698Z","shell.execute_reply.started":"2021-07-21T23:49:38.616392Z","shell.execute_reply":"2021-07-21T23:49:38.619838Z"}}},{"cell_type":"markdown","source":"#### Используемая здесь модель представляет собой модифицированную U-сеть. U-сеть состоит из кодера (понижающего преобразователя) и декодера (повышающего преобразователя). Чтобы изучить надежные функции и уменьшить количество обучаемых параметров, в качестве кодировщика можно использовать предварительно обученную модель. Таким образом, кодировщиком для этой задачи будет предварительно подготовленная модель MobileNetV2, промежуточные выходы которой будут использоваться, а декодером будет блок повышения уровня, уже реализованный в примерах TensorFlow в учебнике Pix2pix.","metadata":{}},{"cell_type":"code","source":"OUTPUT_CHANNELS = 1\nbase_model = tf.keras.applications.MobileNetV2(input_shape=[256, 256, 3], include_top=False)\n\nlayer_names = [\n    'block_1_expand_relu',   # 64x64\n    'block_3_expand_relu',   # 32x32\n    'block_6_expand_relu',   # 16x16\n    'block_13_expand_relu',  # 8x8\n    'block_16_project',      # 4x4\n]\n\nbase_model_outputs = [base_model.get_layer(name).output for name in layer_names]\n\ndown_stack = tf.keras.Model(inputs=base_model.input, outputs=base_model_outputs)\n\ndown_stack.trainable = False\n\nup_stack = [\n    pix2pix.upsample(512, 3),  # 4x4 -> 8x8\n    pix2pix.upsample(256, 3),  # 8x8 -> 16x16\n    pix2pix.upsample(128, 3),  # 16x16 -> 32x32\n    pix2pix.upsample(64, 3),   # 32x32 -> 64x64\n]\n\ndef unet_model(output_channels):\n    inputs = tf.keras.layers.Input(shape=[256, 256, 3])\n\n    skips = down_stack(inputs)\n    x = skips[-1]\n    skips = reversed(skips[:-1])\n\n    for up, skip in zip(up_stack, skips):\n        x = up(x)\n        concat = tf.keras.layers.Concatenate()\n        x = concat([x, skip])\n\n    last = tf.keras.layers.Conv2DTranspose(\n      output_channels, 3, strides=2, activation='sigmoid',\n      padding='same')  \n\n    x = last(x)\n    model = tf.keras.Model(inputs=inputs, outputs=x)\n    model.compile(optimizer='adam',loss = dice_loss,\n              metrics=[dice_coef,'binary_accuracy'])\n\n    return model\n\nmodel = unet_model(1)","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:50:28.73272Z","iopub.execute_input":"2021-10-05T06:50:28.733071Z","iopub.status.idle":"2021-10-05T06:50:30.455327Z","shell.execute_reply.started":"2021-10-05T06:50:28.733045Z","shell.execute_reply":"2021-10-05T06:50:30.454483Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Обучение модели","metadata":{}},{"cell_type":"code","source":"steps_per_epoch = len(tr_df)//BATCH_SIZE\n\n\nhistory = model.fit(tr_dataset,\n                          steps_per_epoch=steps_per_epoch, validation_data=val_dataset, epochs=3,\n                          callbacks=[EarlyStoppingAtMinLoss(),DisplayCallback()]) #,DisplayCallback()","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:50:30.456521Z","iopub.execute_input":"2021-10-05T06:50:30.456856Z","iopub.status.idle":"2021-10-05T06:57:32.441026Z","shell.execute_reply.started":"2021-10-05T06:50:30.456822Z","shell.execute_reply":"2021-10-05T06:57:32.439965Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Получение результата","metadata":{}},{"cell_type":"code","source":"model.evaluate(val_dataset)","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:57:32.442775Z","iopub.execute_input":"2021-10-05T06:57:32.443159Z","iopub.status.idle":"2021-10-05T06:58:03.41379Z","shell.execute_reply.started":"2021-10-05T06:57:32.443118Z","shell.execute_reply":"2021-10-05T06:58:03.413033Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### Точность обучения составила 98,39% для тестовой и 99,34% для обучающей выборки.","metadata":{}},{"cell_type":"code","source":"loss = history.history['loss']\nval_loss = history.history['val_loss']\n\nplt.figure()\nplt.plot(history.epoch, loss, 'r', label='Ошибка обучения')\nplt.plot(history.epoch, val_loss, 'bo', label='Ошибка валидации')\nplt.title('Результаты обучения')\nplt.xlabel('Эпохи')\nplt.ylabel('Значение ошибки')\nplt.ylim([0, 1])\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-10-05T07:02:11.637225Z","iopub.execute_input":"2021-10-05T07:02:11.63759Z","iopub.status.idle":"2021-10-05T07:02:11.798042Z","shell.execute_reply.started":"2021-10-05T07:02:11.637559Z","shell.execute_reply":"2021-10-05T07:02:11.797013Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Посмотрим на некоторые примеры масок.","metadata":{}},{"cell_type":"code","source":"def vis_compare(dataset=val_dataset,num_case=1):\n       \n    for sample in dataset.take(1):\n        image, label = sample[0].numpy(), sample[1].numpy()\n    preds=model.predict(image)\n    if num_case>1:\n        cases=[j for j in np.random.choice(image.shape[0],size=num_case,replace=False)]    \n        for i in cases:\n            truth=(image[i],label[i])\n            pred=(image[i],preds[i])\n            print(f\"case_number_{i}\")\n            display([image[i],label[i],preds[i]])\n            print('\\n')\n            print(464*'*')\n            print('\\n')\n    else:\n        truth=(image[0],label[0])\n        pred=(image[0],preds[0])\n        display([image[0],label[0],preds[0]])   \n    plt.show()\n    \nvis_compare(val_dataset,4)","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:58:03.415178Z","iopub.execute_input":"2021-10-05T06:58:03.415585Z","iopub.status.idle":"2021-10-05T06:58:04.862486Z","shell.execute_reply.started":"2021-10-05T06:58:03.415534Z","shell.execute_reply":"2021-10-05T06:58:04.861489Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### **Вывод:**\nВ ходе выполнения лабораторной работы научились реализовывать нейронные сети для сегментации \nобъектов на изображениях с использованием библиотеки TensorFlow. ","metadata":{}},{"cell_type":"code","source":"vis_compare(dataset=val_dataset,num_case=10)","metadata":{"execution":{"iopub.status.busy":"2021-10-05T06:58:04.863861Z","iopub.execute_input":"2021-10-05T06:58:04.864322Z","iopub.status.idle":"2021-10-05T06:58:07.930113Z","shell.execute_reply.started":"2021-10-05T06:58:04.864282Z","shell.execute_reply":"2021-10-05T06:58:07.929166Z"},"trusted":true},"outputs":[],"execution_count":null}]}