{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# -*- coding: utf-8 -*-\n\n\nimport os\nimport csv\nimport random\nimport pydicom\nimport numpy as np\nimport pandas as pd\nfrom skimage import measure\nfrom skimage.transform import resize\n\nimport tensorflow as tf\nfrom tensorflow import keras\n\nfrom matplotlib import pyplot as plt\n\nimport keras.layers\nfrom keras.models import Sequential\nfrom keras.optimizers import SGD\nfrom keras.layers import Input, Dense, Convolution2D, MaxPooling2D, AveragePooling2D, ZeroPadding2D, Dropout, Flatten, merge, Reshape, Activation\nfrom keras.layers.normalization import BatchNormalization\nfrom keras.layers import Conv2D\nfrom keras.models import Model\nfrom keras import backend as K\nfrom sklearn.metrics import log_loss\n#from ResNet.custom_layers.scale_layer import Scale\nimport sys","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport cv2 as cv\nimport os\nfrom tqdm import tqdm\n\n\n# Define a function to show image through 48*48 pixels\ndef show(img):\n    show_image = img.reshape(48, 48)\n    print(show_image)\n    print(show_image.shape)\n    cv.imshow('image', show_image)\n    cv.waitKey(0)\n\n\ndef parse_images(data):\n    pixels_values = data.pixels.str.split(\" \").tolist()\n    pixels_values = pd.DataFrame(pixels_values, dtype=int)\n    images = pixels_values.values\n    images = images.astype(np.uint8)\n    return images\n\n\ndef save_data(dir_path, images, labels):\n    if not os.path.exists(dir_path):\n        os.makedirs(dir_path)\n\n    for i in tqdm(range(len(images))):\n        image = images[i].reshape(48, 48)\n        label = str(labels[i])\n        image_path = os.path.join(dir_path, label)\n        if not os.path.exists(image_path):\n            os.makedirs(image_path)\n        image_path = os.path.join(image_path, str(i) + '.png')\n        cv.imwrite(image_path, image)\n\n\ndef save_test_data(dir_path, images):\n    if not os.path.exists(dir_path):\n        os.makedirs(dir_path)\n\n    for i in tqdm(range(len(images))):\n        image = images[i].reshape(48, 48)\n        image_path = os.path.join(dir_path, str(i) + '.png')\n        cv.imwrite(image_path, image)\n\n\ndef read_data(file_path):\n    data = pd.read_csv(file_path)\n    print(data.shape)\n    print(data.head())\n    print(np.unique(data[\"Usage\"].values.ravel()))\n    train_data = data[data.Usage == \"Training\"]\n    valid_data = data[data.Usage == \"PublicTest\"]\n    test_data = data[data.Usage == \"PrivateTest\"]\n    train_images = parse_images(train_data)\n    valid_images = parse_images(valid_data)\n    test_images = parse_images(test_data)\n    train_labels = train_data[\"emotion\"].values.ravel()\n    valid_labels = valid_data[\"emotion\"].values.ravel()\n    test_labels = test_data[\"emotion\"].values.ravel()\n    labels_count = np.unique(train_labels).shape[0]\n    print(np.unique(train_labels))\n    print('The number of different facial expressions is %d' % labels_count)\n\n    # show one image\n    # show(train_images[8])\n\n    print('Start generating images...')\n    save_data('fer2013/train', train_images, train_labels)\n    print('The number of training data set is %d' % (len(train_data)))\n    save_data('fer2013/valid', valid_images, valid_labels)\n    print('The number of validation data set is %d' % (len(valid_data)))\n    save_data('fer2013/test', test_images, test_labels)\n    print('The number of test data set is %d' % (len(test_data)))\n    print('Completed.')\n\n\n\nif __name__ == '__main__':\n    image_pixels = 2304\n    image_width = 48\n    image_height = 48\n\n    class_names = {0: 'Angry', 1: 'Disgust', 2: 'Fear', 3: 'Happy', 4: 'Sad', 5: 'Surprise', 6: 'Neutral'}\n    # emotion = {0:'愤怒', 1:'厌恶', 2:'恐惧', 3:'高兴', 4:'悲伤', 5:'惊讶', 6: '无表情'}\n\n    read_data('../input/fergit/FERGIT.csv')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"###################################### Scale Layer whicch is a seprate file in original model, merged here############\nfrom keras.layers.core import Layer\nfrom keras.engine import InputSpec\nfrom keras import backend as K\n#from keras import initializations\nfrom keras import initializers as initializations\nimport tensorflow as tf\ntry:\n    from keras import initializations\nexcept ImportError:\n    from keras import initializers as initializations\n    \n    \n\nclass Scale(Layer):\n    '''Learns a set of weights and biases used for scaling the input data.\n    the output consists simply in an element-wise multiplication of the input\n    and a sum of a set of constants:\n\n        out = in * gamma + beta,\n\n    where 'gamma' and 'beta' are the weights and biases larned.\n\n    # Arguments\n        axis: integer, axis along which to normalize in mode 0. For instance,\n            if your input tensor has shape (samples, channels, rows, cols),\n            set axis to 1 to normalize per feature map (channels axis).\n        momentum: momentum in the computation of the\n            exponential average of the mean and standard deviation\n            of the data, for feature-wise normalization.\n        weights: Initialization weights.\n            List of 2 Numpy arrays, with shapes:\n            `[(input_shape,), (input_shape,)]`\n        beta_init: name of initialization function for shift parameter\n            (see [initializations](../initializations.md)), or alternatively,\n            Theano/TensorFlow function to use for weights initialization.\n            This parameter is only relevant if you don't pass a `weights` argument.\n        gamma_init: name of initialization function for scale parameter (see\n            [initializations](../initializations.md)), or alternatively,\n            Theano/TensorFlow function to use for weights initialization.\n            This parameter is only relevant if you don't pass a `weights` argument.\n    '''\n    \n    ###\n    #with tf.Session() as sess:\n        #sess.run(tf.global_variables_initializer())\n    ###\n    def __init__(self, weights=None, axis=-1, momentum = 0.9, beta_init='zero', gamma_init='one', **kwargs):\n        self.momentum = momentum\n        self.axis = axis\n        self.beta_init = initializations.get(beta_init)\n        self.gamma_init = initializations.get(gamma_init)\n        self.initial_weights = weights\n        super(Scale, self).__init__(**kwargs)\n\n    def build(self, input_shape):\n\n        \n        self.input_spec = [InputSpec(shape=input_shape)]\n        shape = (int(input_shape[self.axis]),)\n\n        # Compatibility with TensorFlow >= 1.0.0\n        self.gamma = K.variable(self.gamma_init(shape), name='{}_gamma'.format(self.name))\n        self.beta = K.variable(self.beta_init(shape), name='{}_beta'.format(self.name))\n        #self.gamma = self.gamma_init(shape, name='{}_gamma'.format(self.name))\n        #self.beta = self.beta_init(shape, name='{}_beta'.format(self.name))\n        self.trainable_weights = [self.gamma, self.beta]\n\n        if self.initial_weights is not None:\n            self.set_weights(self.initial_weights)\n            del self.initial_weights\n\n    def call(self, x, mask=None):\n        input_shape = self.input_spec[0].shape\n        broadcast_shape = [1] * len(input_shape)\n        broadcast_shape[self.axis] = input_shape[self.axis]\n\n        out = K.reshape(self.gamma, broadcast_shape) * x + K.reshape(self.beta, broadcast_shape)\n        return out\n\n    def get_config(self):\n        config = {\"momentum\": self.momentum, \"axis\": self.axis}\n        base_config = super(Scale, self).get_config()\n        return dict(list(base_config.items()) + list(config.items()))\n","metadata":{"_uuid":"81bbb95175348c08f9d6a2cabade70dafb9ac222","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#############ResNet Model definition########################\n\nsys.setrecursionlimit(3000)\n\ndef identity_block(input_tensor, kernel_size, filters, stage, block):\n    '''The identity_block is the block that has no conv layer at shortcut\n    # Arguments\n        input_tensor: input tensor\n        kernel_size: defualt 3, the kernel size of middle conv layer at main path\n        filters: list of integers, the nb_filters of 3 conv layer at main path\n        stage: integer, current stage label, used for generating layer names\n        block: 'a','b'..., current block label, used for generating layer names\n    '''\n    eps = 1.1e-5\n    nb_filter1, nb_filter2, nb_filter3 = filters\n    conv_name_base = 'res' + str(stage) + block + '_branch'\n    bn_name_base = 'bn' + str(stage) + block + '_branch'\n    scale_name_base = 'scale' + str(stage) + block + '_branch'\n\n    x = Conv2D(nb_filter1, 1, 1, name=conv_name_base + '2a', bias=False)(input_tensor)\n    x = BatchNormalization(epsilon=eps, axis=bn_axis, name=bn_name_base + '2a')(x)\n    x = Scale(axis=bn_axis, name=scale_name_base + '2a')(x)\n    x = Activation('relu', name=conv_name_base + '2a_relu')(x)\n\n    x = ZeroPadding2D((1, 1), name=conv_name_base + '2b_zeropadding')(x)\n    x = Conv2D(nb_filter2, kernel_size, kernel_size,\n                      name=conv_name_base + '2b', bias=False)(x)\n    x = BatchNormalization(epsilon=eps, axis=bn_axis, name=bn_name_base + '2b')(x)\n    x = Scale(axis=bn_axis, name=scale_name_base + '2b')(x)\n    x = Activation('relu', name=conv_name_base + '2b_relu')(x)\n\n    x = Conv2D(nb_filter3, 1, 1, name=conv_name_base + '2c', bias=False)(x)\n    x = BatchNormalization(epsilon=eps, axis=bn_axis, name=bn_name_base + '2c')(x)\n    x = Scale(axis=bn_axis, name=scale_name_base + '2c')(x)\n\n    #x = merge([x, input_tensor], mode='sum', name='res' + str(stage) + block)\n    x= keras.layers.Add()([x, input_tensor])\n    x = Activation('relu', name='res' + str(stage) + block + '_relu')(x)\n    return x\n\ndef conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2, 2)):\n    '''conv_block is the block that has a conv layer at shortcut\n    # Arguments\n        input_tensor: input tensor\n        kernel_size: defualt 3, the kernel size of middle conv layer at main path\n        filters: list of integers, the nb_filters of 3 conv layer at main path\n        stage: integer, current stage label, used for generating layer names\n        block: 'a','b'..., current block label, used for generating layer names\n    Note that from stage 3, the first conv layer at main path is with subsample=(2,2)\n    And the shortcut should have subsample=(2,2) as well\n    '''\n    eps = 1.1e-5\n    nb_filter1, nb_filter2, nb_filter3 = filters\n    conv_name_base = 'res' + str(stage) + block + '_branch'\n    bn_name_base = 'bn' + str(stage) + block + '_branch'\n    scale_name_base = 'scale' + str(stage) + block + '_branch'\n\n    x = Conv2D(nb_filter1, 1, 1, subsample=strides,\n                      name=conv_name_base + '2a', bias=False)(input_tensor)\n    x = BatchNormalization(epsilon=eps, axis=bn_axis, name=bn_name_base + '2a')(x)\n    x = Scale(axis=bn_axis, name=scale_name_base + '2a')(x)\n    x = Activation('relu', name=conv_name_base + '2a_relu')(x)\n\n    x = ZeroPadding2D((1, 1), name=conv_name_base + '2b_zeropadding')(x)\n    x = Conv2D(nb_filter2, kernel_size, kernel_size,\n                      name=conv_name_base + '2b', bias=False)(x)\n    x = BatchNormalization(epsilon=eps, axis=bn_axis, name=bn_name_base + '2b')(x)\n    x = Scale(axis=bn_axis, name=scale_name_base + '2b')(x)\n    x = Activation('relu', name=conv_name_base + '2b_relu')(x)\n\n    x = Conv2D(nb_filter3, 1, 1, name=conv_name_base + '2c', bias=False)(x)\n    x = BatchNormalization(epsilon=eps, axis=bn_axis, name=bn_name_base + '2c')(x)\n    x = Scale(axis=bn_axis, name=scale_name_base + '2c')(x)\n\n    shortcut = Conv2D(nb_filter3, 1, 1, subsample=strides,\n                             name=conv_name_base + '1', bias=False)(input_tensor)\n    shortcut = BatchNormalization(epsilon=eps, axis=bn_axis, name=bn_name_base + '1')(shortcut)\n    shortcut = Scale(axis=bn_axis, name=scale_name_base + '1')(shortcut)\n\n    #x = merge([x, shortcut], mode='sum', name='res' + str(stage) + block)\n    x= keras.layers.Add()([x, shortcut])\n    x = Activation('relu', name='res' + str(stage) + block + '_relu')(x)\n    return x\n\ndef resnet152_model(img_rows, img_cols, color_type=1, num_classes=None):\n    \"\"\"\n    Resnet 152 Model for Keras\n\n    Model Schema and layer naming follow that of the original Caffe implementation\n    https://github.com/KaimingHe/deep-residual-networks\n\n    ImageNet Pretrained Weights \n    Theano: https://drive.google.com/file/d/0Byy2AcGyEVxfZHhUT3lWVWxRN28/view?usp=sharing\n    TensorFlow: https://drive.google.com/file/d/0Byy2AcGyEVxfeXExMzNNOHpEODg/view?usp=sharing\n\n    Parameters:\n      img_rows, img_cols - resolution of inputs\n      channel - 1 for grayscale, 3 for color \n      num_classes - number of class labels for our classification task\n    \"\"\"\n    eps = 1.1e-5\n\n    # Handle Dimension Ordering for different backends\n    global bn_axis\n    if K.image_dim_ordering() == 'tf':\n        bn_axis = 3\n        img_input = Input(shape=(img_rows, img_cols, color_type), name='data')\n    else:\n        bn_axis = 1\n        img_input = Input(shape=(color_type, img_rows, img_cols), name='data')\n\n    x = ZeroPadding2D((3, 3), name='conv1_zeropadding')(img_input)\n    x = Conv2D(64, 7, 7, subsample=(2, 2), name='conv1', bias=False)(x)\n    x = BatchNormalization(epsilon=eps, axis=bn_axis, name='bn_conv1')(x)\n    x = Scale(axis=bn_axis, name='scale_conv1')(x)\n    x = Activation('relu', name='conv1_relu')(x)\n    x = MaxPooling2D((3, 3), strides=(2, 2), name='pool1')(x)\n\n    x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1))\n    x = identity_block(x, 3, [64, 64, 256], stage=2, block='b')\n    x = identity_block(x, 3, [64, 64, 256], stage=2, block='c')\n\n    x = conv_block(x, 3, [128, 128, 512], stage=3, block='a')\n    for i in range(1,8):\n      x = identity_block(x, 3, [128, 128, 512], stage=3, block='b'+str(i))\n\n    x = conv_block(x, 3, [256, 256, 1024], stage=4, block='a')\n    for i in range(1,36):\n      x = identity_block(x, 3, [256, 256, 1024], stage=4, block='b'+str(i))\n\n    x = conv_block(x, 3, [512, 512, 2048], stage=5, block='a')\n    x = identity_block(x, 3, [512, 512, 2048], stage=5, block='b')\n    x = identity_block(x, 3, [512, 512, 2048], stage=5, block='c')\n\n    x_fc = AveragePooling2D((7, 7), name='avg_pool')(x)\n    x_fc = Flatten()(x_fc)\n    x_fc = Dense(1000, activation='softmax', name='fc1000')(x_fc)\n\n    model = Model(img_input, x_fc)\n\n    if K.image_dim_ordering() == 'th':\n      # Use pre-trained weights for Theano backend\n        weights_path ='../input/resnet152-pretrained-weights-tensorflow/resnet152_weights_th.h5'\n    else:\n      # Use pre-trained weights for Tensorflow backend\n        print(\"Loading weights for Tensorflow\")\n        weights_path ='../input/resnet152-pretrained-weights-tensorflow/resnet152_weights_tf.h5'\n\n    model.load_weights(weights_path, by_name=True)\n\n    # Truncate and replace softmax layer for transfer learning\n    # Cannot use model.layers.pop() since model is not of Sequential() type\n    # The method below works since pre-trained weights are stored in layers but not in the model\n    x_newfc = AveragePooling2D((7, 7), name='avg_pool')(x)\n    \n    \n    # output\n    depth=8\n    x_newfc = keras.layers.BatchNormalization(momentum=0.9)(x_newfc)\n    x_newfc = keras.layers.LeakyReLU(0)(x_newfc)\n    x_newfc = keras.layers.Conv2D(1, 1, activation='sigmoid')(x_newfc)\n    x_newfc = keras.layers.UpSampling2D(2**depth)(x_newfc)\n    \n    \n    x_newfc = Flatten()(x_newfc)\n    x_newfc = Dense(num_classes, activation='softmax', name='fc8')(x_newfc)\n\n    model = Model(img_input, x_newfc)\n\n    # Learning rate is changed to 0.001\n    sgd = SGD(lr=1e-3, decay=1e-6, momentum=0.9, nesterov=True)\n    model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])\n\n    return model\n\ndef resnet101_model(img_rows, img_cols, color_type=1, num_classes=None):\n    \"\"\"\n    Resnet 101 Model for Keras\n    Model Schema and layer naming follow that of the original Caffe implementation\n    https://github.com/KaimingHe/deep-residual-networks\n    ImageNet Pretrained Weights\n    Theano: https://drive.google.com/file/d/0Byy2AcGyEVxfdUV1MHJhelpnSG8/view?usp=sharing\n    TensorFlow: https://drive.google.com/file/d/0Byy2AcGyEVxfTmRRVmpGWDczaXM/view?usp=sharing\n    Parameters:\n      img_rows, img_cols - resolution of inputs\n      channel - 1 for grayscale, 3 for color\n      num_classes - number of class labels for our classification task\n    \"\"\"\n    eps = 1.1e-5\n\n    # Handle Dimension Ordering for different backends\n    global bn_axis\n    if K.common.image_dim_ordering() == 'tf':\n        bn_axis = 3\n        img_input = Input(shape=(img_rows, img_cols, color_type), name='data')\n    else:\n        bn_axis = 1\n        img_input = Input(shape=(color_type, img_rows, img_cols), name='data')\n\n    x = ZeroPadding2D((3, 3), name='conv1_zeropadding')(img_input)\n    x = Conv2D(64, (7, 7), strides=(2, 2), name='conv1', use_bias=False)(x)\n    x = BatchNormalization(epsilon=eps, axis=bn_axis, name='bn_conv1')(x)\n    x = Scale(axis=bn_axis, name='scale_conv1')(x)\n    x = Activation('relu', name='conv1_relu')(x)\n    x = MaxPooling2D((3, 3), strides=(2, 2), name='pool1')(x)\n\n    x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1))\n    x = identity_block(x, 3, [64, 64, 256], stage=2, block='b')\n    x = identity_block(x, 3, [64, 64, 256], stage=2, block='c')\n\n    x = conv_block(x, 3, [128, 128, 512], stage=3, block='a')\n    for i in range(1, 4):\n        x = identity_block(x, 3, [128, 128, 512], stage=3, block='b' + str(i))\n\n    x = conv_block(x, 3, [256, 256, 1024], stage=4, block='a')\n    for i in range(1, 23):\n        x = identity_block(x, 3, [256, 256, 1024], stage=4, block='b' + str(i))\n\n    x = conv_block(x, 3, [512, 512, 2048], stage=5, block='a')\n    x = identity_block(x, 3, [512, 512, 2048], stage=5, block='b')\n    x = identity_block(x, 3, [512, 512, 2048], stage=5, block='c')\n\n    x_fc = AveragePooling2D((7, 7), name='avg_pool')(x)\n    x_fc = Flatten()(x_fc)\n    x_fc = Dense(1000, activation='softmax', name='fc1000')(x_fc)\n\n    model = Model(img_input, x_fc)\n\n    if K.common.image_dim_ordering() == 'th':\n        # Use pre-trained weights for Theano backend\n        weights_path = '../input/resnet101-weights-tf/resnet101_weights_th.h5'\n    else:\n        # Use pre-trained weights for Tensorflow backend\n        weights_path = '../input/resnet101-weights-tf/resnet101_weights_tf.h5'\n\n    model.load_weights(weights_path, by_name=True)\n\n    # Truncate and replace softmax layer for transfer learning\n    # Cannot use model.layers.pop() since model is not of Sequential() type\n    # The method below works since pre-trained weights are stored in layers but not in the model\n    x_newfc = AveragePooling2D((7, 7), name='avg_pool')(x)\n    x_newfc = Flatten()(x_newfc)\n    x_newfc = Dense(num_classes, activation='softmax', name='fc8')(x_newfc)\n\n    model = Model(img_input, x_newfc)\n\n    # Learning rate is changed to 0.001\n    sgd = SGD(lr=1e-3, decay=1e-6, momentum=0.9, nesterov=True)\n    model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])\n\n    return model\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import keras\nimport tensorflow as tf\n# import keras.backend.tensorflow_backend as tfback\nfrom keras.backend.tensorflow_backend import set_session\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import CSVLogger, ModelCheckpoint, EarlyStopping\nfrom keras.callbacks import ReduceLROnPlateau\n\n# parameters\nimg_width, img_height = 224, 224\nnum_channels = 3\nnum_classes = 7\ntrain_data = 'fer2013/train'\nvalid_data = 'fer2013/valid'\ntest_data = 'fer2013/test'\nnum_train_samples = 28709\nnum_valid_samples = 3589\nverbose = 1\nbatch_size = 32\nnum_epochs = 10000\npatience = 50\n\nif __name__ == '__main__':\n    # build a classifier model\n    model = resnet101_model(img_height, img_width, num_channels, num_classes)\n    \n\n    # prepare data augmentation configuration\n    train_data_gen = ImageDataGenerator(featurewise_center=False,\n                                        featurewise_std_normalization=False,\n                                        rotation_range=10,\n                                        width_shift_range=0.1,\n                                        height_shift_range=0.1,\n                                        zoom_range=0.1,\n                                        horizontal_flip=True)\n    valid_data_gen = ImageDataGenerator()\n    test_data_gen = ImageDataGenerator()\n    # callbacks\n    tensor_board = keras.callbacks.TensorBoard(log_dir='./logs', histogram_freq=0, write_graph=True, write_images=True)\n    log_file_path = './logs/training.log'\n    csv_logger = CSVLogger(log_file_path, append=False)\n    early_stop = EarlyStopping('val_accuracy', patience=patience)\n    reduce_lr = ReduceLROnPlateau('val_accuracy', factor=0.1, patience=int(patience / 4), verbose=1)\n    trained_models_path = 'models/model'\n    model_names = trained_models_path + '_rensenet101.hdf5'\n    model_checkpoint = ModelCheckpoint(model_names, monitor='val_accuracy', verbose=1, save_best_only=True)\n    callbacks = [tensor_board, model_checkpoint, csv_logger, early_stop, reduce_lr]\n\n    # generators\n    train_generator = train_data_gen.flow_from_directory(train_data, (img_width, img_height), batch_size=batch_size,\n                                                         class_mode='categorical')\n    valid_generator = valid_data_gen.flow_from_directory(valid_data, (img_width, img_height), batch_size=batch_size,\n                                                         class_mode='categorical')\n    test_generator = test_data_gen.flow_from_directory(test_data, (img_width, img_height), batch_size=batch_size,\n                                                         class_mode='categorical')\n\n    # fine tune the model\n    model.fit_generator(\n        train_generator,\n        steps_per_epoch=num_train_samples / batch_size,\n        validation_data=valid_generator,\n        validation_steps=num_valid_samples / batch_size,\n        epochs=num_epochs,\n        callbacks=callbacks,\n        verbose=verbose)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_loss, test_acc = model.evaluate_generator(test_generator,verbose=1)\nprint(test_loss, test_acc)\nvalid_loss, valid_acc = model.evaluate_generator(valid_generator,verbose=1)\nprint(valid_loss,valid_acc)","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}