{"cells":[{"metadata":{"_uuid":"fcc7b29ea2d523bd3305f5a22615b9f04f96045d"},"cell_type":"markdown","source":"https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition"},{"metadata":{"trusted":true,"_uuid":"f13e5a7d133d535164dbc66b9d3c161707222902","collapsed":true},"cell_type":"code","source":"# Veamos la data que tenemos\n!ls ../input","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a5d7a741acae2ba0b9cf6c5d0968730d2965408b","collapsed":true},"cell_type":"code","source":"!ls -U ../input/train/ | tail -n 5","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cd06b8a70dab1608817ea1b025dbc620444ede3b","collapsed":true},"cell_type":"code","source":"!ls ../input/test/ | tail -n 5","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e283fd48093a5a65fb5ad921eae54dc299880445"},"cell_type":"markdown","source":"# Cargando las imagenes"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"collapsed":true},"cell_type":"code","source":"import math\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nfrom tqdm import tqdm_notebook\nfrom pathlib import Path\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8ffde293468974ea2859626d21b4a6257331a373","collapsed":true},"cell_type":"code","source":"train_path = Path('../input/train/')\ncat_imgs, dog_imgs = [], []\nfor e in train_path.iterdir():\n    if 'cat' in e.name: cat_imgs.append(e)\n    else              : dog_imgs.append(e)\nlen(cat_imgs), len(dog_imgs)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"dd0db82334247043f40514fe4dea9448c0b47fde","collapsed":true},"cell_type":"code","source":"# Definimos una funcion para leer una imagen y hacer el preprocesamiento\nfrom keras.applications.resnet50 import preprocess_input\nimg_size = 224\n\ndef read_img(path):\n    x = Image.open(path)\n    x = x.resize((img_size, img_size))\n    x = np.asarray(x, np.float32)\n    return preprocess_input(x)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"856a5f42da258f34b35ffedc3d1a8a1f8b220cfb"},"cell_type":"code","source":"# Cargamos una muestra de imagenes para train y validation\n\n# Primero inicializamos los arrays que vamos a usar\nx_train = np.ndarray(shape=(2000, img_size, img_size, 3), dtype=np.float32)\ny_train = np.zeros(shape=(2000), dtype=np.int8)\nx_val = np.ndarray(shape=(200, img_size, img_size, 3), dtype=np.float32)\ny_val = np.zeros(shape=(200), dtype=np.int8)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c962e86df48c583d355e4c9e5b4fbae3511cbbef","collapsed":true},"cell_type":"code","source":"# Cargamos el train set\nfor i,e in tqdm_notebook(enumerate(cat_imgs[:1000] + dog_imgs[:1000])):\n    x_train[i] = read_img(e)\n\ny_train[1000:] = 1 # cat -> 0 | dog -> 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"dd3a8a80874a604edae54c69e6f982a533d042b3","collapsed":true},"cell_type":"code","source":"# Cargamos el validation set\nfor i,e in tqdm_notebook(enumerate(cat_imgs[1000:1100] + dog_imgs[1000:1100])):\n    x_val[i] = read_img(e)\n\ny_val[100:] = 1 # cat -> 0 | dog -> 1","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"305450fc23ec4bbe07fbed37002728c16bc08d3b"},"cell_type":"markdown","source":"# Cargamos una red entrenada\nVamos a cargar la red **ResNet50** ya entrenada, pero sin incluir las capas densas, ya que vamos a adaptar la red a nuestro caso específico."},{"metadata":{"trusted":true,"_uuid":"8b59033d95609d22d1fb0340199dc5078a363a95","collapsed":true},"cell_type":"code","source":"from keras.applications.resnet50 import ResNet50\nbase_model = ResNet50(include_top=False, input_shape=(img_size,img_size,3), pooling='avg')\nbase_model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d04e3b7ad402273ccea07de3f83f0527b4c8d717","collapsed":true},"cell_type":"code","source":"base_model.input, base_model.output","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"225ead4fba38cda171e2cb5c27420322cb13816e","collapsed":true},"cell_type":"code","source":"# Dado que solo queremos entrenar las capas densas del modelo que agregaremos\n# en el siguiente paso, vamos a setear \"trainable = False\" para que los pesos\n# de la red entrenada no cambien.\nbase_model.trainable = False","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"72c61fc149bd8162c9844497a7a5adefd5e74a15"},"cell_type":"markdown","source":"# Creamos el modelo clasificador"},{"metadata":{"trusted":true,"_uuid":"1b75e918a04d9628c2b1187f2bdfb85e0cb99ce8","collapsed":true},"cell_type":"code","source":"from keras.models import Sequential\nfrom keras.layers import Dense, Flatten\nfrom keras.optimizers import Adam\n\ntop_model = Sequential([\n    Dense(128, activation='relu', input_shape=(2048,)),\n    Dense(1, activation='sigmoid')\n])\n\ntop_model.compile(loss='binary_crossentropy', optimizer=Adam(0.001), metrics=['accuracy'])\ntop_model.summary()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1292ede52c3105b784275ac1382b8cce91bc0a10"},"cell_type":"markdown","source":"# Juntamos los 2 modelos"},{"metadata":{"trusted":true,"_uuid":"218a3187ab575debf6c9fe3abced6d97d04fba86","collapsed":true},"cell_type":"code","source":"final_model = Sequential([base_model, top_model])\n\nfinal_model.compile(loss='binary_crossentropy', optimizer=Adam(0.001), metrics=['accuracy'])\nfinal_model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"ff154013dd06e172ab8e6490f1f79cec6581442b"},"cell_type":"markdown","source":"# Entrenando en nuestro dataset"},{"metadata":{"trusted":true,"_uuid":"f5bf9e08df98f7118f0c4f32c0128356039f5542","collapsed":true},"cell_type":"code","source":"# log = final_model.fit(x_train, y_train, batch_size=64, validation_data=[x_val, y_val])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"28485bb2719d2c3b5a3bdc1e1509fe80c435026b","collapsed":true},"cell_type":"markdown","source":"La red de base que estamos usando (ResNet50) tiene bastantes capas y hacer todas estas operaciones toma un tiempo considerable, en CPU hacer este entrenamiento puede resultar impractico.\n# Precompute\nSi tenemos en cuenta que vamos a entrenar nuestro dataset un cierto número de épocas, en cada época se van a repetir exactamente las mismas operaciones en la misma data. Para no redundar, es bastante útil hacer un precompute de la data:\n1. Pasar todas nuestras imagenes por la red base (ResNet50).\n2. Guardamos los features extraidos.\n3. Entrenamos las capas densas con los features extraidos."},{"metadata":{"trusted":true,"_uuid":"4b5e69b30880a2c507278645cddd531a1f9704ac","collapsed":true},"cell_type":"code","source":"precomputed_train = base_model.predict(x_train, batch_size=128, verbose=1)\nprecomputed_train.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"41d90ae534e0430ebd2929f6037bab06038fb4f8","collapsed":true},"cell_type":"code","source":"precomputed_val = base_model.predict(x_val, batch_size=128, verbose=1)\nprecomputed_val.shape","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"25ef73ba4bacf61c23c97b703e4cd3eca31a0f01"},"cell_type":"markdown","source":"# Entrenar a partir de los features extraidos"},{"metadata":{"trusted":true,"_uuid":"b7692ae75c991bdcd548ae6f00fcffa5eb12dfc8","collapsed":true},"cell_type":"code","source":"# Ahora podemos usar un batch_size mas grande, ya que los features son mas pequeños\n# que las imagenes.\nlog = top_model.fit(precomputed_train, y_train, epochs=5, batch_size=256, validation_data=[precomputed_val, y_val])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"7c2e69bbba9e401ae79f0860d48cb9bb813766ad"},"cell_type":"code","source":"def show_results(log):\n    fig, axes = plt.subplots(1, 2, figsize=(14,4))\n    ax1, ax2 = axes\n    ax1.plot(log.history['loss'], label='train')\n    ax1.plot(log.history['val_loss'], label='validation')\n    ax1.set_xlabel('epoch'); ax1.set_ylabel('loss')\n    ax2.plot(log.history['acc'], label='train')\n    ax2.plot(log.history['val_acc'], label='validation')\n    ax2.set_xlabel('epoch'); ax2.set_ylabel('accuracy')\n    for ax in axes: ax.legend()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fe236ded01cf6d633b17aeac019fc5c95d3e73f9","collapsed":true},"cell_type":"code","source":"show_results(log)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ca6322dbcd87586225384f3c5f47bc40b41443bf"},"cell_type":"markdown","source":"# Ejercicio: usando el modelo completo en el test set"},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"156f753e5482474d68bd6146dd0a1c95001ad9eb"},"cell_type":"code","source":"test_path = Path('../input/test/')\ntest_files = list(test_path.iterdir())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"ea5150825528e86bc702e49a99eb2c12795b1168"},"cell_type":"code","source":"def get_class(path):\n    # Cargar la imagen del path\n    img = Image.open(path)\n    \n    # Cambiar el tamaño de la imagen\n    img_resized = img.resize((224, 224))\n    \n    # Cambiar a formato numpy y preprocesar\n    x = np.asarray(img_resized, np.float32)[None]\n    x = preprocess_input(x)\n    \n    # Obtener predicciones\n    y = final_model.predict(x)\n    \n    # Decodear predicciones\n    pred = 'cat' if y < 0.5 else 'dog'\n    \n    # Mostrar la imagen\n    plt.imshow(img)\n    plt.axis('off')\n    plt.title(pred, size=14)\n    \n    return","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7aff89101033f3bb3a797f170668f7efe327d8ec","collapsed":true},"cell_type":"code","source":"sample = np.random.choice(test_files)\nget_class(sample)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"c576338f3b3c926f9cb849e8e44b255c66be5a75"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"57ce9193faf7aa3d00632b095865ef1e76fc2cf2"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}