From 71ee6ee7477be8fe2a2865b5b60fdfef52cf5783 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 25 Apr 2017 07:50:16 +1000 Subject: [PATCH] Make OpenFace work with Python 3 (#231) * Make OpenFace Python 3 compatible, retaining Python 2 compatibility. Tests could be parameterised to test for either Python 2 or 3. Tests currently fail due to different library calculation outcomes? * Tiny change to remove the dependency on nosetest3. * Dockerfile updates for OpenFace + Python3 + Dlib19.2 + OpenCV3.2 * Revert "Dockerfile updates for OpenFace + Python3 + Dlib19.2 + OpenCV3.2" This reverts commit ec08fc92261877d8a2023ab6dc8fd0610641bd2c. * Change for python2 backwards compatibility * Change for python2 backwards compatibility * Change to ensure python2 backwards compatibility * Change to ensure python2 backwards compatibility --- demos/classifier.py | 12 ++++-- demos/classifier_webcam.py | 18 +++++---- evaluation/lfw-classification-unknown.py | 43 +++++++++++---------- evaluation/lfw-classification.py | 5 ++- openface/__init__.py | 6 ++- openface/torch_neural_net.py | 4 +- run-tests.sh | 2 +- tests/openface_api_tests.py | 2 + tests/openface_batch_represent_tests.py | 10 ++--- tests/openface_demo_tests.py | 40 +++++++++---------- tests/openface_neural_net_training_tests.py | 10 ++--- 11 files changed, 85 insertions(+), 67 deletions(-) diff --git a/demos/classifier.py b/demos/classifier.py index d80956c..9800f02 100755 --- a/demos/classifier.py +++ b/demos/classifier.py @@ -26,6 +26,7 @@ import argparse import cv2 import os import pickle +import sys from operator import itemgetter @@ -171,8 +172,11 @@ def train(args): def infer(args, multiple=False): - with open(args.classifierModel, 'r') as f: - (le, clf) = pickle.load(f) + with open(args.classifierModel, 'rb') as f: + if sys.version_info[0] < 3: + (le, clf) = pickle.load(f) + else: + (le, clf) = pickle.load(f, encoding='latin1') for img in args.imgs: print("\n=== {} ===".format(img)) @@ -190,10 +194,10 @@ def infer(args, multiple=False): if args.verbose: print("Prediction took {} seconds.".format(time.time() - start)) if multiple: - print("Predict {} @ x={} with {:.2f} confidence.".format(person, bbx, + print("Predict {} @ x={} with {:.2f} confidence.".format(person.decode('utf-8'), bbx, confidence)) else: - print("Predict {} with {:.2f} confidence.".format(person, confidence)) + print("Predict {} with {:.2f} confidence.".format(person.decode('utf-8'), confidence)) if isinstance(clf, GMM): dist = np.linalg.norm(rep - clf.means_[maxI]) print(" + Distance from the mean: {}".format(dist)) diff --git a/demos/classifier_webcam.py b/demos/classifier_webcam.py index 5406190..122bfb6 100755 --- a/demos/classifier_webcam.py +++ b/demos/classifier_webcam.py @@ -33,6 +33,7 @@ import argparse import cv2 import os import pickle +import sys import numpy as np np.set_printoptions(precision=2) @@ -97,13 +98,16 @@ def getRep(bgrImg): print("Neural network forward pass took {} seconds.".format( time.time() - start)) - # print reps + # print (reps) return reps def infer(img, args): with open(args.classifierModel, 'r') as f: - (le, clf) = pickle.load(f) # le - label and clf - classifer + if sys.version_info[0] < 3: + (le, clf) = pickle.load(f) # le - label and clf - classifer + else: + (le, clf) = pickle.load(f, encoding='latin1') # le - label and clf - classifer reps = getRep(img) persons = [] @@ -112,21 +116,21 @@ def infer(img, args): try: rep = rep.reshape(1, -1) except: - print "No Face detected" + print ("No Face detected") return (None, None) start = time.time() predictions = clf.predict_proba(rep).ravel() - # print predictions + # print (predictions) maxI = np.argmax(predictions) # max2 = np.argsort(predictions)[-3:][::-1][1] persons.append(le.inverse_transform(maxI)) - # print str(le.inverse_transform(max2)) + ": "+str( predictions [max2]) + # print (str(le.inverse_transform(max2)) + ": "+str( predictions [max2])) # ^ prints the second prediction confidences.append(predictions[maxI]) if args.verbose: print("Prediction took {} seconds.".format(time.time() - start)) pass - # print("Predict {} with {:.2f} confidence.".format(person, confidence)) + # print("Predict {} with {:.2f} confidence.".format(person.decode('utf-8'), confidence)) if isinstance(clf, GMM): dist = np.linalg.norm(rep - clf.means_[maxI]) print(" + Distance from the mean: {}".format(dist)) @@ -185,7 +189,7 @@ if __name__ == '__main__': while True: ret, frame = video_capture.read() persons, confidences = infer(frame, args) - print "P: " + str(persons) + " C: " + str(confidences) + print ("P: " + str(persons) + " C: " + str(confidences)) try: # append with two floating point precision confidenceList.append('%.2f' % confidences[0]) diff --git a/evaluation/lfw-classification-unknown.py b/evaluation/lfw-classification-unknown.py index a81359e..491d18d 100755 --- a/evaluation/lfw-classification-unknown.py +++ b/evaluation/lfw-classification-unknown.py @@ -181,10 +181,13 @@ def getRep(imgPath): def inferFromTest(args): for clfChoice in clfChoices: - print "===============" - print "Using the classifier: " + clfChoice + print ("===============") + print ("Using the classifier: " + clfChoice) with open(os.path.join(args.featureFolder[0], clfChoice + ".pkl"), 'r') as f_clf: - (le, clf) = pickle.load(f_clf) + if sys.version_info[0] < 3: + (le, clf) = pickle.load(f_clf) + else: + (le, clf) = pickle.load(f_clf, encoding='latin1') correctPrediction = 0 inCorrectPrediction = 0 @@ -204,7 +207,7 @@ def inferFromTest(args): try: rep = getRep(img).reshape(1, -1) except Exception as e: - print e + print (e) continue start = time.time() predictions = clf.predict_proba(rep).ravel() @@ -218,7 +221,7 @@ def inferFromTest(args): if args.verbose: print( "Predict {} with {:.2f} confidence.".format( - person, confidence)) + person.decode('utf-8'), confidence)) sumConfidence += confidence @@ -234,11 +237,11 @@ def inferFromTest(args): dist = np.linalg.norm(rep - clf.means_[maxI]) print(" + Distance from the mean: {}".format(dist)) - print "Results for the classifier: " + clfChoice - print "Correct Prediction :" + str(correctPrediction) - print "In-correct Prediction: " + str(inCorrectPrediction) - print "Accuracy :" + str(float(correctPrediction) / (correctPrediction + inCorrectPrediction)) - print "Avg Confidence: " + str(float(sumConfidence) / (correctPrediction + inCorrectPrediction)) + print ("Results for the classifier: " + clfChoice) + print ("Correct Prediction :" + str(correctPrediction)) + print ("In-correct Prediction: " + str(inCorrectPrediction)) + print ("Accuracy :" + str(float(correctPrediction) / (correctPrediction + inCorrectPrediction))) + print ("Avg Confidence: " + str(float(sumConfidence) / (correctPrediction + inCorrectPrediction))) def preprocess(args): @@ -256,8 +259,8 @@ def preprocess(args): try: noOfImages.append(len(os.listdir(folder))) folderName.append(folder.split('/')[-1:][0]) - # print folder.split('/')[-1:][0] +": " + - # str(len(os.listdir(folder))) + # print (folder.split('/')[-1:][0] +": " + + # str(len(os.listdir(folder)))) except: pass @@ -269,7 +272,7 @@ def preprocess(args): for f, n in zip(folderName_sorted, noOfImages_sorted): text_file.write("{} : {} \n".format(f, n)) if args.verbose: - print "Sorting lfw dataset took {} seconds.".format(time.time() - start) + print ("Sorting lfw dataset took {} seconds.".format(time.time() - start)) start = time.time() # Copy known train dataset @@ -289,7 +292,7 @@ def preprocess(args): print('Directory not copied. Error: %s' % e) if args.verbose: - print "Copying train dataset from lfw took {} seconds.".format(time.time() - start) + print ("Copying train dataset from lfw took {} seconds.".format(time.time() - start)) start = time.time() # Take 10% images from train dataset as test dataset for known @@ -309,8 +312,8 @@ def preprocess(args): destPath, 'test_known_raw', folder.split('/')[-1:][0])): os.makedirs(os.path.join(destPath, 'test_known_raw', folder.split('/')[-1:][0])) - # print "Created {}".format(os.path.join(destPath, - # 'test_known_raw', folder.split('/')[-1:][0])) + # print ("Created {}".format(os.path.join(destPath, + # 'test_known_raw', folder.split('/')[-1:][0]))) for i in range(int(0.9 * len(images)), len(images)): destFile = os.path.join(destPath, 'test_known_raw', folder.split( '/')[-1:][0], images[i].split('/')[-1:][0]) @@ -319,7 +322,7 @@ def preprocess(args): except: pass if args.verbose: - print "Spliting lfw dataset took {} seconds.".format(time.time() - start) + print ("Spliting lfw dataset took {} seconds.".format(time.time() - start)) start = time.time() # Copy unknown test dataset @@ -339,7 +342,7 @@ def preprocess(args): print('Directory not copied. Error: %s' % e) if args.verbose: - print "Copying test dataset from lfw took {} seconds.".format(time.time() - start) + print ("Copying test dataset from lfw took {} seconds.".format(time.time() - start)) start = time.time() class Args(): @@ -380,7 +383,7 @@ def preprocess(args): p.join() if args.verbose: - print "Aligning the raw train data took {} seconds.".format(time.time() - start) + print ("Aligning the raw train data took {} seconds.".format(time.time() - start)) start = time.time() os.system( @@ -394,7 +397,7 @@ def preprocess(args): 'train_known_aligned')) if args.verbose: - print "Extracting features from aligned train data took {} seconds.".format(time.time() - start) + print ("Extracting features from aligned train data took {} seconds.".format(time.time() - start)) start = time.time() diff --git a/evaluation/lfw-classification.py b/evaluation/lfw-classification.py index ba902f2..83dbfdd 100755 --- a/evaluation/lfw-classification.py +++ b/evaluation/lfw-classification.py @@ -125,7 +125,10 @@ def cacheToFile(file_name): def decorator(original_func): global cache try: - cache = pickle.load(open(file_name, 'rb')) + if sys.version_info[0] < 3: + cache = pickle.load(open(file_name, 'rb')) + else: + cache = pickle.load(open(file_name, 'rb'), encoding='latin1') except: cache = None diff --git a/openface/__init__.py b/openface/__init__.py index 9afcb80..4b7a0fc 100644 --- a/openface/__init__.py +++ b/openface/__init__.py @@ -1,7 +1,9 @@ # flake8: noqa +from __future__ import absolute_import + from .align_dlib import AlignDlib from .torch_neural_net import TorchNeuralNet -import data -import helper +from . import data +from . import helper diff --git a/openface/torch_neural_net.py b/openface/torch_neural_net.py index 5997818..8d932e7 100644 --- a/openface/torch_neural_net.py +++ b/openface/torch_neural_net.py @@ -81,7 +81,7 @@ class TorchNeuralNet: '-model', model, '-imgDim', str(imgDim)] if cuda: self.cmd.append('-cuda') - self.p = Popen(self.cmd, stdin=PIPE, stdout=PIPE, bufsize=0) + self.p = Popen(self.cmd, stdin=PIPE, stdout=PIPE, bufsize=0, universal_newlines=True) def exitHandler(): if self.p.poll() is None: @@ -160,7 +160,7 @@ cmd: {} stdout: {} """.format(self.cmd, self.p.stdout.read())) - self.p.stdin.write(imgPath + "\n") + self.p.stdin.write(imgPath + '\n') output = self.p.stdout.readline() try: rep = [float(x) for x in output.strip().split(',')] diff --git a/run-tests.sh b/run-tests.sh index 689858c..12ed357 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -4,4 +4,4 @@ set -e cd $(dirname $0) -nosetests-2.7 -v +nosetests -v diff --git a/tests/openface_api_tests.py b/tests/openface_api_tests.py index cb4dde7..652a188 100644 --- a/tests/openface_api_tests.py +++ b/tests/openface_api_tests.py @@ -52,6 +52,8 @@ def test_pipeline(): # assert np.isclose(norm(rgbImg), 11.1355) bb = align.getLargestFaceBoundingBox(rgbImg) + print ("Bounding box found was: ") + print (bb) assert bb.left() == 341 assert bb.right() == 1006 assert bb.top() == 193 diff --git a/tests/openface_batch_represent_tests.py b/tests/openface_batch_represent_tests.py index e1cd261..926d629 100644 --- a/tests/openface_batch_represent_tests.py +++ b/tests/openface_batch_represent_tests.py @@ -40,19 +40,19 @@ def test_batch_represent(): workDir = tempfile.mkdtemp(prefix='OpenFaceBatchRep-') - cmd = ['python2', os.path.join(openfaceDir, 'util', 'align-dlib.py'), + cmd = ['python3', os.path.join(openfaceDir, 'util', 'align-dlib.py'), os.path.join(lfwSubset, 'raw'), 'align', 'outerEyesAndNose', os.path.join(workDir, 'aligned')] - p = Popen(cmd, stdout=PIPE, stderr=PIPE) + p = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) (out, err) = p.communicate() print(out) print(err) assert p.returncode == 0 - cmd = ['python2', os.path.join(openfaceDir, 'util', 'align-dlib.py'), + cmd = ['python3', os.path.join(openfaceDir, 'util', 'align-dlib.py'), os.path.join(lfwSubset, 'raw'), 'align', 'outerEyesAndNose', os.path.join(workDir, 'aligned')] - p = Popen(cmd, stdout=PIPE, stderr=PIPE) + p = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) (out, err) = p.communicate() print(out) print(err) @@ -61,7 +61,7 @@ def test_batch_represent(): cmd = ['th', './batch-represent/main.lua', '-data', os.path.join(workDir, 'aligned'), '-outDir', os.path.join(workDir, 'reps')] - p = Popen(cmd, stdout=PIPE, stderr=PIPE) + p = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) (out, err) = p.communicate() print(out) print(err) diff --git a/tests/openface_demo_tests.py b/tests/openface_demo_tests.py index a086766..77a194e 100644 --- a/tests/openface_demo_tests.py +++ b/tests/openface_demo_tests.py @@ -28,61 +28,61 @@ lfwSubset = os.path.join(openfaceDir, 'data', 'lfw-subset') def test_compare_demo(): - cmd = ['python2', os.path.join(openfaceDir, 'demos', 'compare.py'), + cmd = ['python3', os.path.join(openfaceDir, 'demos', 'compare.py'), os.path.join(exampleImages, 'lennon-1.jpg'), os.path.join(exampleImages, 'lennon-2.jpg')] - p = Popen(cmd, stdout=PIPE, stderr=PIPE) + p = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) (out, err) = p.communicate() print(out) print(err) - assert "0.763" in out + assert '0.763' in out def test_classification_demo_pretrained(): - cmd = ['python2', os.path.join(openfaceDir, 'demos', 'classifier.py'), + cmd = ['python3', os.path.join(openfaceDir, 'demos', 'classifier.py'), 'infer', os.path.join(openfaceDir, 'models', 'openface', 'celeb-classifier.nn4.small2.v1.pkl'), os.path.join(exampleImages, 'carell.jpg')] - p = Popen(cmd, stdout=PIPE, stderr=PIPE) + p = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) (out, err) = p.communicate() print(out) print(err) - assert "Predict SteveCarell with 0.97 confidence." in out + assert 'Predict SteveCarell with 0.97 confidence.' in out def test_classification_demo_pretrained_multi(): - cmd = ['python2', os.path.join(openfaceDir, 'demos', 'classifier.py'), + cmd = ['python3', os.path.join(openfaceDir, 'demos', 'classifier.py'), 'infer', '--multi', os.path.join(openfaceDir, 'models', 'openface', 'celeb-classifier.nn4.small2.v1.pkl'), os.path.join(exampleImages, 'longoria-cooper.jpg')] - p = Popen(cmd, stdout=PIPE, stderr=PIPE) + p = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) (out, err) = p.communicate() print(out) print(err) - assert "Predict EvaLongoria @ x=91 with 0.99 confidence." in out - assert "Predict BradleyCooper @ x=191 with 0.99 confidence." in out + assert 'Predict EvaLongoria @ x=91 with 0.99 confidence.' in out + assert 'Predict BradleyCooper @ x=191 with 0.99 confidence.' in out def test_classification_demo_training(): - assert os.path.isdir(lfwSubset), "Get lfw-subset by running ./data/download-lfw-subset.sh" + assert os.path.isdir(lfwSubset), 'Get lfw-subset by running ./data/download-lfw-subset.sh' workDir = tempfile.mkdtemp(prefix='OpenFaceCls-') - cmd = ['python2', os.path.join(openfaceDir, 'util', 'align-dlib.py'), + cmd = ['python3', os.path.join(openfaceDir, 'util', 'align-dlib.py'), os.path.join(lfwSubset, 'raw'), 'align', 'outerEyesAndNose', os.path.join(workDir, 'aligned')] - p = Popen(cmd, stdout=PIPE, stderr=PIPE) + p = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) (out, err) = p.communicate() print(out) print(err) assert p.returncode == 0 - cmd = ['python2', os.path.join(openfaceDir, 'util', 'align-dlib.py'), + cmd = ['python3', os.path.join(openfaceDir, 'util', 'align-dlib.py'), os.path.join(lfwSubset, 'raw'), 'align', 'outerEyesAndNose', os.path.join(workDir, 'aligned')] - p = Popen(cmd, stdout=PIPE, stderr=PIPE) + p = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) (out, err) = p.communicate() print(out) print(err) @@ -91,26 +91,26 @@ def test_classification_demo_training(): cmd = ['th', './batch-represent/main.lua', '-data', os.path.join(workDir, 'aligned'), '-outDir', os.path.join(workDir, 'reps')] - p = Popen(cmd, stdout=PIPE, stderr=PIPE) + p = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) (out, err) = p.communicate() print(out) print(err) assert p.returncode == 0 - cmd = ['python2', os.path.join(openfaceDir, 'demos', 'classifier.py'), + cmd = ['python3', os.path.join(openfaceDir, 'demos', 'classifier.py'), 'train', os.path.join(workDir, 'reps')] - p = Popen(cmd, stdout=PIPE, stderr=PIPE) + p = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) (out, err) = p.communicate() print(out) print(err) assert p.returncode == 0 - cmd = ['python2', os.path.join(openfaceDir, 'demos', 'classifier.py'), + cmd = ['python3', os.path.join(openfaceDir, 'demos', 'classifier.py'), 'infer', os.path.join(workDir, 'reps', 'classifier.pkl'), os.path.join(lfwSubset, 'raw', 'Adrien_Brody', 'Adrien_Brody_0001.jpg')] - p = Popen(cmd, stdout=PIPE, stderr=PIPE) + p = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) (out, err) = p.communicate() print(out) print(err) diff --git a/tests/openface_neural_net_training_tests.py b/tests/openface_neural_net_training_tests.py index 6fb23d9..cb2bedf 100644 --- a/tests/openface_neural_net_training_tests.py +++ b/tests/openface_neural_net_training_tests.py @@ -37,19 +37,19 @@ def test_dnn_training(): lfwSubset), "Get lfw-subset by running ./data/download-lfw-subset.sh" imgWorkDir = tempfile.mkdtemp(prefix='OpenFaceTrainingTest-Img-') - cmd = ['python2', os.path.join(openfaceDir, 'util', 'align-dlib.py'), + cmd = ['python3', os.path.join(openfaceDir, 'util', 'align-dlib.py'), os.path.join(lfwSubset, 'raw'), 'align', 'outerEyesAndNose', os.path.join(imgWorkDir, 'aligned')] - p = Popen(cmd, stdout=PIPE, stderr=PIPE) + p = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) (out, err) = p.communicate() print(out) print(err) assert p.returncode == 0 - cmd = ['python2', os.path.join(openfaceDir, 'util', 'align-dlib.py'), + cmd = ['python3', os.path.join(openfaceDir, 'util', 'align-dlib.py'), os.path.join(lfwSubset, 'raw'), 'align', 'outerEyesAndNose', os.path.join(imgWorkDir, 'aligned')] - p = Popen(cmd, stdout=PIPE, stderr=PIPE) + p = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) (out, err) = p.communicate() print(out) print(err) @@ -69,7 +69,7 @@ def test_dnn_training(): '-cuda', '-cudnn', '-testing', '-nDonkeys', '-1'] p = Popen(cmd, stdout=PIPE, stderr=PIPE, - cwd=os.path.join(openfaceDir, 'training')) + cwd=os.path.join(openfaceDir, 'training'), universal_newlines=True) (out, err) = p.communicate() print(out) print(err)