├── .gitignore ├── README.md ├── __init__.py ├── common ├── __init__.py └── metrics.py ├── data ├── __init__.py ├── createLabelsFile_iris.py ├── data_tf │ ├── __init__.py │ ├── dataset_factory_tf.py │ ├── dataset_tf.py │ ├── dataset_utils_tf.py │ └── datasets_tf.py ├── datasets_paths.py ├── helpers.py ├── helpers_dataset.py └── helpers_image.py ├── data_rel ├── __init__.py └── data_tf │ ├── __init__.py │ └── dataset_utils_tf.py ├── nets ├── __init__.py ├── alexnet.py ├── cifarnet.py ├── nets_factory.py └── spoofnet_y.py ├── pipeline_tf ├── __init__.py ├── build_image_data_y.py ├── eval_image_classifier_y.py ├── evaluation_y.py ├── image_utils.py ├── paths_namings.py ├── settings_default.py ├── slim_learning_y.py ├── train_image_classifier_y.py ├── y_flags.py └── y_script.sh ├── preprocessing ├── __init__.py ├── preprocessing_factory.py ├── vgg_preprocessing.py ├── y_preprocessing.py └── y_vgg_preprocessing.py └── y_script.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.pyc 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | env/ 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | .hypothesis/ 51 | 52 | # Translations 53 | *.mo 54 | *.pot 55 | 56 | # Django stuff: 57 | *.log 58 | local_settings.py 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # Jupyter Notebook 74 | .ipynb_checkpoints 75 | 76 | # pyenv 77 | .python-version 78 | 79 | # celery beat schedule file 80 | celerybeat-schedule 81 | 82 | # SageMath parsed files 83 | *.sage.py 84 | 85 | # dotenv 86 | .env 87 | 88 | # virtualenv 89 | .venv 90 | venv/ 91 | ENV/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | *.pyc 106 | .vscode -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spoofnet-tensorflow 2 | Tensorflow slim implementation of spoofnet presented in the paper: 3 | Deep Representations for Iris, Face, and Fingerprint Spoofing Detection, 2015 4 | 5 | http://ieeexplore.ieee.org/document/7029061/ 6 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yomna-safaa/spoofnet-tensorflow/bbb0ab6f493a874dd7e43c1cee8e0740a417e9d7/__init__.py -------------------------------------------------------------------------------- /common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yomna-safaa/spoofnet-tensorflow/bbb0ab6f493a874dd7e43c1cee8e0740a417e9d7/common/__init__.py -------------------------------------------------------------------------------- /common/metrics.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | 4 | ################################################################### 5 | ### accracy given scores + threshold: 6 | def Accuracy(prediction_scores, true_labels, threshold): 7 | true_labels = np.asarray(true_labels, dtype='int64') 8 | # pos = real = 1 9 | # neg = attack = fake = 0 10 | scores_results = np.empty(len(prediction_scores),dtype='int64') 11 | tp = 0 12 | tn = 0 13 | fp = 0 14 | fn = 0 15 | for i, s in enumerate(prediction_scores): 16 | if s > threshold: 17 | scores_results[i] = 1 # predicted as positive: tp or fp? 18 | if true_labels[i] == 1: # originally pos #pos = real = 1 19 | tp += 1 20 | else: # originally neg 21 | fp += 1 22 | else: # predicted as negative: tn or fn? # neg = attack = fake = 0 23 | scores_results[i] = 0 24 | if true_labels[i] == 1: # originally pos 25 | fn += 1 26 | else: # originally neg 27 | tn += 1 28 | 29 | print ("Accuracy calculated at threshold: ", threshold) 30 | correctResults = (scores_results == true_labels).sum() 31 | print ("Correctly Classified: ", correctResults, ", out of: ", len(true_labels), " images.") 32 | acc = correctResults * 1.0 / len(true_labels) 33 | print ("Model accuracy (%): ", acc * 100, "%") 34 | 35 | nPos = tp + fn 36 | nNeg = fp + tn 37 | 38 | far = fp * 1.0 / nNeg 39 | frr = fn * 1.0 / nPos 40 | hter = (far + frr) * 100.0 / 2 41 | 42 | acc = (tp + tn) * 1.0 / (nPos + nNeg) # + 1.0e-10) 43 | print ("Accuracy (%): ", acc * 100, "%\nFAR: ", far, ", FRR: ", frr, ', HTER: (%)', hter, "%") 44 | 45 | return acc, far, frr, hter 46 | 47 | 48 | import matplotlib.pyplot as plt 49 | def roc_det(valScores_predicted, valLabels_true, display_details=True): 50 | 51 | ### ROC: fpr vs tpr 52 | # calculate the fpr and tpr for all thresholds of the classification 53 | method = 2 54 | 55 | if method ==1: 56 | from sklearn import metrics 57 | #### ROC method1: 58 | preds = valScores_predicted 59 | y = np.asarray(valLabels_true, dtype='int64') 60 | y[y == 0] = -1 61 | 62 | fpr, tpr, thresholds = metrics.roc_curve(y, preds) 63 | roc_auc = metrics.auc(fpr, tpr) 64 | # print y 65 | # print fpr 66 | # print tpr 67 | # print thresholds 68 | print (roc_auc) 69 | plt.plot(fpr, tpr, 'b', label='AUC = %0.2f' % roc_auc) 70 | plt.legend(loc='lower right') 71 | 72 | ############## 73 | elif method ==2: 74 | 75 | #### ROC method2: 76 | ##### ##### Another way to plot roc, using scatter: 77 | roc_x = [] #fpr 78 | roc_y = [] #tpr 79 | min_score = min(valScores_predicted) 80 | max_score = max(valScores_predicted) 81 | # step = (max_score - min_score) *1.0/100 82 | # step = int(np.ceil(step)) 83 | # thresholds = np.linspace(min_score, max_score, step) 84 | thresholds = np.linspace(min_score, max_score, num=100) 85 | FP=0 86 | TP=0 87 | y = np.asarray(valLabels_true, dtype='int64') 88 | P = sum(y) 89 | N = len(y) - P 90 | 91 | # for (j, T) in enumerate(thresholds): 92 | for (i, T) in enumerate(thresholds): 93 | for i in range(0, len(valScores_predicted)): 94 | if (valScores_predicted[i] > T): 95 | # if (valScores_predicted[i] >= T): #YY: changed this on 10Jan2017 to (>=), since when it was only (>) when threshold ==1, if predSc=1, so it's not >T, and so TP will not be incremented and will stay 0!!!! 96 | if (y[i]==1): 97 | TP = TP + 1 98 | if (y[i]==0): 99 | FP = FP + 1 100 | roc_x.append(FP/float(N)) 101 | roc_y.append(TP/float(P)) 102 | FP=0 103 | TP=0 104 | fpr, tpr = roc_x, roc_y 105 | # plt.scatter(fpr, tpr) #(roc_x, roc_y) 106 | plt.plot(fpr, tpr) 107 | fpr = np.asarray(fpr) 108 | tpr = np.asarray(tpr) 109 | 110 | ################### 111 | plt.title('Receiver Operating Characteristic') 112 | plt.plot([0, 1], [0, 1], 'r--') 113 | plt.xlim([-0.01, 1.01]) 114 | plt.ylim([-0.01, 1.01]) 115 | plt.ylabel('True Positive Rate') 116 | plt.xlabel('False Positive Rate') 117 | plt.show(block=False) 118 | 119 | ################################################################### 120 | ### DET: fpr vs fnr 121 | ### ROC: fpr vs tpr 122 | 123 | ######### DET:: 124 | fnr = 1 - tpr 125 | 126 | plt.title('DET curve') 127 | plt.plot(fpr, fnr, 'b') 128 | # plt.legend(loc = 'lower right') 129 | plt.plot([0, 1], [0, 1], 'r--') 130 | plt.xlim([-0.05, 1.05]) 131 | plt.ylim([-0.05, 1.05]) 132 | plt.ylabel('False Negative Rate') 133 | plt.xlabel('False Positive Rate') 134 | 135 | ################################################################### 136 | ### EER: 137 | d = abs(fpr - fnr) 138 | if display_details: 139 | print (d) 140 | # j = d.argmin() 141 | j = np.where(d == d.min()) 142 | j = j[0] 143 | # print j, d[j] 144 | # print fpr[j], fnr[j] 145 | if len(j)>1: 146 | candidate_thresholds = thresholds[j] 147 | print ("Several EER_Thresholds") 148 | if display_details: 149 | print (candidate_thresholds) 150 | eer_thr_i = candidate_thresholds.argmin() 151 | eer_thr_j = j[eer_thr_i] 152 | # eer_thr1 = candidate_thresholds[eer_thr_i] 153 | # eer_thr2 = thresholds[eer_thr_j] 154 | j = eer_thr_j 155 | eer = fpr[j] 156 | eer_thr = thresholds[j] 157 | eer_thr2 = max(candidate_thresholds) 158 | if eer_thr<0 and max(candidate_thresholds)>0: 159 | print ("Several EER_Thresholds, min = ", eer_thr, ", Will set EER_Threshold = 0") 160 | eer_thr=0 161 | else: 162 | eer = fpr[j] 163 | eer_thr = thresholds[j] 164 | eer_thr2=-1 165 | print ('eer, eer_thr, eer_thr(max): ', eer, eer_thr, eer_thr2) 166 | 167 | plt.scatter(fpr[j], fnr[j]) 168 | 169 | ################################################################### 170 | ## Y: try on Nov10 2016, to get thr which has min (fpr+fnr) 171 | ## mer (min err rate) instead of eer (equal error rate) 172 | s = fpr + fnr 173 | if display_details: 174 | print (s) 175 | jj = np.where(s == s.min()) 176 | jj = jj[0] 177 | if len(jj) > 1: 178 | candidate_thresholds = thresholds[jj] 179 | print ("Several MER_Thresholds") 180 | if display_details: 181 | print (candidate_thresholds) 182 | mer_thr_ii = candidate_thresholds.argmin() 183 | mer_thr_jj = jj[mer_thr_ii] 184 | # eer_thr1 = candidate_thresholds[eer_thr_i] 185 | # eer_thr2 = thresholds[eer_thr_j] 186 | jj = mer_thr_jj 187 | mer = fpr[jj] 188 | mer_thr = thresholds[jj] 189 | if mer_thr < 0 and max(candidate_thresholds) > 0: 190 | print ("Several MER_Thresholds, min = ", mer_thr, ", Will set MER_Threshold = 0") 191 | mer_thr = 0 192 | else: 193 | mer = fpr[jj] 194 | mer_thr = thresholds[jj] 195 | print ('mer, mer_thr: ', mer, mer_thr) 196 | 197 | plt.scatter(fpr[jj], fnr[jj]) 198 | plt.show(block=False) 199 | 200 | ################################################################### 201 | # Accuracy(valScores_predicted, valLabels_true, 0) 202 | # Accuracy(valScores_predicted, valLabels_true, 0.5) 203 | print ("\nEER calculated using this Data = ", eer, ", EER_threshold= ", eer_thr) 204 | Accuracy(valScores_predicted, valLabels_true, eer_thr) 205 | if abs(mer_thr - eer_thr) > 0: 206 | print ("\nMER calculated using this Data = ", mer, ", MER_threshold= ", mer_thr) 207 | Accuracy(valScores_predicted, valLabels_true, mer_thr) 208 | 209 | return eer_thr, mer_thr, eer_thr2 210 | -------------------------------------------------------------------------------- /data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yomna-safaa/spoofnet-tensorflow/bbb0ab6f493a874dd7e43c1cee8e0740a417e9d7/data/__init__.py -------------------------------------------------------------------------------- /data/createLabelsFile_iris.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import os 3 | 4 | import data.datasets_paths as datasets_paths 5 | 6 | ############################################################################# 7 | DB = 'ATVS' 8 | # DB = 'Warsaw' 9 | # DB = 'MobBioFake' 10 | 11 | ###################################################### 12 | if DB == 'ATVS': 13 | SET_rootFolder = datasets_paths.IRIS_ROOT_DIR + datasets_paths.ATVS_SUB_DIR 14 | filePre = "/biosec" 15 | sourceDir = SET_rootFolder + "/ATVS-FIr_DB" 16 | 17 | elif DB == 'Warsaw': 18 | SET_rootFolder = datasets_paths.IRIS_ROOT_DIR + datasets_paths.WARSAW_SUB_DIR 19 | filePre = "/warsaw" 20 | 21 | elif DB == 'MobBioFake': 22 | SET_rootFolder = datasets_paths.IRIS_ROOT_DIR + datasets_paths.MOBBIOFAKE_SUB_DIR 23 | filePre = "/mobbiofake" 24 | 25 | ###################################################### 26 | labelFilesDir = SET_rootFolder + "/labelFiles" 27 | trainFile = labelFilesDir + filePre + "_spoof_train.txt" 28 | testfile = labelFilesDir + filePre + "_spoof_test.txt" 29 | categories_file = labelFilesDir + filePre + "_categories.txt" 30 | 31 | if not os.path.exists(labelFilesDir): 32 | os.makedirs(labelFilesDir) 33 | 34 | ###################################################### 35 | sets = ["FAKE", "REAL"] 36 | caffe_sets = ["train", "test"] 37 | 38 | 39 | ####################################################### 40 | def create_labelsTxtFile_ATVS(): 41 | with open(categories_file, 'w') as writeF: 42 | for s in sets: # label = index (0: FAKE, 1: REAL) 43 | writeF.write("%s\n" % s) 44 | 45 | writeF = labelFilesDir + "/biosec_spoof_all.txt" 46 | with open(writeF, 'wb') as writeF: 47 | mywr = csv.writer(writeF, delimiter=' ') 48 | for label, s in enumerate(sets): # label = index (0: FAKE, 1: REAL) 49 | setDir = sourceDir + "/" + s 50 | usersDir = os.listdir(setDir) ## 50 users 51 | usersDir.sort() 52 | for user in usersDir: 53 | files = os.listdir(setDir + "/" + user) 54 | for img in files: 55 | mywr.writerow([s + '/' + user + '/' + img] + [label]) 56 | 57 | ################### 58 | ### taking 25% for training, and the remaining 75% for testing .. 59 | ## so first 12.5 users (real and fake) for training .. that is since each user has 2 eyes and each eye is treated as 60 | ## a diff user, so take : 61 | # Train: users 1 to 12 + left eye of user 13 62 | # Test: users 14 to 50 + right eye of user 13 63 | trainF = trainFile 64 | with open(trainF, 'wb') as trainF: 65 | mywr = csv.writer(trainF, delimiter=' ') 66 | for label, s in enumerate(sets): # label = index (0: FAKE, 1: REAL) 67 | setDir = sourceDir + "/" + s 68 | usersDir = os.listdir(setDir) ## 50 users 69 | usersDir.sort() 70 | for i, user in enumerate(usersDir): 71 | # Train: users 1 to 12 + left eye of user 13 (i.e: index 0:11, + left of index12 72 | if i > 12: 73 | break 74 | files = os.listdir(setDir + "/" + user) 75 | for img in files: 76 | if i == 12: 77 | if "_l_" in img: 78 | mywr.writerow([s + '/' + user + '/' + img] + [label]) 79 | else: 80 | mywr.writerow([s + '/' + user + '/' + img] + [label]) 81 | 82 | ################### 83 | testF = testfile 84 | with open(testF, 'wb') as testF: 85 | mywr = csv.writer(testF, delimiter=' ') 86 | for label, s in enumerate(sets): # label = index (0: FAKE, 1: REAL) 87 | setDir = sourceDir + "/" + s 88 | usersDir = os.listdir(setDir) ## 50 users 89 | usersDir.sort() 90 | for i, user in enumerate(usersDir): 91 | # Test: users 14 to 50 + right eye of user 13 (i.e.: right of index 12 + index 13 to 49 92 | if i < 12: 93 | continue 94 | files = os.listdir(setDir + "/" + user) 95 | for img in files: 96 | if i == 12: 97 | if "_r_" in img: 98 | mywr.writerow([s + '/' + user + '/' + img] + [label]) 99 | else: 100 | mywr.writerow([s + '/' + user + '/' + img] + [label]) 101 | 102 | 103 | ####################################################### 104 | def create_labelsTxtFile_Warsaw(): 105 | categories_wasaw = ["PRNT", "REAL"] 106 | 107 | with open(categories_file, 'w') as writeF: 108 | for s in categories_wasaw: 109 | writeF.write("%s\n" % s) 110 | 111 | ################### 112 | subF = "Training" 113 | trainSubFolder = SET_rootFolder + "/PNG/" + subF 114 | trainF = trainFile 115 | with open(trainF, 'wb') as trainF: 116 | mywr = csv.writer(trainF, delimiter=' ') 117 | files = os.listdir(trainSubFolder) 118 | for img in files: 119 | if ("_" + categories_wasaw[1] + "_") in img: 120 | l = 1 121 | elif ("_" + categories_wasaw[0] + "_") in img: 122 | l = 0 123 | mywr.writerow([subF + '/' + img] + [l]) 124 | 125 | ################### 126 | testF = testfile 127 | with open(testF, 'wb') as testF: 128 | mywr = csv.writer(testF, delimiter=' ') 129 | 130 | subF = "Testing" 131 | testSubFolder = SET_rootFolder + "/PNG/" + subF 132 | files = os.listdir(testSubFolder) 133 | for img in files: 134 | if "_REAL_" in img: 135 | l = 1 136 | elif "_PRNT_" in img: 137 | l = 0 138 | mywr.writerow([subF + '/' + img] + [l]) 139 | 140 | subF = "Testing.Supplement" 141 | testSupSubFolder = SET_rootFolder + "/PNG/" + subF 142 | files = os.listdir(testSupSubFolder) 143 | for img in files: 144 | if "_REAL_" in img: 145 | l = 1 146 | elif "_PRNT_" in img: 147 | l = 0 148 | mywr.writerow([subF + '/' + img] + [l]) 149 | 150 | 151 | ####################################################### 152 | def create_labelsTxtFile_MobBioFake(): 153 | with open(categories_file, 'w') as writeF: 154 | for s in sets: # label = index (0: FAKE, 1: REAL) 155 | writeF.write("%s\n" % s) 156 | 157 | ################### 158 | subD = "Mobbiofake_DB_train" 159 | subF = SET_rootFolder + "/" + subD 160 | trainF = trainFile 161 | with open(trainF, 'wb') as trainF: 162 | mywr = csv.writer(trainF, delimiter=' ') 163 | for label, s in enumerate(sets): # label = index (0: FAKE, 1: REAL) 164 | setDir = subF + "/" + s 165 | usersDir = os.listdir(setDir) ## 50 users 166 | usersDir.sort() 167 | for user in usersDir: 168 | files = os.listdir(setDir + "/" + user) 169 | for img in files: 170 | mywr.writerow([subD + '/' + s + '/' + user + '/' + img] + [label]) 171 | 172 | ################### 173 | sets_test = ["fake", "real"] 174 | subD = "Mobbiofake_DB_test" 175 | subF = SET_rootFolder + "/" + subD 176 | testF = testfile 177 | with open(testF, 'wb') as testF: 178 | mywr = csv.writer(testF, delimiter=' ') 179 | for label, s in enumerate(sets_test): # label = index (0: FAKE, 1: REAL) 180 | setDir = subF + "/" + s 181 | files = os.listdir(setDir) 182 | for img in files: 183 | mywr.writerow([subD + '/' + s + '/' + img] + [label]) 184 | 185 | 186 | ####################################################### 187 | def create_labelsTxtFile(): 188 | if DB == 'ATVS': 189 | create_labelsTxtFile_ATVS() 190 | 191 | elif DB == 'Warsaw': 192 | create_labelsTxtFile_Warsaw() 193 | 194 | elif DB == 'MobBioFake': 195 | create_labelsTxtFile_MobBioFake() 196 | 197 | 198 | ####################################################### 199 | create_labelsTxtFile() 200 | -------------------------------------------------------------------------------- /data/data_tf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yomna-safaa/spoofnet-tensorflow/bbb0ab6f493a874dd7e43c1cee8e0740a417e9d7/data/data_tf/__init__.py -------------------------------------------------------------------------------- /data/data_tf/dataset_factory_tf.py: -------------------------------------------------------------------------------- 1 | 2 | from data.data_tf.datasets_tf import * 3 | 4 | datasets_map = { 5 | 'catsDogs': CatsDogsData, 6 | 'Warsaw': IrisWarsawData, 7 | 'ATVS': IrisATVSData, 8 | 'MobBioFake': IrisMobBioFakeData, 9 | 'ReplayAttack': ReplayAttackData, 10 | } 11 | 12 | def get_dataset_y(name, split_name, file_pattern): 13 | """Given a dataset name and a split_name returns a Dataset. 14 | 15 | Args: 16 | name: String, the name of the dataset. 17 | split_name: A train/test split name. 18 | dataset_dir: The directory where the dataset files are stored. 19 | file_pattern: The file pattern to use for matching the dataset source files. 20 | reader: The subclass of tf.ReaderBase. If left as `None`, then the default 21 | reader defined by each dataset is used. 22 | 23 | Returns: 24 | A `Dataset` class. 25 | 26 | Raises: 27 | ValueError: If the dataset `name` is unknown. 28 | """ 29 | if name not in datasets_map: 30 | raise ValueError('Name of dataset unknown %s' % name) 31 | datasetName = datasets_map[name] 32 | return datasetName(split_name, file_pattern) 33 | 34 | -------------------------------------------------------------------------------- /data/data_tf/dataset_tf.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | from abc import ABCMeta 4 | from abc import abstractmethod 5 | 6 | import tensorflow as tf 7 | 8 | from data.data_tf import dataset_utils_tf 9 | 10 | 11 | class Dataset_TFRecords(object): 12 | """A simple class for handling data sets.""" 13 | __metaclass__ = ABCMeta 14 | 15 | def __init__(self, name, subset, file_pattern): 16 | """Initialize dataset using a subset and the path to the data.""" 17 | assert subset in self.available_subsets(), self.available_subsets() #SPLITS_TO_SIZES 18 | # if self.subset not in SPLITS_TO_SIZES: 19 | # raise ValueError('split name %s was not recognized.' % self.subset) 20 | self.name = name 21 | self.subset = subset 22 | self.file_pattern = file_pattern 23 | 24 | @abstractmethod 25 | def num_classes(self): 26 | """Returns the number of classes in the data set.""" 27 | pass 28 | 29 | @abstractmethod 30 | def num_examples_per_epoch(self): 31 | """Returns the number of examples in the data subset.""" 32 | pass 33 | 34 | def available_subsets(self): 35 | """Returns the list of available subsets.""" 36 | return ['train', 'validation'] 37 | 38 | 39 | def data_files(self): 40 | """Returns a python list of all (sharded) data subset files. 41 | 42 | Returns: 43 | python list of all (sharded) data set files. 44 | Raises: 45 | ValueError: if there are not data_files matching the subset. 46 | """ 47 | 48 | data_files = tf.gfile.Glob(self.file_pattern) 49 | if not data_files: 50 | print('No files found for dataset %s/%s at %s' % (self.name, 51 | self.subset, 52 | self.file_pattern)) 53 | 54 | exit(-1) 55 | return data_files 56 | 57 | def get_split_slim(self, file_pattern=None, reader=None, tfRecords_dir=None, n_channels=None): 58 | """Gets a dataset tuple with instructions for reading flowers. 59 | 60 | Args: 61 | split_name: A train/validation split name. 62 | dataset_dir: The base directory of the dataset sources. 63 | file_pattern: The file pattern to use when matching the dataset sources. 64 | It is assumed that the pattern contains a '%s' string so that the split 65 | name can be inserted. 66 | reader: The TensorFlow reader type. 67 | 68 | Returns: 69 | A `Dataset` namedtuple. 70 | 71 | Raises: 72 | ValueError: if `split_name` is not a valid train/validation split. 73 | """ 74 | if not file_pattern: 75 | file_pattern = self.file_pattern 76 | 77 | self.tfRecords_dir = tfRecords_dir 78 | self.channels = n_channels 79 | 80 | num_samples = self.num_examples_per_epoch() 81 | if (not num_samples) or (num_samples<1): 82 | # TODO: file patter for counting has to be a subset of file_pattern .. how? 83 | # raise ValueError('Invalid number of samples in tf files') 84 | file_pattern_for_counting = file_pattern.split('*')[0] 85 | file_pattern_for_counting = file_pattern_for_counting.split('/')[-1] 86 | tfrecords_to_count = [os.path.join(self.tfRecords_dir, file) for file in os.listdir(self.tfRecords_dir) \ 87 | if (file.startswith(file_pattern_for_counting))] 88 | num_samples = dataset_utils_tf.number_of_examples_in_tfrecords(tfrecords_to_count) 89 | print('Found %d records in %s files' %(num_samples, file_pattern_for_counting)) 90 | 91 | return dataset_utils_tf.get_split_slim(self.tfRecords_dir, file_pattern, num_samples, self.num_classes(), 92 | self.channels, reader=reader) 93 | 94 | 95 | def reader(self): 96 | """Return a reader for a single entry from the data set. 97 | 98 | See io_ops.py for details of Reader class. 99 | 100 | Returns: 101 | Reader object that reads the data set. 102 | """ 103 | return tf.TFRecordReader() 104 | -------------------------------------------------------------------------------- /data/data_tf/dataset_utils_tf.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | 4 | import tensorflow as tf 5 | 6 | LABELS_FILENAME = 'labels.txt' 7 | 8 | 9 | def number_of_examples_in_tfrecords(tfrecords_to_count): 10 | num_samples = 0 11 | for tfrecord_file in tfrecords_to_count: 12 | for record in tf.python_io.tf_record_iterator(tfrecord_file): 13 | num_samples += 1 14 | 15 | return num_samples 16 | 17 | 18 | def has_labels(dataset_dir, filename=LABELS_FILENAME): 19 | """Specifies whether or not the dataset directory contains a label map file. 20 | 21 | Args: 22 | dataset_dir: The directory in which the labels file is found. 23 | filename: The filename where the class names are written. 24 | 25 | Returns: 26 | `True` if the labels file exists and `False` otherwise. 27 | """ 28 | return tf.gfile.Exists(os.path.join(dataset_dir, filename)) 29 | 30 | 31 | def read_label_file(dataset_dir, filename=LABELS_FILENAME): 32 | """Reads the labels file and returns a mapping from ID to class name. 33 | 34 | Args: 35 | dataset_dir: The directory in which the labels file is found. 36 | filename: The filename where the class names are written. 37 | 38 | Returns: 39 | A map from a label (integer) to class name. 40 | """ 41 | labels_filename = os.path.join(dataset_dir, filename) 42 | with tf.gfile.Open(labels_filename, 'r') as f: 43 | lines = f.read().decode() 44 | lines = lines.split('\n') 45 | lines = filter(None, lines) 46 | 47 | labels_to_class_names = {} 48 | for line in lines: 49 | index = line.index(':') 50 | labels_to_class_names[int(line[:index])] = line[index+1:] 51 | return labels_to_class_names 52 | 53 | 54 | ################################################################################################# 55 | import tensorflow.contrib.slim as slim 56 | # slim = tensorflows.contrib.slim 57 | from pipeline_tf.image_utils import preprocess_image 58 | 59 | 60 | def load_batch_slim(dataset, batch_size, height, width, preprocessing_name, image_preprocessing_fn, 61 | num_readers=1, num_preprocessing_threads=4, per_image_standardization=False, 62 | vgg_sub_mean_pixel=None, vgg_resize_side_in=None, vgg_use_aspect_preserving_resize=None, 63 | labels_offset=0, is_training=False, allow_smaller_final_batch=False): 64 | ''' 65 | Loads a batch for training. 66 | 67 | INPUTS: 68 | - dataset(Dataset): a Dataset class object that is created from the get_split function 69 | - batch_size(int): determines how big of a batch to train 70 | - height(int): the height of the image to resize to during preprocessing 71 | - width(int): the width of the image to resize to during preprocessing 72 | - is_training(bool): to determine whether to perform a training or evaluation preprocessing 73 | 74 | OUTPUTS: 75 | - images(Tensor): a Tensor of the shape (batch_size, height, width, channels) that contain one batch of images 76 | - labels(Tensor): the batch's labels with the shape (batch_size,) (requires one_hot_encoding). 77 | 78 | ''' 79 | if is_training: 80 | provider = slim.dataset_data_provider.DatasetDataProvider( 81 | ## YY: note, shuffle is set to True by default in the Provider init 82 | dataset, 83 | num_readers=num_readers, 84 | common_queue_capacity=20 * batch_size, 85 | common_queue_min=10 * batch_size) 86 | else: 87 | if allow_smaller_final_batch: 88 | provider = slim.dataset_data_provider.DatasetDataProvider( 89 | dataset, num_epochs=1, 90 | shuffle=False, 91 | common_queue_capacity=2 * batch_size, 92 | common_queue_min=batch_size) 93 | else: 94 | provider = slim.dataset_data_provider.DatasetDataProvider( 95 | dataset, 96 | shuffle=False, 97 | common_queue_capacity=2 * batch_size, 98 | common_queue_min=batch_size) 99 | 100 | [raw_image, label, filename] = provider.get(['image', 'label', 'filename']) 101 | label -= labels_offset 102 | 103 | image = preprocess_image(preprocessing_name, image_preprocessing_fn, raw_image, height, width, 104 | per_image_standardization=per_image_standardization, 105 | vgg_sub_mean_pixel=vgg_sub_mean_pixel, vgg_resize_side_in=vgg_resize_side_in, 106 | vgg_use_aspect_preserving_resize=vgg_use_aspect_preserving_resize) 107 | 108 | # As for the raw images, we just do a simple reshape to batch it up 109 | raw_image = tf.expand_dims(raw_image, 0) 110 | raw_image = tf.image.resize_nearest_neighbor(raw_image, [height, width]) 111 | raw_image = tf.squeeze(raw_image) 112 | 113 | # Batch up the image by enqueing the tensors internally in a FIFO queue and dequeueing many elements with tf.train.batch. 114 | images, raw_images, labels, filenames =tf.train.batch( 115 | [image, raw_image, label, filename], 116 | batch_size=batch_size, 117 | num_threads=num_preprocessing_threads, 118 | capacity=5 * batch_size, allow_smaller_final_batch= allow_smaller_final_batch) 119 | 120 | return images, raw_images, labels, filenames 121 | 122 | 123 | ########################################################################## 124 | def get_split_slim(dataset_dir, file_pattern, num_samples, num_classes, channels, reader=None): 125 | """Gets a dataset tuple with instructions for reading flowers. 126 | 127 | Args: 128 | split_name: A train/validation split name. 129 | dataset_dir: The base directory of the dataset sources. 130 | file_pattern: The file pattern to use when matching the dataset sources. 131 | It is assumed that the pattern contains a '%s' string so that the split 132 | name can be inserted. 133 | reader: The TensorFlow reader type. 134 | 135 | Returns: 136 | A `Dataset` namedtuple. 137 | 138 | Raises: 139 | ValueError: if `split_name` is not a valid train/validation split. 140 | """ 141 | 142 | _ITEMS_TO_DESCRIPTIONS = { 143 | 'image': 'A color image of varying size.', 144 | 'label': 'A single integer between 0 and 1', 145 | 'filename': 'A string of file name', 146 | } 147 | 148 | # Allowing None in the signature so that dataset_factory can use the default. 149 | if reader is None: 150 | reader = tf.TFRecordReader 151 | 152 | keys_to_features = { ## YY: names of the keys to extract from the tfexamples of the tfrecord 153 | 'image/encoded': tf.FixedLenFeature((), tf.string, default_value=''), 154 | 'image/format': tf.FixedLenFeature((), tf.string, default_value='png'), 155 | 'image/class/label': tf.FixedLenFeature( 156 | [], tf.int64, default_value=tf.zeros([], dtype=tf.int64)), 157 | 'image/filename': tf.FixedLenFeature((), tf.string, default_value=''), 158 | } 159 | 160 | items_to_handlers = { ## YY: names of the tensors to be returned by the decoder (values coming from keys_to_features) 161 | 'image': slim.tfexample_decoder.Image(channels=channels), 162 | 'label': slim.tfexample_decoder.Tensor('image/class/label'), 163 | 'filename': slim.tfexample_decoder.Tensor('image/filename'), 164 | } 165 | 166 | decoder = slim.tfexample_decoder.TFExampleDecoder( 167 | keys_to_features, items_to_handlers) 168 | 169 | labels_to_names = None 170 | if has_labels(dataset_dir): 171 | labels_to_names = read_label_file(dataset_dir) 172 | 173 | return slim.dataset.Dataset( 174 | data_sources=file_pattern, 175 | reader=reader, 176 | decoder=decoder, 177 | num_samples=num_samples, 178 | items_to_descriptions=_ITEMS_TO_DESCRIPTIONS, 179 | num_classes=num_classes, 180 | labels_to_names=labels_to_names) 181 | 182 | -------------------------------------------------------------------------------- /data/data_tf/datasets_tf.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Google Inc. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | """Small library that points to the flowers data set. 16 | """ 17 | 18 | from data.data_tf.dataset_tf import Dataset_TFRecords 19 | 20 | 21 | class CatsDogsData(Dataset_TFRecords): 22 | 23 | def __init__(self, subset, file_pattern): 24 | super(CatsDogsData, self).__init__('CatsDogs', subset, file_pattern) 25 | 26 | def num_classes(self): 27 | """Returns the number of classes in the data set.""" 28 | return 2 29 | 30 | def num_examples_per_epoch(self): 31 | if self.subset == 'train': 32 | return 20000 33 | 34 | if self.subset == 'validation': 35 | return 5000 36 | 37 | class IrisWarsawData(Dataset_TFRecords): 38 | 39 | def __init__(self, subset, file_pattern): 40 | super(IrisWarsawData, self).__init__('IrisWarsaw', subset, file_pattern) 41 | 42 | def num_classes(self): 43 | """Returns the number of classes in the data set.""" 44 | return 2 45 | 46 | def num_examples_per_epoch(self): 47 | if self.subset == 'train': 48 | return 431 49 | 50 | if self.subset == 'validation': 51 | return 1236 52 | 53 | class IrisATVSData(Dataset_TFRecords): 54 | 55 | def __init__(self, subset, file_pattern): 56 | super(IrisATVSData, self).__init__('IrisATVS', subset, file_pattern) 57 | 58 | def num_classes(self): 59 | """Returns the number of classes in the data set.""" 60 | return 2 61 | 62 | def num_examples_per_epoch(self): 63 | if self.subset == 'train': 64 | return 400 65 | 66 | if self.subset == 'validation': 67 | return 1200 68 | 69 | class IrisMobBioFakeData(Dataset_TFRecords): 70 | 71 | def __init__(self, subset, file_pattern): 72 | super(IrisMobBioFakeData, self).__init__('IrisMobBioFake', subset, file_pattern) 73 | 74 | def num_classes(self): 75 | """Returns the number of classes in the data set.""" 76 | return 2 77 | 78 | def num_examples_per_epoch(self): 79 | if self.subset == 'train': 80 | return 800 81 | 82 | if self.subset == 'validation': 83 | return 800 84 | 85 | class ReplayAttackData(Dataset_TFRecords): 86 | 87 | def __init__(self, subset, file_pattern): 88 | super(ReplayAttackData, self).__init__('ReplayAttack', subset, file_pattern) 89 | 90 | def num_classes(self): 91 | """Returns the number of classes in the data set.""" 92 | return 2 93 | 94 | def num_examples_per_epoch(self): 95 | if self.subset == 'train': 96 | return None 97 | 98 | if self.subset == 'validation': 99 | return None 100 | 101 | if self.subset == 'test': 102 | return None -------------------------------------------------------------------------------- /data/datasets_paths.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | 3 | # ROOT_DIR = "/media/yomna/Work/Y_Work" 4 | ROOT_DIR = "D:\\" 5 | 6 | # ========== 7 | DBs_DIR = os.path.join(ROOT_DIR , "0_ImgsDB") 8 | 9 | IRIS_ROOT_DIR = os.path.join(DBs_DIR , "Spoof_DBs","IRIS") 10 | WARSAW_SUB_DIR = 'LivDet-Iris-2013-Warsaw' 11 | ATVS_SUB_DIR = 'BioSec_ATVS' 12 | MOBBIOFAKE_SUB_DIR = "MobBioFake" 13 | 14 | CATS_DOGS_DIR = os.path.join(DBs_DIR , "Kaggle_CatsVsDogs") 15 | 16 | TF_CHECKPOINTS_ROOT_DIR = os.path.join(ROOT_DIR , 'data','models-training_snapshots_tensorflow') 17 | print (TF_CHECKPOINTS_ROOT_DIR) 18 | TFRecords_ROOT_DIR = os.path.join(ROOT_DIR , 'data','data_tf') 19 | 20 | #################################################################### 21 | from abc import ABCMeta, abstractmethod 22 | class DatasetPaths_Y(object): 23 | __metaclass__ = ABCMeta 24 | def __init__(self, name): 25 | self._name = name 26 | 27 | def get_name(self): 28 | return self._name 29 | 30 | @abstractmethod 31 | def root_dir(self): 32 | return 33 | 34 | def sub_dir(self, subset): 35 | return 36 | 37 | @abstractmethod 38 | def csv_files_dir(self): 39 | return 40 | 41 | @abstractmethod 42 | def csv_file(self, subset): 43 | return 44 | 45 | @abstractmethod 46 | def categories_file(self): 47 | return 48 | 49 | def available_subsets(self): 50 | """Returns the list of available subsets.""" 51 | return ['train', 'validation'] 52 | 53 | 54 | ############################################################### 55 | class IrisATVS_Paths(DatasetPaths_Y): 56 | def __init__(self): 57 | super(IrisATVS_Paths, self).__init__('biosec') 58 | 59 | def root_dir(self): 60 | return os.path.join(IRIS_ROOT_DIR , ATVS_SUB_DIR , "/ATVS-FIr_DB") 61 | 62 | def csv_files_dir(self): 63 | return os.path.join(IRIS_ROOT_DIR , ATVS_SUB_DIR , "/labelFiles") 64 | 65 | def csv_file(self, subset): 66 | assert subset in self.available_subsets(), self.available_subsets() 67 | if subset == 'train': 68 | return os.path.join(self.csv_files_dir() ,self._name + "_spoof_train.txt") 69 | 70 | if subset == 'validation': 71 | return os.path.join(self.csv_files_dir() , + self._name + "_spoof_test.txt") 72 | 73 | def categories_file(self): 74 | return os.path.join(self.csv_files_dir(), + self._name + "_categories.txt") 75 | 76 | 77 | ############################################################### 78 | class IrisWarsaw_Paths(DatasetPaths_Y): 79 | def __init__(self): 80 | super(IrisWarsaw_Paths, self).__init__('warsaw') 81 | 82 | def root_dir(self): 83 | return os.path.join(IRIS_ROOT_DIR, WARSAW_SUB_DIR ,"PNG") 84 | 85 | def csv_files_dir(self): 86 | return os.path.join(IRIS_ROOT_DIR , WARSAW_SUB_DIR , "labelFiles") 87 | 88 | def csv_file(self, subset): 89 | assert subset in self.available_subsets(), self.available_subsets() 90 | if subset == 'train': 91 | return os.path.join(self.csv_files_dir() , self._name + "_spoof_train.txt") 92 | 93 | if subset == 'validation': 94 | return os.path.join(self.csv_files_dir(), self._name + "_spoof_test.txt") 95 | 96 | def categories_file(self): 97 | return os.path.join(self.csv_files_dir() , self._name + "_categories.txt") 98 | 99 | 100 | ############################################################### 101 | class IrisMobbiofake_Paths(DatasetPaths_Y): 102 | def __init__(self): 103 | super(IrisMobbiofake_Paths, self).__init__('mobbiofake') 104 | 105 | def root_dir(self): 106 | return IRIS_ROOT_DIR + MOBBIOFAKE_SUB_DIR 107 | 108 | def csv_files_dir(self): 109 | return self.root_dir() + "/labelFiles" 110 | 111 | def csv_file(self, subset): 112 | assert subset in self.available_subsets(), self.available_subsets() 113 | if subset == 'train': 114 | return self.csv_files_dir() + '/' + self._name + "_spoof_train.txt" 115 | 116 | if subset == 'validation': 117 | return self.csv_files_dir() + '/' + self._name + "_spoof_test.txt" 118 | 119 | def categories_file(self): 120 | return self.csv_files_dir() + '/' + self._name + "_categories.txt" 121 | 122 | ############################################################### 123 | class CatsDogs_Paths(DatasetPaths_Y): 124 | def __init__(self): 125 | super(CatsDogs_Paths, self).__init__('catsDogs') 126 | 127 | def root_dir(self): 128 | return CATS_DOGS_DIR 129 | 130 | def sub_dir(self, subset): 131 | assert subset in self.available_subsets(), self.available_subsets() 132 | if subset == 'train': 133 | return self.root_dir() + '/train' 134 | if subset == 'validation': 135 | return None 136 | if subset == 'test': 137 | return self.root_dir() + '/test1' 138 | 139 | def csv_files_dir(self): 140 | return self.root_dir() 141 | 142 | def csv_file(self, subset): 143 | assert subset in self.available_subsets(), self.available_subsets() 144 | if subset == 'train': 145 | return self.csv_files_dir() + '/train.txt' 146 | if subset == 'validation': 147 | return self.csv_files_dir() + '/val.txt' 148 | if subset == 'test': 149 | return self.csv_files_dir() + '/test.txt' 150 | 151 | def available_subsets(self): 152 | """Returns the list of available subsets.""" 153 | return ['train', 'validation', 'test'] 154 | 155 | def categories_file(self): 156 | return self.csv_files_dir() + '/labels.txt' 157 | 158 | 159 | ############################################################### 160 | datasets_paths_map = { 161 | 'catsDogs': CatsDogs_Paths, 162 | 'Warsaw': IrisWarsaw_Paths, 163 | 'ATVS': IrisATVS_Paths, 164 | 'MobBioFake': IrisMobbiofake_Paths, 165 | } 166 | 167 | -------------------------------------------------------------------------------- /data/helpers.py: -------------------------------------------------------------------------------- 1 | """ 2 | Helping functions called by the pipeline modules. 3 | """ 4 | 5 | ######################################################## 6 | def get_lines_in_file(file_path, read=False): 7 | """ 8 | Reads file lines and returns number of lines, and optionally the lines list 9 | 10 | :param file_path 11 | :param read: boolean to alloe=w return of lines contents not just the number of lines 12 | :return: number of lines, and optionally the lines list 13 | """ 14 | nLines = 0 15 | lines = [] 16 | with open(file_path, 'r') as f: 17 | for line in f: 18 | nLines += 1 19 | if read: 20 | lines.append(line.strip()) 21 | return lines, nLines 22 | 23 | ######################################################## 24 | def is_png(filename): 25 | """Determine if a file contains a PNG format image. 26 | 27 | Args: 28 | filename: string, path of the image file. 29 | 30 | Returns: 31 | boolean indicating if the image is a PNG. 32 | """ 33 | return '.png' in filename 34 | 35 | 36 | ######################################################## 37 | def is_jpg(filename): 38 | """Determine if a file contains a PNG format image. 39 | 40 | Args: 41 | filename: string, path of the image file. 42 | 43 | Returns: 44 | boolean indicating if the image is a JPG. 45 | """ 46 | return '.jpg' in filename 47 | -------------------------------------------------------------------------------- /data/helpers_dataset.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import os 3 | import random 4 | 5 | from data import helpers_image, helpers 6 | 7 | 8 | ################################################################### 9 | ############################################################################# 10 | def load_image_list(list_file_path, img_dir=None, delimeter=None): 11 | """ 12 | Read a label file with each line containing a path to an image and its integer class label, separated by a space 13 | the image path should contain no space, if so, it'll be surrounded by double wuotes which have to be accounted for when reading the file 14 | 15 | :param list_file_path: abs path to a labels file 16 | :param img_dir: optiona rppt path to be appended before the images path in case the images paths are relative 17 | :return: list of images path and absolute path and a list of corresponding labels 18 | """ 19 | 20 | f = open(list_file_path, 'r') 21 | image_fullpath_list = [] 22 | image_list = [] 23 | labels = [] 24 | for line in f: 25 | if delimeter: 26 | items = line.split(delimeter) 27 | else: 28 | items = line.split() 29 | nItems = len(items) 30 | lbl = items[-1] 31 | impath = None 32 | if nItems==2: 33 | impath = items[0].strip() 34 | else: 35 | items2 = line.split('"') 36 | if len(items2)>3: 37 | raise (line + 'Error, cant read file, many items found in line') 38 | impath = items2[1] 39 | 40 | if not impath: 41 | raise ('Error, cant read file') 42 | 43 | if img_dir: # a root image directory is passed, meaning paths written in the file are relative to that directory 44 | image_fullpath_list.append(os.path.join(img_dir, impath)) 45 | image_list.append(impath) 46 | else: 47 | image_fullpath_list.append(impath) 48 | 49 | labels.append(lbl.strip()) 50 | return image_fullpath_list, labels, image_list 51 | 52 | 53 | ################################################################### 54 | import csv 55 | def Generate_LabelsFile(imagesRootDir, trainF, valF, categoriesFile, validationPercent=0.2): 56 | """ 57 | Given the root images directory, generate labels text files for the training and validation files. 58 | Each line in a labels file contain a path to an image and it groundtruth label as integer. 59 | Also saves a categories file with each line representing a class name for the corresponding integer labels 60 | 61 | :param validationPercent: float representing percent of images to take from that root directory into the validation set, Default=0.2 62 | :return: paths to the saved labels files 63 | """ 64 | 65 | categoriesDirs = os.listdir(imagesRootDir) 66 | with open(categoriesFile, 'w') as lFile: 67 | for item in categoriesDirs: 68 | lFile.write("%s\n" % item) 69 | 70 | with open(trainF, 'wb') as tF, open(valF, 'w') as vF: 71 | tF_wr = csv.writer(tF, delimiter=' ') 72 | vF_wr = csv.writer(vF, delimiter=' ') 73 | for label, category in enumerate(categoriesDirs): 74 | files = os.listdir(imagesRootDir + '/' + category) 75 | nAllImages = len(files) 76 | nTrain = nAllImages - int(round(nAllImages * validationPercent)) 77 | trainImgs = files[0:nTrain] 78 | valFiles = files[nTrain:] 79 | 80 | for img in trainImgs: 81 | tF_wr.writerow([imagesRootDir + '/' + category + '/' + img] + [label]) 82 | for img in valFiles: 83 | vF_wr.writerow([imagesRootDir + '/' + category + '/' + img] + [label]) 84 | 85 | return categoriesDirs 86 | 87 | ################################################################### 88 | def read_image_files_from_csv(csv_file, data_dir=None, labels_file=None, test=False, delimiter=None): 89 | """Build a list of all images files and labels in the data set. 90 | 91 | Args: 92 | data_dir: string, path to the root directory of images. 93 | 94 | labels_file: string, path to the labels file. 95 | 96 | 97 | Returns: 98 | filenames: list of strings; each string is a path to an image file. 99 | texts: list of strings; each string is the class, e.g. 'dog' 100 | labels: list of integer; each integer identifies the ground truth. 101 | """ 102 | imgs_paths, labels, _ = load_image_list(csv_file, data_dir, delimiter) 103 | filenames = np.asarray(imgs_paths) 104 | labels = np.asarray(labels, dtype='int32') 105 | if (not test) and (labels_file is not None): 106 | categories, _ = helpers.get_lines_in_file(labels_file, read=True) 107 | texts = np.asarray([categories[label] for label in labels]) 108 | else: 109 | texts = np.asarray([''] * len(labels)) 110 | 111 | return filenames, texts, labels 112 | 113 | 114 | ############################################################ 115 | def calc_mean_pixel(filenames): 116 | sumImg = None 117 | nImages=0 118 | print ('Calculating mean image from %d images' % len(filenames)) 119 | for i, filename in enumerate(filenames): 120 | image = helpers_image.load_and_resize_image(filename, height=0, width=0, mode='RGB') 121 | if (i%100) == 0: 122 | print (i), 123 | if (i % 5000) == 0: 124 | print() 125 | if sumImg is None: 126 | h = image.shape[0] 127 | w = image.shape[1] 128 | sumImg = np.zeros((h, w, 3), np.float64) # don't know images sizes yet 129 | sumImg += image 130 | nImages+=1 131 | 132 | meanImg = np.round(sumImg / nImages).astype(np.uint8) 133 | meanPixel = np.mean(meanImg, axis=0) 134 | meanPixel = np.round(np.mean(meanPixel, axis=0)) 135 | return meanPixel 136 | 137 | 138 | ################################################################## 139 | def find_image_files(data_dir, labels_file, from_file=False, csv_file=None, test=False, start_labels_at_1=False): 140 | """Build a list of all images files and labels in the data set. 141 | 142 | Args: 143 | data_dir: string, path to the root directory of images. 144 | labels_file: string, path to the labels file. 145 | 146 | Returns: 147 | filenames: list of strings; each string is a path to an image file. 148 | texts: list of strings; each string is the class, e.g. 'dog' 149 | labels: list of integer; each integer identifies the ground truth. 150 | """ 151 | if from_file and not (csv_file is None): 152 | unique_labels = None 153 | filenames, texts, labels = read_image_files_from_csv(csv_file, data_dir, labels_file, test) 154 | if start_labels_at_1 and not test: 155 | labels+=1 156 | 157 | else: 158 | print('Determining list of input files and labels from %s.' % data_dir) 159 | unique_labels = [l.strip() for l in tf.gfile.FastGFile( 160 | labels_file, 'r').readlines()] 161 | 162 | labels = [] 163 | filenames = [] 164 | texts = [] 165 | 166 | ## YY: 167 | # label_index = 1 168 | if start_labels_at_1: 169 | # Leave label index 0 empty as a background class. 170 | label_index = 1 171 | else: 172 | label_index = 0 173 | 174 | # Construct the list of JPEG files and labels. 175 | for text in unique_labels: 176 | jpeg_file_path = '%s/%s/*' % (data_dir, text) 177 | matching_files = tf.gfile.Glob(jpeg_file_path) 178 | 179 | labels.extend([label_index] * len(matching_files)) 180 | texts.extend([text] * len(matching_files)) 181 | filenames.extend(matching_files) 182 | 183 | if not label_index % 100: 184 | print('Finished finding files in %d of %d classes.' % ( 185 | label_index, len(labels))) 186 | label_index += 1 187 | 188 | # Shuffle the ordering of all image files in order to guarantee 189 | # random ordering of the images with respect to label in the 190 | # saved TFRecord files. Make the randomization repeatable. 191 | shuffled_index = list(range(len(filenames))) 192 | random.seed(12345) 193 | random.shuffle(shuffled_index) 194 | 195 | filenames = [filenames[i] for i in shuffled_index] 196 | if not test: 197 | texts = [texts[i] for i in shuffled_index] 198 | labels = [labels[i] for i in shuffled_index] 199 | 200 | if unique_labels: 201 | print('Found %d JPEG files across %d labels inside %s.' % 202 | (len(filenames), len(unique_labels), data_dir)) 203 | else: 204 | print('Found %d JPEG files inside %s.' % 205 | (len(filenames), data_dir)) 206 | return filenames, texts, labels 207 | 208 | 209 | ################################################################## 210 | ################################################################## 211 | -------------------------------------------------------------------------------- /data/helpers_image.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import PIL.Image 4 | import scipy.misc 5 | 6 | ############################################################################ 7 | def load_and_resize_image(path, height, width, mode='RGB'): 8 | """ 9 | Returns an np.ndarray (height x width x channels) 10 | 11 | mode -- (RGB for color or L for grayscale) 12 | """ 13 | 14 | image = PIL.Image.open(path) # YY => RGB 8 bits, jpeg format, instance of Image class, not ndarray 15 | image = image.convert(mode) 16 | image = np.array(image) # YY => ndarray, uint8 values bet 0 and 255, shape 240x320x3 (h x w x ch) 17 | if height > 0 and width > 0: 18 | image = scipy.misc.imresize(image, (height, width), 19 | 'bilinear') # YY => ndarray, uint8 values bet 0 and 255, shape (h2 x w2 x ch) 20 | 21 | return image 22 | 23 | -------------------------------------------------------------------------------- /data_rel/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yomna-safaa/spoofnet-tensorflow/bbb0ab6f493a874dd7e43c1cee8e0740a417e9d7/data_rel/__init__.py -------------------------------------------------------------------------------- /data_rel/data_tf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yomna-safaa/spoofnet-tensorflow/bbb0ab6f493a874dd7e43c1cee8e0740a417e9d7/data_rel/data_tf/__init__.py -------------------------------------------------------------------------------- /data_rel/data_tf/dataset_utils_tf.py: -------------------------------------------------------------------------------- 1 | # from __future__ import absolute_import 2 | # from __future__ import division 3 | # from __future__ import print_function 4 | 5 | import os 6 | 7 | import tensorflow as tf 8 | 9 | LABELS_FILENAME = 'labels.txt' 10 | 11 | def number_of_examples_in_tfrecords(tfrecords_to_count): 12 | num_samples = 0 13 | for tfrecord_file in tfrecords_to_count: 14 | for record in tf.python_io.tf_record_iterator(tfrecord_file): 15 | num_samples += 1 16 | 17 | return num_samples 18 | 19 | 20 | def has_labels(dataset_dir, filename=LABELS_FILENAME): 21 | """Specifies whether or not the dataset directory contains a label map file. 22 | 23 | Args: 24 | dataset_dir: The directory in which the labels file is found. 25 | filename: The filename where the class names are written. 26 | 27 | Returns: 28 | `True` if the labels file exists and `False` otherwise. 29 | """ 30 | return tf.gfile.Exists(os.path.join(dataset_dir, filename)) 31 | 32 | 33 | def read_label_file(dataset_dir, filename=LABELS_FILENAME): 34 | """Reads the labels file and returns a mapping from ID to class name. 35 | 36 | Args: 37 | dataset_dir: The directory in which the labels file is found. 38 | filename: The filename where the class names are written. 39 | 40 | Returns: 41 | A map from a label (integer) to class name. 42 | """ 43 | labels_filename = os.path.join(dataset_dir, filename) 44 | with tf.gfile.Open(labels_filename, 'r') as f: 45 | lines = f.read().decode() 46 | lines = lines.split('\n') 47 | lines = filter(None, lines) 48 | 49 | labels_to_class_names = {} 50 | for line in lines: 51 | index = line.index(':') 52 | labels_to_class_names[int(line[:index])] = line[index+1:] 53 | return labels_to_class_names 54 | 55 | 56 | ################################################################################################# 57 | slim = tf.contrib.slim 58 | from pipeline_tf.image_utils import preprocess_image 59 | 60 | 61 | def load_batch_slim(dataset, batch_size, height, width, preprocessing_name, image_preprocessing_fn, 62 | num_readers=1, num_preprocessing_threads=4, per_image_standardization=False, 63 | vgg_sub_mean_pixel=None, vgg_resize_side_in=None, vgg_use_aspect_preserving_resize=None, 64 | labels_offset=0, is_training=False, allow_smaller_final_batch=False): 65 | ''' 66 | Loads a batch for training. 67 | 68 | INPUTS: 69 | - dataset(Dataset): a Dataset class object that is created from the get_split function 70 | - batch_size(int): determines how big of a batch to train 71 | - height(int): the height of the image to resize to during preprocessing 72 | - width(int): the width of the image to resize to during preprocessing 73 | - is_training(bool): to determine whether to perform a training or evaluation preprocessing 74 | 75 | OUTPUTS: 76 | - images(Tensor): a Tensor of the shape (batch_size, height, width, channels) that contain one batch of images 77 | - labels(Tensor): the batch's labels with the shape (batch_size,) (requires one_hot_encoding). 78 | 79 | ''' 80 | if is_training: 81 | provider = slim.dataset_data_provider.DatasetDataProvider( 82 | ## YY: note, shuffle is set to True by default in the Provider init 83 | dataset, 84 | num_readers=num_readers, 85 | common_queue_capacity=20 * batch_size, 86 | common_queue_min=10 * batch_size) 87 | else: 88 | if allow_smaller_final_batch: 89 | provider = slim.dataset_data_provider.DatasetDataProvider( 90 | dataset, num_epochs=1, 91 | shuffle=False, 92 | common_queue_capacity=2 * batch_size, 93 | common_queue_min=batch_size) 94 | else: 95 | provider = slim.dataset_data_provider.DatasetDataProvider( 96 | dataset, 97 | shuffle=False, 98 | common_queue_capacity=2 * batch_size, 99 | common_queue_min=batch_size) 100 | 101 | [raw_image, label, filename] = provider.get(['image', 'label', 'filename']) 102 | label -= labels_offset 103 | 104 | image = preprocess_image(preprocessing_name, image_preprocessing_fn, raw_image, height, width, 105 | per_image_standardization=per_image_standardization, 106 | vgg_sub_mean_pixel=vgg_sub_mean_pixel, vgg_resize_side_in=vgg_resize_side_in, 107 | vgg_use_aspect_preserving_resize=vgg_use_aspect_preserving_resize) 108 | 109 | # As for the raw images, we just do a simple reshape to batch it up 110 | raw_image = tf.expand_dims(raw_image, 0) 111 | raw_image = tf.image.resize_nearest_neighbor(raw_image, [height, width]) 112 | raw_image = tf.squeeze(raw_image) 113 | 114 | # Batch up the image by enqueing the tensors internally in a FIFO queue and dequeueing many elements with tf.train.batch. 115 | images, raw_images, labels, filenames =tf.train.batch( 116 | [image, raw_image, label, filename], 117 | batch_size=batch_size, 118 | num_threads=num_preprocessing_threads, 119 | capacity=5 * batch_size, allow_smaller_final_batch= allow_smaller_final_batch) 120 | 121 | return images, raw_images, labels, filenames 122 | 123 | 124 | ########################################################################## 125 | def get_split_slim(dataset_dir, file_pattern, num_samples, num_classes, channels, reader=None): 126 | """Gets a dataset tuple with instructions for reading flowers. 127 | 128 | Args: 129 | split_name: A train/validation split name. 130 | dataset_dir: The base directory of the dataset sources. 131 | file_pattern: The file pattern to use when matching the dataset sources. 132 | It is assumed that the pattern contains a '%s' string so that the split 133 | name can be inserted. 134 | reader: The TensorFlow reader type. 135 | 136 | Returns: 137 | A `Dataset` namedtuple. 138 | 139 | Raises: 140 | ValueError: if `split_name` is not a valid train/validation split. 141 | """ 142 | 143 | _ITEMS_TO_DESCRIPTIONS = { 144 | 'image': 'A color image of varying size.', 145 | 'label': 'A single integer between 0 and 1', 146 | 'filename': 'A string of file name', 147 | } 148 | 149 | # Allowing None in the signature so that dataset_factory can use the default. 150 | if reader is None: 151 | reader = tf.TFRecordReader 152 | 153 | keys_to_features = { ## YY: names of the keys to extract from the tfexamples of the tfrecord 154 | 'image/encoded': tf.FixedLenFeature((), tf.string, default_value=''), 155 | 'image/format': tf.FixedLenFeature((), tf.string, default_value='png'), 156 | 'image/class/label': tf.FixedLenFeature( 157 | [], tf.int64, default_value=tf.zeros([], dtype=tf.int64)), 158 | 'image/filename': tf.FixedLenFeature((), tf.string, default_value=''), 159 | } 160 | 161 | items_to_handlers = { ## YY: names of the tensors to be returned by the decoder (values coming from keys_to_features) 162 | 'image': slim.tfexample_decoder.Image(channels=channels), 163 | 'label': slim.tfexample_decoder.Tensor('image/class/label'), 164 | 'filename': slim.tfexample_decoder.Tensor('image/filename'), 165 | } 166 | 167 | decoder = slim.tfexample_decoder.TFExampleDecoder( 168 | keys_to_features, items_to_handlers) 169 | 170 | labels_to_names = None 171 | if has_labels(dataset_dir): 172 | labels_to_names = read_label_file(dataset_dir) 173 | 174 | return slim.dataset.Dataset( 175 | data_sources=file_pattern, 176 | reader=reader, 177 | decoder=decoder, 178 | num_samples=num_samples, 179 | items_to_descriptions=_ITEMS_TO_DESCRIPTIONS, 180 | num_classes=num_classes, 181 | labels_to_names=labels_to_names) 182 | 183 | -------------------------------------------------------------------------------- /nets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yomna-safaa/spoofnet-tensorflow/bbb0ab6f493a874dd7e43c1cee8e0740a417e9d7/nets/__init__.py -------------------------------------------------------------------------------- /nets/alexnet.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 The TensorFlow Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | """Contains a model definition for AlexNet. 16 | 17 | This work was first described in: 18 | ImageNet Classification with Deep Convolutional Neural Networks 19 | Alex Krizhevsky, Ilya Sutskever and Geoffrey E. Hinton 20 | 21 | and later refined in: 22 | One weird trick for parallelizing convolutional neural networks 23 | Alex Krizhevsky, 2014 24 | 25 | Here we provide the implementation proposed in "One weird trick" and not 26 | "ImageNet Classification", as per the paper, the LRN layers have been removed. 27 | 28 | Usage: 29 | with slim.arg_scope(alexnet.alexnet_v2_arg_scope()): 30 | outputs, end_points = alexnet.alexnet_v2(inputs) 31 | 32 | @@alexnet_v2 33 | """ 34 | 35 | from __future__ import absolute_import 36 | from __future__ import division 37 | from __future__ import print_function 38 | 39 | import tensorflow as tf 40 | 41 | slim = tf.contrib.slim 42 | trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev) 43 | 44 | 45 | def alexnet_v2_arg_scope(weight_decay=0.0005): 46 | with slim.arg_scope([slim.conv2d, slim.fully_connected], 47 | activation_fn=tf.nn.relu, 48 | biases_initializer=tf.constant_initializer(0.1), 49 | weights_regularizer=slim.l2_regularizer(weight_decay)): 50 | with slim.arg_scope([slim.conv2d], padding='SAME'): 51 | with slim.arg_scope([slim.max_pool2d], padding='VALID') as arg_sc: 52 | return arg_sc 53 | 54 | 55 | def alexnet_v2(inputs, 56 | num_classes=1000, 57 | is_training=True, 58 | dropout_keep_prob=0.5, 59 | spatial_squeeze=True, 60 | scope='alexnet_v2'): 61 | """AlexNet version 2. 62 | 63 | Described in: http://arxiv.org/pdf/1404.5997v2.pdf 64 | Parameters from: 65 | github.com/akrizhevsky/cuda-convnet2/blob/master/layers/ 66 | layers-imagenet-1gpu.cfg 67 | 68 | Note: All the fully_connected layers have been transformed to conv2d layers. 69 | To use in classification mode, resize input to 224x224. To use in fully 70 | convolutional mode, set spatial_squeeze to false. 71 | The LRN layers have been removed and change the initializers from 72 | random_normal_initializer to xavier_initializer. 73 | 74 | Args: 75 | inputs: a tensor of size [batch_size, height, width, channels]. 76 | num_classes: number of predicted classes. 77 | is_training: whether or not the model is being trained. 78 | dropout_keep_prob: the probability that activations are kept in the dropout 79 | layers during training. 80 | spatial_squeeze: whether or not should squeeze the spatial dimensions of the 81 | outputs. Useful to remove unnecessary dimensions for classification. 82 | scope: Optional scope for the variables. 83 | 84 | Returns: 85 | the last op containing the log predictions and end_points dict. 86 | """ 87 | with tf.variable_scope(scope, 'alexnet_v2', [inputs]) as sc: 88 | end_points_collection = sc.name + '_end_points' 89 | # Collect outputs for conv2d, fully_connected and max_pool2d. 90 | with slim.arg_scope([slim.conv2d, slim.fully_connected, slim.max_pool2d], 91 | outputs_collections=[end_points_collection]): 92 | net = slim.conv2d(inputs, 64, [11, 11], 4, padding='VALID', 93 | scope='conv1') 94 | net = slim.max_pool2d(net, [3, 3], 2, scope='pool1') 95 | net = slim.conv2d(net, 192, [5, 5], scope='conv2') 96 | net = slim.max_pool2d(net, [3, 3], 2, scope='pool2') 97 | net = slim.conv2d(net, 384, [3, 3], scope='conv3') 98 | net = slim.conv2d(net, 384, [3, 3], scope='conv4') 99 | net = slim.conv2d(net, 256, [3, 3], scope='conv5') 100 | net = slim.max_pool2d(net, [3, 3], 2, scope='pool5') 101 | 102 | # Use conv2d instead of fully_connected layers. 103 | with slim.arg_scope([slim.conv2d], 104 | weights_initializer=trunc_normal(0.005), 105 | biases_initializer=tf.constant_initializer(0.1)): 106 | net = slim.conv2d(net, 4096, [5, 5], padding='VALID', 107 | scope='fc6') 108 | net = slim.dropout(net, dropout_keep_prob, is_training=is_training, 109 | scope='dropout6') 110 | net = slim.conv2d(net, 4096, [1, 1], scope='fc7') 111 | net = slim.dropout(net, dropout_keep_prob, is_training=is_training, 112 | scope='dropout7') 113 | net = slim.conv2d(net, num_classes, [1, 1], 114 | activation_fn=None, 115 | normalizer_fn=None, 116 | biases_initializer=tf.zeros_initializer(), 117 | scope='fc8') 118 | 119 | # Convert end_points_collection into a end_point dict. 120 | end_points = slim.utils.convert_collection_to_dict(end_points_collection) 121 | if spatial_squeeze: 122 | net = tf.squeeze(net, [1, 2], name='fc8/squeezed') 123 | end_points[sc.name + '/fc8'] = net 124 | return net, end_points 125 | alexnet_v2.default_image_size = 224 126 | -------------------------------------------------------------------------------- /nets/cifarnet.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 The TensorFlow Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | """Contains a variant of the CIFAR-10 model definition.""" 16 | 17 | from __future__ import absolute_import 18 | from __future__ import division 19 | from __future__ import print_function 20 | 21 | import tensorflow as tf 22 | 23 | slim = tf.contrib.slim 24 | 25 | trunc_normal = lambda stddev: tf.truncated_normal_initializer(stddev=stddev) 26 | 27 | 28 | def cifarnet(images, num_classes=10, is_training=False, 29 | dropout_keep_prob=0.5, 30 | prediction_fn=slim.softmax, 31 | scope='CifarNet'): 32 | """Creates a variant of the CifarNet model. 33 | 34 | Note that since the output is a set of 'logits', the values fall in the 35 | interval of (-infinity, infinity). Consequently, to convert the outputs to a 36 | probability distribution over the characters, one will need to convert them 37 | using the softmax function: 38 | 39 | logits = cifarnet.cifarnet(images, is_training=False) 40 | probabilities = tf.nn.softmax(logits) 41 | predictions = tf.argmax(logits, 1) 42 | 43 | Args: 44 | images: A batch of `Tensors` of size [batch_size, height, width, channels]. 45 | num_classes: the number of classes in the dataset. 46 | is_training: specifies whether or not we're currently training the model. 47 | This variable will determine the behaviour of the dropout layer. 48 | dropout_keep_prob: the percentage of activation values that are retained. 49 | prediction_fn: a function to get predictions out of logits. 50 | scope: Optional variable_scope. 51 | 52 | Returns: 53 | logits: the pre-softmax activations, a tensor of size 54 | [batch_size, `num_classes`] 55 | end_points: a dictionary from components of the network to the corresponding 56 | activation. 57 | """ 58 | end_points = {} 59 | 60 | with tf.variable_scope(scope, 'CifarNet', [images, num_classes]): 61 | net = slim.conv2d(images, 64, [5, 5], scope='conv1') 62 | end_points['conv1'] = net 63 | net = slim.max_pool2d(net, [3, 3], 2, padding='SAME', scope='pool1') #YY:[2, 2], 2, scope='pool1') ## YY: 20May2017 ,testing to be the same as my model without slim 64 | end_points['pool1'] = net 65 | net = tf.nn.lrn(net, 4, bias=1.0, alpha=0.001/9.0, beta=0.75, name='norm1') 66 | net = slim.conv2d(net, 64, [5, 5], scope='conv2') 67 | end_points['conv2'] = net 68 | net = tf.nn.lrn(net, 4, bias=1.0, alpha=0.001/9.0, beta=0.75, name='norm2') 69 | net = slim.max_pool2d(net, [3, 3], 2, padding='SAME', scope='pool2') #YY:[2, 2], 2, scope='pool2') ## YY: 20May2017 ,testing to be the same as my model without slim 70 | end_points['pool2'] = net 71 | net = slim.flatten(net) 72 | end_points['Flatten'] = net 73 | net = slim.fully_connected(net, 384, scope='fc3') 74 | end_points['fc3'] = net 75 | net = slim.dropout(net, dropout_keep_prob, is_training=is_training, 76 | scope='dropout3') 77 | net = slim.fully_connected(net, 192, scope='fc4') 78 | end_points['fc4'] = net 79 | logits = slim.fully_connected(net, num_classes, 80 | biases_initializer=tf.zeros_initializer(), 81 | weights_initializer=trunc_normal(1/192.0), 82 | weights_regularizer=None, 83 | activation_fn=None, 84 | scope='logits') 85 | 86 | end_points['Logits'] = logits 87 | end_points['Predictions'] = prediction_fn(logits, scope='Predictions') 88 | 89 | return logits, end_points 90 | cifarnet.default_image_size = 32 91 | 92 | 93 | def cifarnet_arg_scope(weight_decay=0.004): 94 | """Defines the default cifarnet argument scope. 95 | 96 | Args: 97 | weight_decay: The weight decay to use for regularizing the model. 98 | 99 | Returns: 100 | An `arg_scope` to use for the inception v3 model. 101 | """ 102 | with slim.arg_scope( 103 | [slim.conv2d], 104 | weights_initializer=tf.truncated_normal_initializer(stddev=5e-2), 105 | activation_fn=tf.nn.relu): 106 | with slim.arg_scope( 107 | [slim.fully_connected], 108 | biases_initializer=tf.constant_initializer(0.1), 109 | weights_initializer=trunc_normal(0.04), 110 | weights_regularizer=slim.l2_regularizer(weight_decay), 111 | activation_fn=tf.nn.relu) as sc: 112 | return sc 113 | -------------------------------------------------------------------------------- /nets/nets_factory.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 The TensorFlow Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | """Contains a factory for building various models.""" 16 | 17 | from __future__ import absolute_import 18 | from __future__ import division 19 | from __future__ import print_function 20 | import functools 21 | 22 | import tensorflow as tf 23 | 24 | from nets import alexnet 25 | from nets import cifarnet 26 | from nets import spoofnet_y 27 | 28 | slim = tf.contrib.slim 29 | 30 | networks_map = {'alexnet_v2': alexnet.alexnet_v2, 31 | 'cifarnet': cifarnet.cifarnet, 32 | 'spoofnet_y': spoofnet_y.spoofnet_y, #YY 33 | 'spoofnet_y_BN': spoofnet_y.spoofnet_y, #YY 34 | 'spoofnet_y_noLRN': spoofnet_y.spoofnet_y_noLRN, #YY 35 | 'spoofnet_y_BN_noLRN': spoofnet_y.spoofnet_y_noLRN, #YY 36 | 'spoofnet_y2_noLRN': spoofnet_y.spoofnet_y2_noLRN, #YY 37 | 'spoofnet_y2_BN_noLRN': spoofnet_y.spoofnet_y2_noLRN, 38 | } 39 | 40 | arg_scopes_map = {'alexnet_v2': alexnet.alexnet_v2_arg_scope, 41 | 'cifarnet': cifarnet.cifarnet_arg_scope, 42 | 'spoofnet_y': spoofnet_y.spoofnet_y_arg_scope, #YY 43 | 'spoofnet_y_BN': spoofnet_y.spoofnet_y_arg_scope_BN, #YY 44 | 'spoofnet_y_noLRN': spoofnet_y.spoofnet_y_arg_scope, #YY 45 | 'spoofnet_y_BN_noLRN': spoofnet_y.spoofnet_y_arg_scope_BN, #YY 46 | 'spoofnet_y2_noLRN': spoofnet_y.spoofnet_y_arg_scope, #YY 47 | 'spoofnet_y2_BN_noLRN': spoofnet_y.spoofnet_y_arg_scope_BN, 48 | } 49 | 50 | 51 | def get_network_fn(name, num_classes, weight_decay=0.0, is_training=False): 52 | """Returns a network_fn such as `logits, end_points = network_fn(images)`. 53 | 54 | Args: 55 | name: The name of the network. 56 | num_classes: The number of classes to use for classification. 57 | weight_decay: The l2 coefficient for the model weights. 58 | is_training: `True` if the model is being used for training and `False` 59 | otherwise. 60 | 61 | Returns: 62 | network_fn: A function that applies the model to a batch of images. It has 63 | the following signature: 64 | logits, end_points = network_fn(images) 65 | Raises: 66 | ValueError: If network `name` is not recognized. 67 | """ 68 | if name not in networks_map: 69 | raise ValueError('Name of network unknown %s' % name) 70 | func = networks_map[name] 71 | @functools.wraps(func) 72 | # def network_fn(images): ## YY: orig 73 | def network_fn(images, **kwargs): ## YY: updated 20May2017 to allow passinf of droupout_keep_prob during train 74 | arg_scope = arg_scopes_map[name](weight_decay=weight_decay) 75 | with slim.arg_scope(arg_scope): 76 | # return func(images, num_classes, is_training=is_training) #YY: orig 77 | return func(images, num_classes, is_training=is_training, **kwargs) ## YY: updated 20May2017 to allow passinf of droupout_keep_prob during train 78 | if hasattr(func, 'default_image_size'): 79 | network_fn.default_image_size = func.default_image_size 80 | 81 | return network_fn 82 | -------------------------------------------------------------------------------- /nets/spoofnet_y.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 The TensorFlow Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | """Contains a variant of the CIFAR-10 model definition.""" 16 | 17 | from __future__ import absolute_import 18 | from __future__ import division 19 | from __future__ import print_function 20 | 21 | import tensorflow as tf 22 | 23 | slim = tf.contrib.slim 24 | 25 | trunc_normal = lambda stddev: tf.truncated_normal_initializer(stddev=stddev) 26 | 27 | 28 | def spoofnet_y(images, num_classes=10, is_training=False, 29 | dropout_keep_prob=0.5, 30 | prediction_fn=slim.softmax, 31 | scope='SpoofNetY'): 32 | """Creates a variant of the CifarNet model. 33 | 34 | Note that since the output is a set of 'logits', the values fall in the 35 | interval of (-infinity, infinity). Consequently, to convert the outputs to a 36 | probability distribution over the characters, one will need to convert them 37 | using the softmax function: 38 | 39 | logits = cifarnet.cifarnet(images, is_training=False) 40 | probabilities = tf.nn.softmax(logits) 41 | predictions = tf.argmax(logits, 1) 42 | 43 | Args: 44 | images: A batch of `Tensors` of size [batch_size, height, width, channels]. 45 | num_classes: the number of classes in the dataset. 46 | is_training: specifies whether or not we're currently training the model. 47 | This variable will determine the behaviour of the dropout layer. 48 | dropout_keep_prob: the percentage of activation values that are retained. 49 | prediction_fn: a function to get predictions out of logits. 50 | scope: Optional variable_scope. 51 | 52 | Returns: 53 | logits: the pre-softmax activations, a tensor of size 54 | [batch_size, `num_classes`] 55 | end_points: a dictionary from components of the network to the corresponding 56 | activation. 57 | """ 58 | end_points = {} 59 | 60 | with tf.variable_scope(scope, 'SpoofNetY', [images, num_classes]): 61 | with slim.arg_scope([slim.batch_norm, slim.dropout], 62 | is_training=is_training): 63 | net = slim.conv2d(images, 16, [5, 5], scope='conv1') # cifar: 64 64 | end_points['conv1'] = net 65 | net = slim.max_pool2d(net, [3, 3], 2, scope='pool1') #YY:[2, 2], 2, scope='pool1') ## YY: 20May2017 ,testing to be the same as my model without slim 66 | end_points['pool1'] = net 67 | net = tf.nn.lrn(net, 4, bias=1.0, alpha=0.001/9.0, beta=0.75, name='norm1') 68 | net = slim.conv2d(net, 64, [5, 5], scope='conv2') 69 | end_points['conv2'] = net 70 | net = slim.max_pool2d(net, [3, 3], 2, scope='pool2') # YY:[2, 2], 2, scope='pool2') ## YY: 20May2017 ,testing to be the same as my model without slim 71 | end_points['pool2'] = net 72 | net = tf.nn.lrn(net, 4, bias=1.0, alpha=0.001/9.0, beta=0.75, name='norm2') ## YY: switch maxpool and lrn from cifar10 73 | # net = slim.max_pool2d(net, [3, 3], 2, padding='SAME', scope='pool2') #YY:[2, 2], 2, scope='pool2') ## YY: 20May2017 ,testing to be the same as my model without slim 74 | # end_points['pool2'] = net 75 | net = slim.flatten(net) 76 | end_points['Flatten'] = net ## YY: spoonet, no fc layers, only the final fc layer of logits 77 | # net = slim.fully_connected(net, 384, scope='fc3') 78 | # end_points['fc3'] = net 79 | # net = slim.dropout(net, dropout_keep_prob, is_training=is_training, 80 | # scope='dropout3') 81 | # net = slim.fully_connected(net, 192, scope='fc4') 82 | # end_points['fc4'] = net 83 | logits = slim.fully_connected(net, num_classes, 84 | biases_initializer=tf.zeros_initializer(), 85 | weights_initializer=trunc_normal(0.0005), #trunc_normal(1/192.0), 86 | weights_regularizer=None, # TODO, use reg)wd) or not for logits? 87 | activation_fn=None, 88 | normalizer_fn=None, 89 | scope='logits') 90 | 91 | end_points['Logits'] = logits 92 | end_points['Predictions'] = prediction_fn(logits, scope='Predictions') 93 | 94 | return logits, end_points 95 | 96 | def spoofnet_y_noLRN(images, num_classes=10, is_training=False, 97 | dropout_keep_prob=0.5, 98 | prediction_fn=slim.softmax, 99 | scope='SpoofNetY'): 100 | """Creates a variant of the CifarNet model. 101 | 102 | Note that since the output is a set of 'logits', the values fall in the 103 | interval of (-infinity, infinity). Consequently, to convert the outputs to a 104 | probability distribution over the characters, one will need to convert them 105 | using the softmax function: 106 | 107 | logits = cifarnet.cifarnet(images, is_training=False) 108 | probabilities = tf.nn.softmax(logits) 109 | predictions = tf.argmax(logits, 1) 110 | 111 | Args: 112 | images: A batch of `Tensors` of size [batch_size, height, width, channels]. 113 | num_classes: the number of classes in the dataset. 114 | is_training: specifies whether or not we're currently training the model. 115 | This variable will determine the behaviour of the dropout layer. 116 | dropout_keep_prob: the percentage of activation values that are retained. 117 | prediction_fn: a function to get predictions out of logits. 118 | scope: Optional variable_scope. 119 | 120 | Returns: 121 | logits: the pre-softmax activations, a tensor of size 122 | [batch_size, `num_classes`] 123 | end_points: a dictionary from components of the network to the corresponding 124 | activation. 125 | """ 126 | end_points = {} 127 | 128 | with tf.variable_scope(scope, 'SpoofNetY', [images, num_classes], reuse=tf.AUTO_REUSE): 129 | with slim.arg_scope([slim.batch_norm, slim.dropout], 130 | is_training=is_training): 131 | net = slim.conv2d(images, 16, [5, 5], scope='conv1') # cifar: 64 132 | end_points['conv1'] = net 133 | net = slim.max_pool2d(net, [3, 3], 2, scope='pool1') #YY:[2, 2], 2, scope='pool1') ## YY: 20May2017 ,testing to be the same as my model without slim 134 | end_points['pool1'] = net 135 | # net = tf.nn.lrn(net, 4, bias=1.0, alpha=0.001/9.0, beta=0.75, name='norm1') 136 | net = slim.conv2d(net, 64, [5, 5], scope='conv2') 137 | end_points['conv2'] = net 138 | net = slim.max_pool2d(net, [3, 3], 2, scope='pool2') # YY:[2, 2], 2, scope='pool2') ## YY: 20May2017 ,testing to be the same as my model without slim 139 | end_points['pool2'] = net 140 | # net = tf.nn.lrn(net, 4, bias=1.0, alpha=0.001/9.0, beta=0.75, name='norm2') ## YY: switch maxpool and lrn from cifar10 141 | # net = slim.max_pool2d(net, [3, 3], 2, padding='SAME', scope='pool2') #YY:[2, 2], 2, scope='pool2') ## YY: 20May2017 ,testing to be the same as my model without slim 142 | # end_points['pool2'] = net 143 | net = slim.flatten(net) 144 | end_points['Flatten'] = net ## YY: spoonet, no fc layers, only the final fc layer of logits 145 | # net = slim.fully_connected(net, 384, scope='fc3') 146 | # end_points['fc3'] = net 147 | # net = slim.dropout(net, dropout_keep_prob, is_training=is_training, 148 | # scope='dropout3') 149 | # net = slim.fully_connected(net, 192, scope='fc4') 150 | # end_points['fc4'] = net 151 | logits = slim.fully_connected(net, num_classes, 152 | biases_initializer=tf.zeros_initializer(), 153 | weights_initializer=trunc_normal(0.0005), #trunc_normal(1/192.0), 154 | weights_regularizer=None, # TODO, use reg)wd) or not for logits? 155 | activation_fn=None, 156 | normalizer_fn=None, 157 | scope='logits') 158 | 159 | end_points['Logits'] = logits 160 | end_points['Predictions'] = prediction_fn(logits, scope='Predictions') 161 | 162 | return logits, end_points 163 | 164 | def spoofnet_y2_noLRN(images, num_classes=10, is_training=False, 165 | dropout_keep_prob=0.5, 166 | prediction_fn=slim.softmax, 167 | scope='SpoofNetY'): 168 | """Creates a variant of the CifarNet model. 169 | 170 | Note that since the output is a set of 'logits', the values fall in the 171 | interval of (-infinity, infinity). Consequently, to convert the outputs to a 172 | probability distribution over the characters, one will need to convert them 173 | using the softmax function: 174 | 175 | logits = cifarnet.cifarnet(images, is_training=False) 176 | probabilities = tf.nn.softmax(logits) 177 | predictions = tf.argmax(logits, 1) 178 | 179 | Args: 180 | images: A batch of `Tensors` of size [batch_size, height, width, channels]. 181 | num_classes: the number of classes in the dataset. 182 | is_training: specifies whether or not we're currently training the model. 183 | This variable will determine the behaviour of the dropout layer. 184 | dropout_keep_prob: the percentage of activation values that are retained. 185 | prediction_fn: a function to get predictions out of logits. 186 | scope: Optional variable_scope. 187 | 188 | Returns: 189 | logits: the pre-softmax activations, a tensor of size 190 | [batch_size, `num_classes`] 191 | end_points: a dictionary from components of the network to the corresponding 192 | activation. 193 | """ 194 | end_points = {} 195 | 196 | with tf.variable_scope(scope, 'SpoofNetY', [images, num_classes]): 197 | with slim.arg_scope([slim.batch_norm, slim.dropout], 198 | is_training=is_training): 199 | net = slim.conv2d(images, 16, [5, 5], scope='conv1') # cifar: 64 200 | end_points['conv1'] = net 201 | net = slim.max_pool2d(net, [3, 3], 2, scope='pool1') #YY:[2, 2], 2, scope='pool1') ## YY: 20May2017 ,testing to be the same as my model without slim 202 | end_points['pool1'] = net 203 | # net = tf.nn.lrn(net, 4, bias=1.0, alpha=0.001/9.0, beta=0.75, name='norm1') 204 | net = slim.conv2d(net, 64, [5, 5], scope='conv2') 205 | end_points['conv2'] = net 206 | net = slim.max_pool2d(net, [3, 3], 2, scope='pool2') # YY:[2, 2], 2, scope='pool2') ## YY: 20May2017 ,testing to be the same as my model without slim 207 | end_points['pool2'] = net 208 | # net = tf.nn.lrn(net, 4, bias=1.0, alpha=0.001/9.0, beta=0.75, name='norm2') ## YY: switch maxpool and lrn from cifar10 209 | # net = slim.max_pool2d(net, [3, 3], 2, padding='SAME', scope='pool2') #YY:[2, 2], 2, scope='pool2') ## YY: 20May2017 ,testing to be the same as my model without slim 210 | # end_points['pool2'] = net 211 | net = slim.flatten(net) 212 | end_points['Flatten'] = net ## YY: spoonet, no fc layers, only the final fc layer of logits 213 | net = slim.fully_connected(net, 512, scope='fc') 214 | end_points['fc'] = net 215 | net = slim.dropout(net, dropout_keep_prob, is_training=is_training, 216 | scope='dropout') 217 | # net = slim.fully_connected(net, 192, scope='fc4') 218 | # end_points['fc4'] = net 219 | logits = slim.fully_connected(net, num_classes, 220 | biases_initializer=tf.zeros_initializer(), 221 | weights_initializer=trunc_normal(0.0005), #trunc_normal(1/192.0), 222 | weights_regularizer=None, # TODO, use reg)wd) or not for logits? 223 | activation_fn=None, 224 | normalizer_fn=None, 225 | scope='logits') 226 | 227 | end_points['Logits'] = logits 228 | end_points['Predictions'] = prediction_fn(logits, scope='Predictions') 229 | 230 | return logits, end_points 231 | 232 | 233 | spoofnet_y.default_image_size = 112 234 | 235 | 236 | def spoofnet_y_arg_scope_BN(weight_decay=0.0004, 237 | use_batch_norm=True, 238 | batch_norm_decay=0.9, #0.9997, ## YY: dec to 0.9 based on hint from https://github.com/tensorflow/tensorflow/issues/1122#issuecomment-261041193 239 | batch_norm_epsilon=0.001 240 | ): 241 | """Defines the default cifarnet argument scope. 242 | 243 | Args: 244 | weight_decay: The weight decay to use for regularizing the model. 245 | 246 | Returns: 247 | An `arg_scope` to use for the inception v3 model. 248 | """ 249 | ## YY: add batch normalization 250 | batch_norm_params = { 251 | # Decay for the moving averages. 252 | 'decay': batch_norm_decay, 253 | # epsilon to prevent 0s in variance. 254 | 'epsilon': batch_norm_epsilon, 255 | # collection containing update_ops. 256 | # 'updates_collections': tf.GraphKeys.UPDATE_OPS, 257 | # # YY: hint from: https://github.com/tensorflow/tensorflow/issues/1122#issuecomment-235928564: 258 | # # But what it is important is that either you pass updates_collections=None so 259 | # # the moving_mean and moving_variance are updated in-place, otherwise you will need gather the update_ops and make sure they are run. 260 | # 'updates_collections': None 261 | } 262 | if use_batch_norm: 263 | normalizer_fn = slim.batch_norm 264 | normalizer_params = batch_norm_params 265 | else: 266 | normalizer_fn = None 267 | normalizer_params = {} 268 | with slim.arg_scope( 269 | [slim.conv2d], 270 | weights_initializer=tf.truncated_normal_initializer(stddev=5e-2), #TODO: or: weights_initializer=slim.variance_scaling_initializer(), as inception/vgg/resnet 271 | weights_regularizer=slim.l2_regularizer(weight_decay), 272 | activation_fn=tf.nn.relu, 273 | normalizer_fn=normalizer_fn, 274 | normalizer_params=normalizer_params 275 | ): 276 | # with slim.arg_scope( 277 | # [slim.fully_connected], 278 | # biases_initializer=tf.constant_initializer(0.1), 279 | # weights_initializer=trunc_normal(0.04), 280 | # weights_regularizer=slim.l2_regularizer(weight_decay), 281 | # activation_fn=tf.nn.relu): 282 | with slim.arg_scope([slim.max_pool2d], padding='SAME') as sc: 283 | return sc 284 | 285 | 286 | def spoofnet_y_arg_scope(weight_decay=0.0004): 287 | """Defines the default cifarnet argument scope. 288 | 289 | Args: 290 | weight_decay: The weight decay to use for regularizing the model. 291 | 292 | Returns: 293 | An `arg_scope` to use for the inception v3 model. 294 | """ 295 | with slim.arg_scope( 296 | [slim.conv2d], 297 | weights_initializer=tf.truncated_normal_initializer(stddev=5e-2), #TODO: or: weights_initializer=slim.variance_scaling_initializer(), as inception/vgg/resnet 298 | # weights_regularizer=slim.l2_regularizer(weight_decay), 299 | activation_fn=tf.nn.relu 300 | ): 301 | # with slim.arg_scope( 302 | # [slim.fully_connected], 303 | # biases_initializer=tf.constant_initializer(0.1), 304 | # weights_initializer=trunc_normal(0.04), 305 | # weights_regularizer=slim.l2_regularizer(weight_decay), 306 | # activation_fn=tf.nn.relu): 307 | with slim.arg_scope([slim.max_pool2d], padding='SAME') as sc: 308 | return sc 309 | -------------------------------------------------------------------------------- /pipeline_tf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yomna-safaa/spoofnet-tensorflow/bbb0ab6f493a874dd7e43c1cee8e0740a417e9d7/pipeline_tf/__init__.py -------------------------------------------------------------------------------- /pipeline_tf/evaluation_y.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import numpy as np 3 | import os 4 | import time 5 | from datetime import datetime 6 | 7 | from tensorflow.python.platform import tf_logging as logging 8 | from tensorflow.python import platform 9 | from common import metrics 10 | import tensorflow as tf 11 | 12 | ############################################################################# 13 | def report_accuracy(pred_scores_all, labels_all, threshold, display_details=False): 14 | 15 | if isinstance(threshold, list): 16 | acc_at_in_thr = [] 17 | for threshold_i in threshold: 18 | n_all = len(labels_all) 19 | acc1, far1, frr1, hter1 = metrics.Accuracy(pred_scores_all, labels_all, threshold_i) 20 | corr = round(acc1 * n_all) 21 | incorrect = n_all - corr 22 | logging.info( 23 | "----------- Accuracy at given threshold [%.4f](%%); %.2f%%, FAR: %.4f , FRR: %.4f, HTER: %.4f%%. N_incorrect = %d/%d", 24 | threshold_i, acc1 * 100, far1, frr1, hter1, incorrect, n_all) 25 | acc_at_in_thr.extend([acc1 * 100]) 26 | 27 | else: 28 | n_all = len(labels_all) 29 | acc1, far1, frr1, hter1 = metrics.Accuracy(pred_scores_all, labels_all, threshold) 30 | corr = round(acc1 * n_all) 31 | incorrect = n_all - corr 32 | logging.info( 33 | "----------- Accuracy at given threshold [%.4f](%%); %.2f%%, FAR: %.4f , FRR: %.4f, HTER: %.4f%%. N_incorrect = %d/%d", 34 | threshold, acc1 * 100, far1, frr1, hter1, incorrect, n_all) 35 | acc_at_in_thr = acc1 * 100 36 | 37 | 38 | eer_thr, mer_thr, eer_thr_max = metrics.roc_det(pred_scores_all, labels_all, display_details=display_details) 39 | acc2, far2, frr2, hter2 = metrics.Accuracy(pred_scores_all, labels_all, eer_thr) 40 | corr = round(acc2 * n_all) 41 | incorrect = n_all - corr 42 | logging.info( 43 | "----------- Accuracy at eer threshold [%.4f](%%); %.2f%%, FAR: %.4f , FRR: %.4f, HTER: %.4f%%. N_incorrect = %d/%d", 44 | eer_thr, acc2 * 100, far2, frr2, hter2, incorrect, n_all) 45 | 46 | return acc_at_in_thr, eer_thr, eer_thr_max 47 | 48 | 49 | ############################################################################# 50 | def write_results_file(results_file, filenames_all, labels_all, pred_scores_all, ind_incorrect, categories_list=None): 51 | if os.path.exists(results_file): 52 | os.rename(results_file, results_file+'-old.txt') 53 | 54 | write_scores=False 55 | if len(pred_scores_all)>0: 56 | write_scores=True 57 | incorrect_filenames_all2 = [filenames_all[j] for j in ind_incorrect] 58 | incorrect_labels_all2 = [labels_all[j] for j in ind_incorrect] 59 | pos_pred_scores_for_incorrect = [pred_scores_all[j] for j in ind_incorrect] 60 | 61 | print('Creating output file %s' % results_file) 62 | with open(results_file, 'w') as lFile: 63 | writer = csv.writer(lFile) 64 | writer.writerow(('filename', 'true_label', 'pos_pred_score')) 65 | for i, filename in enumerate(incorrect_filenames_all2): 66 | true_label = incorrect_labels_all2[i] 67 | if categories_list is not None: 68 | if write_scores: 69 | row=(incorrect_filenames_all2[i], '%d[%s]' % (true_label, categories_list[true_label]), '%.4f' % pos_pred_scores_for_incorrect[i]) 70 | else: 71 | row = (incorrect_filenames_all2[i], '%d[%s]' % (true_label, categories_list[true_label])) 72 | else: 73 | if write_scores: 74 | row = (incorrect_filenames_all2[i], true_label, '%.4f' % pos_pred_scores_for_incorrect[i]) 75 | else: 76 | row = (incorrect_filenames_all2[i], true_label) 77 | 78 | writer.writerow(row) 79 | 80 | ########################################################################3 81 | def get_eval_ops(logits, labels, one_hot=False, scope='', calc_accuracy=True): 82 | """Evaluate the quality of the logits at predicting the label. 83 | Args: 84 | logits: Logits tensor, float - [batch_size, NUM_CLASSES]. 85 | labels: Labels tensor, int32 - [batch_size], with values in the 86 | range [0, NUM_CLASSES). 87 | Returns: 88 | A scalar int32 tensor with the number of examples (out of batch_size) 89 | that were predicted correctly. 90 | """ 91 | print('Evaluation Ops..') 92 | with tf.name_scope(scope): 93 | # For a classifier model, we can use the in_top_k Op. 94 | # It returns a bool tensor with shape [batch_size] that is true for 95 | # the examples where the label's is was in the top k (here k=1) 96 | # of all logits for that example. 97 | # labels = tf.cast(labels, tf.int64) 98 | if one_hot: 99 | labels = tf.argmax(labels, 1) 100 | top_1_op = tf.nn.in_top_k(logits, labels, 1) 101 | num_correct = tf.reduce_sum(tf.cast(top_1_op, tf.float32)) 102 | 103 | if calc_accuracy: 104 | acc_percent = tf.divide(num_correct, labels.shape[0].value) 105 | else: 106 | acc_percent = tf.constant(0.0) 107 | 108 | # ============= 109 | y_const = tf.constant(-1, dtype=labels.dtype) 110 | y_greater = tf.greater(labels, y_const) 111 | n_all = tf.reduce_sum(tf.cast(y_greater, tf.float32)) 112 | 113 | return top_1_op, acc_percent * 100.0, num_correct, n_all, labels 114 | 115 | 116 | ######################################################################## 117 | def get_eval_ops_slim(logits, labels, one_hot=False, scope=''): 118 | slim = tf.contrib.slim 119 | with tf.name_scope(scope + '/Streaming'): 120 | if one_hot: 121 | labels = tf.argmax(labels, 1) 122 | 123 | predictions = tf.argmax(logits, 1) 124 | labels = tf.squeeze(labels) 125 | 126 | names_to_values, names_to_updates = slim.metrics.aggregate_metric_map({ 127 | 'Accuracy': slim.metrics.streaming_accuracy(predictions, labels), 128 | }) 129 | return names_to_values, names_to_updates 130 | 131 | 132 | ######################################################################## 133 | def evaluate_loop_slim_streaming_metrics(sess, num_val_iter, eval_ops): 134 | """ They have no return,s each metrisc write to summary .. so just monitor the tensorboard""" 135 | 136 | step = 0 137 | while step < num_val_iter: 138 | sess.run(eval_ops) 139 | logging.info('Evaluation [%d/%d]', step+1, num_val_iter) 140 | step += 1 141 | 142 | 143 | ######################################################################## 144 | def evaluate_loop_y(sess, num_val_iter, batch_size, eval_ops, display_details=False, threshold=None, filenames=None, 145 | results_file=None, eval_ops_slim=None): 146 | 147 | total_sample_count = num_val_iter * batch_size 148 | logging.info('%s: starting evaluation on Examples: %d, for %d iter.' % ( 149 | datetime.now(), total_sample_count, num_val_iter)) 150 | 151 | # Counts the number of correct predictions. 152 | count_top_1 = 0.0 153 | n_correct_all = 0 154 | step = 0 155 | n_all = 0 156 | pred_scores_all = [] 157 | labels_all = [] 158 | filenames_all = [] 159 | ind_incorrect = [] 160 | incorrect_filenames_all = [] 161 | incorrect_filenames_correct_labels = [] 162 | 163 | start_time = time.time() 164 | while step < num_val_iter: 165 | if filenames is None: 166 | val_results = sess.run(eval_ops) # => [top_1_op, acc, n_correct, n_in_batch, labels_in_batch ] 167 | else: 168 | if eval_ops_slim is None: 169 | val_results, filenames_in_batch = sess.run([eval_ops, filenames]) 170 | else: 171 | val_results, filenames_in_batch, _ = sess.run([eval_ops, filenames, eval_ops_slim]) 172 | filenames_all.extend(filenames_in_batch) 173 | top_1 = val_results[0] 174 | acc = val_results[1] 175 | n_correct = val_results[2] 176 | n_in_batch = val_results[3] 177 | labels_in_batch = val_results[4] 178 | labels_all.extend(labels_in_batch) 179 | if filenames is not None: 180 | ind_incorrect_tmp = np.where(top_1 == False)[0] 181 | incorrect_filenames_all.extend(list(filenames_in_batch[ind_incorrect_tmp])) 182 | incorrect_filenames_correct_labels.extend(list(labels_in_batch[ind_incorrect_tmp])) 183 | ind_incorrect.extend(list(ind_incorrect_tmp + (step * batch_size))) 184 | if len(val_results)>5: 185 | probabilities = val_results[5] 186 | pred_scores = probabilities[:, 1] # assume score to be the pred prob of the positive class [1] 187 | pred_scores_all.extend(pred_scores) 188 | 189 | count_top_1 += np.sum(top_1) 190 | n_correct_all += n_correct 191 | n_all += n_in_batch 192 | step += 1 193 | logging.info('Evaluation [%d/%d]. n_correct/n_in_batch: %d/%d', step, num_val_iter, n_correct, n_in_batch) 194 | 195 | total_sample_count = n_all 196 | accuracyy = n_correct_all * 100.0 / total_sample_count 197 | 198 | eval_time = time.time() - start_time 199 | logging.info('--- Evaluated on Examples: %d, for %d iter.' % (total_sample_count, num_val_iter)) 200 | logging.info('--- Testing time: %.3f' % (eval_time)) 201 | 202 | acc_percent=0.0 203 | precision_at_1=0.0 204 | 205 | if filenames is not None: 206 | print ('------ Incorrect_filenames based on top_1 (0.5 threshold):') 207 | print (incorrect_filenames_all) 208 | write_results_file(results_file, filenames_all, labels_all, pred_scores_all, ind_incorrect) 209 | 210 | acc_at_in_thr, eer_thr, eer_thr_max = 0, None, None 211 | if len(val_results) > 5: 212 | if threshold is None: 213 | threshold = 0.5 214 | else: 215 | report_accuracy(pred_scores_all, labels_all,0.5, display_details) 216 | acc_at_in_thr, eer_thr, eer_thr_max = report_accuracy(pred_scores_all, labels_all, threshold, display_details) 217 | 218 | 219 | return accuracyy, n_correct_all, acc_percent, precision_at_1, total_sample_count, acc_at_in_thr, eer_thr, eer_thr_max 220 | 221 | 222 | ############################################################ 223 | from data import helpers 224 | from pipeline_tf import image_utils 225 | from preprocessing import preprocessing_factory 226 | 227 | class Classifier_PL(): 228 | def __init__(self, eval_image_size, n_channels, preprocessing_name, encode_type='JPEG', 229 | oversample=False, per_image_standardization=False, 230 | vgg_sub_mean_pixel=None, vgg_resize_side_in=None, 231 | vgg_use_aspect_preserving_resize=None): 232 | 233 | self.tensor1_pl = tf.placeholder(tf.float32, (None, eval_image_size, eval_image_size, n_channels)) 234 | self.tensor2_pl = tf.placeholder(tf.float32, (None, eval_image_size, eval_image_size, n_channels)) 235 | self.tf_concat_op = tf.concat([self.tensor1_pl, self.tensor2_pl], 0) 236 | 237 | image_preprocessing_fn_at_eval = preprocessing_factory.get_preprocessing(preprocessing_name, is_training=False) 238 | image_crop_processing_fn = preprocessing_factory.get_img_crop_preprocessing(preprocessing_name) 239 | self.raw_images_pl = tf.placeholder(tf.float32, [None, None, 3]) 240 | self.preprocessed_img_crops = image_utils.get_preprocessed_img_crops(self.raw_images_pl, preprocessing_name, 241 | eval_image_size, eval_image_size, 242 | image_preprocessing_fn_at_eval, image_crop_processing_fn, 243 | oversample=oversample, 244 | per_image_standardization=per_image_standardization, 245 | vgg_sub_mean_pixel=vgg_sub_mean_pixel, 246 | vgg_resize_side_in=vgg_resize_side_in, 247 | vgg_use_aspect_preserving_resize=vgg_use_aspect_preserving_resize) 248 | self.coder = image_utils.ImageCoder_TF() 249 | self.encode_type = encode_type 250 | 251 | ############################################################ 252 | def classify_batch(self, sess, softmax_output, images_pl, image_files, 253 | summary_op=None, summary_writer=None): 254 | first = True 255 | batch_sizes = [] 256 | # crops_all=[] 257 | for image_file in image_files: 258 | _, im_batch = image_utils.make_batch_from_img_pl(sess, self.preprocessed_img_crops, self.raw_images_pl, image_file, 259 | self.coder, encode_type=self.encode_type, 260 | summary_op=summary_op, summary_writer=summary_writer) 261 | batch_sz = im_batch.shape[0] 262 | batch_sizes.extend([batch_sz]) 263 | if first: 264 | y_batch_ = im_batch 265 | first = False 266 | else: 267 | y_batch_ = sess.run(self.tf_concat_op, feed_dict={self.tensor1_pl: y_batch_, self.tensor2_pl: im_batch}) 268 | 269 | batch_results_all = sess.run(softmax_output, feed_dict={images_pl: y_batch_}) 270 | n = 0 271 | img = 0 272 | output_all = np.zeros([len(batch_sizes), 2]) 273 | for sz in batch_sizes: 274 | batch_results = batch_results_all[n:n + sz] 275 | n += sz # .value 276 | output = batch_results[0] 277 | batch_sz = batch_results.shape[0] 278 | for i in range(1, batch_sz): 279 | output = output + batch_results[i] 280 | 281 | output /= batch_sz 282 | output_all[img] = output 283 | img += 1 284 | 285 | return output_all 286 | 287 | ########################################################################## 288 | def classify(self, sess, softmax_output, images_pl, image_file): 289 | # print('Running file %s' % image_file) 290 | crops, im_batch = image_utils.make_batch_from_img_pl(sess, self.preprocessed_img_crops, self.raw_images_pl, image_file, 291 | self.coder, encode_type=self.encode_type) 292 | 293 | batch_results = sess.run(softmax_output, feed_dict={images_pl: im_batch}) 294 | output = batch_results[0] 295 | batch_sz = batch_results.shape[0] 296 | logging.info(' - Ran batch of %d images' % batch_sz) 297 | for i in range(1, batch_sz): 298 | output = output + batch_results[i] 299 | 300 | output /= batch_sz 301 | 302 | return output 303 | 304 | ############################################################ 305 | def evaluate_loop_placeholder(self, sess, probabilities_op, images_pl, 306 | filenames, categories_file, labels, threshold=None, 307 | results_file=None, batch_size=1, summary_op=None, summary_writer=None): 308 | 309 | output = None 310 | writer=None 311 | if results_file is not None: 312 | if os.path.exists(results_file): 313 | os.rename(results_file, results_file + '-old.txt') 314 | print('Creating output file %s' % results_file) 315 | output = open(results_file, 'w') 316 | writer = csv.writer(output) 317 | writer.writerow(('file', 'predicted_label', 'score_of_prediction')) 318 | 319 | label_list, _ = helpers.get_lines_in_file(categories_file, read=True) 320 | n = len(filenames) 321 | pred_scores_all=np.zeros(n) 322 | ind_incorrect=[] 323 | 324 | i=0 325 | if batch_size > 1: 326 | final_batch = False 327 | while not final_batch: 328 | if (i+batch_size)>len(filenames): 329 | image_files = filenames[i:len(filenames)] 330 | final_batch=True 331 | else: 332 | image_files = filenames[i:i+batch_size] 333 | 334 | if len(image_files)<1: 335 | break 336 | 337 | logging.info(time.strftime('%Y-%m-%d-%H:%M:%S', time.gmtime()) + ' Running files [%d-%d/%d]' % (i, i+batch_size-1, n)) 338 | probabilities = self.classify_batch(sess, probabilities_op, images_pl, 339 | image_files, summary_op=summary_op, summary_writer=summary_writer) 340 | pred_scores_all[i:i+batch_size] = probabilities[:,1] # assume score to be the pred prob of the positive class [1] 341 | best = np.argmax(probabilities, axis=1) 342 | for m, image_file in enumerate(image_files): 343 | if not labels[i+m] == best[m]: 344 | ind_incorrect.extend([i+m]) 345 | if writer is not None: 346 | writer.writerow((image_file, label_list[best[m]], '%.2f' % probabilities[m,best[m]])) 347 | i += batch_size 348 | 349 | else: # batch_size = 1 350 | for i,image_file in enumerate(filenames): 351 | if image_file is None: continue 352 | # try: 353 | logging.info(time.strftime('%Y-%m-%d-%H:%M:%S', time.gmtime()) + ' Running file [%d/%d]: %s' % (i,n, image_file)) 354 | probabilities = self.classify(sess, probabilities_op, images_pl,image_file) 355 | pred_scores_all[i] = probabilities[1] # assume score to be the pred prob of the positive class [1] 356 | best = np.argmax(probabilities) 357 | if not labels[i]==best: 358 | ind_incorrect.extend([i]) 359 | if writer is not None: 360 | writer.writerow((image_file, label_list[best], '%.2f' % probabilities[best])) 361 | 362 | ########### 363 | if output is not None: 364 | output.close() 365 | 366 | acc, eer_thr, eer_thr_max = report_accuracy(pred_scores_all, labels, threshold=0.5) 367 | acc_at_in_thr = 0 368 | if threshold is not None: 369 | acc_at_in_thr, _ , _= report_accuracy(pred_scores_all, labels, threshold) 370 | 371 | if results_file is not None: 372 | new_results_file = os.path.dirname(results_file) + '/incorrect_filenames_' + os.path.basename(results_file) 373 | write_results_file(new_results_file, filenames, labels, pred_scores_all, ind_incorrect, label_list) 374 | 375 | return acc, acc_at_in_thr, eer_thr, eer_thr_max -------------------------------------------------------------------------------- /pipeline_tf/image_utils.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | from data import helpers, helpers_image 3 | from preprocessing.y_vgg_preprocessing import resize 4 | 5 | ###################################################################### 6 | class ImageCoder_TF(object): 7 | """Helper class that provides TensorFlow image coding utilities.""" 8 | 9 | def __init__(self): 10 | # Create a single Session to run all image coding calls. 11 | self._sess = tf.Session() 12 | ## YY: TODO : i used image.rgb_to_grayscale .. but could EASIER use decode_png/decode_jpeg with channels=1 :D 13 | 14 | self._jpg_string = tf.placeholder(dtype=tf.string) 15 | self._png_string = tf.placeholder(dtype=tf.string) 16 | self._image_string = tf.placeholder(dtype=tf.string) 17 | self._uint8_image = tf.placeholder(dtype=tf.uint8) 18 | 19 | ## convert strings jpg <-> png ... decode then encode 20 | self._png_to_jpg = self._png_string_to_jpg_string(self._png_string) 21 | self._jpg_to_png = self._jpg_string_to_png_string(self._jpg_string) 22 | 23 | ## decoders: string to uint8 24 | self._decoded_jpg_image = tf.image.decode_jpeg(self._jpg_string) 25 | self._decoded_png_image = tf.image.decode_png(self._png_string) 26 | 27 | self._decoded_jpg_image_rgb = tf.image.decode_jpeg(self._jpg_string, channels=3) 28 | self._decoded_png_image_rgb = tf.image.decode_png(self._png_string, channels=3) 29 | 30 | self._decoded_jpg_image_grey = tf.image.decode_jpeg(self._jpg_string, channels=1) 31 | self._decoded_png_image_grey = tf.image.decode_png(self._png_string, channels=1) 32 | 33 | self._encoded_png_str = self._uint8_image_to_png_string(self._uint8_image) 34 | self._encoded_jpg_str = self._uint8_image_to_jpg_string(self._uint8_image) 35 | self._encoded_png_str_gray_fromRGB = self._uint8_rgb_image_to_grey_png_string(self._uint8_image) 36 | self._encoded_jpg_str_gray_fromRGB = self._uint8_rgb_image_to_grey_jpg_string(self._uint8_image) 37 | 38 | def _uint8_image_to_png_string(self, uint8_image): 39 | return tf.image.encode_png(uint8_image) 40 | 41 | def _uint8_image_to_jpg_string(self, uint8_image): #, format='rgb'): 42 | return tf.image.encode_jpeg(uint8_image) #, format=format) #, quality=100) 43 | 44 | def _png_string_to_jpg_string(self, png_string): 45 | # Initializes function that converts PNG to JPEG data. 46 | image = tf.image.decode_png(png_string) #, channels=3) 47 | png_to_jpeg = self._uint8_image_to_jpg_string(image) 48 | return png_to_jpeg 49 | 50 | def _jpg_string_to_png_string(self, jpg_string): 51 | # Initializes function that converts JPEG to PNG data (str). 52 | image = tf.image.decode_jpeg(jpg_string) #, channels=3) 53 | jpg_to_png = self._uint8_image_to_png_string(image) 54 | return jpg_to_png 55 | 56 | def _uint8_rgb_image_to_grey_png_string(self, rgb_image): 57 | ## The conversion functions work only on float images, so you need to convert images in other formats using convert_image_dtype 58 | ## convert encoded string to grayscale: 59 | # rgb_image_float = tf.image.convert_image_dtype(rgb_image, tf.float32) 60 | tmp_grayscale_image = tf.image.rgb_to_grayscale(rgb_image) #_float) 61 | # tmp_grayscale_image = tf.image.convert_image_dtype(tmp_grayscale_image, tf.uint8) 62 | encoded_png_str = self._uint8_image_to_png_string(tmp_grayscale_image) 63 | return encoded_png_str 64 | 65 | def _uint8_rgb_image_to_grey_jpg_string(self, uint8_image): 66 | # tmp_grayscale_image = tf.image.rgb_to_grayscale(uint8_image) 67 | ## The conversion functions work only on float images, so you need to convert images in other formats using convert_image_dtype 68 | ## convert encoded string to grayscale: 69 | rgb_image_float = tf.image.convert_image_dtype(uint8_image, tf.float32) 70 | tmp_grayscale_image_float = tf.image.rgb_to_grayscale(rgb_image_float) 71 | tmp_grayscale_image = tf.image.convert_image_dtype(tmp_grayscale_image_float, tf.uint8) 72 | encoded_jpg_str = self._uint8_image_to_jpg_string(tmp_grayscale_image) #, format='grayscale') 73 | return encoded_jpg_str 74 | 75 | def png_to_jpeg(self, image_string): 76 | return self._sess.run(self._png_to_jpg, 77 | feed_dict={self._png_string: image_string}) 78 | 79 | def jpeg_to_png(self, image_string): 80 | return self._sess.run(self._jpg_to_png, 81 | feed_dict={self._jpg_string: image_string}) 82 | 83 | def convert_jpg_to_graycale(self, image_str_jpg): 84 | img = self.decode_jpeg(image_str_jpg) 85 | if img.shape[2] == 1: 86 | return self._sess.run(self._encoded_jpg_str, 87 | feed_dict={self._uint8_image: img}) 88 | elif img.shape[2] == 3: 89 | return self._sess.run(self._encoded_jpg_str_gray_fromRGB, 90 | feed_dict={self._uint8_image: img}) 91 | 92 | def convert_png_to_graycale(self, image_str_png): 93 | img = self.decode_png(image_str_png) 94 | if img.shape[2] == 1: 95 | return self._sess.run(self._encoded_png_str, 96 | feed_dict={self._uint8_image: img}) 97 | elif img.shape[2] == 3: 98 | return self._sess.run(self._encoded_png_str_gray_fromRGB, 99 | feed_dict={self._uint8_image: img}) 100 | 101 | def decode_png(self, image_string, grayscale=None): 102 | if grayscale is None: 103 | image = self._sess.run(self._decoded_png_image, 104 | feed_dict={self._png_string: image_string}) 105 | else: 106 | if grayscale: 107 | image = self._sess.run(self._decoded_png_image_grey, 108 | feed_dict={self._png_string: image_string}) 109 | assert len(image.shape) == 3 110 | assert image.shape[2] == 1 111 | else: 112 | image = self._sess.run(self._decoded_png_image_rgb, 113 | feed_dict={self._png_string: image_string}) 114 | assert len(image.shape) == 3 115 | assert image.shape[2] == 3 116 | 117 | return image 118 | 119 | def decode_jpeg(self, image_string, grayscale=None): 120 | if grayscale is None: 121 | image = self._sess.run(self._decoded_jpg_image, 122 | feed_dict={self._jpg_string: image_string}) 123 | else: 124 | if grayscale: 125 | image = self._sess.run(self._decoded_jpg_image_grey, 126 | feed_dict={self._jpg_string: image_string}) 127 | assert len(image.shape) == 3 128 | assert image.shape[2] == 1 129 | else: 130 | image = self._sess.run(self._decoded_jpg_image_rgb, 131 | feed_dict={self._jpg_string: image_string}) 132 | assert len(image.shape) == 3 133 | assert image.shape[2] == 3 134 | 135 | return image 136 | 137 | ## YY: 138 | def encode_to_png(self, uint8_image): 139 | return self._sess.run(self._encoded_png_str, 140 | feed_dict={self._uint8_image: uint8_image}) 141 | 142 | def encode_to_jpg(self, uint8_image): 143 | return self._sess.run(self._encoded_jpg_str, 144 | feed_dict={self._uint8_image: uint8_image}) 145 | 146 | 147 | ############################################################ 148 | def modify_image_string(image_string, coder, out_grayscale, format): 149 | if format=='JPEG': 150 | image = coder.decode_jpeg(image_string, grayscale=out_grayscale) 151 | image_string = coder.encode_to_jpg(image) 152 | image = coder.decode_jpeg(image_string) 153 | elif format == 'PNG': 154 | image = coder.decode_png(image_string, grayscale=out_grayscale) 155 | image_string = coder.encode_to_png(image) 156 | image = coder.decode_png(image_string) 157 | 158 | return image_string, image 159 | 160 | 161 | ###################################################################### 162 | def process_image_string(image_string, filename, coder, out_grayscale=False, encode_type='JPEG'): 163 | # Convert any PNG to JPEG's for consistency. 164 | if encode_type == 'JPEG': 165 | if not helpers.is_jpg(filename): 166 | if helpers.is_png(filename): 167 | print('Converting PNG to JPEG for %s' % filename) 168 | image_string = coder.png_to_jpeg(image_string) 169 | else: 170 | print('Converting img to JPEG for %s' % filename) 171 | mode = 'RGB' if not out_grayscale else 'L' 172 | image = helpers_image.load_and_resize_image(filename, height=0, width=0, mode=mode) 173 | if out_grayscale: 174 | image = image[:, :, np.newaxis] 175 | image_string = coder.encode_to_jpg(image) 176 | elif encode_type == 'PNG': 177 | if not helpers.is_png(filename): 178 | if helpers.is_jpg(filename): 179 | print('Converting JPEG to PNG for %s' % filename) 180 | image_string = coder.jpeg_to_png(image_string) 181 | else: 182 | print('Converting img to PNG for %s' % filename) 183 | mode = 'RGB' if not out_grayscale else 'L' 184 | image = helpers_image.load_and_resize_image(filename, height=0, width=0, mode=mode) 185 | if out_grayscale: 186 | image = image[:, :, np.newaxis] 187 | image_string = coder.encode_to_png(image) 188 | 189 | ## YYY: note: the coming lines are just for checking (decoding to encude encoding was done right) 190 | if encode_type == 'JPEG': 191 | # Decode the RGB JPEG. 192 | image = coder.decode_jpeg(image_string) # , grayscale=grayscale) 193 | elif encode_type == 'PNG': 194 | # Decode the RGB JPEG. 195 | image = coder.decode_png(image_string) # , grayscale=grayscale) 196 | 197 | #### 198 | if out_grayscale: 199 | if image.shape[2] == 3: # img is color . convert it to gray 200 | image_string, image = modify_image_string(image_string, coder, out_grayscale, encode_type) 201 | else: # output must be color: 202 | if image.shape[2] == 1: # img is gray . convert it to rgb 203 | image_string, image = modify_image_string(image_string, coder, out_grayscale, encode_type) 204 | 205 | return image_string, image 206 | 207 | 208 | ################################### 209 | def process_image_file(filename, coder, out_grayscale=False, encode_type='JPEG'): 210 | """Process a single image file. 211 | 212 | Args: 213 | filename: string, path to an image file e.g., '/path/to/example.JPG'. 214 | coder: instance of ImageCoder_TF to provide TensorFlow image coding utils. 215 | Returns: 216 | image_buffer: string, JPEG encoding of RGB image. 217 | height: integer, image height in pixels. 218 | width: integer, image width in pixels. 219 | """ 220 | # Read the image file. 221 | with tf.gfile.FastGFile(filename, 'r') as f: 222 | image_string = f.read() 223 | 224 | image_string, image = process_image_string(image_string, filename, coder, out_grayscale, encode_type) 225 | 226 | assert len(image.shape) == 3 227 | height = image.shape[0] 228 | width = image.shape[1] 229 | if out_grayscale: 230 | assert image.shape[2] == 1 231 | else: 232 | assert image.shape[2] == 3 233 | 234 | return image_string, height, width, image.shape[2], image 235 | 236 | 237 | ###################################################################### 238 | def preprocess_image(preprocessing_name, image_preprocessing_fn, raw_image, height, width, 239 | per_image_standardization=False, 240 | vgg_sub_mean_pixel=None, vgg_resize_side_in=None, 241 | vgg_use_aspect_preserving_resize=None, do_crop=True): 242 | if not do_crop: 243 | if (preprocessing_name == 'y_vgg') or (preprocessing_name == 'y_combined'): 244 | return image_preprocessing_fn(raw_image, 245 | sub_mean_pixel=vgg_sub_mean_pixel, 246 | use_per_img_std=per_image_standardization) 247 | else: 248 | return image_preprocessing_fn(raw_image) 249 | 250 | if preprocessing_name == 'vgg': 251 | vgg_resize_side = height 252 | image = image_preprocessing_fn(raw_image, height, width, 253 | resize_side_min=vgg_resize_side, 254 | resize_side_max=vgg_resize_side) 255 | elif (preprocessing_name == 'y_vgg') or (preprocessing_name == 'y_combined'): 256 | image = image_preprocessing_fn(raw_image, height, width, 257 | resize_side_min=vgg_resize_side_in, 258 | resize_side_max=vgg_resize_side_in, 259 | sub_mean_pixel=vgg_sub_mean_pixel, 260 | use_per_img_std=per_image_standardization, 261 | use_aspect_preserving_resize=vgg_use_aspect_preserving_resize) 262 | else: 263 | image = image_preprocessing_fn(raw_image, height, width) 264 | 265 | return image 266 | 267 | 268 | 269 | ######################################################################## 270 | def get_preprocessed_img_crops(raw_image, preprocessing_name, final_height, final_width, 271 | image_preprocessing_fn_at_eval, image_crop_processing_fn, 272 | oversample=False, 273 | per_image_standardization=False, 274 | vgg_sub_mean_pixel=None, vgg_resize_side_in=None, 275 | vgg_use_aspect_preserving_resize=None): 276 | 277 | if oversample: 278 | if vgg_resize_side_in is None: 279 | raise ValueError('no resize size given during multicrop, only final size') 280 | elif (final_height == final_width) and (final_height == vgg_resize_side_in): 281 | raise ValueError('resize size given during multicrop is equal to final crop size') 282 | 283 | crops = [] 284 | if oversample is False: 285 | print('Running a single image') 286 | image = preprocess_image(preprocessing_name, image_preprocessing_fn_at_eval, raw_image, final_height, 287 | final_width, per_image_standardization=per_image_standardization, 288 | vgg_sub_mean_pixel=vgg_sub_mean_pixel, vgg_resize_side_in=vgg_resize_side_in, 289 | vgg_use_aspect_preserving_resize=vgg_use_aspect_preserving_resize) 290 | 291 | crops.append(image) 292 | else: 293 | print('Running multi-cropped image') 294 | 295 | ################################ 296 | # resized = tf.image.resize_images(raw_image, (vgg_resize_side_in, vgg_resize_side_in)) 297 | resized = resize(raw_image, vgg_resize_side_in, use_aspect_pres_resize=vgg_use_aspect_preserving_resize) 298 | tf.summary.image('y_resized', tf.expand_dims(resized, 0)) 299 | h = vgg_resize_side_in # image.shape[0] 300 | w = vgg_resize_side_in # image.shape[1] 301 | hl = h - final_height 302 | wl = w - final_width 303 | corners = [(0, 0), (0, wl), (hl, 0), (hl, wl), (int(hl / 2), int(wl / 2))] 304 | for corner in corners: 305 | ch, cw = corner 306 | cropped = tf.image.crop_to_bounding_box(resized, ch, cw, final_height, final_width) 307 | tf.summary.image('y_cropped', tf.expand_dims(cropped, 0)) 308 | cropped = preprocess_image(preprocessing_name, image_crop_processing_fn, cropped, height=0, width=0, 309 | per_image_standardization=per_image_standardization, 310 | vgg_sub_mean_pixel=vgg_sub_mean_pixel, do_crop=False) 311 | crops.append(cropped) 312 | tf.summary.image('y_cropped_processed', tf.expand_dims(cropped, 0)) 313 | 314 | flipped = tf.image.flip_left_right(cropped) 315 | tf.summary.image('y_flipped_processed', tf.expand_dims(flipped, 0)) 316 | crops.append(flipped) 317 | 318 | image_batch = tf.stack(crops) 319 | return crops, image_batch 320 | 321 | 322 | ######################################################################## 323 | def make_batch_from_img_pl(sess, preprocessed_img_crops, raw_images_pl, filename, coder, 324 | encode_type='JPEG', summary_op=None, summary_writer=None): 325 | 326 | _, _, _, _, raw_image = process_image_file(filename, coder, encode_type=encode_type) 327 | 328 | if summary_op is not None: 329 | [crops, image_batch], summaries = sess.run([preprocessed_img_crops, summary_op], feed_dict={raw_images_pl: raw_image}) 330 | summary_writer.add_summary(summaries) 331 | else: 332 | [crops, image_batch] = sess.run(preprocessed_img_crops, feed_dict={raw_images_pl: raw_image}) 333 | return crops, image_batch 334 | # image_batch = tf.stack(crops) 335 | # return image_batch 336 | -------------------------------------------------------------------------------- /pipeline_tf/paths_namings.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## ================================================================= 4 | ## ================================================================= 5 | import os.path 6 | def generate_name_suffix(GRAYSCALE, F_encode_type): 7 | name_suffix = 'TFCoder' 8 | if GRAYSCALE: 9 | name_suffix += '-grey' 10 | name_suffix += '-%s' % (F_encode_type) 11 | 12 | return name_suffix 13 | 14 | 15 | ## ================================================================= 16 | def generate_checkpoints_dir(FLAGS_Y, image_size): 17 | 18 | if FLAGS_Y.channels == 3: 19 | set_grayscale = False 20 | elif FLAGS_Y.channels == 1: 21 | set_grayscale = True 22 | 23 | name_suffix = generate_name_suffix(set_grayscale, FLAGS_Y.encode_type) 24 | 25 | # =========================================== 26 | checkpoints_dir_prefix, _ = get_dataset_chkpoints_dir_pre(FLAGS_Y.dataset_name) 27 | print ( ' ----------- ', checkpoints_dir_prefix) 28 | MODEL = FLAGS_Y.model_name 29 | OPTIMIZER = FLAGS_Y.optimizer 30 | 31 | IMG_SIZE = image_size 32 | LR_INITIAL = FLAGS_Y.initial_learning_rate 33 | WD=FLAGS_Y.weight_decay 34 | BATCH_SIZE = FLAGS_Y.batch_size 35 | USE_PER_IM_STD = FLAGS_Y.per_image_standardization 36 | 37 | # =========================================== 38 | sub_dir = os.path.join(name_suffix, MODEL, OPTIMIZER) 39 | train_postfix = 'I' + str(IMG_SIZE) + '_iniLR' + str(LR_INITIAL) + '_B' + str(BATCH_SIZE) 40 | 41 | if USE_PER_IM_STD: 42 | train_postfix += '_perImStd' 43 | 44 | if WD is not None: 45 | train_postfix += '_wd' + str(WD) 46 | 47 | checkpoints_dir = os.path.join(checkpoints_dir_prefix, sub_dir, train_postfix) 48 | print(checkpoints_dir) 49 | 50 | return checkpoints_dir 51 | 52 | 53 | ## ================================================================= 54 | def file_pattern_tfrecords(FLAGS_Y, tfRecords_dir, split_name): 55 | if FLAGS_Y.channels == 3: 56 | set_grayscale = False 57 | elif FLAGS_Y.channels == 1: 58 | set_grayscale = True 59 | 60 | name_suffix = generate_name_suffix(set_grayscale, FLAGS_Y.encode_type) 61 | print(name_suffix) 62 | tf_record_pattern = os.path.join(tfRecords_dir, '%s-%s*' % (split_name, name_suffix)) 63 | 64 | return tf_record_pattern 65 | 66 | 67 | ## ================================================================= 68 | from data.datasets_paths import TF_CHECKPOINTS_ROOT_DIR, TFRecords_ROOT_DIR, datasets_paths_map 69 | def get_dataset_chkpoints_dir_pre(dataset_name): 70 | 71 | # =================================== 72 | if dataset_name not in datasets_paths_map: 73 | raise ValueError('Name of dataset unknown %s' % dataset_name) 74 | path_dataset = datasets_paths_map[dataset_name]() 75 | checkpoints_dir = os.path.join(TF_CHECKPOINTS_ROOT_DIR , path_dataset.get_name()) 76 | return checkpoints_dir, path_dataset 77 | 78 | 79 | # =========================== 80 | def get_dataset_paths_and_settings(dataset_name): 81 | checkpoints_dir_prefix, path_dataset = get_dataset_chkpoints_dir_pre(dataset_name) 82 | 83 | labels_file_name = path_dataset.categories_file() 84 | validation_exists = False 85 | regenerate_label_files = False 86 | 87 | TRAIN_IMGS_DIR = None 88 | VAL_IMGS_DIR = None 89 | TEST_IMGS_DIR = None 90 | 91 | TRAIN_CSV_FILE = None 92 | VAL_CSV_FILE = None 93 | TEST_CSV_FILE = None 94 | 95 | # =================================== 96 | if dataset_name == 'catsDogs': 97 | TFRecords_DIR = TFRecords_ROOT_DIR + "/" + path_dataset.get_name() 98 | 99 | TRAIN_IMGS_DIR = path_dataset.sub_dir('train') 100 | VAL_IMGS_DIR = None 101 | TEST_IMGS_DIR = path_dataset.sub_dir('test') 102 | 103 | TRAIN_CSV_FILE = path_dataset.csv_file('train') 104 | VAL_CSV_FILE = path_dataset.csv_file('validation') 105 | TEST_CSV_FILE = path_dataset.csv_file('test') 106 | 107 | elif (dataset_name == 'Warsaw') or (dataset_name == 'ATVS') or (dataset_name == 'MobBioFake'): 108 | TFRecords_DIR = TFRecords_ROOT_DIR + "/" + path_dataset.get_name() 109 | 110 | TRAIN_IMGS_DIR = path_dataset.root_dir() 111 | VAL_IMGS_DIR = path_dataset.root_dir() 112 | 113 | TRAIN_CSV_FILE = path_dataset.csv_file('train') 114 | VAL_CSV_FILE = path_dataset.csv_file('validation') 115 | 116 | labels_file_name = path_dataset.categories_file() 117 | 118 | ################=========================== 119 | imgs_sub_dirs = {'train': TRAIN_IMGS_DIR, 120 | 'validation': VAL_IMGS_DIR, 121 | 'test': TEST_IMGS_DIR} 122 | 123 | csv_files = {'train': TRAIN_CSV_FILE, 124 | 'validation': VAL_CSV_FILE, 125 | 'test': TEST_CSV_FILE} 126 | 127 | return checkpoints_dir_prefix, TFRecords_DIR, imgs_sub_dirs, csv_files, labels_file_name 128 | -------------------------------------------------------------------------------- /pipeline_tf/settings_default.py: -------------------------------------------------------------------------------- 1 | ## ================================================================== 2 | # ======== Data: 3 | # DATASET_NAME= 'catsDogs' 4 | # DATASET_NAME = 'ATVS' 5 | DATASET_NAME = 'Warsaw' 6 | # DATASET_NAME = 'MobBioFake' 7 | 8 | # ======== 9 | nCHANNELS = 3 10 | # nCHANNELS = 1 # GRAYSCALE 11 | 12 | F_encode_type = 'PNG' 13 | # F_encode_type = 'JPEG' 14 | 15 | # =============== 16 | USE_PER_IM_STD = False 17 | # USE_PER_IM_STD = True 18 | 19 | ## ================================================================= 20 | # ======== Training: 21 | MODEL = 'cifar10' # 'cifar10', or 'inception',or 'alexnet', 'googlenet', 'overfeat', 'vgg', 'spoofnet_y' 22 | # MODEL = 'alexnet' 23 | MODEL = 'spoofnet_y' 24 | 25 | # =============== 26 | OPTIMIZER='rmsprop' # 'RMSPROP' (used by inception), 'GRADDESCENT' (used by cifar10 and other tutorials), 'ADAGRAD' (AdaptiveGrad), 'ADADELTA', 'ADAM', 'MOM' (nesterov momentum), 27 | # OPTIMIZER = 'sgd' 28 | # 'The name of the optimizer, one of "adadelta", "adagrad", "adam",' 29 | # '"ftrl", "momentum", "sgd" or "rmsprop".') 30 | 31 | WEIGHT_DECAY = 0.0004 32 | 33 | # The decay to use for the moving average. 34 | MOVING_AVERAGE_DECAY = 0.9999 35 | 36 | # =============== 37 | LR_INITIAL = 0.01 ## YY: def for inception = 0.1 38 | LR_DECAY_EPOCS = 200 #60 ## YY: def for inception = 30 39 | LR_DECAY_FACTOR = 0.1 ## YY: 'gamme' in caffe ... ## YY: def for inception = 0.16 40 | 41 | # =============== 42 | _VAL_STEP = 50 43 | _MAX_TRAIN_STEPS = 2500 44 | _CHKPT_STEP = 50 #500 # 5000 45 | _DISPLAY_STEP = 10 46 | _SUMMARY_STEP = 10 47 | 48 | ## ================================================================= 49 | IMG_SIZE = None 50 | BATCH_SIZE = 128 51 | if (MODEL == 'cifar10'): 52 | IMG_SIZE = 24 53 | IMG_SIZE = 112 54 | BATCH_SIZE = 128 55 | elif MODEL == 'spoofnet_y': 56 | IMG_SIZE = 24 57 | IMG_SIZE = 112 58 | BATCH_SIZE = 128 59 | elif MODEL == 'alexnet': 60 | IMG_SIZE = 227 61 | BATCH_SIZE = 64 #32 #64 62 | _VAL_STEP = 40 63 | _CHKPT_STEP = 20 64 | elif MODEL == 'inception': 65 | IMG_SIZE = 299 66 | BATCH_SIZE = 32 67 | elif MODEL == 'googlenet': 68 | pass 69 | elif MODEL == 'overfeat': 70 | pass 71 | elif MODEL == 'vgg': 72 | pass 73 | -------------------------------------------------------------------------------- /pipeline_tf/slim_learning_y.py: -------------------------------------------------------------------------------- 1 | ## YY: modified from source: tensorflow-master/tensorflow/contrib/slim/python/slim/learning.py 2 | 3 | from __future__ import absolute_import 4 | from __future__ import division 5 | from __future__ import print_function 6 | 7 | import os 8 | import sys 9 | import time 10 | 11 | from pipeline_tf import evaluation_y 12 | from tensorflow.contrib.framework.python.ops import variables 13 | from tensorflow.core.protobuf import config_pb2 14 | from tensorflow.python.client import timeline 15 | from tensorflow.python.framework import constant_op 16 | from tensorflow.python.framework import errors 17 | from tensorflow.python.framework import ops 18 | from tensorflow.python.lib.io import file_io 19 | from tensorflow.python.ops import control_flow_ops 20 | from tensorflow.python.ops import data_flow_ops 21 | from tensorflow.python.ops import math_ops 22 | from tensorflow.python.ops import variables as tf_variables 23 | from tensorflow.python.platform import tf_logging as logging 24 | from tensorflow.python.summary import summary 25 | from tensorflow.python.training import saver as tf_saver 26 | from tensorflow.python.training import supervisor 27 | from tensorflow.python.training import training_util 28 | 29 | __all__ = [ 30 | 'train_step_y', 'train_y' 31 | ] 32 | 33 | 34 | _USE_GLOBAL_STEP = 0 35 | 36 | def _wait_for_step(sess, global_step, step): 37 | """Wait till the global step has reached at least 'step'. 38 | 39 | Args: 40 | sess: A session. 41 | global_step: A Tensor. 42 | step: Int. The global step to reach. 43 | """ 44 | while True: 45 | if training_util.global_step(sess, global_step) >= step: 46 | break 47 | time.sleep(1.0) 48 | 49 | 50 | def train_step_y(sess, train_op, global_step, train_step_kwargs): 51 | """Function that takes a gradient step and specifies whether to stop. 52 | 53 | Args: 54 | sess: The current session. 55 | train_op: An `Operation` that evaluates the gradients and returns the 56 | total loss. 57 | global_step: A `Tensor` representing the global training step. 58 | train_step_kwargs: A dictionary of keyword arguments. 59 | 60 | Returns: 61 | The total loss and a boolean indicating whether or not to stop training. 62 | 63 | Raises: 64 | ValueError: if 'should_trace' is in `train_step_kwargs` but `logdir` is not. 65 | """ 66 | start_time = time.time() 67 | 68 | trace_run_options = None 69 | run_metadata = None 70 | if 'should_trace' in train_step_kwargs: 71 | if 'logdir' not in train_step_kwargs: 72 | raise ValueError('logdir must be present in train_step_kwargs when ' 73 | 'should_trace is present') 74 | if sess.run(train_step_kwargs['should_trace']): 75 | trace_run_options = config_pb2.RunOptions( 76 | trace_level=config_pb2.RunOptions.FULL_TRACE) 77 | run_metadata = config_pb2.RunMetadata() 78 | 79 | total_loss, np_global_step = sess.run([train_op, global_step], 80 | options=trace_run_options, 81 | run_metadata=run_metadata) 82 | # logging.info('Global step value in train_step_y: ' + str(np_global_step)) 83 | time_elapsed = time.time() - start_time 84 | 85 | if run_metadata is not None: 86 | tl = timeline.Timeline(run_metadata.step_stats) 87 | trace = tl.generate_chrome_trace_format() 88 | trace_filename = os.path.join(train_step_kwargs['logdir'], 89 | 'tf_trace-%d.json' % np_global_step) 90 | logging.info('Writing trace to %s', trace_filename) 91 | file_io.write_string_to_file(trace_filename, trace) 92 | if 'summary_writer' in train_step_kwargs: 93 | train_step_kwargs['summary_writer'].add_run_metadata(run_metadata, 94 | 'run_metadata-%d' % 95 | np_global_step) 96 | 97 | if 'should_log' in train_step_kwargs: 98 | if sess.run(train_step_kwargs['should_log']): 99 | logging.info('global step %d: loss = %.4f (%.2f sec/step)', 100 | np_global_step, total_loss, time_elapsed) 101 | 102 | # TODO(nsilberman): figure out why we can't put this into sess.run. The 103 | # issue right now is that the stop check depends on the global step. The 104 | # increment of global step often happens via the train op, which used 105 | # created using optimizer.apply_gradients. 106 | # 107 | # Since running `train_op` causes the global step to be incremented, one 108 | # would expected that using a control dependency would allow the 109 | # should_stop check to be run in the same session.run call: 110 | # 111 | # with ops.control_dependencies([train_op]): 112 | # should_stop_op = ... 113 | # 114 | # However, this actually seems not to work on certain platforms. 115 | if 'should_stop' in train_step_kwargs: 116 | should_stop = sess.run(train_step_kwargs['should_stop']) 117 | else: 118 | should_stop = False 119 | 120 | return total_loss, should_stop, np_global_step 121 | 122 | _USE_DEFAULT = 0 123 | 124 | def train_y(train_op, 125 | logdir, 126 | train_step_fn=train_step_y, 127 | train_step_kwargs=_USE_DEFAULT, 128 | train_step_kwargs_extra=None, # YY: i added these to be able to pass extra args for evaluation 129 | log_every_n_steps=1, 130 | eval_ops=None, # :YY 131 | num_evals=0, # YY 132 | eval_ops_valid=None, # :YY 133 | num_evals_valid=0, # YY 134 | graph=None, 135 | master='', 136 | is_chief=True, 137 | global_step=None, 138 | number_of_steps=None, 139 | init_op=_USE_DEFAULT, 140 | init_feed_dict=None, 141 | local_init_op=_USE_DEFAULT, 142 | init_fn=None, 143 | ready_op=_USE_DEFAULT, 144 | summary_op=_USE_DEFAULT, 145 | save_summaries_secs=600, 146 | summary_writer=_USE_DEFAULT, 147 | startup_delay_steps=0, 148 | saver=None, 149 | save_interval_secs=600, 150 | # sync_optimizer=None, # :YY 151 | session_config=None, 152 | trace_every_n_steps=None): 153 | """Runs a training loop using a TensorFlow supervisor. 154 | 155 | When the sync_optimizer is supplied, gradient updates are applied 156 | synchronously. Otherwise, gradient updates are applied asynchronous. 157 | 158 | Args: 159 | train_op: A `Tensor` that, when executed, will apply the gradients and 160 | return the loss value. 161 | logdir: The directory where training logs are written to. If None, model 162 | checkpoints and summaries will not be written. 163 | train_step_fn: The function to call in order to execute a single gradient 164 | step. The function must have take exactly four arguments: the current 165 | session, the `train_op` `Tensor`, a global step `Tensor` and a dictionary. 166 | train_step_kwargs: A dictionary which is passed to the `train_step_fn`. By 167 | default, two `Boolean`, scalar ops called "should_stop" and "should_log" 168 | are provided. 169 | log_every_n_steps: The frequency, in terms of global steps, that the loss 170 | and global step and logged. 171 | graph: The graph to pass to the supervisor. If no graph is supplied the 172 | default graph is used. 173 | master: The address of the tensorflow master. 174 | is_chief: Specifies whether or not the training is being run by the primary 175 | replica during replica training. 176 | global_step: The `Tensor` representing the global step. If left as `None`, 177 | then slim.variables.get_or_create_global_step() is used. 178 | number_of_steps: The max number of gradient steps to take during training. 179 | If the value is left as None, training proceeds indefinitely. 180 | init_op: The initialization operation. If left to its default value, then 181 | the session is initialized by calling `tf.global_variables_initializer()`. 182 | init_feed_dict: A feed dictionary to use when executing the `init_op`. 183 | local_init_op: The local initialization operation. If left to its default 184 | value, then the session is initialized by calling 185 | `tf.local_variables_initializer()` and `tf.tables_initializer()`. 186 | init_fn: An optional callable to be executed after `init_op` is called. The 187 | callable must accept one argument, the session being initialized. 188 | ready_op: Operation to check if the model is ready to use. If left to its 189 | default value, then the session checks for readiness by calling 190 | `tf.report_uninitialized_variables()`. 191 | summary_op: The summary operation. 192 | save_summaries_secs: How often, in seconds, to save summaries. 193 | summary_writer: `SummaryWriter` to use. Can be `None` 194 | to indicate that no summaries should be written. If unset, we 195 | create a SummaryWriter. 196 | startup_delay_steps: The number of steps to wait for before beginning. Note 197 | that this must be 0 if a sync_optimizer is supplied. 198 | saver: Saver to save checkpoints. If None, a default one will be created 199 | and used. 200 | save_interval_secs: How often, in seconds, to save the model to `logdir`. 201 | sync_optimizer: an instance of tf.train.SyncReplicasOptimizer. If the 202 | argument is supplied, gradient updates will be synchronous. If left as 203 | `None`, gradient updates will be asynchronous. 204 | session_config: An instance of `tf.ConfigProto` that will be used to 205 | configure the `Session`. If left as `None`, the default will be used. 206 | trace_every_n_steps: produce and save a `Timeline` in Chrome trace format 207 | and add it to the summaries every `trace_every_n_steps`. If None, no trace 208 | information will be produced or saved. 209 | 210 | Returns: 211 | the value of the loss function after training. 212 | 213 | Raises: 214 | ValueError: if `train_op` is empty or if `startup_delay_steps` is 215 | non-zero when `sync_optimizer` is supplied, if `number_of_steps` is 216 | negative, or if `trace_every_n_steps` is not `None` and no `logdir` is 217 | provided. 218 | """ 219 | if train_op is None: 220 | raise ValueError('train_op cannot be None.') 221 | 222 | if logdir is None: 223 | if summary_op != _USE_DEFAULT: 224 | raise ValueError('Cannot provide summary_op because logdir=None') 225 | if saver is not None: 226 | raise ValueError('Cannot provide saver because logdir=None') 227 | if trace_every_n_steps is not None: 228 | raise ValueError('Cannot provide trace_every_n_steps because ' 229 | 'logdir=None') 230 | 231 | if number_of_steps is not None and number_of_steps <= 0: 232 | raise ValueError( 233 | '`number_of_steps` must be either None or a positive number.') 234 | 235 | graph = graph or ops.get_default_graph() 236 | with graph.as_default(): 237 | if global_step is None: 238 | global_step = variables.get_or_create_global_step() 239 | saver = saver or tf_saver.Saver() 240 | 241 | with ops.name_scope('init_ops'): 242 | if init_op == _USE_DEFAULT: 243 | init_op = tf_variables.global_variables_initializer() 244 | 245 | if ready_op == _USE_DEFAULT: 246 | ready_op = tf_variables.report_uninitialized_variables() 247 | 248 | if local_init_op == _USE_DEFAULT: 249 | ## YY: I separated them, 250 | y_local_init_op =tf_variables.local_variables_initializer() 251 | ## end YY 252 | local_init_op = control_flow_ops.group( 253 | y_local_init_op, # YY # tf_variables.local_variables_initializer(), 254 | data_flow_ops.tables_initializer()) 255 | 256 | ready_for_local_init_op = None 257 | 258 | if summary_op == _USE_DEFAULT: 259 | summary_op = summary.merge_all() 260 | 261 | if summary_writer == _USE_DEFAULT: 262 | summary_writer = supervisor.Supervisor.USE_DEFAULT 263 | 264 | if train_step_kwargs == _USE_DEFAULT: 265 | with ops.name_scope('train_step'): 266 | train_step_kwargs = {} 267 | 268 | if number_of_steps: 269 | should_stop_op = math_ops.greater_equal(global_step, number_of_steps) 270 | else: 271 | should_stop_op = constant_op.constant(False) 272 | train_step_kwargs['should_stop'] = should_stop_op 273 | train_step_kwargs['should_log'] = math_ops.equal( 274 | math_ops.mod(global_step, log_every_n_steps), 0) 275 | if is_chief and trace_every_n_steps is not None: 276 | train_step_kwargs['should_trace'] = math_ops.equal( 277 | math_ops.mod(global_step, trace_every_n_steps), 0) 278 | train_step_kwargs['logdir'] = logdir 279 | ## YY: 280 | if train_step_kwargs_extra is not None: 281 | for name in train_step_kwargs_extra: 282 | train_step_kwargs[name] = train_step_kwargs_extra[name] 283 | ## :YY 284 | 285 | sv = supervisor.Supervisor( 286 | graph=graph, 287 | is_chief=is_chief, 288 | logdir=logdir, 289 | init_op=init_op, 290 | init_feed_dict=init_feed_dict, 291 | local_init_op=local_init_op, 292 | ready_for_local_init_op=ready_for_local_init_op, 293 | ready_op=ready_op, 294 | summary_op=summary_op, 295 | summary_writer=summary_writer, 296 | global_step=global_step, 297 | saver=saver, 298 | save_summaries_secs=save_summaries_secs, 299 | save_model_secs=save_interval_secs, 300 | init_fn=init_fn) 301 | 302 | if summary_writer is not None: 303 | train_step_kwargs['summary_writer'] = sv.summary_writer 304 | train_step_kwargs['local_init_op'] = y_local_init_op # tf_variables.local_variables_initializer() #local_init_op ## YY I added this 305 | 306 | should_retry = True 307 | while should_retry: 308 | try: 309 | should_retry = False 310 | with sv.managed_session( 311 | master, start_standard_services=False, config=session_config) as sess: 312 | logging.info('Starting Session.') 313 | if is_chief: 314 | if logdir: 315 | sv.start_standard_services(sess) 316 | elif startup_delay_steps > 0: 317 | _wait_for_step(sess, global_step, 318 | min(startup_delay_steps, number_of_steps or 319 | sys.maxint)) 320 | sv.start_queue_runners(sess) 321 | logging.info('Starting Queues.') 322 | try: 323 | while not sv.should_stop(): 324 | total_loss, should_stop = train_step_fn( 325 | sess, train_op, global_step, train_step_kwargs) 326 | if should_stop: 327 | logging.info('Stopping Training.') 328 | break 329 | except errors.OutOfRangeError: 330 | # OutOfRangeError is thrown when epoch limit per 331 | # tf.train.limit_epochs is reached. 332 | logging.info('Caught OutOfRangeError. Stopping Training.') 333 | if logdir and sv.is_chief: 334 | logging.info('Finished training! Saving model to disk.') 335 | sv.saver.save(sess, sv.save_path, global_step=sv.global_step) 336 | 337 | ## YY: evaluating here 338 | if eval_ops is not None: 339 | logging.info('********* Starting evaluation on Training set, at ' + time.strftime('%Y-%m-%d-%H:%M:%S', 340 | time.gmtime())) 341 | evaluation_y.evaluate_loop_slim_streaming_metrics(sess, num_evals, eval_ops) 342 | summary_str = sess.run(summary_op) 343 | sv.summary_computed(sess, summary_str) 344 | logging.info('********* Finished evaluation on Training set, at ' + time.strftime('%Y-%m-%d-%H:%M:%S', 345 | time.gmtime())) 346 | ## YY: starting evaluation on validation set if exist: 347 | if eval_ops_valid is not None: 348 | logging.info('********* Starting evaluation on Validation set, at ' + time.strftime('%Y-%m-%d-%H:%M:%S', 349 | time.gmtime())) 350 | np_global_step = training_util.global_step(sess, global_step) 351 | evaluation_y.evaluate_loop_slim_streaming_metrics(sess, num_evals_valid, eval_ops_valid) 352 | summary_str = sess.run(summary_op) 353 | sv.summary_writer.add_summary(summary_str, np_global_step) 354 | logging.info('********* Finished evaluation on Validation set, at ' + time.strftime('%Y-%m-%d-%H:%M:%S', 355 | time.gmtime())) 356 | # :YY 357 | 358 | except errors.AbortedError: 359 | # Always re-run on AbortedError as it indicates a restart of one of the 360 | # distributed tensorflow servers. 361 | logging.info('Retrying training!') 362 | should_retry = True 363 | 364 | return total_loss 365 | 366 | -------------------------------------------------------------------------------- /pipeline_tf/y_flags.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | from pipeline_tf import settings_default 3 | 4 | ## ================================================================= 5 | ################# 6 | # Training steps 7 | ################# 8 | 9 | tf.app.flags.DEFINE_integer('max_number_of_steps', settings_default._MAX_TRAIN_STEPS, 10 | """Number of batches to run. The maximum number of training steps.""") 11 | 12 | _CHKPT_STEP = settings_default._CHKPT_STEP 13 | _SUMMARY_STEP = settings_default._SUMMARY_STEP 14 | 15 | tf.app.flags.DEFINE_integer( 16 | 'log_every_n_steps', settings_default._DISPLAY_STEP, 17 | 'The frequency with which logs are print.') 18 | tf.app.flags.DEFINE_integer( 19 | 'validation_every_n_steps', settings_default._VAL_STEP, 20 | 'The frequency with which training set is evaluated.') 21 | 22 | tf.app.flags.DEFINE_integer( 23 | 'test_every_n_steps', -1, 24 | 'The frequency with which validation/test set is evaluated.') 25 | 26 | ## ================================================================= 27 | tf.app.flags.DEFINE_boolean('start_labels_at_1', False, ##True, 28 | """Whether label 0 is reserved for background during building data tf records. let Default = False""") 29 | 30 | ## ================================================================= 31 | ####################### 32 | # Dataset Flags # 33 | ####################### 34 | tf.app.flags.DEFINE_string( 35 | 'dataset_name', settings_default.DATASET_NAME, 36 | 'The name of the dataset to load.') 37 | 38 | tf.app.flags.DEFINE_string('tfRecords_dir', None, 39 | 'Output data directory') 40 | tf.app.flags.DEFINE_string('encode_type', settings_default.F_encode_type, 41 | 'PNG or JPEG') 42 | 43 | ## ================================================================= 44 | tf.app.flags.DEFINE_string( 45 | 'model_name', settings_default.MODEL, 46 | 'The name of the architecture to train.') 47 | 48 | tf.app.flags.DEFINE_integer('image_size', settings_default.IMG_SIZE, 49 | """Provide square images of this size.""") 50 | tf.app.flags.DEFINE_integer('vgg_resize_side', None, 51 | """.""") 52 | tf.app.flags.DEFINE_boolean('vgg_use_aspect_preserving_resize', True, 53 | """""") 54 | tf.app.flags.DEFINE_boolean('vgg_sub_mean_pixel', True, 55 | """""") 56 | tf.app.flags.DEFINE_integer('channels', settings_default.nCHANNELS, 57 | """Color or grayscale.""") 58 | tf.app.flags.DEFINE_integer('batch_size', settings_default.BATCH_SIZE, 59 | """Number of images to process in a batch.""") 60 | 61 | tf.app.flags.DEFINE_boolean('per_image_standardization', settings_default.USE_PER_IM_STD, 62 | """at image preprocessing during training/eval, sub mean and divide by std from img itself""") 63 | 64 | tf.app.flags.DEFINE_string('checkpoints_dir_prefix', None, 65 | """Directory where to write/read event logs """ 66 | """and checkpoint.""") 67 | 68 | ###################### 69 | # Optimization Flags # 70 | ###################### 71 | 72 | tf.app.flags.DEFINE_string( 73 | 'optimizer', settings_default.OPTIMIZER, 74 | 'The name of the optimizer, one of "adadelta", "adagrad", "adam",' 75 | '"ftrl", "momentum", "sgd" or "rmsprop".') 76 | 77 | tf.app.flags.DEFINE_float( 78 | 'weight_decay', settings_default.WEIGHT_DECAY, 79 | 'The weight decay on the model weights.') 80 | 81 | tf.app.flags.DEFINE_float('opt_epsilon', 1.0, 'Epsilon term for the optimizer.') 82 | 83 | tf.app.flags.DEFINE_float('rmsprop_momentum', 0.9, 'Momentum.') 84 | 85 | tf.app.flags.DEFINE_float('rmsprop_decay', 0.9, 'Decay term for RMSProp.') 86 | 87 | tf.app.flags.DEFINE_float( 88 | 'adadelta_rho', 0.95, 89 | 'The decay rate for adadelta.') 90 | 91 | tf.app.flags.DEFINE_float( 92 | 'adagrad_initial_accumulator_value', 0.1, 93 | 'Starting value for the AdaGrad accumulators.') 94 | 95 | tf.app.flags.DEFINE_float( 96 | 'adam_beta1', 0.9, 97 | 'The exponential decay rate for the 1st moment estimates.') 98 | 99 | tf.app.flags.DEFINE_float( 100 | 'adam_beta2', 0.999, 101 | 'The exponential decay rate for the 2nd moment estimates.') 102 | 103 | tf.app.flags.DEFINE_float('ftrl_learning_rate_power', -0.5, 104 | 'The learning rate power.') 105 | 106 | tf.app.flags.DEFINE_float( 107 | 'ftrl_initial_accumulator_value', 0.1, 108 | 'Starting value for the FTRL accumulators.') 109 | 110 | tf.app.flags.DEFINE_float( 111 | 'ftrl_l1', 0.0, 'The FTRL l1 regularization strength.') 112 | 113 | tf.app.flags.DEFINE_float( 114 | 'ftrl_l2', 0.0, 'The FTRL l2 regularization strength.') 115 | 116 | tf.app.flags.DEFINE_float( 117 | 'momentum', 0.9, 118 | 'The momentum for the MomentumOptimizer and RMSPropOptimizer.') 119 | 120 | ####################### 121 | # Learning Rate Flags # 122 | ####################### 123 | 124 | tf.app.flags.DEFINE_float('num_epochs_per_decay', settings_default.LR_DECAY_EPOCS, 125 | """Epochs after which learning rate decays.""") 126 | 127 | tf.app.flags.DEFINE_string( 128 | 'learning_rate_decay_type', 129 | 'exponential', 130 | 'Specifies how the learning rate is decayed. One of "fixed", "exponential",' 131 | ' or "polynomial"') 132 | 133 | tf.app.flags.DEFINE_float('initial_learning_rate', settings_default.LR_INITIAL, 'Initial learning rate.') 134 | 135 | tf.app.flags.DEFINE_float( 136 | 'learning_rate_decay_factor', 137 | settings_default.LR_DECAY_FACTOR, 138 | 'Learning rate decay factor.') 139 | 140 | tf.app.flags.DEFINE_float( 141 | 'end_learning_rate', 0.0001, 142 | 'The minimal end learning rate used by a polynomial decay learning rate.') 143 | 144 | tf.app.flags.DEFINE_float( 145 | 'moving_average_decay', settings_default.MOVING_AVERAGE_DECAY, 146 | 'The decay to use for the moving average.' 147 | 'If left as None, then moving averages are not used.') 148 | 149 | ## ================================================================= 150 | tf.app.flags.DEFINE_integer( 151 | 'num_readers', 1, 152 | 'The number of parallel readers that read data from the dataset during train.') 153 | 154 | tf.app.flags.DEFINE_integer( 155 | 'num_preprocessing_threads', 4, 156 | 'The number of threads used to create the batches.') 157 | 158 | tf.app.flags.DEFINE_integer( 159 | 'labels_offset', 0, 160 | 'An offset for the labels in the dataset. This flag is primarily used to ' 161 | 'evaluate the VGG and ResNet architectures which do not use a background ' 162 | 'class for the ImageNet dataset.') 163 | 164 | tf.app.flags.DEFINE_string( 165 | 'preprocessing_name', None, 'The name of the preprocessing to use. If left ' 166 | 'as `None`, then the model_name flag is used.') -------------------------------------------------------------------------------- /pipeline_tf/y_script.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # DATASET='catsDogs' 4 | # DATASET='ATVS' 5 | DATASET='Warsaw' 6 | # DATASET='MobBioFake' 7 | 8 | ################################ 9 | # ============ Settings: 10 | PERIMGSTD=False # default if to compare with slim inception preprocessing 11 | CHANNELS=3 # default if to compare with slim inception preprocessing 12 | ENCODE=JPEG 13 | 14 | TRAINSTEPS=2000 15 | LR=0.001 16 | WD=0.0004 17 | SZ=112 18 | VGGRESIZE=$SZ 19 | 20 | ################################ 21 | #PREPROCESS=y_vgg 22 | PREPROCESS=y_combined # like y_vgg + distort brightness and contrast 23 | 24 | VGGRESIZE=128 25 | VGGUSEASPECTPRES=False 26 | VGGSUBMEAN=False 27 | 28 | ################################## 29 | MODEL1=spoofnet_y_BN_noLRN 30 | 31 | ################## 32 | python --version 33 | 34 | python ./pipeline_tf/train_image_classifier_y.py \ 35 | --dataset_name=$DATASET \ 36 | --model_name=$MODEL1 \ 37 | --preprocessing_name=$PREPROCESS \ 38 | --image_size=$SZ \ 39 | --encode_type=$ENCODE \ 40 | --vgg_resize_side=$VGGRESIZE \ 41 | --vgg_use_aspect_preserving_resize=$VGGUSEASPECTPRES \ 42 | --vgg_sub_mean_pixel=$VGGSUBMEAN \ 43 | --initial_learning_rate=$LR \ 44 | --weight_decay=$WD \ 45 | --per_image_standardization=$PERIMGSTD \ 46 | --channels=$CHANNELS \ 47 | --max_number_of_steps=$TRAINSTEPS \ 48 | --save_interval_secs=60 \ 49 | --save_summaries_secs=60 \ 50 | --log_every_n_steps=10 \ 51 | --validation_every_n_steps=100 \ 52 | --test_every_n_steps=200 53 | 54 | python ./pipeline_tf/eval_image_classifier_y.py \ 55 | --dataset_name=$DATASET \ 56 | --dataset_split_name_y='train' \ 57 | --dataset_split_name_y2='validation' \ 58 | --use_placeholders=False \ 59 | --eval_batch_size=100 \ 60 | --model_name=$MODEL1 \ 61 | --preprocessing_name=$PREPROCESS \ 62 | --image_size=$SZ \ 63 | --encode_type=$ENCODE \ 64 | --vgg_resize_side=$VGGRESIZE \ 65 | --vgg_use_aspect_preserving_resize=$VGGUSEASPECTPRES \ 66 | --vgg_sub_mean_pixel=$VGGSUBMEAN \ 67 | --initial_learning_rate=$LR \ 68 | --weight_decay=$WD \ 69 | --per_image_standardization=$PERIMGSTD \ 70 | --channels=$CHANNELS 71 | 72 | python ./pipeline_tf/eval_image_classifier_y.py \ 73 | --dataset_name=$DATASET \ 74 | --dataset_split_name_y='train' \ 75 | --dataset_split_name_y2='validation' \ 76 | --use_placeholders=True \ 77 | --oversample_at_eval=True \ 78 | --eval_batch_size=10 \ 79 | --model_name=$MODEL1 \ 80 | --preprocessing_name=$PREPROCESS \ 81 | --image_size=$SZ \ 82 | --encode_type=$ENCODE \ 83 | --vgg_resize_side=$VGGRESIZE \ 84 | --vgg_use_aspect_preserving_resize=$VGGUSEASPECTPRES \ 85 | --vgg_sub_mean_pixel=$VGGSUBMEAN \ 86 | --initial_learning_rate=$LR \ 87 | --weight_decay=$WD \ 88 | --per_image_standardization=$PERIMGSTD \ 89 | --channels=$CHANNELS 90 | 91 | -------------------------------------------------------------------------------- /preprocessing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yomna-safaa/spoofnet-tensorflow/bbb0ab6f493a874dd7e43c1cee8e0740a417e9d7/preprocessing/__init__.py -------------------------------------------------------------------------------- /preprocessing/preprocessing_factory.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 The TensorFlow Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | """Contains a factory for building various models.""" 16 | 17 | from __future__ import absolute_import 18 | from __future__ import division 19 | from __future__ import print_function 20 | 21 | import tensorflow as tf 22 | from preprocessing import vgg_preprocessing 23 | from preprocessing import y_vgg_preprocessing, y_preprocessing 24 | 25 | slim = tf.contrib.slim 26 | 27 | preprocessing_fn_map = { 28 | 'alexnet_v2': y_preprocessing, 29 | 'y_vgg': y_vgg_preprocessing, 30 | 'y_combined': y_preprocessing, 31 | 'vgg': vgg_preprocessing, 32 | } 33 | 34 | def get_preprocessing(name, is_training=False): 35 | """Returns preprocessing_fn(image, height, width, **kwargs). 36 | 37 | Args: 38 | name: The name of the preprocessing function. 39 | is_training: `True` if the model is being used for training and `False` 40 | otherwise. 41 | 42 | Returns: 43 | preprocessing_fn: A function that preprocessing a single image (pre-batch). 44 | It has the following signature: 45 | image = preprocessing_fn(image, output_height, output_width, ...). 46 | 47 | Raises: 48 | ValueError: If Preprocessing `name` is not recognized. 49 | """ 50 | 51 | 52 | if name not in preprocessing_fn_map: 53 | raise ValueError('Preprocessing name [%s] was not recognized' % name) 54 | 55 | def preprocessing_fn(image, output_height, output_width, **kwargs): 56 | return preprocessing_fn_map[name].preprocess_image( 57 | image, output_height, output_width, is_training=is_training, **kwargs) 58 | 59 | return preprocessing_fn 60 | 61 | 62 | def get_img_crop_preprocessing(name): 63 | """Returns preprocessing_fn(image, height, width, **kwargs). 64 | 65 | Args: 66 | name: The name of the preprocessing function. 67 | is_training: `True` if the model is being used for training and `False` 68 | otherwise. 69 | 70 | Returns: 71 | preprocessing_fn: A function that preprocessing a single image (pre-batch). 72 | It has the following signature: 73 | image = preprocessing_fn(image, output_height, output_width, ...). 74 | 75 | Raises: 76 | ValueError: If Preprocessing `name` is not recognized. 77 | """ 78 | 79 | if name not in preprocessing_fn_map: 80 | raise ValueError('Preprocessing name [%s] was not recognized' % name) 81 | 82 | def process_image_crop_fn(image_crop, **kwargs): 83 | return preprocessing_fn_map[name].process_image_crop(image_crop, **kwargs) 84 | 85 | return process_image_crop_fn -------------------------------------------------------------------------------- /preprocessing/vgg_preprocessing.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 The TensorFlow Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | """Provides utilities to preprocess images. 16 | 17 | The preprocessing steps for VGG were introduced in the following technical 18 | report: 19 | 20 | Very Deep Convolutional Networks For Large-Scale Image Recognition 21 | Karen Simonyan and Andrew Zisserman 22 | arXiv technical report, 2015 23 | PDF: http://arxiv.org/pdf/1409.1556.pdf 24 | ILSVRC 2014 Slides: http://www.robots.ox.ac.uk/~karen/pdf/ILSVRC_2014.pdf 25 | CC-BY-4.0 26 | 27 | More information can be obtained from the VGG website: 28 | www.robots.ox.ac.uk/~vgg/research/very_deep/ 29 | """ 30 | 31 | from __future__ import absolute_import 32 | from __future__ import division 33 | from __future__ import print_function 34 | 35 | 36 | from tensorflow.python.ops import control_flow_ops 37 | import tensorflow as tf 38 | 39 | slim = tf.contrib.slim 40 | 41 | _R_MEAN = 123.68 42 | _G_MEAN = 116.78 43 | _B_MEAN = 103.94 44 | 45 | _RESIZE_SIDE_MIN = 256 46 | _RESIZE_SIDE_MAX = 512 47 | 48 | 49 | def _crop(image, offset_height, offset_width, crop_height, crop_width): 50 | """Crops the given image using the provided offsets and sizes. 51 | 52 | Note that the method doesn't assume we know the input image size but it does 53 | assume we know the input image rank. 54 | 55 | Args: 56 | image: an image of shape [height, width, channels]. 57 | offset_height: a scalar tensor indicating the height offset. 58 | offset_width: a scalar tensor indicating the width offset. 59 | crop_height: the height of the cropped image. 60 | crop_width: the width of the cropped image. 61 | 62 | Returns: 63 | the cropped (and resized) image. 64 | 65 | Raises: 66 | InvalidArgumentError: if the rank is not 3 or if the image dimensions are 67 | less than the crop size. 68 | """ 69 | original_shape = tf.shape(image) 70 | 71 | rank_assertion = tf.Assert( 72 | tf.equal(tf.rank(image), 3), 73 | ['Rank of image must be equal to 3.']) 74 | cropped_shape = control_flow_ops.with_dependencies( 75 | [rank_assertion], 76 | tf.stack([crop_height, crop_width, original_shape[2]])) 77 | 78 | size_assertion = tf.Assert( 79 | tf.logical_and( 80 | tf.greater_equal(original_shape[0], crop_height), 81 | tf.greater_equal(original_shape[1], crop_width)), 82 | ['Crop size greater than the image size.']) 83 | 84 | offsets = tf.to_int32(tf.stack([offset_height, offset_width, 0])) 85 | 86 | # Use tf.slice instead of crop_to_bounding box as it accepts tensors to 87 | # define the crop size. 88 | image = control_flow_ops.with_dependencies( 89 | [size_assertion], 90 | tf.slice(image, offsets, cropped_shape)) 91 | return tf.reshape(image, cropped_shape) 92 | 93 | 94 | def _random_crop(image_list, crop_height, crop_width): 95 | """Crops the given list of images. 96 | 97 | The function applies the same crop to each image in the list. This can be 98 | effectively applied when there are multiple image inputs of the same 99 | dimension such as: 100 | 101 | image, depths, normals = _random_crop([image, depths, normals], 120, 150) 102 | 103 | Args: 104 | image_list: a list of image tensors of the same dimension but possibly 105 | varying channel. 106 | crop_height: the new height. 107 | crop_width: the new width. 108 | 109 | Returns: 110 | the image_list with cropped images. 111 | 112 | Raises: 113 | ValueError: if there are multiple image inputs provided with different size 114 | or the images are smaller than the crop dimensions. 115 | """ 116 | if not image_list: 117 | raise ValueError('Empty image_list.') 118 | 119 | # Compute the rank assertions. 120 | rank_assertions = [] 121 | for i in range(len(image_list)): 122 | image_rank = tf.rank(image_list[i]) 123 | rank_assert = tf.Assert( 124 | tf.equal(image_rank, 3), 125 | ['Wrong rank for tensor %s [expected] [actual]', 126 | image_list[i].name, 3, image_rank]) 127 | rank_assertions.append(rank_assert) 128 | 129 | image_shape = control_flow_ops.with_dependencies( 130 | [rank_assertions[0]], 131 | tf.shape(image_list[0])) 132 | image_height = image_shape[0] 133 | image_width = image_shape[1] 134 | crop_size_assert = tf.Assert( 135 | tf.logical_and( 136 | tf.greater_equal(image_height, crop_height), 137 | tf.greater_equal(image_width, crop_width)), 138 | ['Crop size greater than the image size.']) 139 | 140 | asserts = [rank_assertions[0], crop_size_assert] 141 | 142 | for i in range(1, len(image_list)): 143 | image = image_list[i] 144 | asserts.append(rank_assertions[i]) 145 | shape = control_flow_ops.with_dependencies([rank_assertions[i]], 146 | tf.shape(image)) 147 | height = shape[0] 148 | width = shape[1] 149 | 150 | height_assert = tf.Assert( 151 | tf.equal(height, image_height), 152 | ['Wrong height for tensor %s [expected][actual]', 153 | image.name, height, image_height]) 154 | width_assert = tf.Assert( 155 | tf.equal(width, image_width), 156 | ['Wrong width for tensor %s [expected][actual]', 157 | image.name, width, image_width]) 158 | asserts.extend([height_assert, width_assert]) 159 | 160 | # Create a random bounding box. 161 | # 162 | # Use tf.random_uniform and not numpy.random.rand as doing the former would 163 | # generate random numbers at graph eval time, unlike the latter which 164 | # generates random numbers at graph definition time. 165 | max_offset_height = control_flow_ops.with_dependencies( 166 | asserts, tf.reshape(image_height - crop_height + 1, [])) 167 | max_offset_width = control_flow_ops.with_dependencies( 168 | asserts, tf.reshape(image_width - crop_width + 1, [])) 169 | offset_height = tf.random_uniform( 170 | [], maxval=max_offset_height, dtype=tf.int32) 171 | offset_width = tf.random_uniform( 172 | [], maxval=max_offset_width, dtype=tf.int32) 173 | 174 | return [_crop(image, offset_height, offset_width, 175 | crop_height, crop_width) for image in image_list] 176 | 177 | 178 | def _central_crop(image_list, crop_height, crop_width): 179 | """Performs central crops of the given image list. 180 | 181 | Args: 182 | image_list: a list of image tensors of the same dimension but possibly 183 | varying channel. 184 | crop_height: the height of the image following the crop. 185 | crop_width: the width of the image following the crop. 186 | 187 | Returns: 188 | the list of cropped images. 189 | """ 190 | outputs = [] 191 | for image in image_list: 192 | image_height = tf.shape(image)[0] 193 | image_width = tf.shape(image)[1] 194 | 195 | offset_height = (image_height - crop_height) / 2 196 | offset_width = (image_width - crop_width) / 2 197 | 198 | outputs.append(_crop(image, offset_height, offset_width, 199 | crop_height, crop_width)) 200 | return outputs 201 | 202 | 203 | def _mean_image_subtraction(image, means): 204 | """Subtracts the given means from each image channel. 205 | 206 | For example: 207 | means = [123.68, 116.779, 103.939] 208 | image = _mean_image_subtraction(image, means) 209 | 210 | Note that the rank of `image` must be known. 211 | 212 | Args: 213 | image: a tensor of size [height, width, C]. 214 | means: a C-vector of values to subtract from each channel. 215 | 216 | Returns: 217 | the centered image. 218 | 219 | Raises: 220 | ValueError: If the rank of `image` is unknown, if `image` has a rank other 221 | than three or if the number of channels in `image` doesn't match the 222 | number of values in `means`. 223 | """ 224 | if image.get_shape().ndims != 3: 225 | raise ValueError('Input must be of size [height, width, C>0]') 226 | num_channels = image.get_shape().as_list()[-1] 227 | if len(means) != num_channels: 228 | raise ValueError('len(means) must match the number of channels') 229 | 230 | channels = tf.split(axis=2, num_or_size_splits=num_channels, value=image) 231 | for i in range(num_channels): 232 | channels[i] -= means[i] 233 | return tf.concat(axis=2, values=channels) 234 | 235 | 236 | def _smallest_size_at_least(height, width, smallest_side): 237 | """Computes new shape with the smallest side equal to `smallest_side`. 238 | 239 | Computes new shape with the smallest side equal to `smallest_side` while 240 | preserving the original aspect ratio. 241 | 242 | Args: 243 | height: an int32 scalar tensor indicating the current height. 244 | width: an int32 scalar tensor indicating the current width. 245 | smallest_side: A python integer or scalar `Tensor` indicating the size of 246 | the smallest side after resize. 247 | 248 | Returns: 249 | new_height: an int32 scalar tensor indicating the new height. 250 | new_width: and int32 scalar tensor indicating the new width. 251 | """ 252 | smallest_side = tf.convert_to_tensor(smallest_side, dtype=tf.int32) 253 | 254 | height = tf.to_float(height) 255 | width = tf.to_float(width) 256 | smallest_side = tf.to_float(smallest_side) 257 | 258 | scale = tf.cond(tf.greater(height, width), 259 | lambda: smallest_side / width, 260 | lambda: smallest_side / height) 261 | new_height = tf.to_int32(height * scale) 262 | new_width = tf.to_int32(width * scale) 263 | return new_height, new_width 264 | 265 | 266 | def _aspect_preserving_resize(image, smallest_side): 267 | """Resize images preserving the original aspect ratio. 268 | 269 | Args: 270 | image: A 3-D image `Tensor`. 271 | smallest_side: A python integer or scalar `Tensor` indicating the size of 272 | the smallest side after resize. 273 | 274 | Returns: 275 | resized_image: A 3-D tensor containing the resized image. 276 | """ 277 | smallest_side = tf.convert_to_tensor(smallest_side, dtype=tf.int32) 278 | 279 | shape = tf.shape(image) 280 | height = shape[0] 281 | width = shape[1] 282 | new_height, new_width = _smallest_size_at_least(height, width, smallest_side) 283 | image = tf.expand_dims(image, 0) 284 | resized_image = tf.image.resize_bilinear(image, [new_height, new_width], 285 | align_corners=False) 286 | resized_image = tf.squeeze(resized_image) 287 | resized_image.set_shape([None, None, 3]) 288 | return resized_image 289 | 290 | 291 | def preprocess_for_train(image, 292 | output_height, 293 | output_width, 294 | resize_side_min=_RESIZE_SIDE_MIN, 295 | resize_side_max=_RESIZE_SIDE_MAX): 296 | """Preprocesses the given image for training. 297 | 298 | Note that the actual resizing scale is sampled from 299 | [`resize_size_min`, `resize_size_max`]. 300 | 301 | Args: 302 | image: A `Tensor` representing an image of arbitrary size. 303 | output_height: The height of the image after preprocessing. 304 | output_width: The width of the image after preprocessing. 305 | resize_side_min: The lower bound for the smallest side of the image for 306 | aspect-preserving resizing. 307 | resize_side_max: The upper bound for the smallest side of the image for 308 | aspect-preserving resizing. 309 | 310 | Returns: 311 | A preprocessed image. 312 | """ 313 | resize_side = tf.random_uniform( 314 | [], minval=resize_side_min, maxval=resize_side_max+1, dtype=tf.int32) 315 | 316 | image = _aspect_preserving_resize(image, resize_side) 317 | image = _random_crop([image], output_height, output_width)[0] 318 | image.set_shape([output_height, output_width, 3]) 319 | image = tf.to_float(image) 320 | image = tf.image.random_flip_left_right(image) 321 | return _mean_image_subtraction(image, [_R_MEAN, _G_MEAN, _B_MEAN]) 322 | 323 | 324 | def preprocess_for_eval(image, output_height, output_width, resize_side): 325 | """Preprocesses the given image for evaluation. 326 | 327 | Args: 328 | image: A `Tensor` representing an image of arbitrary size. 329 | output_height: The height of the image after preprocessing. 330 | output_width: The width of the image after preprocessing. 331 | resize_side: The smallest side of the image for aspect-preserving resizing. 332 | 333 | Returns: 334 | A preprocessed image. 335 | """ 336 | image = _aspect_preserving_resize(image, resize_side) 337 | image = _central_crop([image], output_height, output_width)[0] 338 | image.set_shape([output_height, output_width, 3]) 339 | image = tf.to_float(image) 340 | return _mean_image_subtraction(image, [_R_MEAN, _G_MEAN, _B_MEAN]) 341 | 342 | 343 | def preprocess_image(image, output_height, output_width, is_training=False, 344 | resize_side_min=_RESIZE_SIDE_MIN, 345 | resize_side_max=_RESIZE_SIDE_MAX): 346 | """Preprocesses the given image. 347 | 348 | Args: 349 | image: A `Tensor` representing an image of arbitrary size. 350 | output_height: The height of the image after preprocessing. 351 | output_width: The width of the image after preprocessing. 352 | is_training: `True` if we're preprocessing the image for training and 353 | `False` otherwise. 354 | resize_side_min: The lower bound for the smallest side of the image for 355 | aspect-preserving resizing. If `is_training` is `False`, then this value 356 | is used for rescaling. 357 | resize_side_max: The upper bound for the smallest side of the image for 358 | aspect-preserving resizing. If `is_training` is `False`, this value is 359 | ignored. Otherwise, the resize side is sampled from 360 | [resize_size_min, resize_size_max]. 361 | 362 | Returns: 363 | A preprocessed image. 364 | """ 365 | if is_training: 366 | return preprocess_for_train(image, output_height, output_width, 367 | resize_side_min, resize_side_max) 368 | else: 369 | return preprocess_for_eval(image, output_height, output_width, 370 | resize_side_min) 371 | -------------------------------------------------------------------------------- /preprocessing/y_preprocessing.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 The TensorFlow Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | """Provides utilities to preprocess images. 16 | 17 | The preprocessing steps for VGG were introduced in the following technical 18 | report: 19 | 20 | Very Deep Convolutional Networks For Large-Scale Image Recognition 21 | Karen Simonyan and Andrew Zisserman 22 | arXiv technical report, 2015 23 | PDF: http://arxiv.org/pdf/1409.1556.pdf 24 | ILSVRC 2014 Slides: http://www.robots.ox.ac.uk/~karen/pdf/ILSVRC_2014.pdf 25 | CC-BY-4.0 26 | 27 | More information can be obtained from the VGG website: 28 | www.robots.ox.ac.uk/~vgg/research/very_deep/ 29 | """ 30 | 31 | # from __future__ import absolute_import 32 | # from __future__ import division 33 | # from __future__ import print_function 34 | 35 | from tensorflow.python.ops import control_flow_ops 36 | from preprocessing.y_vgg_preprocessing import resize 37 | 38 | import tensorflow as tf 39 | slim = tf.contrib.slim 40 | 41 | _R_MEAN = 123.68 42 | _G_MEAN = 116.78 43 | _B_MEAN = 103.94 44 | 45 | _RESIZE_SIDE_MIN = 256 46 | _RESIZE_SIDE_MAX = 512 47 | 48 | 49 | def _crop(image, offset_height, offset_width, crop_height, crop_width): 50 | """Crops the given image using the provided offsets and sizes. 51 | 52 | Note that the method doesn't assume we know the input image size but it does 53 | assume we know the input image rank. 54 | 55 | Args: 56 | image: an image of shape [height, width, channels]. 57 | offset_height: a scalar tensor indicating the height offset. 58 | offset_width: a scalar tensor indicating the width offset. 59 | crop_height: the height of the cropped image. 60 | crop_width: the width of the cropped image. 61 | 62 | Returns: 63 | the cropped (and resized) image. 64 | 65 | Raises: 66 | InvalidArgumentError: if the rank is not 3 or if the image dimensions are 67 | less than the crop size. 68 | """ 69 | original_shape = tf.shape(image) 70 | 71 | rank_assertion = tf.Assert( 72 | tf.equal(tf.rank(image), 3), 73 | ['Rank of image must be equal to 3.']) 74 | cropped_shape = control_flow_ops.with_dependencies( 75 | [rank_assertion], 76 | tf.stack([crop_height, crop_width, original_shape[2]])) 77 | 78 | size_assertion = tf.Assert( 79 | tf.logical_and( 80 | tf.greater_equal(original_shape[0], crop_height), 81 | tf.greater_equal(original_shape[1], crop_width)), 82 | ['Crop size greater than the image size.']) 83 | 84 | offsets = tf.to_int32(tf.stack([offset_height, offset_width, 0])) 85 | 86 | # Use tf.slice instead of crop_to_bounding box as it accepts tensors to 87 | # define the crop size. 88 | image = control_flow_ops.with_dependencies( 89 | [size_assertion], 90 | tf.slice(image, offsets, cropped_shape)) 91 | return tf.reshape(image, cropped_shape) 92 | 93 | 94 | def _random_crop(image_list, crop_height, crop_width): 95 | """Crops the given list of images. 96 | 97 | The function applies the same crop to each image in the list. This can be 98 | effectively applied when there are multiple image inputs of the same 99 | dimension such as: 100 | 101 | image, depths, normals = _random_crop([image, depths, normals], 120, 150) 102 | 103 | Args: 104 | image_list: a list of image tensors of the same dimension but possibly 105 | varying channel. 106 | crop_height: the new height. 107 | crop_width: the new width. 108 | 109 | Returns: 110 | the image_list with cropped images. 111 | 112 | Raises: 113 | ValueError: if there are multiple image inputs provided with different size 114 | or the images are smaller than the crop dimensions. 115 | """ 116 | if not image_list: 117 | raise ValueError('Empty image_list.') 118 | 119 | # Compute the rank assertions. 120 | rank_assertions = [] 121 | for i in range(len(image_list)): 122 | image_rank = tf.rank(image_list[i]) 123 | rank_assert = tf.Assert( 124 | tf.equal(image_rank, 3), 125 | ['Wrong rank for tensor %s [expected] [actual]', 126 | image_list[i].name, 3, image_rank]) 127 | rank_assertions.append(rank_assert) 128 | 129 | image_shape = control_flow_ops.with_dependencies( 130 | [rank_assertions[0]], 131 | tf.shape(image_list[0])) 132 | image_height = image_shape[0] 133 | image_width = image_shape[1] 134 | crop_size_assert = tf.Assert( 135 | tf.logical_and( 136 | tf.greater_equal(image_height, crop_height), 137 | tf.greater_equal(image_width, crop_width)), 138 | ['Crop size greater than the image size.']) 139 | 140 | asserts = [rank_assertions[0], crop_size_assert] 141 | 142 | for i in range(1, len(image_list)): 143 | image = image_list[i] 144 | asserts.append(rank_assertions[i]) 145 | shape = control_flow_ops.with_dependencies([rank_assertions[i]], 146 | tf.shape(image)) 147 | height = shape[0] 148 | width = shape[1] 149 | 150 | height_assert = tf.Assert( 151 | tf.equal(height, image_height), 152 | ['Wrong height for tensor %s [expected][actual]', 153 | image.name, height, image_height]) 154 | width_assert = tf.Assert( 155 | tf.equal(width, image_width), 156 | ['Wrong width for tensor %s [expected][actual]', 157 | image.name, width, image_width]) 158 | asserts.extend([height_assert, width_assert]) 159 | 160 | # Create a random bounding box. 161 | # 162 | # Use tf.random_uniform and not numpy.random.rand as doing the former would 163 | # generate random numbers at graph eval time, unlike the latter which 164 | # generates random numbers at graph definition time. 165 | max_offset_height = control_flow_ops.with_dependencies( 166 | asserts, tf.reshape(image_height - crop_height + 1, [])) 167 | max_offset_width = control_flow_ops.with_dependencies( 168 | asserts, tf.reshape(image_width - crop_width + 1, [])) 169 | offset_height = tf.random_uniform( 170 | [], maxval=max_offset_height, dtype=tf.int32) 171 | offset_width = tf.random_uniform( 172 | [], maxval=max_offset_width, dtype=tf.int32) 173 | 174 | return [_crop(image, offset_height, offset_width, 175 | crop_height, crop_width) for image in image_list] 176 | 177 | 178 | def _central_crop(image_list, crop_height, crop_width): 179 | """Performs central crops of the given image list. 180 | 181 | Args: 182 | image_list: a list of image tensors of the same dimension but possibly 183 | varying channel. 184 | crop_height: the height of the image following the crop. 185 | crop_width: the width of the image following the crop. 186 | 187 | Returns: 188 | the list of cropped images. 189 | """ 190 | outputs = [] 191 | for image in image_list: 192 | image_height = tf.shape(image)[0] 193 | image_width = tf.shape(image)[1] 194 | 195 | offset_height = (image_height - crop_height) / 2 196 | offset_width = (image_width - crop_width) / 2 197 | 198 | outputs.append(_crop(image, offset_height, offset_width, 199 | crop_height, crop_width)) 200 | return outputs 201 | 202 | 203 | def _mean_image_subtraction(image, means): 204 | """Subtracts the given means from each image channel. 205 | 206 | For example: 207 | means = [123.68, 116.779, 103.939] 208 | image = _mean_image_subtraction(image, means) 209 | 210 | Note that the rank of `image` must be known. 211 | 212 | Args: 213 | image: a tensor of size [height, width, C]. 214 | means: a C-vector of values to subtract from each channel. 215 | 216 | Returns: 217 | the centered image. 218 | 219 | Raises: 220 | ValueError: If the rank of `image` is unknown, if `image` has a rank other 221 | than three or if the number of channels in `image` doesn't match the 222 | number of values in `means`. 223 | """ 224 | if image.get_shape().ndims != 3: 225 | raise ValueError('Input must be of size [height, width, C>0]') 226 | num_channels = image.get_shape().as_list()[-1] 227 | if len(means) != num_channels: 228 | raise ValueError('len(means) must match the number of channels') 229 | 230 | channels = tf.split(axis=2, num_or_size_splits=num_channels, value=image) 231 | for i in range(num_channels): 232 | channels[i] -= means[i] 233 | return tf.concat(axis=2, values=channels) 234 | 235 | 236 | def preprocess_for_train(image, 237 | output_height, 238 | output_width, 239 | resize_side_min=_RESIZE_SIDE_MIN, 240 | resize_side_max=_RESIZE_SIDE_MAX, # YY: ): 241 | sub_mean_pixel=True, use_per_img_std=False, 242 | use_aspect_pres_resize=True): 243 | """Preprocesses the given image for training. 244 | 245 | Note that the actual resizing scale is sampled from 246 | [`resize_size_min`, `resize_size_max`]. 247 | 248 | Args: 249 | image: A `Tensor` representing an image of arbitrary size. 250 | output_height: The height of the image after preprocessing. 251 | output_width: The width of the image after preprocessing. 252 | resize_side_min: The lower bound for the smallest side of the image for 253 | aspect-preserving resizing. 254 | resize_side_max: The upper bound for the smallest side of the image for 255 | aspect-preserving resizing. 256 | 257 | Returns: 258 | A preprocessed image. 259 | """ 260 | resize_side = tf.random_uniform( 261 | [], minval=resize_side_min, maxval=resize_side_max+1, dtype=tf.int32) 262 | 263 | tf.summary.image('image_orig', tf.expand_dims(image, 0)) 264 | image = resize(image, resize_side, use_aspect_pres_resize) 265 | tf.summary.image('image_rsz', tf.expand_dims(image, 0)) 266 | image = _random_crop([image], output_height, output_width)[0] 267 | tf.summary.image('image_crop', tf.expand_dims(image, 0)) 268 | image.set_shape([output_height, output_width, 3]) 269 | image = tf.to_float(image) 270 | image = tf.image.random_flip_left_right(image) 271 | tf.summary.image('image_flip', tf.expand_dims(image, 0)) 272 | image = tf.image.random_brightness(image, max_delta=32. / 255.) # YY 273 | image = tf.image.random_contrast(image, lower=0.5, upper=1.5) # YY 274 | return process_image_crop(image, sub_mean_pixel, use_per_img_std) 275 | 276 | 277 | def preprocess_for_eval(image, output_height, output_width, resize_side, # YY: ): 278 | sub_mean_pixel=True, use_per_img_std=False, 279 | use_aspect_pres_resize=True): 280 | """Preprocesses the given image for evaluation. 281 | 282 | Args: 283 | image: A `Tensor` representing an image of arbitrary size. 284 | output_height: The height of the image after preprocessing. 285 | output_width: The width of the image after preprocessing. 286 | resize_side: The smallest side of the image for aspect-preserving resizing. 287 | 288 | Returns: 289 | A preprocessed image. 290 | """ 291 | image = resize(image, resize_side, use_aspect_pres_resize) 292 | image = _central_crop([image], output_height, output_width)[0] 293 | image.set_shape([output_height, output_width, 3]) 294 | image = tf.to_float(image) 295 | return process_image_crop(image, sub_mean_pixel, use_per_img_std) 296 | 297 | 298 | def process_image_crop(image, sub_mean_pixel=True, use_per_img_std=False): 299 | if sub_mean_pixel: 300 | image = _mean_image_subtraction(image, [_R_MEAN, _G_MEAN, _B_MEAN]) 301 | elif use_per_img_std: 302 | ## YY: from cifar10, was not here: 303 | # Subtract off the mean and divide by the variance of the pixels. 304 | print('Performing PerImageStandarization') 305 | image = tf.image.per_image_standardization(image) 306 | tf.summary.image('img_per_img_std', 307 | tf.expand_dims(image, 0)) 308 | return image 309 | 310 | def preprocess_image(image, output_height, output_width, is_training=False, 311 | resize_side_min=_RESIZE_SIDE_MIN, 312 | resize_side_max=_RESIZE_SIDE_MAX, # YY: ): 313 | use_per_img_std=False, sub_mean_pixel=True, 314 | use_aspect_preserving_resize=True): 315 | """Preprocesses the given image. 316 | 317 | Args: 318 | image: A `Tensor` representing an image of arbitrary size. 319 | output_height: The height of the image after preprocessing. 320 | output_width: The width of the image after preprocessing. 321 | is_training: `True` if we're preprocessing the image for training and 322 | `False` otherwise. 323 | resize_side_min: The lower bound for the smallest side of the image for 324 | aspect-preserving resizing. If `is_training` is `False`, then this value 325 | is used for rescaling. 326 | resize_side_max: The upper bound for the smallest side of the image for 327 | aspect-preserving resizing. If `is_training` is `False`, this value is 328 | ignored. Otherwise, the resize side is sampled from 329 | [resize_size_min, resize_size_max]. 330 | 331 | Returns: 332 | A preprocessed image. 333 | """ 334 | if is_training: 335 | return preprocess_for_train(image, output_height, output_width, 336 | resize_side_min, resize_side_max, 337 | use_per_img_std=use_per_img_std, sub_mean_pixel=sub_mean_pixel, 338 | use_aspect_pres_resize=use_aspect_preserving_resize,) # YY 339 | else: 340 | return preprocess_for_eval(image, output_height, output_width, 341 | resize_side_min, 342 | use_per_img_std=use_per_img_std, sub_mean_pixel=sub_mean_pixel, 343 | use_aspect_pres_resize=use_aspect_preserving_resize) 344 | -------------------------------------------------------------------------------- /preprocessing/y_vgg_preprocessing.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 The TensorFlow Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | """Provides utilities to preprocess images. 16 | 17 | The preprocessing steps for VGG were introduced in the following technical 18 | report: 19 | 20 | Very Deep Convolutional Networks For Large-Scale Image Recognition 21 | Karen Simonyan and Andrew Zisserman 22 | arXiv technical report, 2015 23 | PDF: http://arxiv.org/pdf/1409.1556.pdf 24 | ILSVRC 2014 Slides: http://www.robots.ox.ac.uk/~karen/pdf/ILSVRC_2014.pdf 25 | CC-BY-4.0 26 | 27 | More information can be obtained from the VGG website: 28 | www.robots.ox.ac.uk/~vgg/research/very_deep/ 29 | """ 30 | 31 | from __future__ import absolute_import 32 | from __future__ import division 33 | from __future__ import print_function 34 | 35 | from tensorflow.python.ops import control_flow_ops 36 | import tensorflow as tf 37 | 38 | slim = tf.contrib.slim 39 | 40 | _R_MEAN = 123.68 41 | _G_MEAN = 116.78 42 | _B_MEAN = 103.94 43 | 44 | _RESIZE_SIDE_MIN = 256 45 | _RESIZE_SIDE_MAX = 512 46 | 47 | 48 | def _crop(image, offset_height, offset_width, crop_height, crop_width): 49 | """Crops the given image using the provided offsets and sizes. 50 | 51 | Note that the method doesn't assume we know the input image size but it does 52 | assume we know the input image rank. 53 | 54 | Args: 55 | image: an image of shape [height, width, channels]. 56 | offset_height: a scalar tensor indicating the height offset. 57 | offset_width: a scalar tensor indicating the width offset. 58 | crop_height: the height of the cropped image. 59 | crop_width: the width of the cropped image. 60 | 61 | Returns: 62 | the cropped (and resized) image. 63 | 64 | Raises: 65 | InvalidArgumentError: if the rank is not 3 or if the image dimensions are 66 | less than the crop size. 67 | """ 68 | original_shape = tf.shape(image) 69 | 70 | rank_assertion = tf.Assert( 71 | tf.equal(tf.rank(image), 3), 72 | ['Rank of image must be equal to 3.']) 73 | cropped_shape = control_flow_ops.with_dependencies( 74 | [rank_assertion], 75 | tf.stack([crop_height, crop_width, original_shape[2]])) 76 | 77 | size_assertion = tf.Assert( 78 | tf.logical_and( 79 | tf.greater_equal(original_shape[0], crop_height), 80 | tf.greater_equal(original_shape[1], crop_width)), 81 | ['Crop size greater than the image size.']) 82 | 83 | offsets = tf.to_int32(tf.stack([offset_height, offset_width, 0])) 84 | 85 | # Use tf.slice instead of crop_to_bounding box as it accepts tensors to 86 | # define the crop size. 87 | image = control_flow_ops.with_dependencies( 88 | [size_assertion], 89 | tf.slice(image, offsets, cropped_shape)) 90 | return tf.reshape(image, cropped_shape) 91 | 92 | 93 | def _random_crop(image_list, crop_height, crop_width): 94 | """Crops the given list of images. 95 | 96 | The function applies the same crop to each image in the list. This can be 97 | effectively applied when there are multiple image inputs of the same 98 | dimension such as: 99 | 100 | image, depths, normals = _random_crop([image, depths, normals], 120, 150) 101 | 102 | Args: 103 | image_list: a list of image tensors of the same dimension but possibly 104 | varying channel. 105 | crop_height: the new height. 106 | crop_width: the new width. 107 | 108 | Returns: 109 | the image_list with cropped images. 110 | 111 | Raises: 112 | ValueError: if there are multiple image inputs provided with different size 113 | or the images are smaller than the crop dimensions. 114 | """ 115 | if not image_list: 116 | raise ValueError('Empty image_list.') 117 | 118 | # Compute the rank assertions. 119 | rank_assertions = [] 120 | for i in range(len(image_list)): 121 | image_rank = tf.rank(image_list[i]) 122 | rank_assert = tf.Assert( 123 | tf.equal(image_rank, 3), 124 | ['Wrong rank for tensor %s [expected] [actual]', 125 | image_list[i].name, 3, image_rank]) 126 | rank_assertions.append(rank_assert) 127 | 128 | image_shape = control_flow_ops.with_dependencies( 129 | [rank_assertions[0]], 130 | tf.shape(image_list[0])) 131 | image_height = image_shape[0] 132 | image_width = image_shape[1] 133 | crop_size_assert = tf.Assert( 134 | tf.logical_and( 135 | tf.greater_equal(image_height, crop_height), 136 | tf.greater_equal(image_width, crop_width)), 137 | ['Crop size greater than the image size.']) 138 | 139 | asserts = [rank_assertions[0], crop_size_assert] 140 | 141 | for i in range(1, len(image_list)): 142 | image = image_list[i] 143 | asserts.append(rank_assertions[i]) 144 | shape = control_flow_ops.with_dependencies([rank_assertions[i]], 145 | tf.shape(image)) 146 | height = shape[0] 147 | width = shape[1] 148 | 149 | height_assert = tf.Assert( 150 | tf.equal(height, image_height), 151 | ['Wrong height for tensor %s [expected][actual]', 152 | image.name, height, image_height]) 153 | width_assert = tf.Assert( 154 | tf.equal(width, image_width), 155 | ['Wrong width for tensor %s [expected][actual]', 156 | image.name, width, image_width]) 157 | asserts.extend([height_assert, width_assert]) 158 | 159 | # Create a random bounding box. 160 | # 161 | # Use tf.random_uniform and not numpy.random.rand as doing the former would 162 | # generate random numbers at graph eval time, unlike the latter which 163 | # generates random numbers at graph definition time. 164 | max_offset_height = control_flow_ops.with_dependencies( 165 | asserts, tf.reshape(image_height - crop_height + 1, [])) 166 | max_offset_width = control_flow_ops.with_dependencies( 167 | asserts, tf.reshape(image_width - crop_width + 1, [])) 168 | offset_height = tf.random_uniform( 169 | [], maxval=max_offset_height, dtype=tf.int32) 170 | offset_width = tf.random_uniform( 171 | [], maxval=max_offset_width, dtype=tf.int32) 172 | 173 | return [_crop(image, offset_height, offset_width, 174 | crop_height, crop_width) for image in image_list] 175 | 176 | 177 | def _central_crop(image_list, crop_height, crop_width): 178 | """Performs central crops of the given image list. 179 | 180 | Args: 181 | image_list: a list of image tensors of the same dimension but possibly 182 | varying channel. 183 | crop_height: the height of the image following the crop. 184 | crop_width: the width of the image following the crop. 185 | 186 | Returns: 187 | the list of cropped images. 188 | """ 189 | outputs = [] 190 | for image in image_list: 191 | image_height = tf.shape(image)[0] 192 | image_width = tf.shape(image)[1] 193 | 194 | offset_height = (image_height - crop_height) / 2 195 | offset_width = (image_width - crop_width) / 2 196 | 197 | outputs.append(_crop(image, offset_height, offset_width, 198 | crop_height, crop_width)) 199 | return outputs 200 | 201 | 202 | def _mean_image_subtraction(image, means): 203 | """Subtracts the given means from each image channel. 204 | 205 | For example: 206 | means = [123.68, 116.779, 103.939] 207 | image = _mean_image_subtraction(image, means) 208 | 209 | Note that the rank of `image` must be known. 210 | 211 | Args: 212 | image: a tensor of size [height, width, C]. 213 | means: a C-vector of values to subtract from each channel. 214 | 215 | Returns: 216 | the centered image. 217 | 218 | Raises: 219 | ValueError: If the rank of `image` is unknown, if `image` has a rank other 220 | than three or if the number of channels in `image` doesn't match the 221 | number of values in `means`. 222 | """ 223 | if image.get_shape().ndims != 3: 224 | raise ValueError('Input must be of size [height, width, C>0]') 225 | num_channels = image.get_shape().as_list()[-1] 226 | if len(means) != num_channels: 227 | raise ValueError('len(means) must match the number of channels') 228 | 229 | channels = tf.split(axis=2, num_or_size_splits=num_channels, value=image) 230 | for i in range(num_channels): 231 | channels[i] -= means[i] 232 | return tf.concat(axis=2, values=channels) 233 | 234 | 235 | def _smallest_size_at_least(height, width, smallest_side): 236 | """Computes new shape with the smallest side equal to `smallest_side`. 237 | 238 | Computes new shape with the smallest side equal to `smallest_side` while 239 | preserving the original aspect ratio. 240 | 241 | Args: 242 | height: an int32 scalar tensor indicating the current height. 243 | width: an int32 scalar tensor indicating the current width. 244 | smallest_side: A python integer or scalar `Tensor` indicating the size of 245 | the smallest side after resize. 246 | 247 | Returns: 248 | new_height: an int32 scalar tensor indicating the new height. 249 | new_width: and int32 scalar tensor indicating the new width. 250 | """ 251 | smallest_side = tf.convert_to_tensor(smallest_side, dtype=tf.int32) 252 | 253 | height = tf.to_float(height) 254 | width = tf.to_float(width) 255 | smallest_side = tf.to_float(smallest_side) 256 | 257 | scale = tf.cond(tf.greater(height, width), 258 | lambda: smallest_side / width, 259 | lambda: smallest_side / height) 260 | new_height = tf.to_int32(height * scale) 261 | new_width = tf.to_int32(width * scale) 262 | return new_height, new_width 263 | 264 | 265 | def _aspect_preserving_resize(image, smallest_side): 266 | """Resize images preserving the original aspect ratio. 267 | 268 | Args: 269 | image: A 3-D image `Tensor`. 270 | smallest_side: A python integer or scalar `Tensor` indicating the size of 271 | the smallest side after resize. 272 | 273 | Returns: 274 | resized_image: A 3-D tensor containing the resized image. 275 | """ 276 | smallest_side = tf.convert_to_tensor(smallest_side, dtype=tf.int32) 277 | 278 | shape = tf.shape(image) 279 | height = shape[0] 280 | width = shape[1] 281 | new_height, new_width = _smallest_size_at_least(height, width, smallest_side) 282 | image = tf.expand_dims(image, 0) 283 | resized_image = tf.image.resize_bilinear(image, [new_height, new_width], 284 | align_corners=False) 285 | resized_image = tf.squeeze(resized_image) 286 | resized_image.set_shape([None, None, 3]) 287 | return resized_image 288 | 289 | 290 | def _square_resize(image, side_size): 291 | """ 292 | 293 | Args: 294 | image: A 3-D image `Tensor`. 295 | smallest_side: A python integer or scalar `Tensor` indicating the size of 296 | the smallest side after resize. 297 | 298 | Returns: 299 | resized_image: A 3-D tensor containing the resized image. 300 | """ 301 | image = tf.expand_dims(image, 0) 302 | resized_image = tf.image.resize_bilinear(image, [side_size, side_size], 303 | align_corners=False) 304 | resized_image = tf.squeeze(resized_image) 305 | resized_image.set_shape([None, None, 3]) 306 | return resized_image 307 | 308 | 309 | def resize(image, smallest_side, use_aspect_pres_resize=True): 310 | if use_aspect_pres_resize: 311 | return _aspect_preserving_resize(image, smallest_side) 312 | else: 313 | return _square_resize(image, smallest_side) 314 | 315 | 316 | def preprocess_for_train(image, 317 | output_height, 318 | output_width, 319 | resize_side_min=_RESIZE_SIDE_MIN, 320 | resize_side_max=_RESIZE_SIDE_MAX, # YY: ): 321 | sub_mean_pixel=True, use_per_img_std=False, 322 | use_aspect_pres_resize=True): 323 | """Preprocesses the given image for training. 324 | 325 | Note that the actual resizing scale is sampled from 326 | [`resize_size_min`, `resize_size_max`]. 327 | 328 | Args: 329 | image: A `Tensor` representing an image of arbitrary size. 330 | output_height: The height of the image after preprocessing. 331 | output_width: The width of the image after preprocessing. 332 | resize_side_min: The lower bound for the smallest side of the image for 333 | aspect-preserving resizing. 334 | resize_side_max: The upper bound for the smallest side of the image for 335 | aspect-preserving resizing. 336 | 337 | Returns: 338 | A preprocessed image. 339 | """ 340 | resize_side = tf.random_uniform( 341 | [], minval=resize_side_min, maxval=resize_side_max+1, dtype=tf.int32) 342 | 343 | tf.summary.image('image_orig', tf.expand_dims(image, 0)) 344 | image = resize(image, resize_side, use_aspect_pres_resize) 345 | tf.summary.image('image_rsz', tf.expand_dims(image, 0)) 346 | image = _random_crop([image], output_height, output_width)[0] 347 | tf.summary.image('image_crop', tf.expand_dims(image, 0)) 348 | image.set_shape([output_height, output_width, 3]) 349 | image = tf.to_float(image) 350 | image = tf.image.random_flip_left_right(image) 351 | tf.summary.image('image_flip', tf.expand_dims(image, 0)) 352 | return process_image_crop(image, sub_mean_pixel, use_per_img_std) 353 | # if sub_mean_pixel: 354 | # image = _mean_image_subtraction(image, [_R_MEAN, _G_MEAN, _B_MEAN]) 355 | # tf.summary.image('image_subMean', tf.expand_dims(image, 0)) 356 | # elif use_per_img_std: 357 | # ## YY: from cifar10, was not here: 358 | # # Subtract off the mean and divide by the variance of the pixels. 359 | # print('Performing PerImageStandarization') 360 | # image = tf.image.per_image_standardization(image) 361 | # tf.summary.image('img_per_img_std', 362 | # tf.expand_dims(image, 0)) 363 | # return image 364 | 365 | 366 | def preprocess_for_eval(image, output_height, output_width, resize_side, # YY: ): 367 | sub_mean_pixel=True, use_per_img_std=False, 368 | use_aspect_pres_resize=True): 369 | """Preprocesses the given image for evaluation. 370 | 371 | Args: 372 | image: A `Tensor` representing an image of arbitrary size. 373 | output_height: The height of the image after preprocessing. 374 | output_width: The width of the image after preprocessing. 375 | resize_side: The smallest side of the image for aspect-preserving resizing. 376 | 377 | Returns: 378 | A preprocessed image. 379 | """ 380 | image = resize(image, resize_side, use_aspect_pres_resize) 381 | image = _central_crop([image], output_height, output_width)[0] 382 | image.set_shape([output_height, output_width, 3]) 383 | image = tf.to_float(image) 384 | return process_image_crop(image, sub_mean_pixel, use_per_img_std) 385 | # if sub_mean_pixel: 386 | # image = _mean_image_subtraction(image, [_R_MEAN, _G_MEAN, _B_MEAN]) 387 | # elif use_per_img_std: 388 | # ## YY: from cifar10, was not here: 389 | # # Subtract off the mean and divide by the variance of the pixels. 390 | # print('Performing PerImageStandarization') 391 | # image = tf.image.per_image_standardization(image) 392 | # tf.summary.image('img_per_img_std', 393 | # tf.expand_dims(image, 0)) 394 | # return image 395 | 396 | 397 | 398 | def process_image_crop(image, sub_mean_pixel=True, use_per_img_std=False): 399 | if sub_mean_pixel: 400 | image = _mean_image_subtraction(image, [_R_MEAN, _G_MEAN, _B_MEAN]) 401 | elif use_per_img_std: 402 | ## YY: from cifar10, was not here: 403 | # Subtract off the mean and divide by the variance of the pixels. 404 | print('Performing PerImageStandarization') 405 | image = tf.image.per_image_standardization(image) 406 | tf.summary.image('img_per_img_std', 407 | tf.expand_dims(image, 0)) 408 | return image 409 | 410 | 411 | def preprocess_image(image, output_height, output_width, is_training=False, 412 | resize_side_min=_RESIZE_SIDE_MIN, 413 | resize_side_max=_RESIZE_SIDE_MAX, # YY: ): 414 | use_per_img_std=False, sub_mean_pixel=True, 415 | use_aspect_preserving_resize=True): 416 | """Preprocesses the given image. 417 | 418 | Args: 419 | image: A `Tensor` representing an image of arbitrary size. 420 | output_height: The height of the image after preprocessing. 421 | output_width: The width of the image after preprocessing. 422 | is_training: `True` if we're preprocessing the image for training and 423 | `False` otherwise. 424 | resize_side_min: The lower bound for the smallest side of the image for 425 | aspect-preserving resizing. If `is_training` is `False`, then this value 426 | is used for rescaling. 427 | resize_side_max: The upper bound for the smallest side of the image for 428 | aspect-preserving resizing. If `is_training` is `False`, this value is 429 | ignored. Otherwise, the resize side is sampled from 430 | [resize_size_min, resize_size_max]. 431 | 432 | Returns: 433 | A preprocessed image. 434 | """ 435 | if is_training: 436 | return preprocess_for_train(image, output_height, output_width, 437 | resize_side_min, resize_side_max, 438 | use_per_img_std=use_per_img_std, sub_mean_pixel=sub_mean_pixel, 439 | use_aspect_pres_resize=use_aspect_preserving_resize,) # YY 440 | else: 441 | return preprocess_for_eval(image, output_height, output_width, 442 | resize_side_min, 443 | use_per_img_std=use_per_img_std, sub_mean_pixel=sub_mean_pixel, 444 | use_aspect_pres_resize=use_aspect_preserving_resize) 445 | -------------------------------------------------------------------------------- /y_script.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # DATASET='catsDogs' 4 | # DATASET='ATVS' 5 | DATASET='Warsaw' 6 | # DATASET='MobBioFake' 7 | 8 | ################################ 9 | # ============ Settings: 10 | PERIMGSTD=False # default if to compare with slim inception preprocessing 11 | CHANNELS=3 # default if to compare with slim inception preprocessing 12 | ENCODE=JPEG 13 | 14 | TRAINSTEPS=2000 15 | LR=0.001 16 | WD=0.0004 17 | SZ=112 18 | VGGRESIZE=$SZ 19 | 20 | ################################ 21 | #PREPROCESS=y_vgg 22 | PREPROCESS=y_combined # like y_vgg + distort brightness and contrast 23 | 24 | VGGRESIZE=128 25 | VGGUSEASPECTPRES=False 26 | VGGSUBMEAN=False 27 | 28 | ################################## 29 | MODEL1=spoofnet_y_BN_noLRN 30 | 31 | ################## /usr/bin/ 32 | # python ./pipeline_tf/train_image_classifier_y.py \ 33 | # --dataset_name=$DATASET \ 34 | # --model_name=$MODEL1 \ 35 | # --preprocessing_name=$PREPROCESS \ 36 | # --image_size=$SZ \ 37 | # --encode_type=$ENCODE \ 38 | # --vgg_resize_side=$VGGRESIZE \ 39 | # --vgg_use_aspect_preserving_resize=$VGGUSEASPECTPRES \ 40 | # --vgg_sub_mean_pixel=$VGGSUBMEAN \ 41 | # --initial_learning_rate=$LR \ 42 | # --weight_decay=$WD \ 43 | # --per_image_standardization=$PERIMGSTD \ 44 | # --channels=$CHANNELS \ 45 | # --max_number_of_steps=$TRAINSTEPS \ 46 | # --save_interval_secs=60 \ 47 | # --save_summaries_secs=60 \ 48 | # --log_every_n_steps=10 \ 49 | # --validation_every_n_steps=100 \ 50 | # --test_every_n_steps=200 51 | 52 | python ./pipeline_tf/eval_image_classifier_y.py \ 53 | --dataset_name=$DATASET \ 54 | --dataset_split_name_y='train' \ 55 | --dataset_split_name_y2='validation' \ 56 | --use_placeholders=False \ 57 | --eval_batch_size=100 \ 58 | --model_name=$MODEL1 \ 59 | --preprocessing_name=$PREPROCESS \ 60 | --image_size=$SZ \ 61 | --encode_type=$ENCODE \ 62 | --vgg_resize_side=$VGGRESIZE \ 63 | --vgg_use_aspect_preserving_resize=$VGGUSEASPECTPRES \ 64 | --vgg_sub_mean_pixel=$VGGSUBMEAN \ 65 | --initial_learning_rate=$LR \ 66 | --weight_decay=$WD \ 67 | --per_image_standardization=$PERIMGSTD \ 68 | --channels=$CHANNELS 69 | 70 | # python ./pipeline_tf/eval_image_classifier_y.py \ 71 | # --dataset_name=$DATASET \ 72 | # --dataset_split_name_y='train' \ 73 | # --dataset_split_name_y2='validation' \ 74 | # --use_placeholders=True \ 75 | # --oversample_at_eval=True \ 76 | # --eval_batch_size=10 \ 77 | # --model_name=$MODEL1 \ 78 | # --preprocessing_name=$PREPROCESS \ 79 | # --image_size=$SZ \ 80 | # --encode_type=$ENCODE \ 81 | # --vgg_resize_side=$VGGRESIZE \ 82 | # --vgg_use_aspect_preserving_resize=$VGGUSEASPECTPRES \ 83 | # --vgg_sub_mean_pixel=$VGGSUBMEAN \ 84 | # --initial_learning_rate=$LR \ 85 | # --weight_decay=$WD \ 86 | # --per_image_standardization=$PERIMGSTD \ 87 | # --channels=$CHANNELS 88 | 89 | --------------------------------------------------------------------------------