├── model ├── __init__.py ├── deep_id.pyc ├── __init__.pyc ├── my_verification_model.py └── deep_id.py ├── dataset ├── __init__.py ├── __init__.pyc ├── facescrub_dataset.py ├── crop_face.py ├── separate_trainvaltest.py ├── compute_imagemean.py └── sklearn_dataset.py ├── .gitignore ├── graph.py ├── README.md ├── test_main.py ├── requirements.txt └── main.py /model/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dataset/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /model/deep_id.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamwoh/face_recognition/HEAD/model/deep_id.pyc -------------------------------------------------------------------------------- /model/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamwoh/face_recognition/HEAD/model/__init__.pyc -------------------------------------------------------------------------------- /dataset/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamwoh/face_recognition/HEAD/dataset/__init__.pyc -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | dataset/ytf 3 | dataset/lfw 4 | dataset/facescrub 5 | dataset/facescrub_crop 6 | dataset/facescrub_crop_test 7 | dataset/facescrub_crop_train 8 | dataset/facescrub_crop_val 9 | dataset/facescrub_meanstd 10 | dataset/imdb 11 | dataset/imdb_crop 12 | dataset/wiki_crop 13 | dataset/facescrub_actors.txt 14 | dataset/facescrub_actresses.txt 15 | dataset/facescrub_bbox.txt 16 | dataset/facescrub_dataset_prepare.py 17 | trained 18 | *.pyc 19 | -------------------------------------------------------------------------------- /graph.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy as np 4 | import time 5 | import matplotlib 6 | from matplotlib import pyplot as plt 7 | 8 | 9 | def getFigAx(): 10 | fig, ax = plt.subplots(1, 1) 11 | ax.hold(True) 12 | plt.show(False) 13 | plt.draw() 14 | return fig, ax 15 | 16 | 17 | def closeFig(fig): 18 | plt.close(fig) 19 | 20 | 21 | def refresh(fig, axes, Y, color): 22 | # for x, y in enumerate(Y): 23 | axes.plot(np.arange(len(Y)), Y, color) 24 | fig.canvas.draw() 25 | -------------------------------------------------------------------------------- /dataset/facescrub_dataset.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import os 3 | import cv2 4 | 5 | from keras.preprocessing.image import ImageDataGenerator 6 | 7 | dirname = os.path.dirname(__file__) 8 | trainDatasetPath = '{}/facescrub_train'.format(dirname) 9 | testDatasetPath = '{}/facescrub_test'.format(dirname) 10 | valDatasetPath = '{}/facescrub_val'.format(dirname) 11 | 12 | 13 | def getDataGenerator(datadir, meanstddir, batchSize, shuffle): 14 | dataGenerator = ImageDataGenerator(featurewise_center=True, 15 | featurewise_std_normalization=True, 16 | horizontal_flip=True) 17 | 18 | mean = np.load(meanstddir + '/mean.npy') 19 | std = np.load(meanstddir + '/std.npy') 20 | 21 | nImages = 0 22 | classes = [] 23 | for subdir in sorted(os.listdir(datadir)): 24 | if os.path.isdir(os.path.join(datadir, subdir)): 25 | classes.append(subdir) 26 | nImages += len(os.listdir(os.path.join(datadir, subdir))) 27 | 28 | # need to swap channel 29 | mean[0, 0, :] = mean[0, 0, ::-1] 30 | std[0, 0, :] = mean[0, 0, ::-1] 31 | 32 | dataGenerator.mean = mean 33 | dataGenerator.std = std 34 | 35 | generator = dataGenerator.flow_from_directory(datadir, 36 | target_size=(55, 47), 37 | batch_size=batchSize, 38 | shuffle=shuffle, 39 | class_mode='sparse', 40 | classes=classes, 41 | seed=np.random.randint(100000)) 42 | return generator, nImages 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Face Recognition based on DeepID 2 | 3 | Implementation of DeepID based on the paper "Sun Y, Wang X, Tang X. Deep learning face representation from predicting 10,000 classes[C]//Computer Vision and Pattern Recognition (CVPR), 2014 IEEE Conference on. IEEE, 2014: 1891-1898." 4 | 5 | ## Dataset preparation 6 | LFW - refer to sklearn.dataset 7 | 8 | Facescrub - http://vintage.winklerbros.net/facescrub.html 9 | 10 | Cropped only faces, separate them into train, val, and test set with ratio of 0.7, 0.1, 0.2 respectively 11 | 12 | ## Current state 13 | Only done face identification, working on face verification 14 | 15 | ## Training 16 | Initially learning rate of 0.01 using exponential decay on 100000 steps/0.9 decay rate 17 | 18 | Monitor the training graph, if it stays at a loss/accuracy for a long time, initialise learning rate with 0.005 or lower (my guess on it, i think it is because it reaches a local minimum gradient, couldn't go deeper) 19 | 20 | ## Reminder 21 | 1. Small dataset will be easily overfit as there is nothing much to "learn" from the dataset 22 | 23 | 2. Due to Internet speed and storage problem, I choose a smaller than CASIA dataset (stated in the paper), but bigger than LFW which is facescrub 24 | 25 | 3. My code is in continue training state, if you want a new training, comment the "load" code 26 | 27 | ## Performance 28 | Training on LFW - maximum of 80% accuracy (only 68 classes, I choose minimum of 10 faces) 29 | 30 | Training on Facescrub - still training, but reached 75% accuracy by the time I commit (530 classes) 31 | 32 | ## Contact 33 | 34 | Email: kamwoh@gmail.com 35 | 36 | ## Reference 37 | 38 | [1]. https://github.com/RiweiChen/DeepFace 39 | 40 | [2]. https://github.com/stdcoutzyx/DeepID_FaceClassify 41 | 42 | [3]. Sun Y, Wang X, Tang X. Deep learning face representation from predicting 10,000 classes[C]//Computer Vision and Pattern Recognition (CVPR), 2014 IEEE Conference on. IEEE, 2014: 1891-1898. -------------------------------------------------------------------------------- /test_main.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import cv2 4 | import numpy as np 5 | import tensorflow as tf 6 | from PIL import Image 7 | 8 | from dataset import sklearn_dataset as sk 9 | 10 | dirname = os.path.dirname(__file__) 11 | config = tf.ConfigProto() 12 | config.gpu_options.allow_growth = True 13 | with tf.Session(config=config) as sess: 14 | subjectName = 'face-recog-1510565976.19' 15 | imagePath = '/home/woh/Dataset/Abdullah_Gul/2.jpeg' 16 | loadPath = '{}/trained/{}/{}-{}'.format(dirname, subjectName, subjectName, 31201) 17 | saver = tf.train.import_meta_graph(loadPath + '.meta') 18 | saver.restore(sess, loadPath) 19 | 20 | # print [n.name for n in tf.get_default_graph().as_graph_def().node] 21 | for v in tf.global_variables(): 22 | print(v) 23 | 24 | softmax = tf.get_default_graph().get_tensor_by_name('softmax/Reshape_1:0') 25 | inputs = tf.get_default_graph().get_tensor_by_name('Placeholder:0') 26 | is_training = tf.get_default_graph().get_tensor_by_name('Placeholder_2:0') 27 | deepid = tf.get_default_graph().get_tensor_by_name('fully_connected/Relu:0') 28 | keep_prob = tf.get_default_graph().get_tensor_by_name('Placeholder_3:0') 29 | argmax = tf.get_default_graph().get_tensor_by_name('ArgMax_1:0') 30 | ident_fc = tf.get_default_graph().get_tensor_by_name('fully_connected_1/Relu:0') 31 | 32 | data = np.load('{}/dataset/lfw/image_mean_and_std.npz'.format(dirname)) 33 | mean = data['channelMean'] 34 | std = data['std'] 35 | image = cv2.imread(imagePath) 36 | image = cv2.resize(image, (47, 55), cv2.INTER_CUBIC) 37 | imageCopy = np.copy(image) 38 | image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32) 39 | image -= mean 40 | image /= std + 1e-7 41 | image = np.expand_dims(image, 0) 42 | 43 | pred = sess.run(softmax, feed_dict={ 44 | inputs: image, 45 | is_training: False, 46 | keep_prob: 1 47 | }) 48 | 49 | # print 'pred', pred 50 | # print 'sorted', np.argsort(pred[0])[::-1] 51 | # print sk.mapTargetToName('lfwColor_0.5' , pred[0]) 52 | 53 | indices = np.argsort(pred[0])[::-1] 54 | for j in range(10): 55 | print(sk.mapTargetToName('lfwColor_0.5', indices[j]), pred[0][indices[j]]) 56 | 57 | cv2.imshow('test', imageCopy) 58 | cv2.waitKey(0) 59 | -------------------------------------------------------------------------------- /model/my_verification_model.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | from tensorflow.contrib import slim 4 | 5 | 6 | def get_model(lr, global_step=None): 7 | layers = {} 8 | train_ops = {} 9 | # todo: stack inputs 10 | layers['l_inputs'] = tf.placeholder(tf.float32, shape=[None, 160], name='l_inputs') 11 | layers['r_inputs'] = tf.placeholder(tf.float32, shape=[None, 160], name='r_inputs') 12 | layers['verif_labels'] = tf.placeholder(tf.int64, shape=[None, ], name='verif_labels') 13 | layers['keep_prob'] = tf.placeholder(tf.float32, name='keep_prob') 14 | layers['is_training'] = tf.placeholder(tf.bool, name='is_training') 15 | 16 | with slim.arg_scope([slim.fully_connected], 17 | weights_initializer=tf.contrib.layers.xavier_initializer(), 18 | weights_regularizer=slim.l2_regularizer(0.0005), 19 | biases_initializer=tf.constant_initializer(0.1), 20 | activation_fn=tf.nn.relu): 21 | layers['l_local_fc'] = slim.fully_connected(layers['l_inputs'], 80, scope='l_local_fc') 22 | layers['r_local_fc'] = slim.fully_connected(layers['r_inputs'], 80, scope='r_local_fc') 23 | layers['concat_local_fc'] = tf.concat([layers['l_local_fc'], layers['r_local_fc']], 1, 24 | name='concat_local_fc') 25 | 26 | layers['fc_1'] = slim.fully_connected(layers['concat_local_fc'], 4800, scope='fc_1') 27 | layers['fc_1_dropout'] = slim.dropout(layers['fc_1'], keep_prob=layers['keep_prob'], 28 | is_training=layers['is_training'], scope='fc_1_dropout') 29 | 30 | layers['output_fc'] = slim.fully_connected(layers['fc_1_dropout'], 2, scope='output', activation_fn=tf.identity) 31 | layers['output_softmax'] = slim.softmax(layers['output_fc'], scope='output_softmax') 32 | layers['softmax_loss'] = tf.losses.sparse_softmax_cross_entropy(labels=layers['verif_labels'], 33 | logits=layers['output_fc']) 34 | 35 | layers['argmax'] = tf.argmax(layers['output_fc'], axis=1, name='argmax') 36 | layers['equal'] = tf.equal(layers['argmax'], layers['verif_labels'], name='equal') 37 | layers['cast'] = tf.cast(layers['equal'], dtype=tf.float32, name='cast') 38 | layers['accuracy'] = tf.reduce_mean(layers['cast'], name='accuracy') 39 | 40 | verif_optimizer = tf.train.MomentumOptimizer(lr, 0.9) 41 | verif_op = verif_optimizer.minimize(layers['softmax_loss'], global_step=global_step) 42 | 43 | train_ops['verif_op'] = verif_op 44 | 45 | return layers, train_ops 46 | -------------------------------------------------------------------------------- /dataset/crop_face.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | import os 4 | 5 | import sys 6 | 7 | 8 | def cropCenterFaceByRatio(image, widthRatio, heightRatio, croppedSize): 9 | height, width = image.shape[:2] 10 | leftRightRatio = widthRatio / 2 11 | topBottomRatio = heightRatio / 2 12 | centerX = width / 2 13 | centerY = height / 2 14 | leftRightWidth = width * leftRightRatio 15 | topBottomHeight = height * topBottomRatio 16 | x1, y1 = max(0, centerX - leftRightWidth), max(0, centerY - topBottomHeight) 17 | x2, y2 = min(centerX + leftRightWidth, width), min(centerY + topBottomHeight, height) 18 | return image[y1:y2, x1:x2] 19 | 20 | 21 | def cropFaceByBoundingBoxFromDir(datadir, bboxes, croppedSize, saveDir): 22 | i = 1 23 | for root, dirs, files in os.walk(datadir): 24 | if files != []: 25 | for filename in files: 26 | imagePath = os.path.join(root, filename) 27 | classname = os.path.basename(os.path.dirname(imagePath)) 28 | basename = os.path.basename(imagePath) 29 | basename, extension = os.path.splitext(basename) 30 | 31 | if extension.lower() == '.gif': 32 | extension = '.png' 33 | 34 | if imagePath not in bboxes: 35 | continue 36 | 37 | savepath = '{}/{}/{}{}'.format(saveDir, classname, basename, extension) 38 | sys.stdout.write('\r{} {}/{} image(s)'.format(savepath, i, len(bboxes))) 39 | sys.stdout.flush() 40 | i += 1 41 | 42 | if os.path.exists(savepath): 43 | continue 44 | 45 | bbox = bboxes[imagePath] 46 | x1, y1, x2, y2 = bbox 47 | image = cv2.imread(imagePath) 48 | 49 | if image is None: 50 | continue 51 | 52 | croppedImage = image[y1:y2, x1:x2] 53 | resizedImage = cv2.resize(croppedImage, croppedSize, interpolation=cv2.INTER_AREA) 54 | 55 | if not os.path.exists(os.path.dirname(savepath)): 56 | os.makedirs(os.path.dirname(savepath)) 57 | 58 | cv2.imwrite(savepath, resizedImage) 59 | print('done!') 60 | 61 | 62 | def main(): 63 | dirname = os.path.dirname(__file__) 64 | dataDir = '{}/facescrub'.format(dirname) 65 | saveDir = '{}/facescrub_crop'.format(dirname) 66 | bboxesPath = '{}/facescrub_bbox.txt'.format(dirname) 67 | bboxes = {} 68 | 69 | with open(bboxesPath) as f: 70 | for line in f: 71 | filepath, bbox = line.split('\t') 72 | bbox = [int(v) for v in bbox.split(',')] 73 | bboxes[filepath] = bbox 74 | 75 | cropFaceByBoundingBoxFromDir(dataDir, bboxes, (47, 55), saveDir) 76 | 77 | 78 | if __name__ == '__main__': 79 | main() 80 | -------------------------------------------------------------------------------- /dataset/separate_trainvaltest.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import numpy as np 4 | import shutil 5 | 6 | import sys 7 | 8 | 9 | def isValidExtension(path): 10 | extension = os.path.splitext(path)[1] 11 | return extension.lower() in ['.jpg', '.jpeg', '.png', '.gif'] 12 | 13 | 14 | def separateToTrainValTest(datadir, trainRatio, valRatio, testRatio): 15 | if sum([trainRatio, valRatio, testRatio]) != 1: 16 | raise Exception('sum of ratio parameter not equal 1') 17 | 18 | 19 | for root, dirs, files in os.walk(datadir): 20 | if dirs != []: 21 | for dir in dirs: 22 | dirpath = os.path.join(root, dir) 23 | filenames = os.listdir(dirpath) 24 | 25 | np.random.seed(np.random.randint(100000)) 26 | np.random.shuffle(filenames) 27 | 28 | total = len(filenames) 29 | valLength = int(total * valRatio) 30 | testLength = int(total * testRatio) 31 | trainLength = total - valLength - testLength 32 | 33 | sys.stdout.write('\rprocessing {}'.format(dir)) 34 | sys.stdout.flush() 35 | 36 | j = 0 37 | 38 | if not os.path.exists(os.path.join(datadir + '_val', dir)): 39 | os.makedirs(os.path.join(datadir + '_val', dir)) 40 | 41 | if not os.path.exists(os.path.join(datadir + '_test', dir)): 42 | os.makedirs(os.path.join(datadir + '_test', dir)) 43 | 44 | if not os.path.exists(os.path.join(datadir + '_train', dir)): 45 | os.makedirs(os.path.join(datadir + '_train', dir)) 46 | 47 | for _ in range(valLength): 48 | filepath = os.path.join(root, dir, filenames[j]) 49 | newfilepath = os.path.join(datadir + '_val', dir, filenames[j]) 50 | if not os.path.exists(newfilepath): 51 | shutil.copy(filepath, newfilepath) 52 | j += 1 53 | 54 | for _ in range(testLength): 55 | filepath = os.path.join(root, dir, filenames[j]) 56 | newfilepath = os.path.join(datadir + '_test', dir, filenames[j]) 57 | if not os.path.exists(newfilepath): 58 | shutil.copy(filepath, newfilepath) 59 | j += 1 60 | 61 | for _ in range(trainLength): 62 | filepath = os.path.join(root, dir, filenames[j]) 63 | newfilepath = os.path.join(datadir + '_train', dir, filenames[j]) 64 | if not os.path.exists(newfilepath): 65 | shutil.copy(filepath, newfilepath) 66 | j += 1 67 | 68 | print('done') 69 | 70 | def main(): 71 | dirname = os.path.dirname(__file__) 72 | dataDir = '{}/facescrub_crop'.format(dirname) 73 | separateToTrainValTest(dataDir, 0.7, 0.1, 0.2) 74 | 75 | if __name__ == '__main__': 76 | main() -------------------------------------------------------------------------------- /dataset/compute_imagemean.py: -------------------------------------------------------------------------------- 1 | import os 2 | import cv2 3 | import numpy as np 4 | import sys 5 | 6 | 7 | def computeImageMean(datadir, grayscale=False): 8 | channel = 1 if grayscale else 3 9 | mean = np.zeros((1, 1, channel), dtype=np.float64) 10 | nImages = 0 11 | imageShape = None 12 | 13 | print('computing image mean') 14 | 15 | for root, dirs, files in os.walk(datadir): 16 | if files != []: 17 | for filename in files: 18 | filepath = os.path.join(root, filename) 19 | 20 | sys.stdout.write('\rprocessing {}'.format(filepath)) 21 | sys.stdout.flush() 22 | 23 | if grayscale: 24 | image = cv2.imread(filepath, 0) 25 | else: 26 | image = cv2.imread(filepath) 27 | 28 | if image.shape[:2] != [55, 47]: 29 | image = cv2.resize(image, (47, 55), interpolation=cv2.INTER_AREA) 30 | 31 | imageShape = image.shape 32 | imageMean = np.mean(image, axis=(0, 1)).reshape((1, 1, channel)) 33 | 34 | mean += imageMean 35 | nImages += 1 36 | 37 | mean /= nImages 38 | print 39 | return mean, nImages, imageShape 40 | 41 | 42 | def computeImageStd(datadir, mean, nImages, imageShape, grayscale=False): 43 | channel = 1 if grayscale else 3 44 | sumsquare = np.zeros((imageShape[0], imageShape[1], channel), dtype=np.float64) 45 | rcount = nImages * imageShape[0] * imageShape[1] 46 | 47 | print('computing image std') 48 | 49 | for root, dirs, files in os.walk(datadir): 50 | if files != []: 51 | for filename in files: 52 | filepath = os.path.join(root, filename) 53 | 54 | sys.stdout.write('\rprocessing {}'.format(filepath)) 55 | sys.stdout.flush() 56 | 57 | if grayscale: 58 | image = cv2.imread(filepath, 0) 59 | else: 60 | image = cv2.imread(filepath) 61 | 62 | if image.shape[:2] != [55, 47]: 63 | image = cv2.resize(image, (47, 55), interpolation=cv2.INTER_AREA) 64 | 65 | image_mean = image - mean # image minus mean 66 | image_mean = np.square(image_mean) 67 | 68 | sumsquare += image_mean 69 | 70 | sumsquare = np.sum(sumsquare, axis=(0, 1), keepdims=True) 71 | variance = sumsquare / rcount 72 | std = np.sqrt(variance) 73 | print 74 | return std 75 | 76 | 77 | def main(): 78 | dirname = os.path.dirname(__file__) 79 | imageMeanPath = '{}/facescrub_meanstd/mean'.format(dirname) 80 | imageStdPath = '{}/facescrub_meanstd/std'.format(dirname) 81 | 82 | imageDir = '{}/facescrub_crop_train'.format(dirname) 83 | 84 | mean, nImages, imageShape = computeImageMean(imageDir) 85 | std = computeImageStd(imageDir, mean, nImages, imageShape) 86 | 87 | if not os.path.exists(os.path.dirname(imageMeanPath)): 88 | os.makedirs(os.path.dirname(imageMeanPath)) 89 | 90 | if not os.path.exists(os.path.dirname(imageStdPath)): 91 | os.makedirs(os.path.dirname(imageStdPath)) 92 | 93 | np.save(imageMeanPath, mean) 94 | np.save(imageStdPath, std) 95 | 96 | 97 | if __name__ == '__main__': 98 | main() 99 | -------------------------------------------------------------------------------- /model/deep_id.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | from tensorflow.contrib import slim 4 | from tensorflow.contrib import keras 5 | 6 | def leaky_relu(alpha): 7 | def op(inputs): 8 | return tf.maximum(alpha * inputs, inputs, name='leaky_relu') 9 | return op 10 | 11 | def get_model(lr, n_classes, global_step=None): 12 | layers = {} 13 | train_ops = {} 14 | 15 | layers['inputs'] = tf.placeholder(dtype=tf.float32, 16 | shape=[None, 55, 47, 3]) 17 | 18 | # layers['zero_mean'] = tf.map_fn(lambda i: tf.image.per_image_standardization(i), layers['inputs']) 19 | layers['labels'] = tf.placeholder(dtype=tf.int64, 20 | shape=[None,]) 21 | # layers['onehot_labels'] = tf.one_hot(layers['labels'], n_classes) 22 | layers['is_training'] = tf.placeholder(dtype=tf.bool) 23 | layers['keep_prob'] = tf.placeholder(dtype=tf.float32) 24 | 25 | # inference 26 | with slim.arg_scope([slim.conv2d, slim.fully_connected], 27 | weights_initializer=tf.contrib.layers.xavier_initializer(), 28 | weights_regularizer=slim.l2_regularizer(0.0005), 29 | biases_initializer=tf.constant_initializer(0.1), 30 | activation_fn=tf.nn.relu): 31 | with slim.arg_scope([slim.conv2d], 32 | padding='VALID'): 33 | layers['conv1'] = slim.conv2d(layers['inputs'], 20, 4, 1) 34 | # layers['bn1'] = slim.batch_norm(layers['conv1'], is_training=layers['is_training']) 35 | layers['pool1'] = slim.max_pool2d(layers['conv1'], 2, 2) 36 | 37 | layers['conv2'] = slim.conv2d(layers['pool1'], 40, 3, 1) 38 | layers['pool2'] = slim.max_pool2d(layers['conv2'], 2, 2) 39 | 40 | layers['conv3'] = slim.conv2d(layers['pool2'], 60, 3, 1) 41 | layers['pool3'] = slim.max_pool2d(layers['conv3'], 2, 2) 42 | 43 | layers['conv4'] = keras.layers.LocallyConnected2D(80, 2, 1, activation=tf.nn.relu)(layers['pool3']) 44 | # layers['conv4'] = slim.conv2d(layers['pool3'], 80, 2, 1) 45 | layers['flatten_pool3'] = slim.flatten(layers['pool3']) 46 | layers['flatten_conv4'] = slim.flatten(layers['conv4']) 47 | 48 | layers['concat'] = tf.concat([layers['flatten_conv4'], layers['flatten_pool3']], 1) 49 | layers['deepid_fc'] = slim.fully_connected(layers['concat'], 160) 50 | layers['deepid_dropout'] = slim.dropout(layers['deepid_fc'], layers['keep_prob'], is_training=layers['is_training']) 51 | 52 | layers['ident_fc'] = slim.fully_connected(layers['deepid_dropout'], n_classes, activation_fn=tf.identity) 53 | layers['ident_softmax'] = slim.softmax(layers['ident_fc']) 54 | # print layers['ident_softmax'] 55 | layers['ident_pred'] = tf.argmax(layers['ident_softmax'], axis=1) 56 | 57 | layers['argmax'] = tf.argmax(layers['ident_fc'], axis=1) 58 | # print layers['argmax'] 59 | layers['equal'] = tf.equal(layers['argmax'], layers['labels']) 60 | layers['cast'] = tf.cast(layers['equal'], tf.float32) 61 | 62 | layers['accuracy'] = tf.reduce_mean(layers['cast']) 63 | 64 | layers['loss'] = tf.losses.sparse_softmax_cross_entropy(labels=layers['labels'], 65 | logits=layers['ident_fc']) 66 | 67 | layers['softmax_error'] = tf.reduce_mean(tf.cast(tf.not_equal(layers['ident_pred'], layers['labels']), tf.float32)) 68 | 69 | # vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES) 70 | # layers['grad'] = tf.gradients(layers['loss'], vars) 71 | # layers['updates'] = [] 72 | # for v, grad in zip(vars, layers['grad']): 73 | # layers['updates'].append(tf.assign_sub(v, lr*grad)) 74 | # 75 | # train_op = tf.group(*layers['updates']) 76 | 77 | # ident_optimizer = tf.train.RMSPropOptimizer(lr, momentum=0.1) 78 | # ident_optimizer = tf.train.AdamOptimizer(lr) 79 | ident_optimizer = tf.train.MomentumOptimizer(lr, 0.9, use_nesterov=True) 80 | # ident_optimizer = tf.train.GradientDescentOptimizer(lr) 81 | ident_op = ident_optimizer.minimize(layers['loss'], global_step=global_step) 82 | 83 | # train_ops['ident'] = train_op 84 | train_ops['ident'] = ident_op 85 | 86 | return layers, train_ops 87 | 88 | # get_model(0.1, 2) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | absl-py==0.7.1 2 | alabaster==0.7.12 3 | altgraph==0.16.1 4 | anaconda-client==1.7.2 5 | anaconda-project==0.8.2 6 | asn1crypto==0.24.0 7 | astor==0.8.0 8 | astroid==2.2.5 9 | astropy==3.1.2 10 | atomicwrites==1.3.0 11 | attrs==19.1.0 12 | Babel==2.6.0 13 | backcall==0.1.0 14 | backports.os==0.1.1 15 | backports.shutil-get-terminal-size==1.0.0 16 | beautifulsoup4==4.7.1 17 | bitarray==0.8.3 18 | bkcharts==0.2 19 | bleach==3.1.0 20 | bokeh==1.0.4 21 | boto==2.49.0 22 | Bottleneck==1.2.1 23 | certifi==2019.3.9 24 | cffi==1.12.2 25 | chardet==3.0.4 26 | Click==7.0 27 | cloudpickle==0.8.0 28 | clyent==1.2.2 29 | cmake==3.14.4 30 | colorama==0.4.1 31 | comtypes==1.1.7 32 | contextlib2==0.5.5 33 | cryptography==2.6.1 34 | cycler==0.10.0 35 | Cython==0.29.6 36 | cytoolz==0.9.0.1 37 | dask==1.1.4 38 | decorator==4.4.0 39 | defusedxml==0.5.0 40 | distributed==1.26.0 41 | dlib==19.7.0 42 | docutils==0.14 43 | entrypoints==0.3 44 | et-xmlfile==1.0.1 45 | fastcache==1.0.2 46 | Flask==1.0.2 47 | future==0.17.1 48 | gast==0.2.2 49 | gevent==1.4.0 50 | google-pasta==0.1.7 51 | greenlet==0.4.15 52 | grpcio==1.22.0 53 | h5py==2.9.0 54 | heapdict==1.0.0 55 | html5lib==1.0.1 56 | idna==2.8 57 | imageio==2.5.0 58 | imagesize==1.1.0 59 | importlib-metadata==0.0.0 60 | ipykernel==5.1.0 61 | ipython==7.4.0 62 | ipython-genutils==0.2.0 63 | ipywidgets==7.4.2 64 | isort==4.3.16 65 | itsdangerous==1.1.0 66 | jdcal==1.4 67 | jedi==0.13.3 68 | Jinja2==2.10 69 | jsonschema==3.0.1 70 | jupyter==1.0.0 71 | jupyter-client==5.2.4 72 | jupyter-console==6.0.0 73 | jupyter-core==4.4.0 74 | jupyterlab==0.35.4 75 | jupyterlab-server==0.2.0 76 | Keras==2.2.4 77 | Keras-Applications==1.0.8 78 | Keras-Preprocessing==1.1.0 79 | keyring==18.0.0 80 | kiwisolver==1.0.1 81 | lazy-object-proxy==1.3.1 82 | llvmlite==0.28.0 83 | locket==0.2.0 84 | lxml==4.3.2 85 | macholib==1.11 86 | Markdown==3.1.1 87 | MarkupSafe==1.1.1 88 | matplotlib==3.0.3 89 | mccabe==0.6.1 90 | menuinst==1.4.16 91 | mistune==0.8.4 92 | mkl-fft==1.0.10 93 | mkl-random==1.0.2 94 | more-itertools==6.0.0 95 | mpmath==1.1.0 96 | msgpack==0.6.1 97 | multipledispatch==0.6.0 98 | nbconvert==5.4.1 99 | nbformat==4.4.0 100 | networkx==2.2 101 | nltk==3.4 102 | nose==1.3.7 103 | notebook==5.7.8 104 | numba==0.43.1 105 | numexpr==2.6.9 106 | numpy==1.16.4 107 | numpydoc==0.8.0 108 | olefile==0.46 109 | opencv-python==4.1.0.25 110 | openpyxl==2.6.1 111 | packaging==19.0 112 | pandas==0.24.2 113 | pandocfilters==1.4.2 114 | parso==0.3.4 115 | partd==0.3.10 116 | path.py==11.5.0 117 | pathlib2==2.3.3 118 | patsy==0.5.1 119 | pefile==2019.4.18 120 | pep8==1.7.1 121 | pickleshare==0.7.5 122 | Pillow==5.4.1 123 | pluggy==0.9.0 124 | ply==3.11 125 | prometheus-client==0.6.0 126 | prompt-toolkit==2.0.9 127 | protobuf==3.9.0 128 | psutil==5.6.1 129 | py==1.8.0 130 | pycodestyle==2.5.0 131 | pycosat==0.6.3 132 | pycparser==2.19 133 | pycrypto==2.6.1 134 | pycurl==7.43.0.2 135 | pyflakes==2.1.1 136 | Pygments==2.3.1 137 | PyInstaller==3.4 138 | pylint==2.3.1 139 | pyodbc==4.0.26 140 | pyOpenSSL==19.0.0 141 | pyparsing==2.3.1 142 | pyreadline==2.1 143 | pyrsistent==0.14.11 144 | PySocks==1.6.8 145 | pytest==4.3.1 146 | pytest-arraydiff==0.3 147 | pytest-astropy==0.5.0 148 | pytest-doctestplus==0.3.0 149 | pytest-openfiles==0.3.2 150 | pytest-remotedata==0.3.1 151 | python-dateutil==2.8.0 152 | pytz==2018.9 153 | PyWavelets==1.0.2 154 | pywin32==223 155 | pywin32-ctypes==0.2.0 156 | pywinpty==0.5.5 157 | PyYAML==5.1 158 | pyzmq==18.0.0 159 | QtAwesome==0.5.7 160 | qtconsole==4.4.3 161 | QtPy==1.7.0 162 | requests==2.21.0 163 | rope==0.12.0 164 | ruamel-yaml==0.15.46 165 | scikit-image==0.14.2 166 | scikit-learn==0.20.3 167 | scipy==1.2.1 168 | seaborn==0.9.0 169 | Send2Trash==1.5.0 170 | simplegeneric==0.8.1 171 | singledispatch==3.4.0.3 172 | six==1.12.0 173 | snowballstemmer==1.2.1 174 | sortedcollections==1.1.2 175 | sortedcontainers==2.1.0 176 | soupsieve==1.8 177 | Sphinx==1.8.5 178 | sphinxcontrib-websupport==1.1.0 179 | spyder==3.3.3 180 | spyder-kernels==0.4.2 181 | SQLAlchemy==1.3.1 182 | statsmodels==0.9.0 183 | sympy==1.3 184 | tables==3.5.1 185 | tblib==1.3.2 186 | tensorboard==1.12.2 187 | tensorflow-estimator==1.14.0 188 | tensorflow-gpu==1.12.0 189 | termcolor==1.1.0 190 | terminado==0.8.1 191 | testpath==0.4.2 192 | toolz==0.9.0 193 | torch==1.1.0 194 | torchvision==0.3.0 195 | tornado==6.0.2 196 | traitlets==4.3.2 197 | typed-ast==1.3.1 198 | unicodecsv==0.14.1 199 | urllib3==1.24.1 200 | wcwidth==0.1.7 201 | webencodings==0.5.1 202 | Werkzeug==0.15.4 203 | widgetsnbextension==3.4.2 204 | win-inet-pton==1.1.0 205 | win-unicode-console==0.5 206 | wincertstore==0.2 207 | wrapt==1.11.1 208 | xlrd==1.2.0 209 | XlsxWriter==1.1.5 210 | xlwings==0.15.4 211 | xlwt==1.3.0 212 | zict==0.1.4 213 | zipp==0.3.3 214 | -------------------------------------------------------------------------------- /dataset/sklearn_dataset.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | from sklearn.datasets import lfw 3 | from keras.preprocessing.image import ImageDataGenerator 4 | import numpy as np 5 | import os 6 | 7 | dirname = os.path.dirname(__file__) 8 | 9 | lfwData = { 10 | 'lfwColor_0.5': lfw.fetch_lfw_people('{}/lfw/dataset'.format(dirname), 11 | min_faces_per_person=10, 12 | color=True), 13 | # 'lfwGray_0.5': lfw.fetch_lfw_people('{}/lfw/dataset'.format(dirname), 14 | # min_faces_per_person=20, 15 | # color=False) 16 | } 17 | # lfwData['lfwGray_0.5'].images = np.expand_dims(lfwData['lfwGray_0.5'].images, -1) 18 | 19 | lfwDataGenerator = { 20 | 'augmentedDataGenerator': ImageDataGenerator(featurewise_center=True, 21 | featurewise_std_normalization=True, 22 | data_format='channels_last', 23 | horizontal_flip=True, 24 | width_shift_range=0.1, 25 | height_shift_range=0.1, 26 | rotation_range=20, 27 | zoom_range=0.2), 28 | 'defaultDataGenerator': ImageDataGenerator(featurewise_center=True, 29 | featurewise_std_normalization=True, 30 | data_format='channels_last', 31 | horizontal_flip=True) 32 | } 33 | 34 | 35 | def mapTargetToName(key, target): 36 | return lfwData[key].target_names[target] 37 | 38 | 39 | def separateToTrainValTest(key, trainRatio, valRatio, testRatio): 40 | if os.path.exists('{}/lfw/{}.npy'.format(dirname, key)): 41 | indices = np.load('{}/lfw/{}.npy'.format(dirname, key)) 42 | trainIndices = indices[0] 43 | valIndices = indices[1] 44 | testIndices = indices[2] 45 | 46 | trainX = lfwData[key].images[trainIndices] 47 | trainY = lfwData[key].target[trainIndices] 48 | 49 | valX = lfwData[key].images[valIndices] 50 | valY = lfwData[key].target[valIndices] 51 | 52 | testX = lfwData[key].images[testIndices] 53 | testY = lfwData[key].target[testIndices] 54 | 55 | return (trainX, trainY), (valX, valY), (testX, testY) 56 | 57 | if key not in lfwData: 58 | raise Exception('please create dataset for {}'.format(key)) 59 | 60 | if sum([trainRatio, valRatio, testRatio]) != 1: 61 | raise Exception('sum of ratio parameter not equal 1') 62 | 63 | trainIndices = [] 64 | valIndices = [] 65 | testIndices = [] 66 | 67 | for i, name in enumerate(lfwData[key].target_names): 68 | personIndices = np.argwhere(lfwData[key].target == i) 69 | np.random.seed(np.random.randint(100000)) 70 | np.random.shuffle(personIndices) 71 | total = personIndices.shape[0] 72 | valLength = int(total * valRatio) 73 | testLength = int(total * testRatio) 74 | trainLength = total - valLength - testLength 75 | j = 0 76 | for _ in xrange(valLength): 77 | valIndices.append(personIndices[j]) 78 | j += 1 79 | 80 | for _ in xrange(testLength): 81 | testIndices.append(personIndices[j]) 82 | j += 1 83 | 84 | for _ in xrange(trainLength): 85 | trainIndices.append(personIndices[j]) 86 | j += 1 87 | 88 | trainIndices = np.squeeze(np.vstack(trainIndices), axis=1) 89 | valIndices = np.squeeze(np.vstack(valIndices), axis=1) 90 | testIndices = np.squeeze(np.vstack(testIndices), axis=1) 91 | 92 | np.save('{}/lfw/{}'.format(dirname, key), [trainIndices, valIndices, testIndices]) 93 | 94 | trainX, trainY = lfwData[key].images[trainIndices], lfwData[key].target[trainIndices] 95 | valX, valY = lfwData[key].images[valIndices], lfwData[key].target[valIndices] 96 | testX, testY = lfwData[key].images[testIndices], lfwData[key].target[testIndices] 97 | 98 | return (trainX, trainY), (valX, valY), (testX, testY) 99 | 100 | 101 | def getClasses(key): 102 | return len(lfwData[key].target_names) 103 | 104 | 105 | def getDataGenerator(dataGeneratorKey, X, Y, batchSize, shuffle, scaledSize=None, fit=False, trainKey=None): 106 | dataGenerator = lfwDataGenerator[dataGeneratorKey] 107 | 108 | # resize if needed 109 | if scaledSize: 110 | def resize(x): 111 | return cv2.resize(x, (scaledSize[1], scaledSize[0])) 112 | 113 | newX = np.zeros((X.shape[0], scaledSize[0], scaledSize[1], X.shape[3]), dtype=X.dtype) 114 | 115 | for i in range(X.shape[0]): 116 | newX[i] = resize(X[i]) 117 | 118 | X = newX 119 | 120 | if fit: 121 | dataGenerator.fit(X) 122 | np.savez('{}/lfw/image_mean_and_std'.format(dirname), 123 | mean=dataGenerator.mean, 124 | std=dataGenerator.std) # for testing stage 125 | else: 126 | if trainKey: 127 | trainDataGenerator = lfwDataGenerator[trainKey] 128 | if trainDataGenerator.mean is not None: 129 | dataGenerator.mean = trainDataGenerator.mean 130 | dataGenerator.std = trainDataGenerator.std 131 | else: 132 | raise Exception('please create train data generator first') 133 | 134 | generator = dataGenerator.flow(X, Y, 135 | batchSize, 136 | shuffle, 137 | seed=np.random.randint(100000)) 138 | return generator 139 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import numpy as np 4 | import tensorflow as tf 5 | 6 | import graph 7 | from dataset import sklearn_dataset as sk 8 | from dataset import facescrub_dataset as fs 9 | from model import deep_id 10 | import time 11 | 12 | 13 | def pipeline_deepid(): 14 | subjectName = 'face-recog-{}'.format(time.time()) 15 | # subjectName = 'face-recog-{}'.format('1511344323.48') 16 | dirname = os.path.dirname(__file__) 17 | config = tf.ConfigProto() 18 | config.gpu_options.allow_growth = True 19 | 20 | lr = 0.01 21 | # lr = 0.001 22 | # lr = 0.0001 23 | # lr = 0.00001 24 | batchSize = 500 25 | trainEpoch = 100 26 | 27 | trainLFW = False 28 | 29 | if trainLFW: 30 | key = 'lfwColor_0.5' 31 | (trainX, trainY), (valX, valY), (testX, testY) = sk.separateToTrainValTest(key, 0.7, 0.1, 0.2) 32 | trainDataGenerator = sk.getDataGenerator('augmentedDataGenerator', 33 | X=trainX, 34 | Y=trainY, 35 | batchSize=batchSize, 36 | shuffle=True, 37 | scaledSize=(55, 47), 38 | fit=True) 39 | valDataGenerator = sk.getDataGenerator('defaultDataGenerator', 40 | X=valX, 41 | Y=valY, 42 | batchSize=batchSize, 43 | shuffle=True, 44 | scaledSize=(55, 47), 45 | trainKey='augmentedDataGenerator') 46 | testDataGenerator = sk.getDataGenerator('defaultDataGenerator', 47 | X=testX, 48 | Y=testY, 49 | batchSize=batchSize, 50 | shuffle=True, 51 | scaledSize=(55, 47), 52 | trainKey='augmentedDataGenerator') 53 | trainSteps = trainEpoch * (trainX.shape[0] / batchSize) 54 | testSteps = int(testX.shape[0] / batchSize) 55 | nClasses = sk.getClasses(key) 56 | else: 57 | datadirPrefix = '{}/dataset/facescrub_crop'.format(dirname) 58 | meanstdDir = '{}/dataset/facescrub_meanstd'.format(dirname) 59 | nClasses = len(os.listdir(datadirPrefix)) 60 | trainDataDir = datadirPrefix + '_train' 61 | valDataDir = datadirPrefix + '_val' 62 | testDataDir = datadirPrefix + '_test' 63 | 64 | trainDataGenerator, nTrainImages = fs.getDataGenerator(trainDataDir, meanstdDir, batchSize, True) 65 | valDataGenerator, nValImages = fs.getDataGenerator(valDataDir, meanstdDir, batchSize, True) 66 | testDataGenerator, nTestImages = fs.getDataGenerator(testDataDir, meanstdDir, batchSize, True) 67 | 68 | print('train -', nTrainImages) 69 | print('val -', nValImages) 70 | print('test -', nTestImages) 71 | print('classes -', nClasses) 72 | 73 | trainSteps = trainEpoch * int(nTrainImages / batchSize) 74 | testSteps = int(nTestImages / batchSize) 75 | valSteps = int(nValImages / batchSize) 76 | 77 | fig1, ax1 = graph.getFigAx() 78 | fig2, ax2 = graph.getFigAx() 79 | 80 | with tf.Session(config=config) as sess: 81 | globalStep = tf.Variable(0, trainable=False) 82 | # learningRate = tf.train.exponential_decay(lr, globalStep, 100000, 0.5) 83 | learningRate = tf.constant(lr) 84 | 85 | valInterval = 1 86 | saveInterval = 500 87 | updateInterval = 500 88 | saveDir = '{}/trained/{}'.format(dirname, subjectName) 89 | 90 | layers, train_ops = deep_id.get_model(learningRate, nClasses, globalStep) 91 | 92 | # for node in tf.get_default_graph().as_graph_def().node: 93 | # print node.name 94 | 95 | sess.run(tf.global_variables_initializer()) 96 | saver = tf.train.Saver(max_to_keep=None) 97 | 98 | layerFetches = [layers['loss'], 99 | layers['accuracy']] 100 | fetches = layerFetches + train_ops.values() 101 | 102 | trainLosses = [] 103 | trainAccuracy = [] 104 | valLosses = [] 105 | valAccuracy = [] 106 | # trainLosses, trainAccuracy, valLosses, valAccuracy = load('{}/trained/{}'.format(dirname, subjectName), 107 | # subjectName, 108 | # 49280, 109 | # saver, 110 | # sess, 111 | # globalStep) 112 | 113 | print('current learning rate', sess.run(learningRate)) 114 | 115 | for step in range(trainSteps): 116 | x, y = trainDataGenerator.next() 117 | loss, acc = sess.run(fetches, feed_dict={ 118 | layers['inputs']: x, 119 | layers['labels']: y, 120 | layers['is_training']: True, 121 | layers['keep_prob']: 0.5 122 | })[:2] 123 | 124 | trainLosses.append(loss) 125 | trainAccuracy.append(acc) 126 | 127 | if step % valInterval == 0: 128 | x, y = valDataGenerator.next() 129 | loss, acc = sess.run(layerFetches, feed_dict={ 130 | layers['inputs']: x, 131 | layers['labels']: y, 132 | layers['is_training']: False, 133 | layers['keep_prob']: 1.0 134 | }) 135 | 136 | valLosses.append(loss) 137 | valAccuracy.append(acc) 138 | 139 | if step % updateInterval == 0: 140 | graph.refresh(fig1, ax1, trainLosses[::updateInterval], 'b-') 141 | graph.refresh(fig1, ax1, trainAccuracy[::updateInterval], 'r-') 142 | graph.refresh(fig2, ax2, valLosses[::updateInterval], 'b-') 143 | graph.refresh(fig2, ax2, valAccuracy[::updateInterval], 'r-') 144 | 145 | print('---', step, '---') 146 | print('last train', trainLosses[-1], trainAccuracy[-1]) 147 | print('last validation', valLosses[-1], valAccuracy[-1]) 148 | 149 | if step % saveInterval == 0: 150 | save(saveDir, 151 | subjectName, 152 | saver, 153 | sess, 154 | globalStep, 155 | trainLosses, 156 | trainAccuracy, 157 | valLosses, 158 | valAccuracy) 159 | 160 | testLosses = [] 161 | testAccuracy = [] 162 | 163 | testDataRes = [] 164 | 165 | for tsteps in range(testSteps): 166 | x, y = testDataGenerator.next() 167 | 168 | loss, acc = sess.run(layerFetches, feed_dict={ 169 | layers['inputs']: x, 170 | layers['labels']: y, 171 | layers['is_training']: False, 172 | layers['keep_prob']: 1.0 173 | }) 174 | 175 | pred, softmax = sess.run([layers['ident_pred'], layers['ident_softmax']], feed_dict={ 176 | layers['inputs']: x, 177 | layers['is_training']: False, 178 | layers['keep_prob']: 1.0 179 | }) 180 | 181 | testDataRes.append((x, y, pred, softmax)) 182 | 183 | testLosses.append(loss) 184 | testAccuracy.append(acc) 185 | 186 | print('average testing', np.mean(testLosses), np.mean(testAccuracy)) 187 | 188 | # if not trainLFW: 189 | # meanstdDir = '{}/dataset/facescrub_meanstd'.format(dirname) 190 | # mean = np.load(meanstdDir + '/mean.npy') 191 | # std = np.load(meanstdDir + '/std.npy') 192 | # 193 | # saveErrorImages(testDataRes, mean, std) 194 | 195 | # save(saveDir, 196 | # subjectName, 197 | # saver, 198 | # sess, 199 | # globalStep, 200 | # trainLosses, 201 | # trainAccuracy, 202 | # valLosses, 203 | # valAccuracy) 204 | 205 | saveWeights(sess, '{}/trained_weight/{}'.format(dirname, subjectName)) 206 | 207 | graph.closeFig(fig1) 208 | graph.closeFig(fig2) 209 | 210 | 211 | def saveWeights(sess, weightsDir): 212 | weights = {} 213 | 214 | for v in tf.global_variables(): 215 | print(v.name) 216 | weights[v.name] = sess.run(v) 217 | 218 | np.savez(weightsDir, **weights) 219 | print('saved to', weightsDir + '.npz') 220 | 221 | 222 | def save(saveDir, subjectName, saver, sess, globalStep, trainLosses, trainAccuracy, valLosses, valAccuracy): 223 | savePath = saveDir + '/{}'.format(subjectName) 224 | print('saved to', saver.save(sess, savePath, global_step=globalStep)) 225 | 226 | np.savez(savePath + '-graph-{}'.format(sess.run(globalStep)), 227 | trainLosses=trainLosses, 228 | trainAccuracy=trainAccuracy, 229 | valLosses=valLosses, 230 | valAccuracy=valAccuracy) 231 | 232 | 233 | def load(loadDir, loadName, loadStep, saver, sess, globalStep): 234 | loadPath = loadDir + '/{}'.format(loadName) 235 | saver.restore(sess, loadPath + '-' + str(loadStep)) 236 | print('loaded ', loadPath + '-' + str(loadStep)) 237 | 238 | data = np.load(loadPath + '-graph-{}.npz'.format(sess.run(globalStep))) 239 | 240 | trainLosses = data['trainLosses'].tolist() 241 | trainAccuracy = data['trainAccuracy'].tolist() 242 | valLosses = data['valLosses'].tolist() 243 | valAccuracy = data['valAccuracy'].tolist() 244 | 245 | return trainLosses, trainAccuracy, valLosses, valAccuracy 246 | 247 | 248 | def saveErrorImages(testDataRes, mean, std): 249 | import cv2 250 | dirname = os.path.dirname(__file__) 251 | i = 0 252 | for x, y, pred, softmax in testDataRes: 253 | x *= (std + 1e-7) 254 | x += mean 255 | x = x.astype(np.uint8) 256 | 257 | for j in range(x.shape[0]): 258 | image = cv2.cvtColor(x[j], cv2.COLOR_RGB2BGR) 259 | label = np.squeeze(y[j]) 260 | p = np.squeeze(pred[j]) 261 | s = np.squeeze(np.max(softmax[j])) 262 | path = '{}/result/{}/{}_{}_{}.png'.format(dirname, label, p, s, i) 263 | if np.equal(label, p): 264 | continue 265 | 266 | if not os.path.exists(os.path.dirname(path)): 267 | os.makedirs(os.path.dirname(path)) 268 | # print image 269 | cv2.imwrite(path, image) 270 | 271 | i += 1 272 | 273 | 274 | if __name__ == '__main__': 275 | pipeline_deepid() 276 | --------------------------------------------------------------------------------