diff --git a/README.md b/README.md index 67cacde..ee07af0 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ We published an academic paper to summary our work "[Fawkes: Protecting Personal ### BEFORE YOU RUN OUR CODE + +If you would like to use Fawkes to protect your images, please check out our binary implementation on the [website](http://sandlab.cs.uchicago.edu/fawkes/#code). + If you are a developer or researcher planning to customize and modify on our existing code. Please refer to [fawkes_dev](https://github.com/Shawn-Shan/fawkes/tree/master/fawkes_dev). -### How to protect my image - - ### Citation ``` @inproceedings{shan2020fawkes, diff --git a/fawkes.egg-info/PKG-INFO b/fawkes.egg-info/PKG-INFO deleted file mode 100644 index 20efb8e..0000000 --- a/fawkes.egg-info/PKG-INFO +++ /dev/null @@ -1,71 +0,0 @@ -Metadata-Version: 2.1 -Name: fawkes -Version: 0.0.1 -Summary: Fawkes protect user privacy -Home-page: https://github.com/Shawn-Shan/fawkes -Author: Shawn Shan -Author-email: shansixiong@cs.uchicago.edu -License: UNKNOWN -Description: # Fawkes - Code implementation of the paper "[Fawkes: Protecting Personal Privacy against Unauthorized Deep Learning Models](https://arxiv.org/pdf/2002.08327.pdf)", at *USENIX Security 2020*. - - ### BEFORE YOU RUN OUR CODE - We appreciate your interest in our work and for trying out our code. We've noticed several cases where incorrect configuration leads to poor performances of protection. If you also observe low detection performance far away from what we presented in the paper, please feel free to open an issue in this repo or contact any of the authors directly. We are more than happy to help you debug your experiment and find out the correct configuration. - - ### ABOUT - - This repository contains code implementation of the paper "[Fawkes: Protecting Personal Privacy against Unauthorized Deep Learning Models](https://arxiv.org/pdf/2002.08327.pdf)", at *USENIX Security 2020*. - - ### DEPENDENCIES - - Our code is implemented and tested on Keras with TensorFlow backend. Following packages are used by our code. - - - `keras==2.3.1` - - `numpy==1.18.4` - - `tensorflow-gpu==1.13.1` - - Our code is tested on `Python 3.6.8` - - ### HOWTO - - #### Download and Config Datasets - The first step is to download several datasets for protection and target selection. - 1. Download the following dataset to your local machine. After downloading the datasets, restructure it the same way as the FaceScrub dataset downloaded. - - FaceScrub -- used for protection evaluation (link) - - VGGFace1 -- used for target select (link) - - VGGFace2 -- used for target select (link) - - WebFace -- used for target select (link) - - 2. Config datasets - open `fawkes/config.py` and update the `DATASETS` dictionary with the path to each dataset. Then run `python fawkes/config.py`. Every time the datasets are updated or moved, remember to rerun the command with the updated path. - - 3. Calculate embeddings using feature extractor. - Run `python3 fawkes/prepare_feature_extractor.py --candidate-datasets scrub vggface1 vggface2 webface`. This will calculate and cache the embeddings using the default feature extractor we provide. To use a customized feature extractor, please look at the Advance section at the end. - - #### Generate Cloak for Images - To generate cloak, run - `python3 fawkes/protection.py --gpu 0 --dataset scrub --feature-extractor webface_dense_robust_extract` - For more information about the detailed parameters, please read `fawkes/protection.py`. - The code will output a directory in `results/` with `cloak_data.p` inside. You can check the cloaked images or inspect the changes in `this notebook`. - - #### Evaluate Cloak Effectiveness - To evaluate the cloak, run `python3 fawkes/eval_cloak.py --gpu 0 --cloak_data PATH-TO-RESULT-DIRECTORY --transfer_model vggface2_inception_extract`. - - The code will print out the tracker model accuracy on uncloaked/original test images of the protected user, which should be close to 0. - - - ### Citation - ``` - @inproceedings{shan2020fawkes, - title={Fawkes: Protecting Personal Privacy against Unauthorized Deep Learning Models}, - author={Shan, Shawn and Wenger, Emily and Zhang, Jiayun and Li, Huiying and Zheng, Haitao and Zhao, Ben Y}, - booktitle="Proc. of USENIX Security", - year={2020} - } - ``` -Platform: UNKNOWN -Classifier: Programming Language :: Python :: 3 -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -Requires-Python: >=3.5 -Description-Content-Type: text/markdown diff --git a/fawkes.egg-info/SOURCES.txt b/fawkes.egg-info/SOURCES.txt deleted file mode 100644 index 2868117..0000000 --- a/fawkes.egg-info/SOURCES.txt +++ /dev/null @@ -1,10 +0,0 @@ -README.md -setup.py -fawkes/__init__.py -fawkes/differentiator.py -fawkes/protection.py -fawkes/utils.py -fawkes.egg-info/PKG-INFO -fawkes.egg-info/SOURCES.txt -fawkes.egg-info/dependency_links.txt -fawkes.egg-info/top_level.txt \ No newline at end of file diff --git a/fawkes.egg-info/dependency_links.txt b/fawkes.egg-info/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/fawkes.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/fawkes.egg-info/top_level.txt b/fawkes.egg-info/top_level.txt deleted file mode 100644 index 83397e2..0000000 --- a/fawkes.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -fawkes diff --git a/fawkes/Untitled.ipynb.REMOVED.git-id b/fawkes/Untitled.ipynb.REMOVED.git-id deleted file mode 100644 index c26ad05..0000000 --- a/fawkes/Untitled.ipynb.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -58d500da850206b845bdd0150fa182a0ff8c50f0 \ No newline at end of file diff --git a/fawkes/__init__.py b/fawkes/__init__.py index 1c4f29b..098d7fa 100644 --- a/fawkes/__init__.py +++ b/fawkes/__init__.py @@ -4,21 +4,17 @@ # @Link : https://www.shawnshan.com/ -__version__ = '0.0.2' +__version__ = '0.0.5' +from .detect_faces import create_mtcnn, run_detect_face from .differentiator import FawkesMaskGeneration -from .utils import load_extractor, init_gpu, select_target_label, dump_image, reverse_process_cloaked, \ - Faces from .protection import main -import logging -import sys -import os -logging.getLogger('tensorflow').disabled = True - +from .utils import load_extractor, init_gpu, select_target_label, dump_image, reverse_process_cloaked, Faces, get_file __all__ = ( - '__version__', + '__version__', 'create_mtcnn', 'run_detect_face', 'FawkesMaskGeneration', 'load_extractor', 'init_gpu', - 'select_target_label', 'dump_image', 'reverse_process_cloaked', 'Faces', 'main' -) \ No newline at end of file + 'select_target_label', 'dump_image', 'reverse_process_cloaked', + 'Faces', 'get_file', 'main', +) diff --git a/fawkes/__pycache__/align_face.cpython-36.pyc b/fawkes/__pycache__/align_face.cpython-36.pyc index ab5f8cd..294bd92 100644 Binary files a/fawkes/__pycache__/align_face.cpython-36.pyc and b/fawkes/__pycache__/align_face.cpython-36.pyc differ diff --git a/fawkes/__pycache__/detect_face.cpython-36.pyc b/fawkes/__pycache__/detect_face.cpython-36.pyc deleted file mode 100644 index 8ee42f7..0000000 Binary files a/fawkes/__pycache__/detect_face.cpython-36.pyc and /dev/null differ diff --git a/fawkes/__pycache__/differentiator.cpython-36.pyc b/fawkes/__pycache__/differentiator.cpython-36.pyc index 0e79165..1fcaa40 100644 Binary files a/fawkes/__pycache__/differentiator.cpython-36.pyc and b/fawkes/__pycache__/differentiator.cpython-36.pyc differ diff --git a/fawkes/__pycache__/utils.cpython-36.pyc b/fawkes/__pycache__/utils.cpython-36.pyc index 77639db..59f6fc6 100644 Binary files a/fawkes/__pycache__/utils.cpython-36.pyc and b/fawkes/__pycache__/utils.cpython-36.pyc differ diff --git a/fawkes/align_face.py b/fawkes/align_face.py index 0d7aa96..59e52f2 100644 --- a/fawkes/align_face.py +++ b/fawkes/align_face.py @@ -1,7 +1,6 @@ -from .detect_face import detect_face, create_mtcnn import numpy as np +from fawkes import create_mtcnn, run_detect_face -# modify the default parameters of np.load np_load_old = np.load np.load = lambda *a, **k: np_load_old(*a, allow_pickle=True, **k) @@ -30,7 +29,7 @@ def align(orig_img, aligner, margin=0.8, detect_multiple_faces=True): orig_img = to_rgb(orig_img) orig_img = orig_img[:, :, 0:3] - bounding_boxes, _ = detect_face(orig_img, minsize, pnet, rnet, onet, threshold, factor) + bounding_boxes, _ = run_detect_face(orig_img, minsize, pnet, rnet, onet, threshold, factor) nrof_faces = bounding_boxes.shape[0] if nrof_faces > 0: det = bounding_boxes[:, 0:4] @@ -66,14 +65,6 @@ def align(orig_img, aligner, margin=0.8, detect_multiple_faces=True): cropped = orig_img[bb[1]:bb[3], bb[0]:bb[2], :] cropped_arr.append(cropped) bounding_boxes_arr.append([bb[0], bb[1], bb[2], bb[3]]) - # scaled = misc.imresize(cropped, (image_size, image_size), interp='bilinear') return cropped_arr, bounding_boxes_arr else: return None -# -# if __name__ == '__main__': -# orig_img = misc.imread('orig_img.jpeg') -# cropped_arr, bounding_boxes_arr = align(orig_img) -# misc.imsave('test_output.jpeg', cropped_arr[0]) -# print(bounding_boxes_arr) -# diff --git a/fawkes/detect_face.py b/fawkes/detect_faces.py similarity index 93% rename from fawkes/detect_face.py rename to fawkes/detect_faces.py index dff56c0..9d6f317 100644 --- a/fawkes/detect_face.py +++ b/fawkes/detect_faces.py @@ -1,38 +1,15 @@ """ Tensorflow implementation of the face detection / alignment algorithm found at https://github.com/kpzhang93/MTCNN_face_detection_alignment """ -# MIT License -# -# Copyright (c) 2016 David Sandberg -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function +import gzip import os +import pickle -import cv2 import numpy as np import tensorflow as tf from six import string_types, iteritems +from skimage.transform import resize def layer(op): @@ -78,13 +55,12 @@ class Network(object): """Construct the network. """ raise NotImplementedError('Must be implemented by the subclass.') - def load(self, data_path, session, ignore_missing=False): + def load(self, data_dict, session, ignore_missing=False): """Load network weights. data_path: The path to the numpy-serialized network weights session: The current TensorFlow session ignore_missing: If true, serialized weights for missing layers are ignored. """ - data_dict = np.load(data_path, encoding='latin1').item() # pylint: disable=no-member for op_name in data_dict: with tf.variable_scope(op_name, reuse=True): @@ -280,21 +256,27 @@ class ONet(Network): def create_mtcnn(sess, model_path): - if not model_path: - model_path, _ = os.path.split(os.path.realpath(__file__)) + model_dir = os.path.join(os.path.expanduser('~'), '.fawkes') + os.makedirs(model_dir, exist_ok=True) + + fp = gzip.open(os.path.join(model_dir, "mtcnn.p.gz"), 'rb') + dnet_weights = pickle.load(fp) + fp.close() with tf.variable_scope('pnet'): data = tf.placeholder(tf.float32, (None, None, None, 3), 'input') pnet = PNet({'data': data}) - pnet.load(os.path.join(model_path, 'weights/det1.npy'), sess) + + # data_dict = np.load(data_path, encoding='latin1').item() # pylint: disable=no-member + pnet.load(dnet_weights[0], sess) with tf.variable_scope('rnet'): data = tf.placeholder(tf.float32, (None, 24, 24, 3), 'input') rnet = RNet({'data': data}) - rnet.load(os.path.join(model_path, 'weights/det2.npy'), sess) + rnet.load(dnet_weights[1], sess) with tf.variable_scope('onet'): data = tf.placeholder(tf.float32, (None, 48, 48, 3), 'input') onet = ONet({'data': data}) - onet.load(os.path.join(model_path, 'weights/det3.npy'), sess) + onet.load(dnet_weights[2], sess) pnet_fun = lambda img: sess.run(('pnet/conv4-2/BiasAdd:0', 'pnet/prob1:0'), feed_dict={'pnet/input:0': img}) rnet_fun = lambda img: sess.run(('rnet/conv5-2/conv5-2:0', 'rnet/prob1:0'), feed_dict={'rnet/input:0': img}) @@ -303,7 +285,7 @@ def create_mtcnn(sess, model_path): return pnet_fun, rnet_fun, onet_fun -def detect_face(img, minsize, pnet, rnet, onet, threshold, factor): +def run_detect_face(img, minsize, pnet, rnet, onet, threshold, factor): """Detects faces in an image, and returns bounding boxes and points for them. img: input image minsize: minimum faces' size @@ -367,11 +349,15 @@ def detect_face(img, minsize, pnet, rnet, onet, threshold, factor): tempimg = np.zeros((24, 24, 3, numbox)) for k in range(0, numbox): tmp = np.zeros((int(tmph[k]), int(tmpw[k]), 3)) + # try: tmp[dy[k] - 1:edy[k], dx[k] - 1:edx[k], :] = img[y[k] - 1:ey[k], x[k] - 1:ex[k], :] + # except ValueError: + # continue if tmp.shape[0] > 0 and tmp.shape[1] > 0 or tmp.shape[0] == 0 and tmp.shape[1] == 0: tempimg[:, :, :, k] = imresample(tmp, (24, 24)) else: return np.empty() + tempimg = (tempimg - 127.5) * 0.0078125 tempimg1 = np.transpose(tempimg, (3, 1, 0, 2)) out = rnet(tempimg1) @@ -776,18 +762,20 @@ def rerec(bboxA): def imresample(img, sz): - im_data = cv2.resize(img, (sz[1], sz[0]), interpolation=cv2.INTER_AREA) # @UndefinedVariable + from keras.preprocessing import image + # im_data = resize(img, (sz[0], sz[1])) + im_data = image.array_to_img(img).resize((sz[1], sz[0])) + im_data = image.img_to_array(im_data) return im_data - # This method is kept for debugging purpose -# h=img.shape[0] -# w=img.shape[1] -# hs, ws = sz -# dx = float(w) / ws -# dy = float(h) / hs -# im_data = np.zeros((hs,ws,3)) -# for a1 in range(0,hs): -# for a2 in range(0,ws): -# for a3 in range(0,3): -# im_data[a1,a2,a3] = img[int(floor(a1*dy)),int(floor(a2*dx)),a3] +# def imresample(img, sz): +# import cv2 +# im_data = cv2.resize(img, (sz[1], sz[0]), interpolation=cv2.INTER_AREA) # @UndefinedVariable # return im_data + + +def to_rgb(img): + w, h = img.shape + ret = np.empty((w, h, 3), dtype=np.uint8) + ret[:, :, 0] = ret[:, :, 1] = ret[:, :, 2] = img + return ret diff --git a/fawkes/differentiator.py b/fawkes/differentiator.py index 17e6b2c..29a9a02 100644 --- a/fawkes/differentiator.py +++ b/fawkes/differentiator.py @@ -11,7 +11,7 @@ from decimal import Decimal import numpy as np import tensorflow as tf -from .utils import preprocess, reverse_preprocess +from fawkes.utils import preprocess, reverse_preprocess class FawkesMaskGeneration: diff --git a/fawkes/protection.py b/fawkes/protection.py index 1072807..209985f 100644 --- a/fawkes/protection.py +++ b/fawkes/protection.py @@ -8,13 +8,16 @@ import os import random import sys import time +import tensorflow as tf +import logging +logging.getLogger('tensorflow').disabled = True import numpy as np - -from .differentiator import FawkesMaskGeneration -from .utils import load_extractor, init_gpu, select_target_label, dump_image, reverse_process_cloaked, \ +from fawkes.differentiator import FawkesMaskGeneration +from fawkes.utils import load_extractor, init_gpu, select_target_label, dump_image, reverse_process_cloaked, \ Faces + random.seed(12243) np.random.seed(122412) @@ -63,11 +66,11 @@ def main(*argv): parser.add_argument('--directory', '-d', type=str, help='directory that contain images for cloaking', default='imgs/') - parser.add_argument('--gpu', type=str, + parser.add_argument('--gpu', '-g', type=str, help='GPU id', default='0') - parser.add_argument('--mode', type=str, - help='cloak generation mode', default='high') + parser.add_argument('--mode', '-m', type=str, + help='cloak generation mode', default='mid') parser.add_argument('--feature-extractor', type=str, help="name of the feature extractor used for optimization", default="high_extract") @@ -88,12 +91,12 @@ def main(*argv): if args.mode == 'low': args.feature_extractor = "high_extract" args.th = 0.003 - args.max_step = 100 - args.lr = 15 + args.max_step = 20 + args.lr = 20 elif args.mode == 'mid': args.feature_extractor = "high_extract" - args.th = 0.005 - args.max_step = 100 + args.th = 0.004 + args.max_step = 50 args.lr = 15 elif args.mode == 'high': args.feature_extractor = "high_extract" @@ -101,10 +104,14 @@ def main(*argv): args.max_step = 100 args.lr = 10 elif args.mode == 'ultra': + if not tf.test.is_gpu_available(): + print("Please enable GPU for ultra setting...") + sys.exit(1) + # args.feature_extractor = ["high_extract", 'high2_extract'] args.feature_extractor = "high_extract" - args.th = 0.01 - args.max_step = 1000 - args.lr = 5 + args.th = 0.015 + args.max_step = 2000 + args.lr = 8 elif args.mode == 'custom': pass else: @@ -115,20 +122,23 @@ def main(*argv): args.format = 'jpeg' sess = init_gpu(args.gpu) - fs_names = [args.feature_extractor] - feature_extractors_ls = [load_extractor(name) for name in fs_names] image_paths = glob.glob(os.path.join(args.directory, "*")) image_paths = [path for path in image_paths if "_cloaked" not in path.split("/")[-1]] if not image_paths: - print("No images in the directory") - exit(1) + raise Exception("No images in the directory") faces = Faces(image_paths, sess, verbose=1) orginal_images = faces.cropped_faces orginal_images = np.array(orginal_images) + fs_names = [args.feature_extractor] + if isinstance(args.feature_extractor, list): + fs_names = args.feature_extractor + + feature_extractors_ls = [load_extractor(name) for name in fs_names] + if args.separate_target: target_embedding = [] for org_img in orginal_images: @@ -154,6 +164,7 @@ def main(*argv): elapsed_time = time.time() - start_time print('attack cost %f s' % (elapsed_time)) + print("Done!") if __name__ == '__main__': diff --git a/fawkes/utils.py b/fawkes/utils.py index c769e31..3e1b7d0 100644 --- a/fawkes/utils.py +++ b/fawkes/utils.py @@ -27,8 +27,7 @@ from keras.preprocessing import image from skimage.transform import resize from sklearn.metrics import pairwise_distances - -from .align_face import align, aligner +from fawkes.align_face import align, aligner from six.moves.urllib.request import urlopen if sys.version_info[0] == 2: @@ -89,6 +88,12 @@ def load_image(path): class Faces(object): def __init__(self, image_paths, sess, verbose=1): + model_dir = os.path.join(os.path.expanduser('~'), '.fawkes') + if not os.path.exists(os.path.join(model_dir, "mtcnn.p.gz")): + os.makedirs(model_dir, exist_ok=True) + get_file("mtcnn.p.gz", "http://sandlab.cs.uchicago.edu/fawkes/files/mtcnn.p.gz", cache_dir=model_dir, + cache_subdir='') + self.verbose = verbose self.aligner = aligner(sess) self.org_faces = [] @@ -102,6 +107,10 @@ class Faces(object): cur_img = load_image(p) self.org_faces.append(cur_img) align_img = align(cur_img, self.aligner, margin=0.7) + if align_img is None: + print("Find 0 face(s) in {}".format(p.split("/")[-1])) + continue + cur_faces = align_img[0] cur_shapes = [f.shape[:-1] for f in cur_faces] @@ -327,6 +336,7 @@ def load_extractor(name): if os.path.exists(model_file): model = keras.models.load_model(model_file) else: + print("Download models...") get_file("{}.h5".format(name), "http://sandlab.cs.uchicago.edu/fawkes/files/{}.h5".format(name), cache_dir=model_dir, cache_subdir='') model = keras.models.load_model(model_file) @@ -568,152 +578,3 @@ def _makedirs_exist_ok(datadir): raise else: os.makedirs(datadir, exist_ok=True) # pylint: disable=unexpected-keyword-arg - -# class CloakData(object): -# def __init__(self, protect_directory=None, img_shape=(224, 224)): -# -# self.img_shape = img_shape -# # self.train_data_dir, self.test_data_dir, self.number_classes, self.number_samples = get_dataset_path(dataset) -# # self.all_labels = sorted(list(os.listdir(self.train_data_dir))) -# self.protect_directory = protect_directory -# -# self.protect_X = self.load_label_data(self.protect_directory) -# -# self.cloaked_protect_train_X = None -# -# self.label2path_train, self.label2path_test, self.path2idx = self.build_data_mapping() -# self.all_training_path = self.get_all_data_path(self.label2path_train) -# self.all_test_path = self.get_all_data_path(self.label2path_test) -# self.protect_class_path = self.get_class_image_files(os.path.join(self.train_data_dir, self.protect_class)) -# -# def get_class_image_files(self, path): -# return [os.path.join(path, f) for f in os.listdir(path)] -# -# def extractor_ls_predict(self, feature_extractors_ls, X): -# feature_ls = [] -# for extractor in feature_extractors_ls: -# cur_features = extractor.predict(X) -# feature_ls.append(cur_features) -# concated_feature_ls = np.concatenate(feature_ls, axis=1) -# concated_feature_ls = normalize(concated_feature_ls) -# return concated_feature_ls -# -# def load_embeddings(self, feature_extractors_names): -# dictionaries = [] -# for extractor_name in feature_extractors_names: -# path2emb = pickle.load(open("../feature_extractors/embeddings/{}_emb_norm.p".format(extractor_name), "rb")) -# dictionaries.append(path2emb) -# -# merge_dict = {} -# for k in dictionaries[0].keys(): -# cur_emb = [dic[k] for dic in dictionaries] -# merge_dict[k] = np.concatenate(cur_emb) -# return merge_dict -# -# def select_target_label(self, feature_extractors_ls, feature_extractors_names, metric='l2'): -# original_feature_x = self.extractor_ls_predict(feature_extractors_ls, self.protect_train_X) -# -# path2emb = self.load_embeddings(feature_extractors_names) -# items = list(path2emb.items()) -# paths = [p[0] for p in items] -# embs = [p[1] for p in items] -# embs = np.array(embs) -# -# pair_dist = pairwise_distances(original_feature_x, embs, metric) -# max_sum = np.min(pair_dist, axis=0) -# sorted_idx = np.argsort(max_sum)[::-1] -# -# highest_num = 0 -# paired_target_X = None -# final_target_class_path = None -# for idx in sorted_idx[:5]: -# target_class_path = paths[idx] -# cur_target_X = self.load_dir(target_class_path) -# cur_target_X = np.concatenate([cur_target_X, cur_target_X, cur_target_X]) -# cur_tot_sum, cur_paired_target_X = self.calculate_dist_score(self.protect_train_X, cur_target_X, -# feature_extractors_ls, -# metric=metric) -# if cur_tot_sum > highest_num: -# highest_num = cur_tot_sum -# paired_target_X = cur_paired_target_X -# final_target_class_path = target_class_path -# -# np.random.shuffle(paired_target_X) -# return final_target_class_path, paired_target_X -# -# def calculate_dist_score(self, a, b, feature_extractors_ls, metric='l2'): -# features1 = self.extractor_ls_predict(feature_extractors_ls, a) -# features2 = self.extractor_ls_predict(feature_extractors_ls, b) -# -# pair_cos = pairwise_distances(features1, features2, metric) -# max_sum = np.min(pair_cos, axis=0) -# max_sum_arg = np.argsort(max_sum)[::-1] -# max_sum_arg = max_sum_arg[:len(a)] -# max_sum = [max_sum[i] for i in max_sum_arg] -# paired_target_X = [b[j] for j in max_sum_arg] -# paired_target_X = np.array(paired_target_X) -# return np.min(max_sum), paired_target_X -# -# def get_all_data_path(self, label2path): -# all_paths = [] -# for k, v in label2path.items(): -# cur_all_paths = [os.path.join(k, cur_p) for cur_p in v] -# all_paths.extend(cur_all_paths) -# return all_paths -# -# def load_label_data(self, label): -# train_label_path = os.path.join(self.train_data_dir, label) -# test_label_path = os.path.join(self.test_data_dir, label) -# train_X = self.load_dir(train_label_path) -# test_X = self.load_dir(test_label_path) -# return train_X, test_X -# -# def load_dir(self, path): -# assert os.path.exists(path) -# x_ls = [] -# for file in os.listdir(path): -# cur_path = os.path.join(path, file) -# im = image.load_img(cur_path, target_size=self.img_shape) -# im = image.img_to_array(im) -# x_ls.append(im) -# raw_x = np.array(x_ls) -# return preprocess_input(raw_x) -# -# def build_data_mapping(self): -# label2path_train = {} -# label2path_test = {} -# idx = 0 -# path2idx = {} -# for label_name in self.all_labels: -# full_path_train = os.path.join(self.train_data_dir, label_name) -# full_path_test = os.path.join(self.test_data_dir, label_name) -# label2path_train[full_path_train] = list(os.listdir(full_path_train)) -# label2path_test[full_path_test] = list(os.listdir(full_path_test)) -# for img_file in os.listdir(full_path_train): -# path2idx[os.path.join(full_path_train, img_file)] = idx -# for img_file in os.listdir(full_path_test): -# path2idx[os.path.join(full_path_test, img_file)] = idx -# idx += 1 -# return label2path_train, label2path_test, path2idx -# -# def generate_data_post_cloak(self, sybil=False): -# assert self.cloaked_protect_train_X is not None -# while True: -# batch_X = [] -# batch_Y = [] -# cur_batch_path = random.sample(self.all_training_path, 32) -# for p in cur_batch_path: -# cur_y = self.path2idx[p] -# if p in self.protect_class_path: -# cur_x = random.choice(self.cloaked_protect_train_X) -# elif sybil and (p in self.sybil_class): -# cur_x = random.choice(self.cloaked_sybil_train_X) -# else: -# im = image.load_img(p, target_size=self.img_shape) -# im = image.img_to_array(im) -# cur_x = preprocess_input(im) -# batch_X.append(cur_x) -# batch_Y.append(cur_y) -# batch_X = np.array(batch_X) -# batch_Y = to_categorical(np.array(batch_Y), num_classes=self.number_classes) -# yield batch_X, batch_Y diff --git a/fawkes_dev/azure.py b/fawkes_dev/azure.py index 79312f7..2aee371 100644 --- a/fawkes_dev/azure.py +++ b/fawkes_dev/azure.py @@ -46,7 +46,8 @@ def detect_face(image_url): conn.request("POST", "/face/v1.0/detect?%s" % params, body, headers) response = conn.getresponse() data = json.loads(response.read()) - print(data) + # + # print(data) conn.close() return data[0]["faceId"] @@ -229,7 +230,6 @@ def eval(original_faceIds, personGroupId, protect_personId): response = conn.getresponse() data = json.loads(response.read()) conn.close() - face = data[0] print(face) if len(face["candidates"]) and face["candidates"][0]["personId"] == protect_personId: @@ -270,8 +270,8 @@ def get_trainStatus(personGroupId): conn.request("GET", "/face/v1.0/persongroups/{}/training?%s".format(personGroupId) % params, body, headers) response = conn.getresponse() data = response.read() - print(data) conn.close() + return data def test_cloak(): @@ -279,12 +279,12 @@ def test_cloak(): total_idx = range(0, 82) TRAIN_RANGE = random.sample(total_idx, NUM_TRAIN) - TEST_RANGE = TRAIN_RANGE + TEST_RANGE = random.sample([i for i in total_idx if i not in TRAIN_RANGE], 20) personGroupId = 'all' # delete_personGroup(personGroupId) - create_personGroupId(personGroupId, personGroupId) + # create_personGroupId(personGroupId, personGroupId) with open("protect_personId.txt", 'r') as f: protect_personId = f.read() @@ -305,22 +305,25 @@ def test_cloak(): print("Unable to add {}-th image of protect person".format(idx)) # add other people - for idx_person in range(500): - personId = create_personId(personGroupId, str(idx_person)) - print("Created personId: {}".format(idx_person)) - for idx_image in range(10): - image_url = "http://sandlab.cs.uchicago.edu/fawkes/files/target_data/{}/{}.jpg".format( - idx_person, idx_image) - r = add_persistedFaceId(personGroupId, personId, image_url) - if r is not None: - print("Added {}".format(idx_image)) - else: - print("Unable to add {}-th image".format(idx_image)) + # for idx_person in range(1300, 5000): + # personId = create_personId(personGroupId, str(idx_person)) + # print("Created personId: {}".format(idx_person)) + # for idx_image in range(10): + # image_url = "http://sandlab.cs.uchicago.edu/fawkes/files/target_data/{}/{}.jpg".format( + # idx_person, idx_image) + # r = add_persistedFaceId(personGroupId, personId, image_url) + # if r is not None: + # print("Added {}".format(idx_image)) + # else: + # print("Unable to add {}-th image".format(idx_image)) # train model based on personGroup + train_personGroup(personGroupId) - time.sleep(4) - get_trainStatus(personGroupId) + + while json.loads(get_trainStatus(personGroupId))['status'] != 'succeeded': + time.sleep(2) + # list_personGroupPerson(personGroupId) # test original image diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index e27e028..0000000 --- a/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -scikit-image -argparse -glob -numpy==1.18.4 \ No newline at end of file diff --git a/setup.py b/setup.py index d0532b2..fbec16e 100644 --- a/setup.py +++ b/setup.py @@ -75,13 +75,15 @@ class DeployCommand(Command): setup_requires = [] install_requires = [ - 'numpy>=1.16.4', - 'tensorflow>=1.13.1', + 'numpy==1.16.4', + # 'tensorflow-gpu>=1.13.1, <=1.14.0', + 'tensorflow>=1.13.1, <=1.14.0', 'argparse', 'keras==2.2.5', 'scikit-image', 'pillow>=7.0.0', 'opencv-python>=4.2.0.34', + 'sklearn', ] setup(