{"cells":[
 {
  "cell_type": "code",
  "execution_count": null,
  "metadata": {
   "collapsed": false
  },
  "outputs": [],
  "source": "import os\nimport h5py\nimport numpy as np\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.models import Sequential\nfrom keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D\nfrom keras.layers import Activation, Dropout, Flatten, Dense\nfrom keras.callbacks import ModelCheckpoint\nfrom keras.optimizers import SGD\nimport random\nimport sys\nimport cv2\nimport json\nimport PIL, PIL.Image\nimport imageio\nimport numpy as np\n\nconfiguration_path = sys.argv[1]\nwith open(configuration_path) as f:\n    configuration = json.load(f)\n    \n# path to the model weights file.\nweights_path = configuration['weightsPath']\ntop_model_weights_path = configuration['topModelWeightsPath']\n#weights_path = '../keras/examples/vgg16_weights.h5'\n#top_model_weights_path = 'bottleneck_fc_model.h5'\n# dimensions of our images.\nimg_width, img_height = 224, 224\n\ntrain_data_dir = configuration['trainFolder']\nvalidation_data_dir = configuration['validationFolder']\nnb_train_samples = configuration[\"nb_train_samples\"]\nnb_validation_samples = configuration[\"nb_validation_samples\"]\nnb_epoch = configuration['nb_epoch']\ntrain_data_shape = (1, 512, 7, 7)\n        \ndef generate_arrays_from_bottleneck_folder(path):\n    '''\n    Generator that reads the precomputed weights from the files\n    and gives it to the trainer.\n    \n    It shuffles the entries on every epoch.\n    '''\n    labels = [d for d in os.listdir(path) if os.path.isdir(os.path.join(path, d))]\n    labels.sort()\n    \n    labels_map = {}\n    for i in range(len(labels)):\n        label = labels[i]\n        labels_map[label] = i\n    \n    all_images = []\n    \n    for i in range(len(labels)):\n        label = labels[i]\n        images = [str(a) for a in os.listdir(os.path.join(path, label)) if os.path.isfile(os.path.join(path, label, a))]\n        images.sort()\n        for image in images:\n            all_images.append((label, image))\n    \n    while 1:\n        \n        random.shuffle(all_images)\n        for i in range(len(all_images)):\n            entry = all_images[i]\n            label = entry[0]\n            image = entry[1]\n            \n            x = np.load(open(os.path.join(path, label, image)))\n            y = np.zeros((1, len(labels)))\n            y[0, labels_map[label]] = 1\n\n            yield (x, y)\n                    \ndef write_bottlenecks_to_file(bottlenecks_folder, model, images_path):\n    '''\n    Precomputes the values of the weights for all images\n    and saves them in a folder in order to save time.\n    '''\n    \n    #To use with RGB images\n    #mean_pixel = [123.68, 116.779, 103.939]\n    \n    #To use with BGR images\n    mean_pixel = [103.939, 116.779, 123.68]\n        \n    labels = [d for d in os.listdir(images_path) if os.path.isdir(os.path.join(images_path, d))]\n    labels.sort()\n    line_count = 0\n    \n    for i in range(len(labels)):\n        label = labels[i]\n        if not os.path.exists(os.path.join(bottlenecks_folder, label)):\n            os.makedirs(os.path.join(bottlenecks_folder, label))\n            \n        images = [str(a) for a in os.listdir(os.path.join(images_path, label)) if os.path.isfile(os.path.join(images_path, label, a))]\n        images.sort()\n        for image in images:\n            print(label + \": \" + image)\n            image_path = os.path.join(images_path, label, image)\n                \n            im = imageio.imread(image_path)\n            pil_img = PIL.Image.fromarray(im)\n            resized = pil_img.resize((224, 224))\n            im = np.asarray(resized).astype(np.float32)\n            \n            #Needed here to transform RGB into BGR\n            np.roll(im, 1, axis = -1)\n            for c in range(3):\n                im[:, :, c] = im[:, :, c] - mean_pixel[c]\n            im = im.astype(np.float32, copy=False)\n            im = im.transpose((2, 0, 1))\n            im = np.expand_dims(im, axis = 0)\n                \n            prediction = model.predict(im)\n            if line_count == 0:\n                global train_data_shape\n                train_data_shape = prediction.shape\n            \n            np.save(open(os.path.join(bottlenecks_folder, label, image + \".npy\"), 'w+'), prediction)\n            line_count += 1\n            \ndef save_bottlebeck_features():\n\n    # build the VGG16 network\n    model = Sequential()\n    model.add(ZeroPadding2D((1, 1), input_shape=(3, img_width, img_height)))\n\n    model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_1'))\n    model.add(ZeroPadding2D((1, 1)))\n    model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_2'))\n    model.add(MaxPooling2D((2, 2), strides=(2, 2)))\n\n    model.add(ZeroPadding2D((1, 1)))\n    model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_1'))\n    model.add(ZeroPadding2D((1, 1)))\n    model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_2'))\n    model.add(MaxPooling2D((2, 2), strides=(2, 2)))\n\n    model.add(ZeroPadding2D((1, 1)))\n    model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_1'))\n    model.add(ZeroPadding2D((1, 1)))\n    model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_2'))\n    model.add(ZeroPadding2D((1, 1)))\n    model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_3'))\n    model.add(MaxPooling2D((2, 2), strides=(2, 2)))\n\n    model.add(ZeroPadding2D((1, 1)))\n    model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_1'))\n    model.add(ZeroPadding2D((1, 1)))\n    model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_2'))\n    model.add(ZeroPadding2D((1, 1)))\n    model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_3'))\n    model.add(MaxPooling2D((2, 2), strides=(2, 2)))\n\n    model.add(ZeroPadding2D((1, 1)))\n    model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_1'))\n    model.add(ZeroPadding2D((1, 1)))\n    model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_2'))\n    model.add(ZeroPadding2D((1, 1)))\n    model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_3'))\n    model.add(MaxPooling2D((2, 2), strides=(2, 2)))\n\n    # load the weights of the VGG16 networks\n    # (trained on ImageNet, won the ILSVRC competition in 2014)\n    # note: when there is a complete match between your model definition\n    # and your weight savefile, you can simply call model.load_weights(filename)\n    assert os.path.exists(weights_path), 'Model weights not found (see \"weights_path\" variable in script).'\n    \n    f = h5py.File(weights_path)\n    for k in range(f.attrs['nb_layers']):\n        if k >= len(model.layers):\n            # we don't look at the last (fully-connected) layers in the savefile\n            break\n        g = f['layer_{}'.format(k)]\n        weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]\n        model.layers[k].set_weights(weights)\n    f.close()\n    print('Model loaded.')\n    \n    bottlenecksFolder = configuration['bottlenecksFolder']\n    if not os.path.exists(bottlenecksFolder):\n        os.makedirs(bottlenecksFolder)\n    \n    if not os.path.exists(os.path.join(bottlenecksFolder, 'train')):\n        os.makedirs(os.path.join(bottlenecksFolder, 'train'))\n    if not os.path.exists(os.path.join(bottlenecksFolder, 'validation')):\n        os.makedirs(os.path.join(bottlenecksFolder, 'validation'))\n    \n    write_bottlenecks_to_file(os.path.join(bottlenecksFolder, 'train'), \n                              model, \n                              train_data_dir)\n    \n    write_bottlenecks_to_file(os.path.join(bottlenecksFolder, 'validation'), \n                              model, \n                              validation_data_dir)\n\ndef train_top_model():\n    '''\n    Trains the last layers of the vgg-16 model\n    '''\n    bottlenecksFolder = configuration['bottlenecksFolder']\n    train_path = os.path.join(bottlenecksFolder, \"train\")\n    validation_path = os.path.join(bottlenecksFolder, \"validation\")\n    \n    #1. Last layers of the model.\n    model = Sequential()\n    model.add(Flatten(input_shape=train_data_shape[1:]))\n    model.add(Dense(4096, activation='relu'))\n    model.add(Dropout(0.5))\n    model.add(Dense(4096, activation='relu'))\n    model.add(Dropout(0.5))\n    model.add(Dense(10, activation='softmax'))\n\n    sgd = SGD(lr=0.001, decay=1e-6, momentum=0.9, nesterov=True)\n    model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])\n    \n    #2. Training.\n    print(\"Fitting model\")\n    checkpointsFolder = configuration['checkpointsFolder']\n    checkpointer = ModelCheckpoint(filepath=checkpointsFolder + \"weights.{epoch:02d}-{val_loss:.2f}.hdf5\", verbose=1, save_best_only=False)\n    model.fit_generator(generator = generate_arrays_from_bottleneck_folder(train_path), \n                        samples_per_epoch = nb_train_samples, \n                        nb_epoch = nb_epoch, \n                        validation_data = generate_arrays_from_bottleneck_folder(validation_path),\n                        nb_val_samples = nb_validation_samples,\n                        max_q_size = 10,\n                        callbacks = [checkpointer])\n    \n    model.save_weights(top_model_weights_path, overwrite = True)\n\n#save_bottlebeck_features()\ntrain_top_model()"
 }
],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"}}, "nbformat": 4, "nbformat_minor": 0}