{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Detector de Celulas" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cargar el modelo ssd7 \n", "(https://github.com/pierluigiferrari/ssd_keras#how-to-fine-tune-one-of-the-trained-models-on-your-own-dataset)\n", "\n", "Training del SSD7 (modelo reducido de SSD). Parámetros en config_7.json y descargar VGG_ILSVRC_16_layers_fc_reduced.h5\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Training on: \t{'panel': 1}\n", "\n", "OK create model\n", "\n", "Loading pretrained weights VGG.\n", "\n", "__________________________________________________________________________________________________\n", "Layer (type) Output Shape Param # Connected to \n", "==================================================================================================\n", "input_1 (InputLayer) (None, 400, 400, 3) 0 \n", "__________________________________________________________________________________________________\n", "identity_layer (Lambda) (None, 400, 400, 3) 0 input_1[0][0] \n", "__________________________________________________________________________________________________\n", "conv1 (Conv2D) (None, 400, 400, 32) 2432 identity_layer[0][0] \n", "__________________________________________________________________________________________________\n", "bn1 (BatchNormalization) (None, 400, 400, 32) 128 conv1[0][0] \n", "__________________________________________________________________________________________________\n", "elu1 (ELU) (None, 400, 400, 32) 0 bn1[0][0] \n", "__________________________________________________________________________________________________\n", "pool1 (MaxPooling2D) (None, 200, 200, 32) 0 elu1[0][0] \n", "__________________________________________________________________________________________________\n", "conv2 (Conv2D) (None, 200, 200, 48) 13872 pool1[0][0] \n", "__________________________________________________________________________________________________\n", "bn2 (BatchNormalization) (None, 200, 200, 48) 192 conv2[0][0] \n", "__________________________________________________________________________________________________\n", "elu2 (ELU) (None, 200, 200, 48) 0 bn2[0][0] \n", "__________________________________________________________________________________________________\n", "pool2 (MaxPooling2D) (None, 100, 100, 48) 0 elu2[0][0] \n", "__________________________________________________________________________________________________\n", "conv3 (Conv2D) (None, 100, 100, 64) 27712 pool2[0][0] \n", "__________________________________________________________________________________________________\n", "bn3 (BatchNormalization) (None, 100, 100, 64) 256 conv3[0][0] \n", "__________________________________________________________________________________________________\n", "elu3 (ELU) (None, 100, 100, 64) 0 bn3[0][0] \n", "__________________________________________________________________________________________________\n", "pool3 (MaxPooling2D) (None, 50, 50, 64) 0 elu3[0][0] \n", "__________________________________________________________________________________________________\n", "conv4 (Conv2D) (None, 50, 50, 64) 36928 pool3[0][0] \n", "__________________________________________________________________________________________________\n", "bn4 (BatchNormalization) (None, 50, 50, 64) 256 conv4[0][0] \n", "__________________________________________________________________________________________________\n", "elu4 (ELU) (None, 50, 50, 64) 0 bn4[0][0] \n", "__________________________________________________________________________________________________\n", "pool4 (MaxPooling2D) (None, 25, 25, 64) 0 elu4[0][0] \n", "__________________________________________________________________________________________________\n", "conv5 (Conv2D) (None, 25, 25, 48) 27696 pool4[0][0] \n", "__________________________________________________________________________________________________\n", "bn5 (BatchNormalization) (None, 25, 25, 48) 192 conv5[0][0] \n", "__________________________________________________________________________________________________\n", "elu5 (ELU) (None, 25, 25, 48) 0 bn5[0][0] \n", "__________________________________________________________________________________________________\n", "pool5 (MaxPooling2D) (None, 12, 12, 48) 0 elu5[0][0] \n", "__________________________________________________________________________________________________\n", "conv6 (Conv2D) (None, 12, 12, 48) 20784 pool5[0][0] \n", "__________________________________________________________________________________________________\n", "bn6 (BatchNormalization) (None, 12, 12, 48) 192 conv6[0][0] \n", "__________________________________________________________________________________________________\n", "elu6 (ELU) (None, 12, 12, 48) 0 bn6[0][0] \n", "__________________________________________________________________________________________________\n", "pool6 (MaxPooling2D) (None, 6, 6, 48) 0 elu6[0][0] \n", "__________________________________________________________________________________________________\n", "conv7 (Conv2D) (None, 6, 6, 32) 13856 pool6[0][0] \n", "__________________________________________________________________________________________________\n", "bn7 (BatchNormalization) (None, 6, 6, 32) 128 conv7[0][0] \n", "__________________________________________________________________________________________________\n", "elu7 (ELU) (None, 6, 6, 32) 0 bn7[0][0] \n", "__________________________________________________________________________________________________\n", "classes4 (Conv2D) (None, 50, 50, 8) 4616 elu4[0][0] \n", "__________________________________________________________________________________________________\n", "classes5 (Conv2D) (None, 25, 25, 8) 3464 elu5[0][0] \n", "__________________________________________________________________________________________________\n", "classes6 (Conv2D) (None, 12, 12, 8) 3464 elu6[0][0] \n", "__________________________________________________________________________________________________\n", "classes7 (Conv2D) (None, 6, 6, 8) 2312 elu7[0][0] \n", "__________________________________________________________________________________________________\n", "boxes4 (Conv2D) (None, 50, 50, 16) 9232 elu4[0][0] \n", "__________________________________________________________________________________________________\n", "boxes5 (Conv2D) (None, 25, 25, 16) 6928 elu5[0][0] \n", "__________________________________________________________________________________________________\n", "boxes6 (Conv2D) (None, 12, 12, 16) 6928 elu6[0][0] \n", "__________________________________________________________________________________________________\n", "boxes7 (Conv2D) (None, 6, 6, 16) 4624 elu7[0][0] \n", "__________________________________________________________________________________________________\n", "classes4_reshape (Reshape) (None, 10000, 2) 0 classes4[0][0] \n", "__________________________________________________________________________________________________\n", "classes5_reshape (Reshape) (None, 2500, 2) 0 classes5[0][0] \n", "__________________________________________________________________________________________________\n", "classes6_reshape (Reshape) (None, 576, 2) 0 classes6[0][0] \n", "__________________________________________________________________________________________________\n", "classes7_reshape (Reshape) (None, 144, 2) 0 classes7[0][0] \n", "__________________________________________________________________________________________________\n", "anchors4 (AnchorBoxes) (None, 50, 50, 4, 8) 0 boxes4[0][0] \n", "__________________________________________________________________________________________________\n", "anchors5 (AnchorBoxes) (None, 25, 25, 4, 8) 0 boxes5[0][0] \n", "__________________________________________________________________________________________________\n", "anchors6 (AnchorBoxes) (None, 12, 12, 4, 8) 0 boxes6[0][0] \n", "__________________________________________________________________________________________________\n", "anchors7 (AnchorBoxes) (None, 6, 6, 4, 8) 0 boxes7[0][0] \n", "__________________________________________________________________________________________________\n", "classes_concat (Concatenate) (None, 13220, 2) 0 classes4_reshape[0][0] \n", " classes5_reshape[0][0] \n", " classes6_reshape[0][0] \n", " classes7_reshape[0][0] \n", "__________________________________________________________________________________________________\n", "boxes4_reshape (Reshape) (None, 10000, 4) 0 boxes4[0][0] \n", "__________________________________________________________________________________________________\n", "boxes5_reshape (Reshape) (None, 2500, 4) 0 boxes5[0][0] \n", "__________________________________________________________________________________________________\n", "boxes6_reshape (Reshape) (None, 576, 4) 0 boxes6[0][0] \n", "__________________________________________________________________________________________________\n", "boxes7_reshape (Reshape) (None, 144, 4) 0 boxes7[0][0] \n", "__________________________________________________________________________________________________\n", "anchors4_reshape (Reshape) (None, 10000, 8) 0 anchors4[0][0] \n", "__________________________________________________________________________________________________\n", "anchors5_reshape (Reshape) (None, 2500, 8) 0 anchors5[0][0] \n", "__________________________________________________________________________________________________\n", "anchors6_reshape (Reshape) (None, 576, 8) 0 anchors6[0][0] \n", "__________________________________________________________________________________________________\n", "anchors7_reshape (Reshape) (None, 144, 8) 0 anchors7[0][0] \n", "__________________________________________________________________________________________________\n", "classes_softmax (Activation) (None, 13220, 2) 0 classes_concat[0][0] \n", "__________________________________________________________________________________________________\n", "boxes_concat (Concatenate) (None, 13220, 4) 0 boxes4_reshape[0][0] \n", " boxes5_reshape[0][0] \n", " boxes6_reshape[0][0] \n", " boxes7_reshape[0][0] \n", "__________________________________________________________________________________________________\n", "anchors_concat (Concatenate) (None, 13220, 8) 0 anchors4_reshape[0][0] \n", " anchors5_reshape[0][0] \n", " anchors6_reshape[0][0] \n", " anchors7_reshape[0][0] \n", "__________________________________________________________________________________________________\n", "predictions (Concatenate) (None, 13220, 14) 0 classes_softmax[0][0] \n", " boxes_concat[0][0] \n", " anchors_concat[0][0] \n", "==================================================================================================\n", "Total params: 186,192\n", "Trainable params: 185,520\n", "Non-trainable params: 672\n", "__________________________________________________________________________________________________\n" ] } ], "source": [ "from keras.optimizers import Adam, SGD\n", "from keras.callbacks import ModelCheckpoint, LearningRateScheduler, TerminateOnNaN, CSVLogger\n", "from keras import backend as K\n", "from keras.models import load_model\n", "from math import ceil\n", "import numpy as np\n", "from matplotlib import pyplot as plt\n", "import os\n", "import json\n", "import xml.etree.cElementTree as ET\n", "\n", "import sys\n", "sys.path += [os.path.abspath('../ssd_keras-master')]\n", "\n", "from keras_loss_function.keras_ssd_loss import SSDLoss\n", "from keras_layers.keras_layer_AnchorBoxes import AnchorBoxes\n", "from keras_layers.keras_layer_DecodeDetections import DecodeDetections\n", "from keras_layers.keras_layer_DecodeDetectionsFast import DecodeDetectionsFast\n", "from keras_layers.keras_layer_L2Normalization import L2Normalization\n", "from ssd_encoder_decoder.ssd_input_encoder import SSDInputEncoder\n", "from ssd_encoder_decoder.ssd_output_decoder import decode_detections, decode_detections_fast\n", "from data_generator.object_detection_2d_data_generator import DataGenerator\n", "from data_generator.object_detection_2d_geometric_ops import Resize\n", "from data_generator.object_detection_2d_photometric_ops import ConvertTo3Channels\n", "from data_generator.data_augmentation_chain_original_ssd import SSDDataAugmentation\n", "from data_generator.object_detection_2d_misc_utils import apply_inverse_transforms\n", "from eval_utils.average_precision_evaluator import Evaluator\n", "from data_generator.data_augmentation_chain_variable_input_size import DataAugmentationVariableInputSize\n", "from data_generator.data_augmentation_chain_constant_input_size import DataAugmentationConstantInputSize\n", "\n", "\n", "def makedirs(path):\n", " try:\n", " os.makedirs(path)\n", " except OSError:\n", " if not os.path.isdir(path):\n", " raise\n", "\n", " \n", "makedirs(path_anns)\n", "\n", "\n", "\n", "K.tensorflow_backend._get_available_gpus()\n", "\n", "\n", "def lr_schedule(epoch):\n", " if epoch < 80:\n", " return 0.001\n", " elif epoch < 100:\n", " return 0.0001\n", " else:\n", " return 0.00001\n", "\n", "config_path = 'config_7_panel.json'\n", "\n", "\n", "with open(config_path) as config_buffer:\n", " config = json.loads(config_buffer.read())\n", "\n", "###############################\n", "# Parse the annotations\n", "###############################\n", "path_imgs_training = config['train']['train_image_folder']\n", "path_anns_training = config['train']['train_annot_folder']\n", "path_imgs_val = config['test']['test_image_folder']\n", "path_anns_val = config['test']['test_annot_folder']\n", "labels = config['model']['labels']\n", "categories = {}\n", "#categories = {\"Razor\": 1, \"Gun\": 2, \"Knife\": 3, \"Shuriken\": 4} #la categoría 0 es la background\n", "for i in range(len(labels)): categories[labels[i]] = i+1\n", "print('\\nTraining on: \\t' + str(categories) + '\\n')\n", "\n", "####################################\n", "# Parameters\n", "###################################\n", " #%%\n", "img_height = config['model']['input'] # Height of the model input images\n", "img_width = config['model']['input'] # Width of the model input images\n", "img_channels = 3 # Number of color channels of the model input images\n", "mean_color = [123, 117, 104] # The per-channel mean of the images in the dataset. Do not change this value if you're using any of the pre-trained weights.\n", "swap_channels = [2, 1, 0] # The color channel order in the original SSD is BGR, so we'll have the model reverse the color channel order of the input images.\n", "n_classes = len(labels) # Number of positive classes, e.g. 20 for Pascal VOC, 80 for MS COCO\n", "scales_pascal = [0.1, 0.2, 0.37, 0.54, 0.71, 0.88, 1.05] # The anchor box scaling factors used in the original SSD300 for the Pascal VOC datasets\n", "#scales_coco = [0.07, 0.15, 0.33, 0.51, 0.69, 0.87, 1.05] # The anchor box scaling factors used in the original SSD300 for the MS COCO datasets\n", "scales = scales_pascal\n", "aspect_ratios = [[1.0, 2.0, 0.5],\n", " [1.0, 2.0, 0.5, 3.0, 1.0/3.0],\n", " [1.0, 2.0, 0.5, 3.0, 1.0/3.0],\n", " [1.0, 2.0, 0.5, 3.0, 1.0/3.0],\n", " [1.0, 2.0, 0.5],\n", " [1.0, 2.0, 0.5]] # The anchor box aspect ratios used in the original SSD300; the order matters\n", "two_boxes_for_ar1 = True\n", "steps = [8, 16, 32, 64, 100, 300] # The space between two adjacent anchor box center points for each predictor layer.\n", "offsets = [0.5, 0.5, 0.5, 0.5, 0.5, 0.5] # The offsets of the first anchor box center points from the top and left borders of the image as a fraction of the step size for each predictor layer.\n", "clip_boxes = False # Whether or not to clip the anchor boxes to lie entirely within the image boundaries\n", "variances = [0.1, 0.1, 0.2, 0.2] # The variances by which the encoded target coordinates are divided as in the original implementation\n", "normalize_coords = True\n", "\n", "K.clear_session() # Clear previous models from memory.\n", "\n", "\n", "model_path = config['train']['saved_weights_name']\n", "# 3: Instantiate an optimizer and the SSD loss function and compile the model.\n", "# If you want to follow the original Caffe implementation, use the preset SGD\n", "# optimizer, otherwise I'd recommend the commented-out Adam optimizer.\n", "\n", "\n", "if config['model']['backend'] == 'ssd7':\n", " #weights_path = 'VGG_ILSVRC_16_layers_fc_reduced.h5'\n", " scales = [0.08, 0.16, 0.32, 0.64, 0.96] # An explicit list of anchor box scaling factors. If this is passed, it will override `min_scale` and `max_scale`.\n", " aspect_ratios = [0.5 ,1.0, 2.0] # The list of aspect ratios for the anchor boxes\n", " two_boxes_for_ar1 = True # Whether or not you want to generate two anchor boxes for aspect ratio 1\n", " steps = None # In case you'd like to set the step sizes for the anchor box grids manually; not recommended\n", " offsets = None\n", "\n", "if os.path.exists(model_path):\n", " print(\"\\nLoading pretrained weights.\\n\")\n", " # We need to create an SSDLoss object in order to pass that to the model loader.\n", " ssd_loss = SSDLoss(neg_pos_ratio=3, alpha=1.0)\n", "\n", " K.clear_session() # Clear previous models from memory.\n", " model = load_model(model_path, custom_objects={'AnchorBoxes': AnchorBoxes,\n", " 'L2Normalization': L2Normalization,\n", " 'compute_loss': ssd_loss.compute_loss})\n", "\n", "\n", "else:\n", " ####################################\n", " # Build the Keras model.\n", " ###################################\n", "\n", " if config['model']['backend'] == 'ssd300':\n", " #weights_path = 'VGG_VOC0712Plus_SSD_300x300_ft_iter_160000.h5'\n", " from models.keras_ssd300 import ssd_300 as ssd\n", "\n", " model = ssd_300(image_size=(img_height, img_width, img_channels),\n", " n_classes=n_classes,\n", " mode='training',\n", " l2_regularization=0.0005,\n", " scales=scales,\n", " aspect_ratios_per_layer=aspect_ratios,\n", " two_boxes_for_ar1=two_boxes_for_ar1,\n", " steps=steps,\n", " offsets=offsets,\n", " clip_boxes=clip_boxes,\n", " variances=variances,\n", " normalize_coords=normalize_coords,\n", " subtract_mean=mean_color,\n", " swap_channels=swap_channels)\n", "\n", "\n", " elif config['model']['backend'] == 'ssd7':\n", " #weights_path = 'VGG_ILSVRC_16_layers_fc_reduced.h5'\n", " from models.keras_ssd7 import build_model as ssd\n", " scales = [0.08, 0.16, 0.32, 0.64, 0.96] # An explicit list of anchor box scaling factors. If this is passed, it will override `min_scale` and `max_scale`.\n", " aspect_ratios = [0.5 ,1.0, 2.0] # The list of aspect ratios for the anchor boxes\n", " two_boxes_for_ar1 = True # Whether or not you want to generate two anchor boxes for aspect ratio 1\n", " steps = None # In case you'd like to set the step sizes for the anchor box grids manually; not recommended\n", " offsets = None\n", " model = ssd(image_size=(img_height, img_width, img_channels),\n", " n_classes=n_classes,\n", " mode='training',\n", " l2_regularization=0.0005,\n", " scales=scales,\n", " aspect_ratios_global=aspect_ratios,\n", " aspect_ratios_per_layer=None,\n", " two_boxes_for_ar1=two_boxes_for_ar1,\n", " steps=steps,\n", " offsets=offsets,\n", " clip_boxes=clip_boxes,\n", " variances=variances,\n", " normalize_coords=normalize_coords,\n", " subtract_mean=None,\n", " divide_by_stddev=None)\n", "\n", " else :\n", " print('Wrong Backend')\n", "\n", "\n", "\n", " print('OK create model')\n", " #sgd = SGD(lr=config['train']['learning_rate'], momentum=0.9, decay=0.0, nesterov=False)\n", "\n", " # TODO: Set the path to the weights you want to load. only for ssd300 or ssd512\n", "\n", " weights_path = '../ssd_keras-master/VGG_ILSVRC_16_layers_fc_reduced.h5'\n", " print(\"\\nLoading pretrained weights VGG.\\n\")\n", " model.load_weights(weights_path, by_name=True)\n", "\n", " # 3: Instantiate an optimizer and the SSD loss function and compile the model.\n", " # If you want to follow the original Caffe implementation, use the preset SGD\n", " # optimizer, otherwise I'd recommend the commented-out Adam optimizer.\n", "\n", "\n", " #adam = Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0)\n", " #sgd = SGD(lr=0.001, momentum=0.9, decay=0.0, nesterov=False)\n", " optimizer = Adam(lr=config['train']['learning_rate'], beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0)\n", " ssd_loss = SSDLoss(neg_pos_ratio=3, alpha=1.0)\n", " model.compile(optimizer=optimizer, loss=ssd_loss.compute_loss)\n", "\n", " model.summary()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instanciar los generadores de datos y entrenamiento del modelo.\n", "\n", "*Cambio realizado para leer png y jpg. keras-ssd-master/data_generator/object_detection_2d_data_generator.py función parse_xml\n" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "Processing image set 'train.txt': 0%| | 0/1 [00:006}\".format(train_dataset_size))\n", "print(\"Number of images in the validation dataset:\\t{:>6}\".format(val_dataset_size))\n", "\n", "\n", "\n", "##########################\n", "# Define model callbacks.\n", "#########################\n", "\n", "# TODO: Set the filepath under which you want to save the model.\n", "model_checkpoint = ModelCheckpoint(filepath= config['train']['saved_weights_name'],\n", " monitor='val_loss',\n", " verbose=1,\n", " save_best_only=True,\n", " save_weights_only=False,\n", " mode='auto',\n", " period=1)\n", "#model_checkpoint.best =\n", "\n", "csv_logger = CSVLogger(filename='log.csv',\n", " separator=',',\n", " append=True)\n", "\n", "learning_rate_scheduler = LearningRateScheduler(schedule=lr_schedule,\n", " verbose=1)\n", "\n", "terminate_on_nan = TerminateOnNaN()\n", "\n", "callbacks = [model_checkpoint,\n", " csv_logger,\n", " learning_rate_scheduler,\n", " terminate_on_nan]\n", "\n", "\n", "\n", "batch_images, batch_labels = next(train_generator)\n", "\n", "\n", "initial_epoch = 0\n", "final_epoch = 100 #config['train']['nb_epochs']\n", "steps_per_epoch = 50\n", "\n", "history = model.fit_generator(generator=train_generator,\n", " steps_per_epoch=steps_per_epoch,\n", " epochs=final_epoch,\n", " callbacks=callbacks,\n", " validation_data=val_generator,\n", " validation_steps=ceil(val_dataset_size/batch_size),\n", " initial_epoch=initial_epoch,\n", " verbose = 1 if config['train']['debug'] else 2)\n", "\n", "history_path = config['train']['saved_weights_name'].split('.')[0] + '_history'\n", "\n", "np.save(history_path, history.history)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "dict_keys(['val_loss', 'loss', 'lr'])\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "#Graficar aprendizaje\n", "history_path = config['train']['saved_weights_name'].split('.')[0] + '_history'\n", "\n", "hist_load = np.load(history_path + '.npy',allow_pickle=True).item()\n", "\n", "print(hist_load.keys())\n", "\n", "# summarize history for loss\n", "plt.plot(hist_load['loss'])\n", "plt.plot(hist_load['val_loss'])\n", "plt.title('model loss')\n", "plt.ylabel('loss')\n", "plt.xlabel('epoch')\n", "plt.legend(['train', 'test'], loc='upper left')\n", "plt.show()\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Evaluación del Modelo" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of images in the evaluation dataset: 1\n", "\n", "\n", "\n", " 0%| | 0/1 [00:00 0 for x in total_instances)))\n", "\n", " for i in range(1, len(average_precisions)):\n", " print(\"{:<14}{:<6}{}\".format(classes[i], 'AP', round(average_precisions[i], 3)))\n", " print()\n", " print(\"{:<14}{:<6}{}\".format('','mAP', round(mean_average_precision, 3)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cargar nuevamente el modelo desde los pesos.\n", "Predicción" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Training on: \t{'panel': 1}\n", "\n", "Tiempo Total: 1.293\n", "Tiempo promedio por imagen: 0.259\n", "OK\n" ] } ], "source": [ "from imageio import imread\n", "from keras.preprocessing import image\n", "import time\n", "\n", "config_path = 'config_7_panel.json'\n", "input_path = 'panel/Mision_2/'\n", "output_path = 'result_ssd7_panel_2/'\n", "\n", "with open(config_path) as config_buffer:\n", " config = json.loads(config_buffer.read())\n", "\n", "makedirs(output_path)\n", "###############################\n", "# Parse the annotations\n", "###############################\n", "score_threshold = 0.3\n", "labels = config['model']['labels']\n", "categories = {}\n", "#categories = {\"Razor\": 1, \"Gun\": 2, \"Knife\": 3, \"Shuriken\": 4} #la categoría 0 es la background\n", "for i in range(len(labels)): categories[labels[i]] = i+1\n", "print('\\nTraining on: \\t' + str(categories) + '\\n')\n", "\n", "img_height = config['model']['input'] # Height of the model input images\n", "img_width = config['model']['input'] # Width of the model input images\n", "img_channels = 3 # Number of color channels of the model input images\n", "n_classes = len(labels) # Number of positive classes, e.g. 20 for Pascal VOC, 80 for MS COCO\n", "classes = ['background'] + labels\n", "\n", "model_mode = 'training'\n", "# TODO: Set the path to the `.h5` file of the model to be loaded.\n", "model_path = config['train']['saved_weights_name']\n", "\n", "# We need to create an SSDLoss object in order to pass that to the model loader.\n", "ssd_loss = SSDLoss(neg_pos_ratio=3, alpha=1.0)\n", "\n", "K.clear_session() # Clear previous models from memory.\n", "\n", "model = load_model(model_path, custom_objects={'AnchorBoxes': AnchorBoxes,\n", " 'L2Normalization': L2Normalization,\n", " 'DecodeDetections': DecodeDetections,\n", " 'compute_loss': ssd_loss.compute_loss})\n", "\n", "\n", "\n", "\n", "image_paths = []\n", "\n", "if os.path.isdir(input_path):\n", " for inp_file in os.listdir(input_path):\n", " image_paths += [input_path + inp_file]\n", "else:\n", " image_paths += [input_path]\n", "\n", "image_paths = [inp_file for inp_file in image_paths if (inp_file[-4:] in ['.jpg', '.png', 'JPEG'])]\n", "times = []\n", "\n", "\n", "for img_path in image_paths:\n", " orig_images = [] # Store the images here.\n", " input_images = [] # Store resized versions of the images here.\n", " #print(img_path)\n", "\n", " # preprocess image for network\n", " orig_images.append(imread(img_path))\n", " img = image.load_img(img_path, target_size=(img_height, img_width))\n", " img = image.img_to_array(img)\n", " input_images.append(img)\n", " input_images = np.array(input_images)\n", " # process image\n", " start = time.time()\n", " y_pred = model.predict(input_images)\n", " y_pred_decoded = decode_detections(y_pred,\n", " confidence_thresh=score_threshold,\n", " iou_threshold=score_threshold,\n", " top_k=200,\n", " normalize_coords=True,\n", " img_height=img_height,\n", " img_width=img_width)\n", "\n", "\n", " #print(\"processing time: \", time.time() - start)\n", " times.append(time.time() - start)\n", " # correct for image scale\n", "\n", " # visualize detections\n", " # Set the colors for the bounding boxes\n", " colors = plt.cm.brg(np.linspace(0, 1, 21)).tolist()\n", "\n", " plt.figure(figsize=(20,12))\n", " plt.imshow(orig_images[0],cmap = 'gray')\n", "\n", " current_axis = plt.gca()\n", " #print(y_pred)\n", " for box in y_pred_decoded[0]:\n", " # Transform the predicted bounding boxes for the 300x300 image to the original image dimensions.\n", "\n", " xmin = box[2] * orig_images[0].shape[1] / img_width\n", " ymin = box[3] * orig_images[0].shape[0] / img_height\n", " xmax = box[4] * orig_images[0].shape[1] / img_width\n", " ymax = box[5] * orig_images[0].shape[0] / img_height\n", "\n", " color = colors[int(box[0])]\n", " label = '{}: {:.2f}'.format(classes[int(box[0])], box[1])\n", " current_axis.add_patch(plt.Rectangle((xmin, ymin), xmax-xmin, ymax-ymin, color=color, fill=False, linewidth=2))\n", " current_axis.text(xmin, ymin, label, size='x-large', color='white', bbox={'facecolor':color, 'alpha':1.0})\n", "\n", " #plt.figure(figsize=(15, 15))\n", " #plt.axis('off')\n", " save_path = output_path + img_path.split('/')[-1]\n", " plt.savefig(save_path)\n", " plt.close()\n", " \n", "file = open(output_path + 'time.txt','w')\n", "\n", "file.write('Tiempo promedio:' + str(np.mean(times)))\n", "\n", "file.close()\n", "print('Tiempo Total: {:.3f}'.format(np.sum(times)))\n", "print('Tiempo promedio por imagen: {:.3f}'.format(np.mean(times)))\n", "print('OK')" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Processing image set 'training_small.txt': 100%|██████████| 45/45 [00:01<00:00, 27.96it/s]\n", "trophozoite : 135\n", "red blood cell : 3195\n" ] } ], "source": [ "\n", "# Summary instance training\n", "category_train_list = []\n", "for image_label in train_dataset.labels:\n", " category_train_list += [i[0] for i in train_dataset.labels[0]]\n", "summary_category_training = {train_dataset.classes[i]: category_train_list.count(i) for i in list(set(category_train_list))}\n", "for i in summary_category_training.keys():\n", " print(i, ': {:.0f}'.format(summary_category_training[i]))\n" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "45" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.8" } }, "nbformat": 4, "nbformat_minor": 2 }