2
0
mirror of https://github.com/Shawn-Shan/fawkes.git synced 2026-06-12 21:50:46 +05:30
Former-commit-id: 14c0173d9f573e7ccb275b3e366505057ac2c9b1 [formerly e359682d967212b4b3f27923fd659bbade7880e5]
Former-commit-id: a44577686ff64da031231ea323c681185daa8b0d
This commit is contained in:
Shawn-Shan
2020-07-07 11:14:38 -05:00
parent 30fa1635a5
commit e9f1a50653
19 changed files with 112 additions and 348 deletions
-1
View File
@@ -1 +0,0 @@
58d500da850206b845bdd0150fa182a0ff8c50f0
+7 -11
View File
@@ -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'
)
'select_target_label', 'dump_image', 'reverse_process_cloaked',
'Faces', 'get_file', 'main',
)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -11
View File
@@ -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)
#
@@ -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
+1 -1
View File
@@ -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:
+28 -17
View File
@@ -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__':
+12 -151
View File
@@ -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