用時尚的口罩迷惑人臉識別算法 | 翻譯徵文 | 雷鋒字幕組

由Pavel Anoshin拍攝並發佈於Unsplash
Accompanying GitHub repository: //github.com/BruceMacD/Adversarial-Faces
人臉識別的使用越來越多。伴隨着最近關於人臉識別倫理的爭論,對人臉識別算法進行潛在的對抗攻擊縈繞在我的腦海中。從機場到社交媒體,人臉識別無處不在。你幾乎不可能逃過各種人臉掃描。
一個理想的對人臉識別的攻擊像是一件在不明真相的人看來並不顯眼的衣服。在Hyperface項目的啟發下,我決定研究並實現一個可穿戴對抗的例子。在這篇文章中,我將詳細介紹創建一個對抗圖像來欺騙選定類型的人臉檢測算法的過程,以及我如何在一個口罩上實現一個實際的例子。
人臉檢測 vs. 人臉識別
人臉檢測(左)與人臉識別(右)的對比
在深入研究這個項目之前,首先要注意的是人臉檢測和人臉識別之間的區別。人臉檢測指的是在存在人臉的圖像中發現人臉的能力。人臉識別依賴於人臉檢測,但更進一步,試圖確認這是誰的臉。
對於這個項目,我將關注人臉檢測。主要是因為人臉檢測更容易測試。要正確進行人臉識別測試,訪問人臉數據庫是一個常見的方法。
人臉檢測模型
下一步是選擇在其上建立對抗樣本的人臉檢測模型。目前有很多不同的人臉檢測模型在使用。Vikas Gupta 在「學習 OpenCV」上對人臉檢測模型及其實現進行了深入的解釋。我在這裡簡單介紹一下。
人臉檢測-OpenCV, Dlib和深度學習|學習OpenCV
-
深度神經網絡(DNNs): 深度神經網絡可以使用輸入數據集訓練神經網絡,以檢測不同方向的人臉。一種常用的基於深度神經網絡的人臉檢測的方法是SSD(Single Shot MultiBox Detector)模型。深度神經網絡準確且通用。
-
卷積神經網絡(CNN): 卷積神經網絡是一種深度神經網絡,設計用來對圖像的不同部分賦予重要性。它是健壯的,但在 CPU 上相當慢。
-
哈爾級聯分類器(Haar Cascade Classifiers): 哈爾級聯分類器使用帶有大量標記的正例和負例圖像的數據集進行訓練。哈爾級聯分類器的主要缺點是它們只能識別正面人臉。由於神經網絡更加通用,哈爾級聯分類器不再被廣泛使用。
-
方向梯度直方圖(HOG): HOG 是將經過處理的輸入圖像分割成具有方向梯度的單元,然後將結果送入支持向量機的一種人臉檢測方法。HOG 檢測是快速和輕量級的,但對一些不常見的人臉角度不起作用。

來自dlib的一個基於方向梯度直方圖的人臉建模示例
最簡單的攻擊候選模型是方向梯度直方圖。最值得注意的是,HOG 的期望輸入可以很容易地可視化並反饋到面部檢測模型中。將一張臉可視化為一個有方向梯度的直方圖也有一個優點,那就是對於人類觀察者來說,它不是一張明顯的臉。
Python 中基於方向梯度直方圖的人臉檢測
Note: Expanded code samples with the functionality to display results are available on the accompanying GitHub repository.
為了測試這些例子,我需要一個簡單的基於 HOG 的人臉檢測實現。幸運的是,dlib 庫在其frontal_face_detector中內置了一個 HOG 面部檢測器。
import dlib
import cv2cv2.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 表示輸入圖像將被放大一次。放大後的圖像更大,更容易識別人臉。正面人臉檢測的結果是一個邊界框列表,每個邊界框對應一個被檢測到的人臉。

使用 dlib 在我們的可視化 HOG 中檢測人臉的結果
通過可視化 HOG 的預期輸入,您可以看到它被檢測為一張臉。太棒了!我們有了進行對抗攻擊的基礎。
使用隨機優化創建對抗性設計
現在我知道可視化的 HOG 的預期輸入是將被檢測為假陽性的正向的臉部,即我創建的一個打印在口罩上的看起來不明顯的設計。但是影響設計的因素還有很多,我不知道如何去優化。人臉的位置、方向和大小都會影響圖像中檢測到的人臉數量。我本可以簡單地嘗試不同的設計,直到找到一個好的設計,但是讓一個學習模型為我做困難的工作似乎更有趣且不那麼乏味。
我考慮了幾個不同的模型來尋找最優的輸入。我研究了強化學習、生成對抗網絡和 Q-learning。最終我決定使用帶有隨機優化的模擬退火算法,因為它最適合我的問題,即找到可以使 dlib 檢測到最多人臉的相對應的輸入。我使用 PIL (Python Imaging Library)和 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 需要一個一維數組(據我所知)。這意味着我不得不使用一些簡單的解決方案來給不同的數組位置賦予不同的意義(參見索引解釋)。我選擇優化一個 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 個錯誤檢測的人臉。


