├── Dataset └── README ├── Results ├── BCNN_85 │ ├── Loss.png │ └── Accuracy.png └── CNN_75 │ ├── Loss.png │ └── Accuracy.png ├── DataPreprocess ├── datasplits.mat ├── Images │ └── README ├── README ├── DataPreprocess.m └── CreateTFRecords.py ├── LICENSE ├── README.md ├── OxFlowers_CNN_75.py └── OxFlowers_BCNN_85.py /Dataset/README: -------------------------------------------------------------------------------- 1 | The directory to save the train, validation, test dataset & augmented train set. -------------------------------------------------------------------------------- /Results/BCNN_85/Loss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CraneHzm/OxFlowers_BCNN/HEAD/Results/BCNN_85/Loss.png -------------------------------------------------------------------------------- /Results/CNN_75/Loss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CraneHzm/OxFlowers_BCNN/HEAD/Results/CNN_75/Loss.png -------------------------------------------------------------------------------- /Results/CNN_75/Accuracy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CraneHzm/OxFlowers_BCNN/HEAD/Results/CNN_75/Accuracy.png -------------------------------------------------------------------------------- /DataPreprocess/datasplits.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CraneHzm/OxFlowers_BCNN/HEAD/DataPreprocess/datasplits.mat -------------------------------------------------------------------------------- /Results/BCNN_85/Accuracy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CraneHzm/OxFlowers_BCNN/HEAD/Results/BCNN_85/Accuracy.png -------------------------------------------------------------------------------- /DataPreprocess/Images/README: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018/4/5 Hu Zhiming JimmyHu@pku.edu.cn All Rights Reserved. 2 | # The original images. 3 | 4 | Please download the original images from http://www.robots.ox.ac.uk/~vgg/data/flowers/17/ and store them in this directory. 5 | 6 | -------------------------------------------------------------------------------- /DataPreprocess/README: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018/4/12 Hu Zhiming JimmyHu@pku.edu.cn All Rights Reserved. 2 | # The steps to preprocess the original images. 3 | 4 | 5 | # directories & files: 6 | 'Images' directory: stores the original images that are downloaded from http://www.robots.ox.ac.uk/~vgg/data/flowers/17/. 7 | 'DataPreprocess.m': Split the original images into train, validation & test images and augment the train data. 8 | 'CreateTFRecords.py': Use the splitted images and augmented train data to create train_aug.tfrecords, validation.tfrecords & test.tfrecords files. 9 | 10 | 11 | # Usage: 12 | Step1: Download the original images from http://www.robots.ox.ac.uk/~vgg/data/flowers/17/ and store them in 'Images/' directory. 13 | Step2: Run 'DataPreprocess.m' file to split the images and augment the train images. 14 | Step3: Run 'CreateTFRecords.py' file to create the TFRecord files. 15 | Step4: You will get train_aug.tfrecords, validation.tfrecords & test.tfrecords files in '../Dataset/' directory after Step3. 16 | 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jimmy Hu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018/4/5 Zhiming Hu jimmyhu (at) pku.edu.cn All Rights Reserved. 2 | The tensorflow CNN & Bilinear CNN codes for Oxford Flowers 17 Dataset. 3 | 4 | Directories & Files: 5 | 6 | 'DataPreprocess' directory: stores the codes to preprocess the original images. 7 | 'Dataset' directory: stores the TFRecord files created in the DataPreprocess directory. 8 | 'Models' directory: stores our trained models. 9 | 'Results' directory: stores the learning curves of our model. 10 | 'OxFlowers_CNN_75.py': the main function of CNN model. 11 | 'OxFlowers_BCNN_85.py': the main function of Bilinear CNN model. 12 | 13 | Environments: 14 | Python 3.6+ 15 | 16 | tensorflow 1.4.1+ 17 | 18 | Usage: 19 | 20 | Step 1: Check the 'Dataset/' directory to confirm whether the TFRecord files exist. 21 | If not, run the code in 'DataPreprocess/' to create the TFRecord files. 22 | 23 | Step 2: Run 'OxFlowers_CNN_75.py' & 'OxFlowers_BCNN_85.py' to test the model. 24 | The accuracy of 'OxFlowers_CNN_75.py' on the test set is 75.59%. 25 | The accuracy of 'OxFlowers_BCNN_85.py' on the test set is 85.00%. 26 | If the models do not exit, you can uncomment the training code in the main function to retrain the model. 27 | -------------------------------------------------------------------------------- /DataPreprocess/DataPreprocess.m: -------------------------------------------------------------------------------- 1 | % Copyright (c) Hu Zhiming 2018/4/4 JimmyHu@pku.edu.cn All Rights Reserved. 2 | % preprocess the images: split the images into train, validation & test 3 | % sets and augment the train images. 4 | 5 | % load the datasplits mat. 6 | load 'datasplits.mat' 7 | 8 | % the path of the original images. 9 | imgPath1 = 'Images/'; 10 | 11 | % make the directory that we need. 12 | mkdir('Images2'); 13 | % the path of the renamed images. 14 | imgPath2 = 'Images2/'; 15 | 16 | % rename the original images and restore them in imgPath2 17 | % list all the images in imgPath1. 18 | imgDir1 = dir([imgPath1, '*.jpg']); 19 | for i = 1: length(imgDir1) 20 | % read all the images. 21 | img = imread([imgPath1 imgDir1(i).name]); 22 | name2=[imgPath2 num2str(str2num(imgDir1(i).name(7:10))) '.jpg']; 23 | imwrite(img, name2); 24 | end 25 | 26 | % split the train set. 27 | mkdir('Train'); 28 | trainPath = 'Train/'; 29 | for i =1 : length(trn1) 30 | % the name of the training images. 31 | name = [imgPath2 num2str(trn1(i)) '.jpg']; 32 | img = imread(name); 33 | name2 = [trainPath num2str(trn1(i)) '.jpg']; 34 | imwrite(img, name2); 35 | end 36 | 37 | % split the validation set. 38 | mkdir('Validation'); 39 | testPath = 'Validation/'; 40 | for i =1 : length(val1) 41 | % the name of the training images. 42 | name = [imgPath2 num2str(val1(i)) '.jpg']; 43 | img = imread(name); 44 | name2 = [testPath num2str(val1(i)) '.jpg']; 45 | imwrite(img, name2); 46 | end 47 | 48 | % split the test set. 49 | mkdir('Test'); 50 | testPath = 'Test/'; 51 | for i =1 : length(tst1) 52 | % the name of the training images. 53 | name = [imgPath2 num2str(tst1(i)) '.jpg']; 54 | img = imread(name); 55 | name2 = [testPath num2str(tst1(i)) '.jpg']; 56 | imwrite(img, name2); 57 | end 58 | 59 | % Data Augmentation for the original train images. 60 | trainPath = 'Train/'; 61 | % list all the images in trainPath. 62 | trainDir = dir([trainPath, '*.jpg']); 63 | 64 | % Randomly flip the original images. 65 | mkdir('TrainFlip'); 66 | flipPath = 'TrainFlip/'; 67 | for i = 1: length(trainDir) 68 | % the random flag. 69 | flag = rand; 70 | if flag > 0.5 71 | % read the original train images. 72 | img = imread([trainPath trainDir(i).name]); 73 | % flip the original image. 74 | img2 = fliplr(img); 75 | name2=[flipPath trainDir(i).name]; 76 | imwrite(img2, name2); 77 | end 78 | end 79 | 80 | % Randomly crop the original images. 81 | mkdir('TrainCrop'); 82 | cropPath = 'TrainCrop/'; 83 | for i = 1: length(trainDir) 84 | % the random flag. 85 | flag = rand; 86 | if flag > 0.5 87 | % read the original train images. 88 | img = imread([trainPath trainDir(i).name]); 89 | % resize the original image. 90 | img2 = imresize(img, 1.2); 91 | width = size(img, 2); 92 | height = size(img, 1); 93 | % crop the image. 94 | img2 = imcrop(img2, [width*0.1 height*0.1 width height]); 95 | name2=[cropPath trainDir(i).name]; 96 | imwrite(img2, name2); 97 | end 98 | end 99 | 100 | % Randomly crop the original images. 101 | mkdir('TrainNoise'); 102 | noisePath = 'TrainNoise/'; 103 | for i = 1: length(trainDir) 104 | % the random flag. 105 | flag = rand; 106 | if flag > 0.5 107 | % read the original train images. 108 | img = imread([trainPath trainDir(i).name]); 109 | % add noise to the original image. 110 | img2 = imnoise(img, 'salt & pepper', 0.02); 111 | name2=[noisePath trainDir(i).name]; 112 | imwrite(img2, name2); 113 | end 114 | end 115 | -------------------------------------------------------------------------------- /DataPreprocess/CreateTFRecords.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018/4/8 Hu Zhiming JimmyHu@pku.edu.cn All Rights Reserved. 2 | # Create the tarin & test dataset from the given train & test images. 3 | 4 | # import the libs(libs & future libs). 5 | from __future__ import absolute_import 6 | from __future__ import division 7 | from __future__ import print_function 8 | 9 | import os 10 | import tensorflow as tf 11 | # Image is used to process images. 12 | from PIL import Image 13 | 14 | # Get the current work directory. 15 | cwd = os.getcwd() 16 | # create a list of the files in the given directory. 17 | train_dir = os.listdir(cwd+"/Train/") 18 | validation_dir = os.listdir(cwd+"/Validation/") 19 | test_dir = os.listdir(cwd+"/Test/") 20 | # a class to write records to a TFRecords file. 21 | # train_writer = tf.python_io.TFRecordWriter("../Dataset/train.tfrecords") 22 | validation_writer = tf.python_io.TFRecordWriter("../Dataset/validation.tfrecords") 23 | test_writer = tf.python_io.TFRecordWriter("../Dataset/test.tfrecords") 24 | 25 | # the width & height to resize the images. 26 | ImageWidth = 224 27 | ImageHeight= 224 28 | 29 | # the number of images in a category. 30 | Number = 80 31 | 32 | """ 33 | # create the train tfrecords. 34 | for name in train_dir: 35 | # the path of an image. 36 | image_path = cwd + "/Train/"+name 37 | # read the image. 38 | img = Image.open(image_path) 39 | # resize the image. 40 | img = img.resize((ImageWidth, ImageHeight)) 41 | # convert the image to bytes(raw data). 42 | img_raw = img.tobytes() 43 | # calculate the label of this image. 44 | num = name.split('.') 45 | # num is the id of the image in the original image dataset. 46 | num = int(num[0]) 47 | label = int((num-1)/Number) 48 | # print('num: {}, Number: {}, label: {}'.format(num, Number, label)) 49 | # example defines the data format. 50 | example = tf.train.Example(features=tf.train.Features(feature={ 51 | "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label])), 52 | 'img_raw': tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])) 53 | })) 54 | 55 | # Serialize the data to string and write it. 56 | train_writer.write(example.SerializeToString()) 57 | 58 | print('Image Name: {}, label: {}'.format(name, label)) 59 | 60 | # close the TFRecords writer. 61 | train_writer.close() 62 | """ 63 | 64 | # create the validation tfrecords. 65 | for name in validation_dir: 66 | # the path of an image. 67 | image_path = cwd + "/Validation/"+name 68 | # read the image. 69 | img = Image.open(image_path) 70 | # resize the image. 71 | img = img.resize((ImageWidth, ImageHeight)) 72 | # convert the image to bytes(raw data). 73 | img_raw = img.tobytes() 74 | # calculate the label of this image. 75 | num = name.split('.') 76 | # num is the id of the image in the original image dataset. 77 | num = int(num[0]) 78 | label = int((num-1)/Number) 79 | # print('num: {}, Number: {}, label: {}'.format(num, Number, label)) 80 | # example defines the data format. 81 | example = tf.train.Example(features=tf.train.Features(feature={ 82 | "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label])), 83 | 'img_raw': tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])) 84 | })) 85 | 86 | # Serialize the data to string and write it. 87 | validation_writer.write(example.SerializeToString()) 88 | 89 | print('Image Name: {}, label: {}'.format(name, label)) 90 | 91 | # close the TFRecords writer. 92 | validation_writer.close() 93 | 94 | # create the test tfrecords. 95 | for name in test_dir: 96 | # the path of an image. 97 | image_path = cwd + "/Test/"+name 98 | # read the image. 99 | img = Image.open(image_path) 100 | # resize the image. 101 | img = img.resize((ImageWidth, ImageHeight)) 102 | # convert the image to bytes(raw data). 103 | img_raw = img.tobytes() 104 | # calculate the label of this image. 105 | num = name.split('.') 106 | # num is the id of the image in the original image dataset. 107 | num = int(num[0]) 108 | label = int((num-1)/Number) 109 | # print('num: {}, Number: {}, label: {}'.format(num, Number, label)) 110 | # example defines the data format. 111 | example = tf.train.Example(features=tf.train.Features(feature={ 112 | "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label])), 113 | 'img_raw': tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])) 114 | })) 115 | 116 | # Serialize the data to string and write it. 117 | test_writer.write(example.SerializeToString()) 118 | 119 | print('Image Name: {}, label: {}'.format(name, label)) 120 | 121 | # close the TFRecords writer. 122 | test_writer.close() 123 | 124 | # the augmented train set. 125 | # a class to write records to a TFRecords file. 126 | train_aug_writer = tf.python_io.TFRecordWriter("../Dataset/train_aug.tfrecords") 127 | trainFlip_dir = os.listdir(cwd+"/TrainFlip/") 128 | trainCrop_dir = os.listdir(cwd+"/TrainCrop/") 129 | trainNoise_dir = os.listdir(cwd+"/TrainNoise/") 130 | 131 | # write the original train data. 132 | for name in train_dir: 133 | # the path of an image. 134 | image_path = cwd + "/Train/"+name 135 | # read the image. 136 | img = Image.open(image_path) 137 | # resize the image. 138 | img = img.resize((ImageWidth, ImageHeight)) 139 | # convert the image to bytes(raw data). 140 | img_raw = img.tobytes() 141 | # calculate the label of this image. 142 | num = name.split('.') 143 | # num is the id of the image in the original image dataset. 144 | num = int(num[0]) 145 | label = int((num-1)/Number) 146 | # print('num: {}, Number: {}, label: {}'.format(num, Number, label)) 147 | # example defines the data format. 148 | example = tf.train.Example(features=tf.train.Features(feature={ 149 | "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label])), 150 | 'img_raw': tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])) 151 | })) 152 | 153 | # Serialize the data to string and write it. 154 | train_aug_writer.write(example.SerializeToString()) 155 | print('Image Name: {}, label: {}'.format(name, label)) 156 | 157 | # write the flipped train data. 158 | for name in trainFlip_dir: 159 | # the path of an image. 160 | image_path = cwd + "/TrainFlip/"+name 161 | # read the image. 162 | img = Image.open(image_path) 163 | # resize the image. 164 | img = img.resize((ImageWidth, ImageHeight)) 165 | # convert the image to bytes(raw data). 166 | img_raw = img.tobytes() 167 | # calculate the label of this image. 168 | num = name.split('.') 169 | # num is the id of the image in the original image dataset. 170 | num = int(num[0]) 171 | label = int((num-1)/Number) 172 | # print('num: {}, Number: {}, label: {}'.format(num, Number, label)) 173 | # example defines the data format. 174 | example = tf.train.Example(features=tf.train.Features(feature={ 175 | "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label])), 176 | 'img_raw': tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])) 177 | })) 178 | 179 | # Serialize the data to string and write it. 180 | train_aug_writer.write(example.SerializeToString()) 181 | print('Image Name: {}, label: {}'.format(name, label)) 182 | 183 | # write the cropped train data. 184 | for name in trainCrop_dir: 185 | # the path of an image. 186 | image_path = cwd + "/TrainCrop/"+name 187 | # read the image. 188 | img = Image.open(image_path) 189 | # resize the image. 190 | img = img.resize((ImageWidth, ImageHeight)) 191 | # convert the image to bytes(raw data). 192 | img_raw = img.tobytes() 193 | # calculate the label of this image. 194 | num = name.split('.') 195 | # num is the id of the image in the original image dataset. 196 | num = int(num[0]) 197 | label = int((num-1)/Number) 198 | # print('num: {}, Number: {}, label: {}'.format(num, Number, label)) 199 | # example defines the data format. 200 | example = tf.train.Example(features=tf.train.Features(feature={ 201 | "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label])), 202 | 'img_raw': tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])) 203 | })) 204 | 205 | # Serialize the data to string and write it. 206 | train_aug_writer.write(example.SerializeToString()) 207 | print('Image Name: {}, label: {}'.format(name, label)) 208 | 209 | # write the noised train data. 210 | for name in trainNoise_dir: 211 | # the path of an image. 212 | image_path = cwd + "/TrainNoise/"+name 213 | # read the image. 214 | img = Image.open(image_path) 215 | # resize the image. 216 | img = img.resize((ImageWidth, ImageHeight)) 217 | # convert the image to bytes(raw data). 218 | img_raw = img.tobytes() 219 | # calculate the label of this image. 220 | num = name.split('.') 221 | # num is the id of the image in the original image dataset. 222 | num = int(num[0]) 223 | label = int((num-1)/Number) 224 | # print('num: {}, Number: {}, label: {}'.format(num, Number, label)) 225 | # example defines the data format. 226 | example = tf.train.Example(features=tf.train.Features(feature={ 227 | "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label])), 228 | 'img_raw': tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])) 229 | })) 230 | 231 | # Serialize the data to string and write it. 232 | train_aug_writer.write(example.SerializeToString()) 233 | print('Image Name: {}, label: {}'.format(name, label)) 234 | 235 | # close the TFRecords writer. 236 | train_aug_writer.close() 237 | -------------------------------------------------------------------------------- /OxFlowers_CNN_75.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018/4/6 Hu Zhiming JimmyHu@pku.edu.cn All Rights Reserved. 2 | # The CNN estimator for 17_OxFlowers Dataset. 3 | 4 | 5 | ####################################### 6 | # Network Architecture 7 | # input layer 8 | # conv3_32 9 | # maxpool 10 | # conv3_64 11 | # maxpool 12 | # conv3_128 13 | # maxpool 14 | # conv3_256 15 | # maxpool 16 | # conv3_512 17 | # maxpool 18 | # conv3_1024 19 | # maxpool 20 | # FC-1024 21 | # output layer 22 | ####################################### 23 | 24 | 25 | # import the libs(libs & future libs). 26 | from __future__ import absolute_import 27 | from __future__ import division 28 | from __future__ import print_function 29 | 30 | import tensorflow as tf 31 | import datetime 32 | 33 | 34 | # the params of the input dataset. 35 | # the width, height & channels of the images in the input TFRecords file. 36 | ImageWidth = 224 37 | ImageHeight = 224 38 | ImageChannels = 3 39 | # the number of categories. 40 | CategoryNum = 17 41 | 42 | # the params for training. 43 | # the batch size for training. 44 | Batch_Size = 85 45 | # Steps is the number of training steps in a time. 46 | Steps = 200 47 | # Loops is the total number of training times. 48 | # Total_Training_Steps = Steps* Loops 49 | Loops = 6 50 | 51 | 52 | # Output thogging info. 53 | # Use tensorboard --logdir=PATH to view the graphs. 54 | tf.logging.set_verbosity(tf.logging.INFO) 55 | 56 | 57 | def cnn_model_fn(features, labels, mode): 58 | """the model function for CNN OxFlower.""" 59 | # Input Layer 60 | # Reshape X to 4-D tensor: [batch_size, width, height, channels] 61 | # oxflower images are 224*224 pixels, and have 3 color channels 62 | input_layer = tf.reshape(features['x'], [-1, ImageWidth, ImageHeight, ImageChannels]) 63 | # print(type(features)) 64 | # print(features) 65 | # print(input_layer.shape) 66 | # print(type(labels)) 67 | # input('1:') 68 | 69 | # Convolutional Layer #1 70 | conv1 = tf.layers.conv2d( 71 | inputs = input_layer, 72 | filters = 32, 73 | kernel_size = 3, 74 | padding = "same") 75 | 76 | # Batch Normalization Layer #3 77 | bn1 = tf.layers.batch_normalization(inputs = conv1) 78 | layer1 = tf.nn.relu(bn1) 79 | 80 | 81 | # Pooling Layer #1 82 | pool1 = tf.layers.max_pooling2d(inputs = layer1, pool_size = [2, 2], strides = 2) 83 | 84 | # Convolutional Layer #2 85 | conv2 = tf.layers.conv2d( 86 | inputs = pool1, 87 | filters = 64, 88 | kernel_size = 3, 89 | padding = "same") 90 | 91 | # Batch Normalization Layer #3 92 | bn2 = tf.layers.batch_normalization(inputs = conv2) 93 | layer2 = tf.nn.relu(bn2) 94 | 95 | # Pooling Layer #2 96 | pool2 = tf.layers.max_pooling2d(inputs = layer2, pool_size = [2, 2], strides = 2) 97 | 98 | # Convolutional Layer #3 99 | conv3 = tf.layers.conv2d( 100 | inputs = pool2, 101 | filters = 128, 102 | kernel_size = 3, 103 | padding = "same") 104 | 105 | # Batch Normalization Layer #3 106 | bn3 = tf.layers.batch_normalization(inputs = conv3) 107 | layer3 = tf.nn.relu(bn3) 108 | 109 | # Pooling Layer #3 110 | pool3 = tf.layers.max_pooling2d(inputs = layer3, pool_size = [2, 2], strides = 2) 111 | 112 | # Convolutional Layer #4 113 | conv4 = tf.layers.conv2d( 114 | inputs = pool3, 115 | filters = 256, 116 | kernel_size = 3, 117 | padding = "same") 118 | 119 | # Batch Normalization Layer #4 120 | bn4 = tf.layers.batch_normalization(inputs = conv4) 121 | layer4 = tf.nn.relu(bn4) 122 | 123 | # Pooling Layer #4 124 | pool4 = tf.layers.max_pooling2d(inputs = layer4, pool_size = [2, 2], strides = 2) 125 | 126 | # Convolutional Layer #5 127 | conv5 = tf.layers.conv2d( 128 | inputs = pool4, 129 | filters = 512, 130 | kernel_size = 3, 131 | padding = "same") 132 | 133 | # Batch Normalization Layer #5 134 | bn5 = tf.layers.batch_normalization(inputs = conv5) 135 | layer5 = tf.nn.relu(bn5) 136 | pool5 = tf.layers.max_pooling2d(inputs = layer5, pool_size = [2, 2], strides = 2) 137 | 138 | # Convolutional Layer #6 139 | conv6 = tf.layers.conv2d( 140 | inputs = pool5, 141 | filters = 1024, 142 | kernel_size = 3, 143 | padding = "same",) 144 | 145 | # Batch Normalization Layer #6 146 | bn6 = tf.layers.batch_normalization(inputs = conv6) 147 | layer6 = tf.nn.relu(bn6) 148 | # Pooling Layer #6 149 | pool6 = tf.layers.max_pooling2d(inputs = layer6, pool_size = [2, 2], strides = 2) 150 | 151 | 152 | # Flatten tensor into a batch of vectors 153 | pool6_flat = tf.reshape(pool6, [-1, pool6.shape[1]*pool6.shape[2]*pool6.shape[3]]) 154 | 155 | # Fully Connected Dense Layer #1 156 | fc_1 = tf.layers.dense(inputs = pool6_flat, units = 1024, activation=tf.nn.relu) 157 | 158 | # Add dropout operation; 0.6 probability that element will be kept 159 | dropout_1 = tf.layers.dropout( 160 | inputs = fc_1, rate = 0.8, training=mode == tf.estimator.ModeKeys.TRAIN) 161 | 162 | # Logits layer 163 | # Output Tensor Shape: [batch_size, CategoryNum] 164 | # Default: activation=None, maintaining a linear activation. 165 | logits = tf.layers.dense(inputs = dropout_1, units = CategoryNum) 166 | 167 | predictions = { 168 | # Generate predictions (for PREDICT and EVAL mode) 169 | "classes": tf.argmax(input=logits, axis=1), 170 | # Add `softmax_tensor` to the graph. It is used for PREDICT and by the 171 | # `logging_hook`. 172 | "probabilities": tf.nn.softmax(logits, name="softmax_tensor")} 173 | 174 | if mode == tf.estimator.ModeKeys.PREDICT: 175 | return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions) 176 | 177 | # Calculate Loss (for both TRAIN and EVAL modes) 178 | # No need to use one-hot labels. 179 | loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits) 180 | 181 | # Calculate evaluation metrics. 182 | accuracy = tf.metrics.accuracy(labels=labels, predictions=predictions["classes"], name='acc_op') 183 | eval_metric_ops = {'accuracy': accuracy} 184 | # Use tensorboard --logdir=PATH to view the graphs. 185 | # The tf.summary.scalar will make accuracy available to TensorBoard in both TRAIN and EVAL modes. 186 | tf.summary.scalar('accuracy', accuracy[1]) 187 | 188 | # Configure the Training Op (for TRAIN mode) 189 | if mode == tf.estimator.ModeKeys.TRAIN: 190 | optimizer = tf.train.AdamOptimizer(learning_rate = 0.0001) 191 | train_op = optimizer.minimize(loss=loss,global_step=tf.train.get_global_step()) 192 | return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op) 193 | 194 | # Add evaluation metrics (for EVAL mode) 195 | if mode == tf.estimator.ModeKeys.EVAL: 196 | return tf.estimator.EstimatorSpec(mode=mode, loss=loss, eval_metric_ops=eval_metric_ops) 197 | 198 | 199 | def read_and_decode(filename): 200 | """ 201 | read and decode a TFRecords file. 202 | returns numpy array objects. 203 | pipeline: TFRecords --> queue --> serialized_example --> dict. 204 | """ 205 | # Output strings (e.g. filenames) to a queue for an input pipeline. 206 | filename_queue = tf.train.string_input_producer([filename]) 207 | # print(filename_queue) 208 | # A Reader that outputs the records from a TFRecords file. 209 | reader = tf.TFRecordReader() 210 | # reader.read(queue) 211 | # Args queue: A Queue or a mutable string Tensor representing a handle to a Queue, with string work items. 212 | # Returns: A tuple of Tensors (key, value). key: A string scalar Tensor. value: A string scalar Tensor. 213 | _, serialized_example = reader.read(filename_queue) 214 | # print(serialized_example) 215 | 216 | # Parses a single Example proto. 217 | # Returns a dict mapping feature keys to Tensor and SparseTensor values. 218 | features = tf.parse_single_example(serialized_example,features={ 219 | 'label': tf.FixedLenFeature([], tf.int64), 'img_raw' : tf.FixedLenFeature([], tf.string),}) 220 | # Reinterpret the bytes of a string as a vector of numbers. 221 | imgs = tf.decode_raw(features['img_raw'], tf.uint8) 222 | # print(img.dtype) 223 | # print(img.shape) 224 | # Reshapes a tensor. 225 | imgs = tf.reshape(imgs, [-1, ImageWidth, ImageHeight, ImageChannels]) 226 | # cast the data from (0, 255) to (-0.5, 0.5) 227 | # (-0.5, 0.5) may be better than (0, 1). 228 | imgs = tf.cast(imgs, tf.float32) * (1. / 255) - 0.5 229 | labels = tf.cast(features['label'], tf.int64) 230 | 231 | # print(type(imgs)) 232 | # print(imgs.shape) 233 | # print(type(labels)) 234 | # print(labels.shape) 235 | return imgs, labels 236 | 237 | 238 | def parse_function(example_proto): 239 | """parse function is used to parse a single TFRecord example in the dataset.""" 240 | # Parses a single Example proto. 241 | # Returns a dict mapping feature keys to Tensor and SparseTensor values. 242 | features = tf.parse_single_example(example_proto,features={ 243 | 'label': tf.FixedLenFeature([], tf.int64), 'img_raw' : tf.FixedLenFeature([], tf.string),}) 244 | # Reinterpret the bytes of a string as a vector of numbers. 245 | imgs = tf.decode_raw(features['img_raw'], tf.uint8) 246 | # Reshapes a tensor. 247 | imgs = tf.reshape(imgs, [ImageWidth, ImageHeight, 3]) 248 | # cast the data from (0, 255) to (-0.5, 0.5) 249 | # (-0.5, 0.5) may be better than (0, 1). 250 | imgs = tf.cast(imgs, tf.float32) * (1. / 255) - 0.5 251 | labels = tf.cast(features['label'], tf.int64) 252 | return {'x': imgs}, labels 253 | 254 | 255 | def train_input_fn(tfrecords, batch_size): 256 | """ 257 | An input function for training mode. 258 | tfrecords: the filename of the training TFRecord file, batch_size: the batch size. 259 | """ 260 | # read the TFRecord file into a dataset. 261 | dataset = tf.data.TFRecordDataset(tfrecords) 262 | # parse the dataset. 263 | dataset = dataset.map(parse_function) 264 | # the size of the buffer for shuffling. 265 | # buffer_size should be greater than the number of examples in the Dataset, ensuring that the data is completely shuffled. 266 | buffer_size = 10000 267 | # Shuffle, repeat, and batch the examples. 268 | dataset = dataset.shuffle(buffer_size).repeat().batch(batch_size) 269 | # print(dataset) 270 | 271 | # make an one shot iterator to get the data of a batch. 272 | train_iterator = dataset.make_one_shot_iterator() 273 | # get the features and labels. 274 | features, labels = train_iterator.get_next() 275 | # print(features) 276 | # print(labels) 277 | return features, labels 278 | 279 | def eval_input_fn(tfrecords, batch_size): 280 | """ 281 | An input function for evaluation mode. 282 | tfrecords: the filename of the evaluation/test TFRecord file, batch_size: the batch size. 283 | """ 284 | # read the TFRecord file into a dataset. 285 | dataset = tf.data.TFRecordDataset(tfrecords) 286 | # parse the dataset. 287 | dataset = dataset.map(parse_function) 288 | 289 | # Shuffle, repeat, and batch the examples. 290 | dataset = dataset.batch(batch_size) 291 | # print(dataset) 292 | # make an one shot iterator to get the data of a batch. 293 | eval_iterator = dataset.make_one_shot_iterator() 294 | # get the features and labels. 295 | features, labels = eval_iterator.get_next() 296 | # print(features) 297 | # print(labels) 298 | return features, labels 299 | 300 | 301 | def main(unused_argv): 302 | 303 | # Create the Estimator 304 | oxflower_classifier = tf.estimator.Estimator( 305 | model_fn=cnn_model_fn, 306 | model_dir="Models/CNN_75/") 307 | 308 | """ 309 | # Uncomment this to retain the model. 310 | # train and validate the model in a loop. 311 | # the start time of training. 312 | start_time = datetime.datetime.now() 313 | for i in range(Loops): 314 | # Train the model 315 | oxflower_classifier.train( 316 | input_fn=lambda:train_input_fn('Dataset/train_aug.tfrecords', Batch_Size), 317 | steps = Steps) 318 | # Evaluate the model on validation set. 319 | eval_results = oxflower_classifier.evaluate(input_fn=lambda:eval_input_fn('Dataset/validation.tfrecords', Batch_Size)) 320 | # Calculate the accuracy of our CNN model. 321 | accuracy = eval_results['accuracy']*100 322 | print('\n\ntraining steps: {}'.format((i+1)*Steps)) 323 | print('Validation set accuracy: {:0.2f}%\n\n'.format(accuracy)) 324 | 325 | # the end time of training. 326 | end_time = datetime.datetime.now() 327 | print('\n\n\ntraining starts at: {}'.format(start_time)) 328 | print('\ntraining ends at: {}\n\n\n'.format(end_time)) 329 | """ 330 | 331 | # evaluate the model on test set. 332 | # Evaluate the model on test set. 333 | eval_results = oxflower_classifier.evaluate(input_fn=lambda:eval_input_fn('Dataset/test.tfrecords', Batch_Size)) 334 | # Calculate the accuracy of our CNN model. 335 | accuracy = eval_results['accuracy']*100 336 | print('\n\nTest set accuracy: {:0.2f}%\n\n'.format(accuracy)) 337 | 338 | if __name__ == "__main__": 339 | """tf.app.run() runs the main function in this module by default.""" 340 | tf.app.run() 341 | -------------------------------------------------------------------------------- /OxFlowers_BCNN_85.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018/4/11 Hu Zhiming JimmyHu@pku.edu.cn All Rights Reserved. 2 | # The Bilinear CNN estimator for 17_OxFlowers Dataset. 3 | 4 | 5 | ####################################### 6 | # Network Architecture: 7 | # input layer 8 | # conv3_32 9 | # maxpool 10 | # conv3_64 11 | # maxpool 12 | # conv3_128 13 | # maxpool 14 | # conv3_256 15 | # maxpool 16 | # conv3_512 17 | # maxpool 18 | # conv3_512 19 | # Bilinear Layer(The 2 convolution layers which are combined by the Bilinear Layer are identical, you can also combine 2 different convolution layers) 20 | # output layer(logits Layer) 21 | ####################################### 22 | 23 | 24 | ####################################### 25 | # Usage: 26 | # The model has been trained for 4000 global steps and the accuracy on test set is 85%. 27 | # Run this code to test the accuracy of our model. 28 | # If you want to retrain the model, uncomment the training code in the main function and set the 'Steps' & 'Loops' global variables to control the training process. 29 | ####################################### 30 | 31 | 32 | 33 | # import the libs(libs & future libs). 34 | from __future__ import absolute_import 35 | from __future__ import division 36 | from __future__ import print_function 37 | 38 | import tensorflow as tf 39 | import datetime 40 | 41 | 42 | # the params of the input dataset. 43 | # the width, height & channels of the images in the input TFRecords file. 44 | ImageWidth = 224 45 | ImageHeight = 224 46 | ImageChannels = 3 47 | # the number of categories. 48 | CategoryNum = 17 49 | 50 | # the params for training. 51 | # the batch size for training. 52 | Batch_Size = 85 53 | # Steps is the number of training steps in a time. 54 | Steps = 200 55 | # Loops is the total number of training times. 56 | # Global_Training_Steps = Steps* Loops 57 | Loops = 0 58 | 59 | 60 | # Output thogging info. 61 | # Use tensorboard --logdir=PATH to view the graphs. 62 | tf.logging.set_verbosity(tf.logging.INFO) 63 | 64 | 65 | def cnn_model_fn(features, labels, mode): 66 | """the model function for CNN OxFlower.""" 67 | # Input Layer 68 | # Reshape X to 4-D tensor: [batch_size, width, height, channels] 69 | # oxflower images are 224*224 pixels, and have 3 color channels 70 | input_layer = tf.reshape(features['x'], [-1, ImageWidth, ImageHeight, ImageChannels]) 71 | # print(type(features)) 72 | # print(features) 73 | # print(input_layer.shape) 74 | # print(type(labels)) 75 | # input('1:') 76 | 77 | # Convolutional Layer #1 78 | conv1 = tf.layers.conv2d( 79 | inputs = input_layer, 80 | filters = 32, 81 | kernel_size = 3, 82 | padding = "same") 83 | 84 | # Batch Normalization Layer #3 85 | bn1 = tf.layers.batch_normalization(inputs = conv1) 86 | layer1 = tf.nn.relu(bn1) 87 | 88 | 89 | # Pooling Layer #1 90 | pool1 = tf.layers.max_pooling2d(inputs = layer1, pool_size = [2, 2], strides = 2) 91 | 92 | # Convolutional Layer #2 93 | conv2 = tf.layers.conv2d( 94 | inputs = pool1, 95 | filters = 64, 96 | kernel_size = 3, 97 | padding = "same") 98 | 99 | # Batch Normalization Layer #3 100 | bn2 = tf.layers.batch_normalization(inputs = conv2) 101 | layer2 = tf.nn.relu(bn2) 102 | 103 | # Pooling Layer #2 104 | pool2 = tf.layers.max_pooling2d(inputs = layer2, pool_size = [2, 2], strides = 2) 105 | 106 | # Convolutional Layer #3 107 | conv3 = tf.layers.conv2d( 108 | inputs = pool2, 109 | filters = 128, 110 | kernel_size = 3, 111 | padding = "same") 112 | 113 | # Batch Normalization Layer #3 114 | bn3 = tf.layers.batch_normalization(inputs = conv3) 115 | layer3 = tf.nn.relu(bn3) 116 | 117 | # Pooling Layer #3 118 | pool3 = tf.layers.max_pooling2d(inputs = layer3, pool_size = [2, 2], strides = 2) 119 | 120 | # Convolutional Layer #4 121 | conv4 = tf.layers.conv2d( 122 | inputs = pool3, 123 | filters = 256, 124 | kernel_size = 3, 125 | padding = "same") 126 | 127 | # Batch Normalization Layer #4 128 | bn4 = tf.layers.batch_normalization(inputs = conv4) 129 | layer4 = tf.nn.relu(bn4) 130 | 131 | # Pooling Layer #4 132 | pool4 = tf.layers.max_pooling2d(inputs = layer4, pool_size = [2, 2], strides = 2) 133 | 134 | # Convolutional Layer #5 135 | conv5 = tf.layers.conv2d( 136 | inputs = pool4, 137 | filters = 512, 138 | kernel_size = 3, 139 | padding = "same") 140 | 141 | # Batch Normalization Layer #5 142 | bn5 = tf.layers.batch_normalization(inputs = conv5) 143 | layer5 = tf.nn.relu(bn5) 144 | pool5 = tf.layers.max_pooling2d(inputs = layer5, pool_size = [2, 2], strides = 2) 145 | 146 | # Convolutional Layer #6 147 | conv6 = tf.layers.conv2d( 148 | inputs = pool5, 149 | filters = 512, 150 | kernel_size = 3, 151 | padding = "same",) 152 | 153 | # Batch Normalization Layer #6 154 | bn6 = tf.layers.batch_normalization(inputs = conv6) 155 | layer6 = tf.nn.relu(bn6) 156 | 157 | # print(layer6) 158 | # input("input: ") 159 | 160 | # The bilinear layer. 161 | # We combine the 2 identical convolution layers in our code. You can also combine 2 different convolution layers. 162 | # The bilinear layer is connected to the final output layer(the logits layer). 163 | phi_I = tf.einsum('ijkm,ijkn->imn', layer6, layer6) 164 | # print(phi_I) 165 | phi_I = tf.reshape(phi_I, [-1,512*512]) 166 | # print(phi_I) 167 | phi_I = tf.divide(phi_I, 49) 168 | # print(phi_I) 169 | phi_I = tf.layers.batch_normalization(inputs = phi_I) 170 | # print(phi_I) 171 | # input("input: ") 172 | 173 | # Add dropout operation; 0.2 probability that element will be kept 174 | dropout_1 = tf.layers.dropout( 175 | inputs = phi_I, rate = 0.8, training=mode == tf.estimator.ModeKeys.TRAIN) 176 | 177 | # Logits layer 178 | # Output Tensor Shape: [batch_size, CategoryNum] 179 | # Default: activation=None, maintaining a linear activation. 180 | logits = tf.layers.dense(inputs = dropout_1, units = CategoryNum) 181 | 182 | predictions = { 183 | # Generate predictions (for PREDICT and EVAL mode) 184 | "classes": tf.argmax(input=logits, axis=1), 185 | # Add `softmax_tensor` to the graph. It is used for PREDICT and by the 186 | # `logging_hook`. 187 | "probabilities": tf.nn.softmax(logits, name="softmax_tensor")} 188 | 189 | if mode == tf.estimator.ModeKeys.PREDICT: 190 | return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions) 191 | 192 | # Calculate Loss (for both TRAIN and EVAL modes) 193 | # No need to use one-hot labels. 194 | loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits) 195 | 196 | # Calculate evaluation metrics. 197 | accuracy = tf.metrics.accuracy(labels=labels, predictions=predictions["classes"], name='acc_op') 198 | eval_metric_ops = {'accuracy': accuracy} 199 | # Use tensorboard --logdir=PATH to view the graphs. 200 | # The tf.summary.scalar will make accuracy available to TensorBoard in both TRAIN and EVAL modes. 201 | tf.summary.scalar('accuracy', accuracy[1]) 202 | 203 | # Configure the Training Op (for TRAIN mode) 204 | if mode == tf.estimator.ModeKeys.TRAIN: 205 | optimizer = tf.train.AdamOptimizer(learning_rate = 0.001) 206 | train_op = optimizer.minimize(loss=loss,global_step=tf.train.get_global_step()) 207 | return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op) 208 | 209 | # Add evaluation metrics (for EVAL mode) 210 | if mode == tf.estimator.ModeKeys.EVAL: 211 | return tf.estimator.EstimatorSpec(mode=mode, loss=loss, eval_metric_ops=eval_metric_ops) 212 | 213 | 214 | def read_and_decode(filename): 215 | """ 216 | read and decode a TFRecords file. 217 | returns numpy array objects. 218 | pipeline: TFRecords --> queue --> serialized_example --> dict. 219 | """ 220 | # Output strings (e.g. filenames) to a queue for an input pipeline. 221 | filename_queue = tf.train.string_input_producer([filename]) 222 | # print(filename_queue) 223 | # A Reader that outputs the records from a TFRecords file. 224 | reader = tf.TFRecordReader() 225 | # reader.read(queue) 226 | # Args queue: A Queue or a mutable string Tensor representing a handle to a Queue, with string work items. 227 | # Returns: A tuple of Tensors (key, value). key: A string scalar Tensor. value: A string scalar Tensor. 228 | _, serialized_example = reader.read(filename_queue) 229 | # print(serialized_example) 230 | 231 | # Parses a single Example proto. 232 | # Returns a dict mapping feature keys to Tensor and SparseTensor values. 233 | features = tf.parse_single_example(serialized_example,features={ 234 | 'label': tf.FixedLenFeature([], tf.int64), 'img_raw' : tf.FixedLenFeature([], tf.string),}) 235 | # Reinterpret the bytes of a string as a vector of numbers. 236 | imgs = tf.decode_raw(features['img_raw'], tf.uint8) 237 | # print(img.dtype) 238 | # print(img.shape) 239 | # Reshapes a tensor. 240 | imgs = tf.reshape(imgs, [-1, ImageWidth, ImageHeight, ImageChannels]) 241 | # cast the data from (0, 255) to (-0.5, 0.5) 242 | # (-0.5, 0.5) may be better than (0, 1). 243 | imgs = tf.cast(imgs, tf.float32) * (1. / 255) - 0.5 244 | labels = tf.cast(features['label'], tf.int64) 245 | 246 | # print(type(imgs)) 247 | # print(imgs.shape) 248 | # print(type(labels)) 249 | # print(labels.shape) 250 | return imgs, labels 251 | 252 | 253 | def parse_function(example_proto): 254 | """parse function is used to parse a single TFRecord example in the dataset.""" 255 | # Parses a single Example proto. 256 | # Returns a dict mapping feature keys to Tensor and SparseTensor values. 257 | features = tf.parse_single_example(example_proto,features={ 258 | 'label': tf.FixedLenFeature([], tf.int64), 'img_raw' : tf.FixedLenFeature([], tf.string),}) 259 | # Reinterpret the bytes of a string as a vector of numbers. 260 | imgs = tf.decode_raw(features['img_raw'], tf.uint8) 261 | # Reshapes a tensor. 262 | imgs = tf.reshape(imgs, [ImageWidth, ImageHeight, 3]) 263 | # cast the data from (0, 255) to (-0.5, 0.5) 264 | # (-0.5, 0.5) may be better than (0, 1). 265 | imgs = tf.cast(imgs, tf.float32) * (1. / 255) - 0.5 266 | labels = tf.cast(features['label'], tf.int64) 267 | return {'x': imgs}, labels 268 | 269 | 270 | def train_input_fn(tfrecords, batch_size): 271 | """ 272 | An input function for training mode. 273 | tfrecords: the filename of the training TFRecord file, batch_size: the batch size. 274 | """ 275 | # read the TFRecord file into a dataset. 276 | dataset = tf.data.TFRecordDataset(tfrecords) 277 | # parse the dataset. 278 | dataset = dataset.map(parse_function) 279 | # the size of the buffer for shuffling. 280 | # buffer_size should be greater than the number of examples in the Dataset, ensuring that the data is completely shuffled. 281 | buffer_size = 10000 282 | # Shuffle, repeat, and batch the examples. 283 | dataset = dataset.shuffle(buffer_size).repeat().batch(batch_size) 284 | # print(dataset) 285 | 286 | # make an one shot iterator to get the data of a batch. 287 | train_iterator = dataset.make_one_shot_iterator() 288 | # get the features and labels. 289 | features, labels = train_iterator.get_next() 290 | # print(features) 291 | # print(labels) 292 | return features, labels 293 | 294 | def eval_input_fn(tfrecords, batch_size): 295 | """ 296 | An input function for evaluation mode. 297 | tfrecords: the filename of the evaluation/test TFRecord file, batch_size: the batch size. 298 | """ 299 | # read the TFRecord file into a dataset. 300 | dataset = tf.data.TFRecordDataset(tfrecords) 301 | # parse the dataset. 302 | dataset = dataset.map(parse_function) 303 | 304 | # Shuffle, repeat, and batch the examples. 305 | dataset = dataset.batch(batch_size) 306 | # print(dataset) 307 | # make an one shot iterator to get the data of a batch. 308 | eval_iterator = dataset.make_one_shot_iterator() 309 | # get the features and labels. 310 | features, labels = eval_iterator.get_next() 311 | # print(features) 312 | # print(labels) 313 | return features, labels 314 | 315 | 316 | def main(unused_argv): 317 | 318 | # Create the Estimator 319 | oxflower_classifier = tf.estimator.Estimator( 320 | model_fn=cnn_model_fn, 321 | model_dir="Models/BCNN_85/") 322 | 323 | """ 324 | # Uncomment this to retain the model. 325 | # train and validate the model in a loop. 326 | # the start time of training. 327 | start_time = datetime.datetime.now() 328 | for i in range(Loops): 329 | # Train the model 330 | oxflower_classifier.train( 331 | input_fn=lambda:train_input_fn('Dataset/train_aug.tfrecords', Batch_Size), 332 | steps = Steps) 333 | # Evaluate the model on validation set. 334 | eval_results = oxflower_classifier.evaluate(input_fn=lambda:eval_input_fn('Dataset/validation.tfrecords', Batch_Size)) 335 | # Calculate the accuracy of our CNN model. 336 | accuracy = eval_results['accuracy']*100 337 | print('\n\ntraining steps: {}'.format((i+1)*Steps)) 338 | print('Validation set accuracy: {:0.2f}%\n\n'.format(accuracy)) 339 | 340 | # the end time of training. 341 | end_time = datetime.datetime.now() 342 | print('\n\n\ntraining starts at: {}'.format(start_time)) 343 | print('\ntraining ends at: {}\n\n\n'.format(end_time)) 344 | """ 345 | 346 | 347 | # Evaluate the model on test set. 348 | eval_results = oxflower_classifier.evaluate(input_fn=lambda:eval_input_fn('Dataset/test.tfrecords', Batch_Size)) 349 | # Calculate the accuracy of our CNN model. 350 | accuracy = eval_results['accuracy']*100 351 | print('\n\nTest set accuracy: {:0.2f}%\n\n'.format(accuracy)) 352 | 353 | if __name__ == "__main__": 354 | """tf.app.run() runs the main function in this module by default.""" 355 | tf.app.run() 356 | --------------------------------------------------------------------------------