{ "cells": [ { "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": 1, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Using TensorFlow backend.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Training on: \t{'1': 1}\n", "\n", "WARNING:tensorflow:From /home/dl-desktop/anaconda3/envs/tf_gpu/lib/python3.6/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Colocations handled automatically by placer.\n", "OK create model\n", "\n", "Loading pretrained weights VGG.\n", "\n", "WARNING:tensorflow:From /home/dl-desktop/Desktop/Rentadrone/ssd_keras-master/keras_loss_function/keras_ssd_loss.py:133: to_float (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Use tf.cast instead.\n", "WARNING:tensorflow:From /home/dl-desktop/Desktop/Rentadrone/ssd_keras-master/keras_loss_function/keras_ssd_loss.py:166: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Use tf.cast instead.\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", "\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_fault_1.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.01, 0.05, 0.1, 0.2, 0.37, 0.54, 0.71] # 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(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": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Processing image set 'train.txt': 100%|██████████| 33/33 [00:00<00:00, 101.41it/s]\n", "Processing image set 'test.txt': 100%|██████████| 2/2 [00:00<00:00, 61.30it/s]\n", "1 : 444\n", "Number of images in the training dataset:\t 33\n", "Number of images in the validation dataset:\t 2\n", "WARNING:tensorflow:From /home/dl-desktop/anaconda3/envs/tf_gpu/lib/python3.6/site-packages/tensorflow/python/ops/math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Deprecated in favor of operator or tf.math.divide.\n", "Epoch 1/500\n", "\n", "Epoch 00001: LearningRateScheduler setting learning rate to 0.001.\n", "100/100 [==============================] - 25s 246ms/step - loss: 11.5508 - val_loss: 6.3620\n", "\n", "Epoch 00001: val_loss improved from inf to 6.36203, saving model to experimento_ssd7_fault_1.h5\n", "Epoch 2/500\n", "\n", "Epoch 00002: LearningRateScheduler setting learning rate to 0.001.\n", "100/100 [==============================] - 22s 225ms/step - loss: 7.4845 - val_loss: 12.4694\n", "\n", "Epoch 00002: val_loss did not improve from 6.36203\n", "Epoch 3/500\n", "\n", "Epoch 00003: LearningRateScheduler setting learning rate to 0.001.\n", "100/100 [==============================] - 24s 237ms/step - loss: 7.0083 - val_loss: 5.9608\n", "\n", "Epoch 00003: val_loss improved from 6.36203 to 5.96082, saving model to experimento_ssd7_fault_1.h5\n", "Epoch 4/500\n", "\n", "Epoch 00004: LearningRateScheduler setting learning rate to 0.001.\n", "100/100 [==============================] - 23s 232ms/step - loss: 6.3241 - val_loss: 7.0951\n", "\n", "Epoch 00004: val_loss did not improve from 5.96082\n", "Epoch 5/500\n", "\n", "Epoch 00005: LearningRateScheduler setting learning rate to 0.001.\n", "100/100 [==============================] - 24s 239ms/step - loss: 5.9832 - val_loss: 5.5583\n", "\n", "Epoch 00005: val_loss improved from 5.96082 to 5.55828, saving model to experimento_ssd7_fault_1.h5\n", "Epoch 6/500\n", "\n", "Epoch 00006: LearningRateScheduler setting learning rate to 0.001.\n", "100/100 [==============================] - 25s 248ms/step - loss: 6.0359 - val_loss: 10.5573\n", "\n", "Epoch 00006: val_loss did not improve from 5.55828\n", "Epoch 7/500\n", "\n", "Epoch 00007: LearningRateScheduler setting learning rate to 0.001.\n", "100/100 [==============================] - 23s 232ms/step - loss: 5.9338 - val_loss: 12.5439\n", "\n", "Epoch 00007: val_loss did not improve from 5.55828\n", "Epoch 8/500\n", "\n", "Epoch 00008: LearningRateScheduler setting learning rate to 0.001.\n", "100/100 [==============================] - 23s 228ms/step - loss: 6.3084 - val_loss: 8.1511\n", "\n", "Epoch 00008: val_loss did not improve from 5.55828\n", "Epoch 9/500\n", "\n", "Epoch 00009: LearningRateScheduler setting learning rate to 0.001.\n", "100/100 [==============================] - 22s 222ms/step - loss: 5.8168 - val_loss: 10.5703\n", "\n", "Epoch 00009: val_loss did not improve from 5.55828\n", "Epoch 10/500\n", "\n", "Epoch 00010: LearningRateScheduler setting learning rate to 0.001.\n", "100/100 [==============================] - 23s 235ms/step - loss: 5.4740 - val_loss: 5.8349\n", "\n", "Epoch 00010: val_loss did not improve from 5.55828\n", "Epoch 11/500\n", "\n", "Epoch 00011: LearningRateScheduler setting learning rate to 0.001.\n", "100/100 [==============================] - 23s 227ms/step - loss: 5.4750 - val_loss: 4.4782\n", "\n", "Epoch 00011: val_loss improved from 5.55828 to 4.47816, saving model to experimento_ssd7_fault_1.h5\n", "Epoch 12/500\n", "\n", "Epoch 00012: LearningRateScheduler setting learning rate to 0.001.\n", " 88/100 [=========================>....] - ETA: 2s - loss: 5.5271" ] } ], "source": [ "#ENTRENAMIENTO DE MODELO\n", "#####################################################################\n", "# Instantiate two `DataGenerator` objects: One for training, one for validation.\n", "######################################################################\n", "# Optional: If you have enough memory, consider loading the images into memory for the reasons explained above.\n", "\n", "train_dataset = DataGenerator(load_images_into_memory=False, hdf5_dataset_path=None)\n", "val_dataset = DataGenerator(load_images_into_memory=False, hdf5_dataset_path=None)\n", "\n", "# 2: Parse the image and label lists for the training and validation datasets. This can take a while.\n", "\n", "\n", "\n", "# The XML parser needs to now what object class names to look for and in which order to map them to integers.\n", "classes = ['background' ] + labels\n", "\n", "train_dataset.parse_xml(images_dirs= [config['train']['train_image_folder']],\n", " image_set_filenames=[config['train']['train_image_set_filename']],\n", " annotations_dirs=[config['train']['train_annot_folder']],\n", " classes=classes,\n", " include_classes='all',\n", " #classes = classes, \n", " #include_classes= [1],\n", " exclude_truncated=False,\n", " exclude_difficult=False,\n", " ret=False)\n", "\n", "val_dataset.parse_xml(images_dirs= [config['test']['test_image_folder']],\n", " image_set_filenames=[config['test']['test_image_set_filename']],\n", " annotations_dirs=[config['test']['test_annot_folder']],\n", " classes=classes,\n", " include_classes='all',\n", " #classes = classes, \n", " #include_classes=[1],\n", " exclude_truncated=False,\n", " exclude_difficult=False,\n", " ret=False)\n", "\n", "#########################\n", "# 3: Set the batch size.\n", "#########################\n", "batch_size = config['train']['batch_size'] # Change the batch size if you like, or if you run into GPU memory issues.\n", "\n", "##########################\n", "# 4: Set the image transformations for pre-processing and data augmentation options.\n", "##########################\n", "# For the training generator:\n", "\n", "\n", "# For the validation generator:\n", "convert_to_3_channels = ConvertTo3Channels()\n", "resize = Resize(height=img_height, width=img_width)\n", "\n", "######################################3\n", "# 5: Instantiate an encoder that can encode ground truth labels into the format needed by the SSD loss function.\n", "#########################################\n", "# The encoder constructor needs the spatial dimensions of the model's predictor layers to create the anchor boxes.\n", "if config['model']['backend'] == 'ssd300':\n", " predictor_sizes = [model.get_layer('conv4_3_norm_mbox_conf').output_shape[1:3],\n", " model.get_layer('fc7_mbox_conf').output_shape[1:3],\n", " model.get_layer('conv6_2_mbox_conf').output_shape[1:3],\n", " model.get_layer('conv7_2_mbox_conf').output_shape[1:3],\n", " model.get_layer('conv8_2_mbox_conf').output_shape[1:3],\n", " model.get_layer('conv9_2_mbox_conf').output_shape[1:3]]\n", " ssd_input_encoder = SSDInputEncoder(img_height=img_height,\n", " img_width=img_width,\n", " n_classes=n_classes,\n", " predictor_sizes=predictor_sizes,\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", " matching_type='multi',\n", " pos_iou_threshold=0.5,\n", " neg_iou_limit=0.5,\n", " normalize_coords=normalize_coords)\n", "\n", "elif config['model']['backend'] == 'ssd7':\n", " predictor_sizes = [model.get_layer('classes4').output_shape[1:3],\n", " model.get_layer('classes5').output_shape[1:3],\n", " model.get_layer('classes6').output_shape[1:3],\n", " model.get_layer('classes7').output_shape[1:3]]\n", " ssd_input_encoder = SSDInputEncoder(img_height=img_height,\n", " img_width=img_width,\n", " n_classes=n_classes,\n", " predictor_sizes=predictor_sizes,\n", " scales=scales,\n", " aspect_ratios_global=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", " matching_type='multi',\n", " pos_iou_threshold=0.5,\n", " neg_iou_limit=0.3,\n", " normalize_coords=normalize_coords)\n", "\n", "\n", "\n", " \n", "data_augmentation_chain = DataAugmentationVariableInputSize(resize_height = img_height,\n", " resize_width = img_width,\n", " random_brightness=(-48, 48, 0.5),\n", " random_contrast=(0.5, 1.8, 0.5),\n", " random_saturation=(0.5, 1.8, 0.5),\n", " random_hue=(18, 0.5),\n", " random_flip=0.5,\n", " n_trials_max=3,\n", " clip_boxes=True,\n", " overlap_criterion='area',\n", " bounds_box_filter=(0.3, 1.0),\n", " bounds_validator=(0.5, 1.0),\n", " n_boxes_min=1,\n", " background=(0,0,0))\n", "#######################\n", "# 6: Create the generator handles that will be passed to Keras' `fit_generator()` function.\n", "#######################\n", "\n", "train_generator = train_dataset.generate(batch_size=batch_size,\n", " shuffle=True,\n", " transformations= [data_augmentation_chain],\n", " label_encoder=ssd_input_encoder,\n", " returns={'processed_images',\n", " 'encoded_labels'},\n", " keep_images_without_gt=False)\n", "\n", "val_generator = val_dataset.generate(batch_size=batch_size,\n", " shuffle=False,\n", " transformations=[convert_to_3_channels,\n", " resize],\n", " label_encoder=ssd_input_encoder,\n", " returns={'processed_images',\n", " 'encoded_labels'},\n", " keep_images_without_gt=False)\n", "\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 image_label]\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", "\n", "\n", "\n", "# Get the number of samples in the training and validations datasets.\n", "train_dataset_size = train_dataset.get_dataset_size()\n", "val_dataset_size = val_dataset.get_dataset_size()\n", "\n", "print(\"Number of images in the training dataset:\\t{:>6}\".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 = 500 #config['train']['nb_epochs']\n", "steps_per_epoch = 100\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*10),\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": [ "classes" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Graficar aprendizaje\n", "\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.ylim((0, 10)) \n", "plt.show()\n", "\n", "print(config['train']['saved_weights_name'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Evaluación del Modelo" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "config_path = 'config_7_fault_1.json'\n", "\n", "with open(config_path) as config_buffer:\n", " config = json.loads(config_buffer.read())\n", "\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", "train_dataset = DataGenerator(load_images_into_memory=False, hdf5_dataset_path=None)\n", "val_dataset = DataGenerator(load_images_into_memory=False, hdf5_dataset_path=None)\n", "\n", "# 2: Parse the image and label lists for the training and validation datasets. This can take a while.\n", "\n", "\n", "\n", "# The XML parser needs to now what object class names to look for and in which order to map them to integers.\n", "classes = ['background' ] + labels\n", "\n", "train_dataset.parse_xml(images_dirs= [config['train']['train_image_folder']],\n", " image_set_filenames=[config['train']['train_image_set_filename']],\n", " annotations_dirs=[config['train']['train_annot_folder']],\n", " classes=classes,\n", " include_classes='all',\n", " #classes = ['background', 'panel', 'cell'], \n", " #include_classes=classes,\n", " exclude_truncated=False,\n", " exclude_difficult=False,\n", " ret=False)\n", "\n", "val_dataset.parse_xml(images_dirs= [config['test']['test_image_folder']],\n", " image_set_filenames=[config['test']['test_image_set_filename']],\n", " annotations_dirs=[config['test']['test_annot_folder']],\n", " classes=classes,\n", " include_classes='all',\n", " #classes = ['background', 'panel', 'cell'], \n", " #include_classes=classes,\n", " exclude_truncated=False,\n", " exclude_difficult=False,\n", " ret=False)\n", "\n", "#########################\n", "# 3: Set the batch size.\n", "#########################\n", "batch_size = config['train']['batch_size'] # Change the batch size if you like, or if you run into GPU memory issues.\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "evaluator = Evaluator(model=model,\n", " n_classes=n_classes,\n", " data_generator=val_dataset,\n", " model_mode='training')\n", "\n", "results = evaluator(img_height=img_height,\n", " img_width=img_width,\n", " batch_size=4,\n", " data_generator_mode='resize',\n", " round_confidences=False,\n", " matching_iou_threshold=0.5,\n", " border_pixels='include',\n", " sorting_algorithm='quicksort',\n", " average_precision_mode='sample',\n", " num_recall_points=11,\n", " ignore_neutral_boxes=True,\n", " return_precisions=True,\n", " return_recalls=True,\n", " return_average_precisions=True,\n", " verbose=True)\n", "\n", "mean_average_precision, average_precisions, precisions, recalls = results\n", "total_instances = []\n", "precisions = []\n", "\n", "for i in range(1, len(average_precisions)):\n", " \n", " print('{:.0f} instances of class'.format(len(recalls[i])),\n", " classes[i], 'with average precision: {:.4f}'.format(average_precisions[i]))\n", " total_instances.append(len(recalls[i]))\n", " precisions.append(average_precisions[i])\n", "\n", "if sum(total_instances) == 0:\n", " \n", " print('No test instances found.')\n", "\n", "else:\n", "\n", " print('mAP using the weighted average of precisions among classes: {:.4f}'.format(sum([a * b for a, b in zip(total_instances, precisions)]) / sum(total_instances)))\n", " print('mAP: {:.4f}'.format(sum(precisions) / sum(x > 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": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ceil(val_dataset_size/batch_size)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cargar nuevamente el modelo desde los pesos.\n", "Predicción" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from imageio import imread\n", "from keras.preprocessing import image\n", "import time\n", "\n", "config_path = 'config_7_fault_1.json'\n", "input_path = ['fault_jpg_1/']\n", "output_path = 'result_ssd7_fault_1/'\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.25\n", "score_threshold_iou = 0.5\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", "\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "image_paths = []\n", "for inp in input_path:\n", " if os.path.isdir(inp):\n", " for inp_file in os.listdir(inp):\n", " image_paths += [inp + inp_file]\n", " else:\n", " image_paths += [inp]\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_iou,\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": null, "metadata": {}, "outputs": [], "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": null, "metadata": {}, "outputs": [], "source": [ "for i in summary_category_training.keys():\n", " print(i, ': {:.0f}'.format(summary_category_training[i]))" ] }, { "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 }