{"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":" # **Classificação de imagens cachorros e gatos**","metadata":{}},{"cell_type":"markdown","source":"# Problema","metadata":{}},{"cell_type":"markdown","source":"Este é um projeto da disciplina de Processamento de Imagens, da UTFPR-CP, cujo o objetivo é criar uma arquitetura de Convolutional Neural Network (CNN) para classificação de imagens de um problema qualquer. Posto isso, escolheu-se classificar cachorros e gatos, utilizando o conjunto de dados disponibilizado no Kaggle, podendo encontra-lo [aqui](https://www.kaggle.com/competitions/dogs-vs-cats).\n\nAo longo do notebook será realizado\n\n* Técnicas de processamento de imagens;\n* Criação da CNN, utilizando o TensorFlow/Keras;","metadata":{}},{"cell_type":"markdown","source":"# Importando bibliotecas","metadata":{}},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport zipfile\nimport pandas as pd\nfrom tqdm import tqdm\nimport tensorflow as tf\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nfrom tensorflow.keras.optimizers import RMSprop\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:13.592411Z","iopub.execute_input":"2022-06-09T16:08:13.594790Z","iopub.status.idle":"2022-06-09T16:08:20.721161Z","shell.execute_reply.started":"2022-06-09T16:08:13.594618Z","shell.execute_reply":"2022-06-09T16:08:20.720070Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Carregando os dados do dataset\n","metadata":{}},{"cell_type":"code","source":"work_path = './cats_and_dogs_filtered'\nos.mkdir(work_path)","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:20.722488Z","iopub.execute_input":"2022-06-09T16:08:20.723086Z","iopub.status.idle":"2022-06-09T16:08:20.728723Z","shell.execute_reply.started":"2022-06-09T16:08:20.723050Z","shell.execute_reply":"2022-06-09T16:08:20.726841Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Extraindo zip\nlocal_zip = '../input/dogs-vs-cats/test1.zip'\nzip_ref = zipfile.ZipFile(local_zip,'r')\nzip_ref.extractall(work_path)\n\nlocal_zip = '../input/dogs-vs-cats/train.zip'\nzip_ref = zipfile.ZipFile(local_zip,'r')\nzip_ref.extractall(work_path)\n\nzip_ref.close()","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:20.729752Z","iopub.execute_input":"2022-06-09T16:08:20.730477Z","iopub.status.idle":"2022-06-09T16:08:40.411477Z","shell.execute_reply.started":"2022-06-09T16:08:20.730439Z","shell.execute_reply":"2022-06-09T16:08:40.410393Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Armazendo em variável os caminhos de treino e test1\ntreino_path = os.path.join(work_path, 'train')\nteste_path = os.path.join(work_path, 'test1')","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:40.413446Z","iopub.execute_input":"2022-06-09T16:08:40.413805Z","iopub.status.idle":"2022-06-09T16:08:40.418335Z","shell.execute_reply.started":"2022-06-09T16:08:40.413769Z","shell.execute_reply":"2022-06-09T16:08:40.417198Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Dados do caminho de treino\ntreino_df = pd.DataFrame({'image_name':os.listdir(treino_path)})\ntreino_df['label'] =treino_df['image_name'].apply(lambda x: x.split('.')[0])\ntreino_df","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:40.420183Z","iopub.execute_input":"2022-06-09T16:08:40.420766Z","iopub.status.idle":"2022-06-09T16:08:40.498715Z","shell.execute_reply.started":"2022-06-09T16:08:40.420731Z","shell.execute_reply":"2022-06-09T16:08:40.497712Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Dados do caminho de test\nteste_df = pd.DataFrame({'image_name':os.listdir(teste_path)})\nteste_df['label'] =teste_df['image_name'].apply(lambda x: x.split('.')[0])\nteste_df","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:40.500314Z","iopub.execute_input":"2022-06-09T16:08:40.500734Z","iopub.status.idle":"2022-06-09T16:08:40.538396Z","shell.execute_reply.started":"2022-06-09T16:08:40.500701Z","shell.execute_reply":"2022-06-09T16:08:40.537443Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Dados do treino com label dog\ncachorro_path_treino = os.path.join(treino_path, 'dog')\nos.mkdir(cachorro_path_treino)\ncachorro_df_treino = treino_df[treino_df.label=='dog']\nfor n in tqdm(cachorro_df_treino.image_name):\n    os.rename((os.path.join(treino_path, n)), (os.path.join(cachorro_path_treino, n)))","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:40.539809Z","iopub.execute_input":"2022-06-09T16:08:40.540246Z","iopub.status.idle":"2022-06-09T16:08:40.974737Z","shell.execute_reply.started":"2022-06-09T16:08:40.540206Z","shell.execute_reply":"2022-06-09T16:08:40.973833Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Dados do treino com label cat\ngato_path_treino = os.path.join(treino_path, 'cat')\nos.mkdir(gato_path_treino)\ngato_df_treino = treino_df[treino_df.label=='cat']\nfor n in tqdm(gato_df_treino.image_name):\n    os.rename((os.path.join(treino_path, n)), (os.path.join(gato_path_treino, n)))","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:40.975980Z","iopub.execute_input":"2022-06-09T16:08:40.976556Z","iopub.status.idle":"2022-06-09T16:08:41.508977Z","shell.execute_reply.started":"2022-06-09T16:08:40.976515Z","shell.execute_reply":"2022-06-09T16:08:41.507675Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Mostrando conteúdos dos subdiretorios do dataset, o principal, o de treino e o de validação\nbase_dir = './cats_and_dogs_filtered'\n\nprint(' Conteúdo do diretório base')\nprint(os.listdir(base_dir))\n\nprint('\\n Conteúdo do diretório de treino')\ntrain_path = f'{base_dir}/train'\nprint(os.listdir(treino_path))\n\nprint('\\n Conteúdo do diretório de validação')\nprint(os.listdir(teste_path)[:10])","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:41.510843Z","iopub.execute_input":"2022-06-09T16:08:41.511274Z","iopub.status.idle":"2022-06-09T16:08:41.531584Z","shell.execute_reply.started":"2022-06-09T16:08:41.511236Z","shell.execute_reply":"2022-06-09T16:08:41.530632Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Armazenando o diretório em uma variável\ntreino_dir = os.path.join(base_dir,'train')\nvalidacao_dir = os.path.join(base_dir,'test1')\n\ntreino_gatos_dir = os.path.join(treino_dir,'cat')\ntreino_cachorros_dir = os.path.join(treino_dir,'dog')","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:41.534621Z","iopub.execute_input":"2022-06-09T16:08:41.535426Z","iopub.status.idle":"2022-06-09T16:08:41.542202Z","shell.execute_reply.started":"2022-06-09T16:08:41.535373Z","shell.execute_reply":"2022-06-09T16:08:41.541036Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Mostrando nome dos arquivos\ntreino_gatos_nomes = os.listdir(treino_gatos_dir)\ntreino_cachorros_nomes = os.listdir(treino_cachorros_dir)\n\nprint(treino_gatos_nomes[:10])\nprint(treino_cachorros_nomes[:10])","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:41.544476Z","iopub.execute_input":"2022-06-09T16:08:41.545413Z","iopub.status.idle":"2022-06-09T16:08:41.582512Z","shell.execute_reply.started":"2022-06-09T16:08:41.545359Z","shell.execute_reply":"2022-06-09T16:08:41.581104Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Quantidade de cachorros e gatos nos conjuntos de treino e validação\nprint(f'Quantidade de gatos no conjunto de treino = {len(treino_gatos_nomes)}')\nprint(f'Quantidade de cachorros no conjunto de treino = {len(treino_cachorros_nomes)}')\nprint(f'Quantidade de cachorros e gatos no conjunto de validação = {len(os.listdir(validacao_dir))}')","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:41.584615Z","iopub.execute_input":"2022-06-09T16:08:41.586207Z","iopub.status.idle":"2022-06-09T16:08:41.614616Z","shell.execute_reply.started":"2022-06-09T16:08:41.586149Z","shell.execute_reply":"2022-06-09T16:08:41.612915Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plotando algumas imagens de cachorros e gatos\n%matplotlib inline\n\nnlinhas = 2\nncolunas = 4\npic_index = 0\n\nfig = plt.gcf()\nfig.set_size_inches(nlinhas*4,ncolunas*1)\n\nproxima_foto_gato = [os.path.join(treino_gatos_dir,fname) for fname in treino_gatos_nomes[pic_index:pic_index+4]]\nproxima_foto_cachorro = [os.path.join(treino_cachorros_dir,fname) for fname in treino_cachorros_nomes[pic_index:pic_index+4]]\n\nfor i ,img_path in enumerate(proxima_foto_gato+proxima_foto_cachorro):\n    sp = plt.subplot(nlinhas,ncolunas,i+1)\n    sp.axis('off')\n    \n    img = mpimg.imread(img_path)\n    plt.imshow(img)\nplt.show()    \n    ","metadata":{"execution":{"iopub.status.busy":"2022-06-09T18:00:41.492131Z","iopub.execute_input":"2022-06-09T18:00:41.492668Z","iopub.status.idle":"2022-06-09T18:00:42.278648Z","shell.execute_reply.started":"2022-06-09T18:00:41.492631Z","shell.execute_reply":"2022-06-09T18:00:42.277891Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Construindo a arquitetura","metadata":{}},{"cell_type":"code","source":"#Criação do modelo\ndef create_model():\n\n  model = tf.keras.models.Sequential([ \n      \n      tf.keras.layers.Conv2D(16,(3,3), activation = 'relu', input_shape=(150,150,3)),\n      tf.keras.layers.MaxPooling2D(2,2),\n\n      tf.keras.layers.Conv2D(32,(3,3), activation = 'relu'),\n      tf.keras.layers.MaxPooling2D(2,2),\n\n      tf.keras.layers.Conv2D(64,(3,3), activation = 'relu'),\n      tf.keras.layers.MaxPooling2D(2,2),\n\n      tf.keras.layers.Flatten(),\n      tf.keras.layers.Dense(512, activation = 'relu'),\n      tf.keras.layers.Dense(1, activation='sigmoid')\n  ])\n\n  #Compilando o modelo\n  model.compile(optimizer=RMSprop(lr=0.001),\n                loss='binary_crossentropy',\n                metrics=['accuracy']) \n    \n  return model","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:42.374484Z","iopub.execute_input":"2022-06-09T16:08:42.374985Z","iopub.status.idle":"2022-06-09T16:08:42.388159Z","shell.execute_reply.started":"2022-06-09T16:08:42.374933Z","shell.execute_reply":"2022-06-09T16:08:42.387100Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = create_model()\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:42.389543Z","iopub.execute_input":"2022-06-09T16:08:42.390262Z","iopub.status.idle":"2022-06-09T16:08:42.846496Z","shell.execute_reply.started":"2022-06-09T16:08:42.390194Z","shell.execute_reply":"2022-06-09T16:08:42.843307Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ImageDataGenerator","metadata":{}},{"cell_type":"code","source":"#Treinando DataAugmentation e Generator\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\ntreino_datagen = ImageDataGenerator(rescale=1./255,\n                 rotation_range=40,\n                 width_shift_range=0.2,\n                 height_shift_range=0.2,\n                 shear_range=0.2,\n                 zoom_range=0.2,\n                 horizontal_flip=True,\n                 fill_mode='nearest',\n                 validation_split=0.2\n) # definindo divisão do conjunto de validação\n\ntreino_generator = treino_datagen.flow_from_directory(\n                   treino_dir,\n                   target_size=(150,150),\n                   batch_size=50,\n                   class_mode='binary',\n                   subset='training'\n) # definindo dados para treino\n\nvalidacao_generator = treino_datagen.flow_from_directory(\n                      treino_dir, \n                      target_size=(150, 150),\n                      batch_size=50,\n                      class_mode='binary',\n                      subset='validation'\n) # definindo dados para validação","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:42.848073Z","iopub.execute_input":"2022-06-09T16:08:42.848665Z","iopub.status.idle":"2022-06-09T16:08:44.223592Z","shell.execute_reply.started":"2022-06-09T16:08:42.848615Z","shell.execute_reply":"2022-06-09T16:08:44.222820Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Função callback para interromper o treinamento quando val_accuracy maior ou igual a 90%\nclass mycallback(tf.keras.callbacks.Callback):\n    def on_epoch_end(self,epoch,logs={}):\n        if(logs.get('val_accuracy')>=0.90):\n            self.model.stop_training = True\n            \ncallback = mycallback()","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:44.224778Z","iopub.execute_input":"2022-06-09T16:08:44.225142Z","iopub.status.idle":"2022-06-09T16:08:44.230981Z","shell.execute_reply.started":"2022-06-09T16:08:44.225106Z","shell.execute_reply":"2022-06-09T16:08:44.229698Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Treinando modelo","metadata":{}},{"cell_type":"code","source":"#Treinando o modelo\nhistory = model.fit(\n    treino_generator,\n    steps_per_epoch = treino_generator.samples    //50,#batch_size, \n    epochs = 20,\n    verbose=1,\n    validation_data = validacao_generator,\n    validation_steps = validacao_generator.samples    //50,#batch_size,\n    callbacks=[callback]\n)","metadata":{"execution":{"iopub.status.busy":"2022-06-09T16:08:44.232394Z","iopub.execute_input":"2022-06-09T16:08:44.233431Z","iopub.status.idle":"2022-06-09T17:51:05.374300Z","shell.execute_reply.started":"2022-06-09T16:08:44.233395Z","shell.execute_reply":"2022-06-09T17:51:05.372476Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Acurácia do treino e validação","metadata":{}},{"cell_type":"code","source":"#Plotando grafico de acur\nacc = history.history['accuracy']\nval_acc = history.history['val_accuracy']\n\nplt.figure(figsize=(8, 8))\nplt.subplot(2, 1, 1)\nplt.plot(acc, 'b', label='Acurácia do treino')\nplt.plot(val_acc, 'r', label='Acurácia da validação')\nplt.legend(loc='lower right')\nplt.ylabel('Acurácia')\nplt.ylim([min(plt.ylim()),1])\nplt.title('Acurácia do treino e da validação')\n\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nplt.subplot(2, 1, 2)\nplt.plot(loss, 'b', label='Loss do treino')\nplt.plot(val_loss, 'r', label='Loss da validação')\nplt.legend(loc='upper right')\nplt.ylabel('Entropia cruzada')\nplt.ylim([0,1.0])\nplt.title('Loss do treino e validação')\nplt.xlabel('epoch')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-06-09T18:12:12.698171Z","iopub.execute_input":"2022-06-09T18:12:12.698571Z","iopub.status.idle":"2022-06-09T18:12:13.039436Z","shell.execute_reply.started":"2022-06-09T18:12:12.698533Z","shell.execute_reply":"2022-06-09T18:12:13.038226Z"},"trusted":true},"execution_count":null,"outputs":[]}]}