Accompanying GitHub repository: https://github.com/BruceMacD/Adversarial-Faces

Распознавание лиц становится все более популярным. В связи с недавними дебатами об этике распознавания лиц я думал о потенциальных атаках против распознавания лиц. Распознавание лиц используется повсюду, от аэропортов до социальных сетей. Кажется, почти невозможно отказаться от сканирования лица.

Идеальная атака на распознавание лиц - это предмет одежды, который незаметен для неосведомленных. Вдохновленный проектом Hyperface, я решил исследовать и реализовать пример носимого противоборства. В этой статье я подробно расскажу о процессе создания состязательного изображения, чтобы обмануть выбранный тип распознавания лиц, и о том, как я реализовал практический пример на лицевой маске.

Обнаружение лиц против распознавания лиц

Прежде чем углубиться в этот проект, важно отметить разницу между распознаванием лиц и распознаванием лиц. Обнаружение лица относится к способности определять, когда лицо присутствует на изображении. Распознавание лиц основывается на распознавании лиц, чтобы определить, присутствует ли лицо на изображении, но оно идет еще дальше и пытается установить, чье это лицо.

В этом проекте я решил сосредоточиться на распознавании лиц. В основном по той причине, что его намного легче протестировать. Для правильного тестирования распознавания лиц доступ к базе данных распознавания лиц был бы идеальным.

Модели обнаружения лица

Следующим шагом было выбрать модель распознавания лиц для построения примера состязательности. В настоящее время используется множество различных моделей распознавания лиц. Викас Гупта предлагает отличный учебник по моделям распознавания лиц и их реализациям в разделе «Learn OpenCV» с подробными объяснениями. Я просто кратко их рассмотрю.



  • Глубокие нейронные сети (DNN): DNN можно обучить с использованием входных наборов данных для обнаружения лиц в различных ориентациях. Одним из популярных методов обнаружения лиц на основе DNN является одноразовый мультибокс-детектор. DNN точны и универсальны.
  • Сверточные нейронные сети (CNN): CNN - это глубокая нейронная сеть, предназначенная для определения важности различных частей изображения. Это надежный, но довольно медленный процессор.
  • Каскадные классификаторы Хаара. Каскады Хаара обучаются с использованием набора данных с большим количеством помеченных как положительных, так и отрицательных примеров изображений. Основным недостатком каскадных классификаторов Хаара является то, что они могут идентифицировать лица только спереди. Они больше не используются широко, поскольку нейронные сети более универсальны.
  • Гистограмма ориентированных градиентов (HOG): HOG - это метод обнаружения лица, который делит обработанное входное изображение на ячейки с градиентной ориентацией перед подачей результата в машину опорных векторов. Обнаружение HOG быстрое и легкое, но не работает для некоторых необычных углов лица.

Модель, которая быстро выделилась как простейший кандидат для атаки, - это гистограмма ориентированных градиентов. В частности, ожидаемый ввод HOG можно легко визуализировать и передать обратно в модель обнаружения лиц. Визуализация лица в виде гистограммы ориентированных градиентов также имеет то преимущество, что не является очевидным лицом для человека-наблюдателя.

Гистограмма распознавания лица с помощью ориентированных градиентов в Python

Note: Expanded code samples with the functionality to display results are available on the accompanying GitHub repository.

Для тестирования примеров мне понадобилась простая реализация распознавания лиц на основе HOG. К счастью, в библиотеке dlib есть детектор лиц HOG, встроенный в frontal_face_detector.

import dlib
import cv2
cv2.imread("path/to/input_img.png")
frontal_face_detector = dlib.get_frontal_face_detector()
upscaling_factor = 1
detected_faces = frontal_face_detector(img, upscaling_factor)

Детектор фронтального лица работает с входным изображением и коэффициентом масштабирования. Коэффициент масштабирования 1 указывает, что входное изображение будет масштабировано один раз. При увеличении масштаба изображение увеличивается, что упрощает распознавание лиц. Результатом фронтального обнаружения лица является список ограничивающих рамок, по одной для каждого обнаруженного лица.

Пройдя визуализацию ожидаемого ввода HOG, вы увидите, что он распознается как лицо. Большой! У нас есть база для нашей враждебной атаки.

Создание состязательного дизайна с использованием случайной оптимизации

Теперь, когда я знал, что визуализация ожидаемого ввода HOG будет обнаружена как ложное срабатывание для фронтального лица, мне нужно было создать дизайн для печати на маске, который бы выглядел незаметно. Однако на дизайн все еще влияло множество факторов, которые я не знал, как оптимизировать. Положение лиц, их ориентация и размер могут влиять на количество лиц, обнаруженных на изображении. Я мог бы просто пробовать разные дизайны, пока не найду хороший, но мне показалось, что больше удовольствия и меньше утомляет позволить обучающейся модели делать за меня тяжелую работу.

Я рассмотрел несколько разных моделей, чтобы найти оптимальный вход. Я исследовал обучение с подкреплением, генеративные состязательные сети и Q-обучение. В конечном итоге я решил использовать имитацию отжига со случайной оптимизацией, поскольку это лучше всего подходит для моей задачи поиска ввода, соответствующего большинству лиц, обнаруженных dlib.

Я использовал PIL (библиотека изображений Python) в сочетании с mlrose (библиотека Python для случайной оптимизации), чтобы сгенерировать изображение и найти лучшее состояние. Оптимизация с помощью mlrose требует начального состояния и фитнес-функции. В моем случае поиск этого оптимального состояния был очень дорогостоящим вычислением, так как сгенерированное состояние нужно было сохранить на диск в виде изображения, чтобы определить количество обнаруженных лиц.

# indexes:
# 0 % 4 = pos_x
# 1 % 4 = pos_y
# 2 % 4 = rotation
# 3 % 4 = scale
initial_state = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

Начиная с начального состояния mlrose требует 1D-массива (насколько я могу судить). Это означало, что мне пришлось использовать немного хитрое решение, чтобы придать разным позициям массива разную значимость (см. Пояснение к индексу). Я решил оптимизировать ввод с 6 гранями, так как я всегда мог воспроизвести дизайн, чтобы увеличить его размер.

def detected_max(state):
    # converts the 1D state array into images
    get_img_from_state(state)
    return len(detect_faces(cv2.imread(OUTPUT)))

Моя фитнес-функция просто состояла из преобразования состояния в изображение с последующим определением количества лиц на этом изображении. Чем больше будет найдено лиц, тем лучше будет физическая форма. Я также попытался изменить функцию фитнеса, чтобы она была выше, в зависимости от размера входных изображений лица HOG. Это может быть лучше, поскольку большие лица с большей вероятностью будут обнаружены в реальной ситуации. Однако я обнаружил, что учет размера лица приводит к увеличению времени вычислений с визуально схожими результатами.

fitness = mlrose.CustomFitness(detected_max)
problem = mlrose.DiscreteOpt(length=24, fitness_fn=fitness,
                             maximize=True, max_val=scale_factor)
schedule = mlrose.ExpDecay()
best_state, max_faces = mlrose.simulated_annealing(problem, schedule=schedule, max_attempts=10, max_iters=1000,
                                          init_state=initial_state, random_state=1)

print('Optimal state found: ', best_state)
print('Max fitness found: ', max_faces)
# save the optimal found
get_img_from_state(best_state)
print("Number of faces in output: ", len(detect_faces(cv2.imread(OUTPUT))))

С настройкой соответствия и начального состояния настройка mlrose для имитации отжига была простой. Я просто назначил наши входные данные и позволил им работать до тех пор, пока не будет найден оптимальный результат. Я прогнал это несколько раз, чтобы получить визуально интересный результат.

Наконец, с этим интересным результатом я добавил несколько штрихов, чтобы скрыть его лицо. Я решил, что я более квалифицирован, чтобы делать это вручную, поскольку намерение состояло в том, чтобы обмануть людей.

Тестирование дизайна на маске

Когда окончательный дизайн был завершен, я создал несколько макетов масок, чтобы проверить, как они были оценены с помощью распознавания лиц HOG. Первоначальные результаты казались многообещающими. Приведенный выше дизайн последовательно возвращал 4–5 ложно обнаруженных лиц.