{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"markdown","source":"# Classificador de Raças de Cachorros usando Tensorflow e Keras\n\n\nNeste notebook iremos implementadar um modelo para classificação de imagens. Classificação é uma das \"tarefas\" em que podemos utilizar Machine Learning, nesta tarefa o ensino é **supervisionado**, em outras palavras nós vamos ensinar ao modelo através de exemplos com gabarito.\n\nNosso modelo deverá receber imagens de veículos e não-veículos e identificar a que **classe** (raça de cachorro) o cachorro pertence.\n\n## Dados\n\nOs dados são oriundos da competição [Dog Breed Indentification do Kaggle](https://www.kaggle.com/c/dog-breed-identification), na qual fornece aproximadamente 10 mil imagens de cachorros de 120 classes.\n\n\n## Modelo\n\nIremos utilizar a [arquitetura da  InceptionV3](https://arxiv.org/abs/1512.00567), ela está implementada no [Keras](https://keras.io/applications/#inceptionv3)\n\n### Avisos\n\nPara fazer o treinamento da InceptionV3 é necessário um grande poder computacional, na qual a maioria das pessoas não possuem. Mas não será por isso que não utilizaremos a Inception, graças ao Kaggle, temos a opção de rodar Kernels (que são muito similares aos notebooks do jupyter) na infraestrutura do próprio Kaggle, para mais informações sobre o suporte a GPU's do Kaggle veja [esse notebook](https://www.kaggle.com/dansbecker/running-kaggle-kernels-with-a-gpu) do [Dan Becker](https://twitter.com/dan_s_becker)\n\n## Conseguindo os dados\n\nPara ter acesso aos dados é necessário uma conta no Kaggle, e ter que entrar na [competição](https://www.kaggle.com/c/dog-breed-identification), e ir na aba Data na competição a baixá-los"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\n%matplotlib inline\nimport matplotlib.pyplot as plt\n\nnp.random.seed(0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"02c8a71ece29a178232e9dbaa7e276771b9e22c7"},"cell_type":"code","source":"input_folder = '/kaggle/input'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7f1befac14426ddfd086dff71415ebf116cff4ba"},"cell_type":"code","source":"# lendo input\ndf_train = pd.read_csv(input_folder+'/labels.csv')\ndf_test = pd.read_csv(input_folder+'/sample_submission.csv')\ndf_train.breed.value_counts().plot(kind='bar', figsize=(15,15), title=\"Quantidade de imagens por raça no treino\");","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"504b2d4ca611b4ad14590ea75265acdca9dd5791"},"cell_type":"code","source":"df_train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"58b2f589d55b4f1c65e1029d733e892edde27e93"},"cell_type":"code","source":"df_test.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7d0e60963df94f6c46ed02468bfad4ac9678a9a1"},"cell_type":"markdown","source":"## Transormando os dados para a \"notação\" one-hot-encoding\n\nPara mais informações sobre o One Hot Enconding leia este [post](https://hackernoon.com/what-is-one-hot-encoding-why-and-when-do-you-have-to-use-it-e3c6186d008f)\n"},{"metadata":{"trusted":true,"_uuid":"0e3fb9189bc51fdc317fab64c191b5854aa58370"},"cell_type":"code","source":"targets_series = pd.Series(df_train['breed'])\none_hot = pd.get_dummies(targets_series, sparse = True)\none_hot_labels = np.asarray(one_hot)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1eb0f06b0ae1b529c3dc6cbca9b7c111ed13d093"},"cell_type":"code","source":"im_size = 224","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"13dcdd5e58d1bbf690ad5d03b2cd10b06fc137ba"},"cell_type":"markdown","source":"## Lendo as imagens\n\nPara treinar a rede é necessário peger as imagens do disco e colocar elas em memória. Não entendeu um 'a' do que eu disse? Tudo bem, é normal. O que eu quis dizer foi que vamos ter que pegar as imagens do HD e colocar elas na memória RAM."},{"metadata":{"trusted":true,"_uuid":"9d222cdecad7acd231c1219b4a34644e0afc58d3"},"cell_type":"code","source":"from tqdm import tqdm # bliblioteca para colocar a porcentagem de andamento do for\nimport cv2 # biblioteca para visão computacional","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"48eea7f6f97e88dac6d5bb2f74bd944eda536b0b"},"cell_type":"code","source":"x_train = []\ny_train = []\nx_test = []","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1358b9a8fe44b3c46869a5f742a19bff831fc809"},"cell_type":"code","source":"i = 0 \nfor f, breed in tqdm(df_train.values):\n    img = cv2.imread(input_folder+'/train/{}.jpg'.format(f))\n    x_train.append(cv2.resize(img, (im_size, im_size)))\n    label = one_hot_labels[i]\n    y_train.append(label)\n    i += 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ef7b84bca44b8b98e8e595a8c5b88ed5208708be"},"cell_type":"code","source":"del df_train # apagando uma variável pra diminuir consumo de memória","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2459fc750bd49ed0b58c18850354b1b702456ce2"},"cell_type":"code","source":"for f in tqdm(df_test['id'].values):\n    img = cv2.imread(input_folder+'/test/{}.jpg'.format(f))\n    x_test.append(cv2.resize(img, (im_size, im_size)))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ab1ed63653409cbb17f079312858827753939815"},"cell_type":"markdown","source":"## Dividindo dataset\n\nGeralmente em dividimos os dados em treino, validação e teste.\n1. Treino: conjunto para treinar o modelo\n2. Validação: conjunto para escolher os melhores hiperparâmetros do modelo (mais tarde falo sobre hiperparâmetros, ok?)\n3. Teste: conjunto para coletar as métricas finais do modelo"},{"metadata":{"trusted":true,"_uuid":"8330926bebc8b2e681db5fc0a10ad663598ab9e7"},"cell_type":"code","source":"from sklearn.model_selection import train_test_split # biblioteca para fazer a divisão dos dados em treino e teste","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"643ec57c09549f9034d1d1c14cb0618f6aca09d7"},"cell_type":"code","source":"num_class = 120\nX_train, X_valid, Y_train, Y_valid = train_test_split(x_train, y_train, shuffle=True,  test_size=0.2, random_state=1)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3b89b322fe04cd8a6aae2017d1920d4e7e9d7c55"},"cell_type":"markdown","source":"## Data augmentation\n\nNós temos dados o suficiente para travar nossas máquinas XD, mas não o suficiente para treinar modelos bastantes robustos, temos poucas imagens por classe.\n\nPara ameninzar esse problema iremos utilizar uma técnica chamada data augmentations, ela transforma uma imagem em diversas, como por exemplo dar um giro vertical, ou horizontal. Como nesse exemplo:\n\n![Imgur](https://i.imgur.com/GJGMou5.png)\n\nLinks legais (em inglês, desculpem):\n\n[Link para a documentação](https://keras.io/preprocessing/image/)\n\n[Tutorial massa do keras](https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html)\n\n[Outro tutorial massa, mas não é do Keras, esse é do Dan Becker](https://www.kaggle.com/dansbecker/data-augmentation)[](http://)"},{"metadata":{"trusted":true,"_uuid":"b1bfefd063c2286770a4a84a60f9c46edf754416"},"cell_type":"code","source":"from keras.preprocessing.image import ImageDataGenerator # biblioteca para data augmetantaion","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b0511f3cdfda94276de4d5e1298fb6cb14945428"},"cell_type":"code","source":"datagen = ImageDataGenerator(width_shift_range=0.2,\n                            height_shift_range=0.2,\n                            zoom_range=0.2,\n                            rotation_range=30,\n                            vertical_flip=False,\n                            horizontal_flip=True) # aqui eu defino os parâmetros que irei \n                                                  # utilizar para gerar as imagens\n\ntrain_generator = datagen.flow(np.array(X_train), np.array(Y_train), \n                               batch_size=32) \nvalid_generator = datagen.flow(np.array(X_valid), np.array(Y_valid), \n                               batch_size=32) ","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"12d0be41e87bb62d28813e408509e587536de72f"},"cell_type":"markdown","source":"## Criação da Inception\n\nA partir de agora iremos criar a rede propriamente dita, iremos utilizar a arquitetura da rede Inception, e os pesos pré-treinada sobre os dados do ImageNet."},{"metadata":{"trusted":true,"_uuid":"1a757b3461c8293ed4f2176416b9e6db37ae650a"},"cell_type":"code","source":"from keras.applications.inception_v3 import InceptionV3\nfrom keras.layers import Dense, Dropout, Flatten\nfrom keras import regularizers\nfrom keras.models import Model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6a1c8dab8ee63ff004312811a1e425eecbfe1aaf"},"cell_type":"code","source":"base_model = InceptionV3(weights=\"imagenet\",include_top=False, input_shape=(im_size, im_size, 3))\ndropout = base_model.output\ndropout = Dropout(0.5)(dropout)\nmodel_with_dropout = Model(inputs=base_model.input, outputs=dropout)\n    \nx = model_with_dropout.output\nx = Flatten()(x)\npredictions = Dense(num_class, activation='softmax',\n                    kernel_regularizer=regularizers.l2(0.0015),\n                    activity_regularizer=regularizers.l1(0.0015))(x)\n    \nmy_model = Model(inputs=model_with_dropout.input, outputs=predictions)\n        \nmy_model.compile(optimizer='sgd',\n                 loss='categorical_crossentropy',\n                 metrics=['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"01d72b62414ca1690bff9d179c57c8375375cbc6"},"cell_type":"markdown","source":"## Treinando o modelo"},{"metadata":{"trusted":true,"_uuid":"2cf300f822959cf2b29c860ffc0219ced4f873cc"},"cell_type":"code","source":"my_model.fit_generator(\n    train_generator,\n    epochs=10, steps_per_epoch=len(X_train) / 18,\n    validation_data=valid_generator, validation_steps=len(X_valid) / 18) # reali","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ce948f90bb140680168430850b4b910f5097f924"},"cell_type":"markdown","source":"## Fazendo predições"},{"metadata":{"trusted":true,"_uuid":"489a3eacfb5d2d2980eb0772ff880cd90e195aa4"},"cell_type":"code","source":"preds = my_model.predict(np.array(x_test), verbose=1)\nsub = pd.DataFrame(preds)\ncol_names = one_hot.columns.values\nsub.columns = col_names\nsub.insert(0, 'id', df_test['id'])\nsub.head(5)\nsub.to_csv(\"submission.csv\")","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}