{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Dogs vs. Cats / Deep Residual Network (ResNet)\n","execution_count":null},{"metadata":{"id":"FRv4vb3qaEyF"},"cell_type":"markdown","source":"# Setup","execution_count":null},{"metadata":{"id":"akHV9qWmZ5GA","trusted":true},"cell_type":"code","source":"!unzip -q   /kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip -d .\n!unzip -q  /kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip -d .","execution_count":null,"outputs":[]},{"metadata":{"id":"XEFvbXHvasxs","trusted":true},"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\nfrom keras.preprocessing.image import load_img,img_to_array\nimport numpy as np\nimport os\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport time\nfrom tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping\nimport shutil\nfrom keras.preprocessing.image import ImageDataGenerator\n\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\nprint(\"GPU is {}\".format(tf.config.list_physical_devices('GPU')))\nprint(\"tensorflow version {}\".format(tf.__version__))\n\nprint(os.listdir(\"./\"))\n\n!nvidia-smi\n\nkeras.backend.clear_session()","execution_count":null,"outputs":[]},{"metadata":{"id":"YjeQJ71_apiz"},"cell_type":"markdown","source":"# Data Pre-processing and Visualization","execution_count":null},{"metadata":{"id":"2jWIHsvGgswV","trusted":true},"cell_type":"code","source":"\ndef show_cats_and_dogs(show=\"\",width=150,height=150, images_path ='./train/'):\n  cols = 25\n  limit = 100\n  index = 0\n  images = list()\n  vertical_images=[]\n \n  for path in os.listdir(images_path):\n    if show != \"\" and  (show in path)==False:\n          continue\n    index=index+1\n    if index%limit==0:\n        break\n    #keras.preprocessing.image\n    image = load_img(images_path+path, target_size=(width,height))\n    image= img_to_array(image) #to numpy\n    image_height, image_width, image_channel = image.shape\n    horizontal_side = np.ones((image_height, 5,  image_channel), dtype=np.float32)*255\n    \n    images.append(image)\n    images.append(horizontal_side)\n\n    if index%cols==0:\n      horizontal_image = np.hstack((images))\n      image_height, image_width, image_channel = horizontal_image.shape\n      vertical_side = np.ones((5, image_width,  image_channel), dtype=np.float32)*255\n      vertical_images.append(horizontal_image)\n      vertical_images.append(vertical_side)\n      images=list()\n  gallery=np.vstack((vertical_images)) \n  plt.figure(figsize=(12,12))\n  plt.xticks([])\n  plt.yticks([])\n  title={\"\":\"cães & gatos\",\n          \"cat\": \"gatos\",\n          \"dog\": \"cães\"}\n  plt.title(\"{} imagens de {} [ path {} ] .\".format(limit, title[show],images_path))\n  plt.imshow(gallery.astype(np.uint8))","execution_count":null,"outputs":[]},{"metadata":{"id":"GlcQRxVYetmV","trusted":true},"cell_type":"code","source":"# raw Dataset\nprint(\"O dataset possui {} imagens de gatos e cães para classificação.\".format(len(os.listdir(\"./train\"))))\nprint(\"O dataset de teste possui {}.\".format(len(os.listdir(\"./test\"))))\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Gatos","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"show_cats_and_dogs(show='cat')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Cães","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"show_cats_and_dogs(show='dog')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Ambos","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"show_cats_and_dogs(show='')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Test","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"show_cats_and_dogs(images_path='./test/')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Pre-processing","execution_count":null},{"metadata":{"id":"5VQhzMUJ201D","trusted":true},"cell_type":"code","source":"image_width,image_height = 150,150#299,299\nlabels =['dog','cat']\nfor d in labels:\n  dir_path = './train/' + d\n  if not os.path.exists(dir_path):\n    print('{} criado.'.format(dir_path))\n    os.mkdir(dir_path)\n  else:\n    print('{} já existe.'.format(dir_path))\n\n\ntrain_path =\"./train/\"\nfor  file in  os.listdir(train_path):\n  category = file.split(\".\")[0]\n  if '.jpg' in file:\n    if 'dog'in category: \n      shutil.copyfile(train_path+file,'./train/dog/'+ file)\n    elif 'cat'in category:  \n      shutil.copyfile(train_path+file,'./train/cat/'+ file)\n","execution_count":null,"outputs":[]},{"metadata":{"id":"3BUweZ334bW7","trusted":true},"cell_type":"code","source":"print(\"Total de cães:\\t{}\".format(sum([len(files) for r, d, files in os.walk('./train/dog/')])))\nprint(\"Total de gatos:\\t{}\".format(sum([len(files) for r, d, files in os.walk('./train/cat/')])))","execution_count":null,"outputs":[]},{"metadata":{"id":"jj3aho2Vg2Bj","trusted":true},"cell_type":"code","source":"keras.backend.clear_session()\nbatch_size=128\nvalidation_split=0.3\nval_size = 7500\ndataset_size = 17500 \ntrain_data_generator = ImageDataGenerator(rescale=1./255, horizontal_flip=True, validation_split=validation_split)\n\ntrain_datagenerator = train_data_generator.flow_from_directory(train_path,\n                                                    target_size=(image_width,image_height ),\n                                                    class_mode=\"categorical\",\n                                                    batch_size=batch_size,\n                                                    shuffle=True,\n                                                    subset='training')\n\nval_datagenerator = train_data_generator.flow_from_directory(train_path,\n                                                     target_size=(image_width,image_height),\n                                                     class_mode=\"categorical\",\n                                                     shuffle=True,\n                                                     batch_size=batch_size,\n                                                     subset='validation')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.layers import Dense, Conv2D,BatchNormalization, Activation,AveragePooling2D, Input,Flatten, add\nfrom tensorflow.keras.callbacks import ModelCheckpoint, LearningRateScheduler,ReduceLROnPlateau\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.regularizers import l2\nfrom tensorflow.keras.models import Model","execution_count":null,"outputs":[]},{"metadata":{"id":"kx-RidqL7507","trusted":true},"cell_type":"code","source":"keras.backend.clear_session()\ninput_shape =  (image_width,image_height,3)\nnum_classes = 2\n# learning_rate_scheduler  reduzir a taxa de aprendizado\ndef learning_rate_scheduler(epoch=0):\n  lr = 1e-3\n  if epoch > 180:\n    lr *= 0.5e-3\n  elif epoch > 160:\n    lr *= 1e-3\n  elif epoch > 120:\n    lr *= 1e-2\n  elif epoch > 80:\n    lr *= 1e-1\n  print('Learning rate: ', lr)\n  return lr\n\ndef resnet_layer(inputs,\n                 num_filters=16,\n                 kernel_size=3,\n                 strides=1,\n                 activation='relu',\n                 batch_normalization=True,\n                 conv_first=True ):\n  #Contruir: 2D Convolution -> Batch Normalization -> Activation\n  conv = Conv2D(num_filters,\n                  kernel_size=kernel_size,\n                  strides=strides,\n                  padding='same',\n                  kernel_initializer='he_normal',\n                  kernel_regularizer=l2(1e-4))\n  x = inputs  \n  if conv_first:\n      x = conv(x)\n      if batch_normalization:\n          x = BatchNormalization()(x)\n      if activation is not None:\n          x = Activation(activation)(x)\n  else:\n      if batch_normalization:\n          x = BatchNormalization()(x)\n      if activation is not None:\n          x = Activation(activation)(x)\n      x = conv(x)\n  return x\n\ndepth=27\nnum_filters_in = 16\nnum_res_blocks = int((depth - 2) / 9)\n\ninputs = Input(shape=input_shape)\nx = resnet_layer(inputs=inputs,num_filters=num_filters_in, conv_first=True)\n#unidades residual\nfor stage in range(3):\n  for res_block in range(num_res_blocks):\n    activation = 'relu'\n    batch_normalization = True\n    strides = 1\n    if stage == 0:\n        num_filters_out = num_filters_in * 4\n        # first layer and first stage\n        if res_block == 0:  \n            activation = None\n            batch_normalization = False\n    else:\n        num_filters_out = num_filters_in * 2\n        # first layer but not first stage\n        if res_block == 0:\n            # downsample\n            strides = 2 \n    #gargalo...\n    \n    y = resnet_layer(inputs=x,\n                      num_filters=num_filters_in,\n                      kernel_size=1,\n                      strides=strides,\n                      activation=activation,\n                      batch_normalization=batch_normalization,\n                      conv_first=False)\n    \n    y = resnet_layer(inputs=y,\n                      num_filters=num_filters_in,\n                      conv_first=False)\n    \n    y = resnet_layer(inputs=y,\n                      num_filters=num_filters_out,\n                      kernel_size=1,\n                      conv_first=False)\n    \n    if res_block == 0:\n        # linear projection residual shortcut connection\n        # to match changed dims\n        x = resnet_layer(inputs=x,\n                          num_filters=num_filters_out,\n                          kernel_size=1,\n                          strides=strides,\n                          activation=None,\n                          batch_normalization=False)\n    x = add([x, y])\n  num_filters_in = num_filters_out\n# v2 has BN-ReLU before Pooling\nx = BatchNormalization()(x)\nx = Activation('relu')(x)\nx = AveragePooling2D(pool_size=8)(x)\ny = Flatten()(x)\noutputs = Dense(num_classes,\n                activation='softmax',\n                kernel_initializer='he_normal')(y)\n\n# instantiate model.\nmodel = Model(inputs=inputs, outputs=outputs)\n\nmodel.compile(loss='categorical_crossentropy', optimizer=Adam(lr=learning_rate_scheduler()), metrics=['acc'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport math\n\nsave_dir = os.path.join(os.getcwd(), 'saved_models')\nmodel_name = 'cifar10_model.{epoch:03d}.h5' \nif not os.path.isdir(save_dir):\n    os.makedirs(save_dir)\nfilepath = os.path.join(save_dir, model_name)\n\ncheckpoint = ModelCheckpoint(filepath=filepath,\n                             monitor='val_acc',\n                             verbose=1,\n                             save_best_only=True)\n\nlr_scheduler = LearningRateScheduler(learning_rate_scheduler)\n\nlr_reducer = ReduceLROnPlateau(factor=np.sqrt(0.1),\n                               cooldown=0,\n                               patience=5,\n                               min_lr=0.5e-6)\n\ncallbacks = [checkpoint, lr_reducer, lr_scheduler]\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"epochs=60\nsteps_per_epoch =  math.ceil(dataset_size / batch_size)\nmodel.fit(train_datagenerator,\n              verbose=1,\n              epochs=epochs,\n               validation_data=val_datagenerator,\n              steps_per_epoch=steps_per_epoch,\n              callbacks=callbacks)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Train Accuracy:{:.3f}\".format(history.history['acc'][-1]))\nprint(\"Val Accuracy:{:.3f}\".format(history.history['val_acc'][-1]))\nprint('')\nprint(\"Train Loss:{:.3f}\".format(history.history['loss'][-1]))\nprint(\"Val Loss:{:.3f}\".format(history.history['val_loss'][-1]))","execution_count":null,"outputs":[]},{"metadata":{"id":"INPYD9zaO3u2","trusted":true},"cell_type":"code","source":"score = model.evaluate_generator(val_datagenerator,verbose=1)\nprint('Val loss: ', score[0])\nprint('Val accuracy', score[1])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Accuracy","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"epochs = list(range(1,len(history.history['acc'])+1))\nepochs\nplt.plot(epochs, history.history['acc'],epochs,history.history['val_acc'])\nplt.legend(('Training','Validation'))\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Loss","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"epochs = list(range(1,len(history.history['loss'])+1))\nepochs\nplt.plot(epochs, history.history['loss'],epochs,history.history['val_loss'])\nplt.legend(('Training','Validation'))\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"id":"AmLm53_n6Kwr","outputId":"bd0e9d1f-25e7-44c0-ffcc-641d334f6b34","trusted":true},"cell_type":"code","source":"test_path =\"./test/\"\nif not os.path.exists(\"./test\"):\n  os.mkdir(\"./test\")\n  print('./test criado.')\n\ndir_path = \"./test/data\"\nif not os.path.exists(dir_path):\n  print('{} criado.'.format(dir_path))\n  os.mkdir(dir_path)\nelse:\n  print('{} já existe.'.format(dir_path))\nfor file in os.listdir(test_path):\n    if '.jpg' in file:\n        shutil.copyfile(test_path+file,dir_path+'/'+file)\n\nprint(\"Total de gatos:\\t{}\".format(sum([len(files) for r, d, files in os.walk(dir_path+'/')])))\n\ntest_path = dir_path+'/'\ntest_data_generator = ImageDataGenerator(rescale=1./255)\n\ntest_generator = test_data_generator.flow_from_directory(directory ='./test',\n                                                         target_size=(image_width,image_height),\n                                                     batch_size=batch_size,\n                                                     class_mode=None,\n                                                     shuffle=False)","execution_count":null,"outputs":[]},{"metadata":{"id":"7xRyFfM83eyh","trusted":true},"cell_type":"code","source":"predict = model.predict(test_generator,verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"index = 56\npath= test_generator.filenames[index]\nplt.figure(figsize=(4, 4))\nimg=load_img('./test/'+path, target_size=(image_width,image_height))\nplt.imshow(img)\nif (predict[index,1]) >= 1.:\n    label='Dog'\nelse:\n    label='Cat'\nplt.title(\"Class: {}\".format(label))\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"id":"8-2zIHgq4D8o","trusted":true},"cell_type":"code","source":"submission = pd.DataFrame({\n    'id':pd.Series(test_generator.filenames),\n    'label':pd.Series(predict[:,1])\n    })\nsubmission['id'] = submission.id.str.extract('(\\d+)')\nsubmission['id']=pd.to_numeric(submission['id']).astype('int')\nsubmission['label']=pd.to_numeric(submission['label']).astype('int')\nsubmission.to_csv(\"submission_fork.csv\",index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.head(10)","execution_count":null,"outputs":[]},{"metadata":{"id":"-A3rIyTCBf_2","trusted":true},"cell_type":"code","source":"shutil.rmtree(\"./test\")\nshutil.rmtree(\"./train\")","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}