作者:Roman Trusov
編譯:元元、桑桑、徐凌霄、錢天培、高寧、餘志文
Google brain最近的研究表明,任何機器學習的分類器都可以被誤導,然後給出錯誤的預測。甚至,只需要利用一些小技巧,你就可以讓分類器輸出幾乎任何你想要的結果。
機器學習可能會被「誤導」的這一現象,正變得越發令人擔憂。考慮到越來越多的系統正在使用AI技術,而且很多系統對保障我們舒適而安全的生活至關重要,比如說,銀行、監控系統、自動取款機(ATM)、筆記本電腦上的人臉識別系統,以及研發中的自動駕駛汽車。關於人工智慧的安全問題,近期的關注點主要圍繞道德層面,今天我們將討論一些更緊迫更現實的問題。
什麼是對抗性攻擊(Adversarial Attacks)
機器學習算法的輸入形式為數值型向量(numeric vectors)。通過設計一種特別的輸入以使模型輸出錯誤的結果,這便被稱為對抗性攻擊。
這怎麼可能呢?沒有一種機器學習算法是完美的,正如人類會犯錯誤一樣,機器智能自然也會出錯——雖然這很罕見。然而,機器學習模型由一系列特定的變換組成的,大多數變換對輸入的輕微變化都非常敏感。利用這種敏感性可以改變算法的運行結果,這是人工智慧安全安全的一個重要問題。
本文中,我們將展示攻擊的幾種主要類型及實例,解釋攻擊易於實施的原因,並討論這個技術所引起的安全隱患。
對抗性攻擊的類型
下面是我們將要重點分析的主要攻擊類型:1.無目標的對抗性攻擊: 這是最普遍的攻擊類型,其目標是使分類器輸出錯誤的結果2.有目標的對抗性攻擊: 這種攻擊稍微困難一些,其目標是使分類器針對你的輸入輸出一個特定的類。
Inception v3 分類器
我們來看看針對Google Inception V3 ImageNet分類器的非目標性對抗攻擊是如何完成的:
圖片注釋:Inception v3 構架,來自於Google
一個經訓練的神經網絡本質上代表一個高維的決策邊界。我們可以把決策邊界想像為一組單元格,同一個單元格中的每一個點(在這個例子中是指每一張圖片)都屬於同一個類別。當然,邊界不是完美的,甚至可以說,這些「單元格」的分類過於粗糙且為線性。這就是該模型的主要漏洞。
理想情況下,一個好的對抗性攻擊是,提供一個與原始圖片數據視覺上無法區分的輸入,卻讓分類器輸出完全不同的預測結果。該攻擊的主要思想是為每一類圖片找到一組能夠把表示向量從原單元格「拖向」另一個單元格輕微的擾動。。本文中,我們將原始圖片稱為「源」(source),把我們加入的擾動稱為「噪聲」(noise)。雖然這並不是一個真正的噪聲,但我們會看到,它其實包含著多重複雜的結構。
所以,現在我們需要知道的只是一個移動方向,使其從初始點(source)移動到臨近的其他單元格, 或者在目標性攻擊的情況下,移至目標類的某個特定單元格。
逐步分析
最簡單但也最有效的方法是快速梯度逐步算法(Fast Gradient Step Method ,FGSM)。這個方法的核心思想是在每一步優化的過程中加入少量噪聲,讓預測結果朝目標類別偏移, 或者如你所願遠離正確的類別。有時候我們需要限制噪聲的振幅以使得攻擊更加隱蔽, 比如說防止某人調查我們的詭計。在我們的例子中,噪聲的振幅意味著像素通道的強度——限制振幅可以確保噪聲幾乎無法察覺,而在最極端的情況下,圖片看起來也只是像一個過度壓縮的jpeg文件.
這是一個純粹的最優化問題——但是在這個例子中,我們優化噪聲的強度來使錯誤最大化。在這個案例中,因為你可以獲取神經網絡的原始輸出信息, 所以你可以直接測量誤差以及計算梯度。
你一定會說, 很不錯, 但是如果我們沒有完整的原始輸出信息怎麼辦, ——比如只有一個分類結果? 如果我們不知道模型的架構怎麼辦?
好,讓我們假設一個最現實的例子。如果我們要攻擊一個完全的「黑箱」, 即接受一張圖片作為輸入,然後輸出該圖片的類別。僅此而已。你該怎麼辦呢?
你可以從相同的方向入手. 首先你需要生成噪音並加到圖片上, 然後將圖片輸入分類器, 並不斷重複這個過程直到機器出錯。不管你是否限制噪聲強度的大小,重複到某個時刻,你都不會再看到正確的分類結果。此時你需要做的事就是找到能得到相同錯誤結果的最弱噪聲,用一個簡單的二分搜索就可以做到.
讓我們來看看為什麼這個方法可行。我們來考慮圖片空間中的不同橫截面,如果你開始向某個方向移動, 你會停在哪兒呢?根據FGSM的定義(沿梯度方向逐步移動),FGSM會使你移動到真實類別和某個錯誤類別的邊界上, 如下圖所示:
圖片標題:對抗方向和隨機方向的橫截面圖集
橫坐標:快速梯度方向(對抗方向)
縱坐標:垂直梯度方向的隨機值(隨機方向)
與David Warde-Farley和Nicolas Papernot合作完成圖片
「真」和「假」之間的邊界幾乎是線性的。我們可以從中得到兩個有趣的結論。首先,如果你沿著梯度的方向進行計算, 一旦碰到了預測的類別改變的區域, 就可以確認攻擊成功了。另一方面,它表明了,決策函數的結構遠比大多數研究者想像的容易。
這個方法很簡單而高效。如果沒有防護措施,這個方法幾乎可以「玩弄」所有的機器學習算法。
讓我們來執行一個無目標性攻擊
成功案例:非目標性攻擊讓你的跑車秒變烤麵包機
在本實驗中,我們將使用PyTorch和torchvision包中的預訓練分類器Inception_v3模型。
讓我們逐步分解攻擊的思路。首先,我們需要選擇一組圖像,將它轉化為對抗樣本。為了簡單方便起見,我將使用NIPS 2017對抗攻擊挑戰賽中的數據集(development set)。
你可以在這裡下載所有的腳本:
https://github.com/tensorflow/cleverhans/tree/master/examples/nips17_adversarial_competition/dataset
mport torchfrom torch import nnfrom torch.autograd import Variablefrom torch.autograd.gradcheck import zero_gradientsimport torchvision.transforms as Tfrom torchvision.models.inception import inception_v3from PIL import Imageimport matplotlib.pyplot as pltimport numpy as np
定義主要的設置,並初始化神經網絡:
classes = eval(open('classes.txt').read())trans = T.Compose([T.ToTensor(), T.Lambda(lambda t: t.unsqueeze(0))])reverse_trans = lambda x: np.asarray(T.ToPILImage()(x))
在這裡,我們需要一個可以將PIL(Python Imaging Library)圖片轉換為Torch張量的轉化,同時我們還需要一個可以輸出numpy矩陣的反向轉換,讓我們可以將其重新轉化為一張圖片。
eps = 2 * 8 / 225.steps = 40norm = float('inf')step_alpha = 0.0001model = inception_v3(pretrained=True, transform_input=True).cuda()loss = nn.CrossEntropyLoss()model.eval();
這是一個可以拿來就用的預訓練神經網絡。這篇教程中的所有操作都是在GPU上運行的,如果你不想使用GPU,只需要將代碼中所有的「.cuda()」調用和「.cpu()」調用刪除即可。
我們也定義了一個損失函數,之後會在此基礎上進行梯度下降。關於「step_alpha」參數,我們稍後會進行進一步討論。
為了使攻擊更加細微,我們需要為所增加的噪音施加約束。一個很好的方法是將噪聲的L-無限範數(即絕對值)限制在一定值,通過這種方法,圖像就不會顯得過亮或過暗。這種方法也很容易理解——像素點數值的絕對值正代表了圖片在某一RBG通道的亮度。
在編寫攻擊代碼之前,讓我們先添加這個可以進行可視化的函數:
def load_image(img_path): img = trans(Image.open(img_path).convert('RGB')) return img
首先,我們從磁碟讀取圖像,並將其轉換為網絡能接受的格式。
def get_class(img): x = Variable(img, volatile=True).cuda() cls = model(x).data.max(1)[1].cpu().numpy()[0] return classes[cls]
默認情況下,分類器只給我們一個類的數字id——該方法既能完成統計推斷,也能給出最可能的分類結果。
def draw_result(img, noise, adv_img): fig, ax = plt.subplots(1, 3, figsize=(15, 10)) orig_class, attack_class = get_class(img), get_class(adv_img) ax[0].imshow(reverse_trans(img[0])) ax[0].set_title('Original image: {}'.format(orig_class.split(',')[0])) ax[1].imshow(noise[0].cpu().numpy().transpose(1, 2, 0)) ax[1].set_title('Attacking noise') ax[2].imshow(reverse_trans(adv_img[0])) ax[2].set_title('Adversarial example: {}'.format(attack_class)) for i in range(3): ax[i].set_axis_off() plt.tight_layout() plt.show()
我們的FGSM攻擊將取決於三個參數:1.最大強度(這不應超過16)2.梯度步數3.步長
一系列試驗後,我們將梯度步數確定在了10-20,將步長定為0.001。通常我們不會把步長設置的太大,以避免結果不穩定。這一步驟和普通梯度下降是一樣的。
def non_targeted_attack(img): img = img.cuda() label = torch.zeros(1, 1).cuda() x, y = Variable(img, requires_grad=True), Variable(label) for step in range(steps): zero_gradients(x) out = model(x) y.data = out.data.max(1)[1] _loss = loss(out, y) _loss.backward() normed_grad = step_alpha * torch.sign(x.grad.data) step_adv = x.data + normed_grad adv = step_adv - img adv = torch.clamp(adv, -eps, eps) result = img + adv result = torch.clamp(result, 0.0, 1.0) x.data = result return result.cpu(), adv.cpu()
通過這樣的修改,我們讓分類器越錯越離譜。我們可以完全控制該流程在兩個「維度」中的細化程度:1.我們用參數eps控制噪聲的幅度:參數越小,輸出圖片的變動也就越小2.我們通過參數step_alpha來控制攻擊的穩定性:和在神經網絡的普通訓練過程中類似,如果把它設置得太高,我們很可能會找不到損失函數的極值點。
如果我們不限制攻擊的幅度,結果則可能類似於目標類中的平均圖像,權衡之後將如下所示:
在我所有的實驗中,使用最小的eps也能帶來不錯的結果——很小的改動就能讓分類器懵逼。為了更清楚地演示,在下面的示範中我將噪音調大了。
讓我們來運行一下「攻擊」,看看我們將得到什麼:
img = load_image('input.png')adv_img, noise = non_targeted_attack(img)draw_result(img, noise, adv_img)
好,所以如果我們想要我們的神經網絡輸出某個特定的類別怎麼辦?這只需要對攻擊代碼做一些小調整就可以了:
def targeted_attack(img, label): img = img.cuda()label = torch.Tensor([label]).long().cuda() x, y = Variable(img, requires_grad=True), Variable(label) for step in range(steps): zero_gradients(x) out = model(x) _loss = loss(out, y) _loss.backward() normed_grad = step_alpha * torch.sign(x.grad.data) step_adv = x.data - normed_grad adv = step_adv - img adv = torch.clamp(adv, -eps, eps) result = img + adv result = torch.clamp(result, 0.0, 1.0) x.data = result return result.cpu(), adv.cpu()
這裡最主要的改變是梯度符號的改變。在無目標性攻擊的過程中,假設目標模型幾乎總是正確的,我們的目標是增大偏差。與無目標攻擊不同,我們現在的目標是使偏差最小化。
step_adv = x.data - normed_grad
讓我們來嘗試一些有趣的例子,試試針對Google的FaceNet進行對抗攻擊。
本例中,FaceNet是一個擁有密集層(dense layer)的Inception_v3特徵提取器,可以識別圖片中的人最可能是誰。我們採用戶外臉部檢測數據集(Labeled Faces in the Wild,LFW)來進行測試,這是面部識別的一個基準。Inception_v3的擴展網絡與另一個分類器結合一起,使用LFW數據集的500張最常見的人臉進行訓練。
圖片解釋:LFW 資料庫範例
攻擊的目標是使數據集中每一個人都被分到「Keanu Reeves」這一類
因為我們有很多張圖片,我們可以選擇性地在代碼中加入一個攻擊成功就停止運行的條件。在對數損失小於0.001時就停止攻擊是很合理的;實踐中,該停止攻擊方法可以顯著提高運行速度,如下圖所示:
圖片標題:目標性攻擊過程中,分類損失函數值逐漸減小
橫坐標:梯度下降步數
縱坐標:損失
圖中有一個很長的平穩期,這意味著大多數時候你可以省很多計算時間。
在我們深入研究之前:僅僅根據收斂所需要的步數,我們可以對該網絡的決策函數做些什麼推斷呢?決策函數的維度太高以至於難以高效檢驗麼? 既然最優化問題這麼容易解決,我們推斷邊界是個很簡單的函數,很可能是線性函數。
這告訴我們什麼呢?第一,神經網絡中的類相距很近。第二,不太明顯的是,如果你僅僅輸入一些隨機噪聲,分類器仍會輸出一些預測結果,這並不總是一件好事。這個在圖像理解領域還是未解決的問題,最近用對抗性訓練解決了這個問題。
一個成功的目標性攻擊需要多少步?
如下圖所示:
圖片標題:目標性攻擊的梯度下降步數
有目標攻擊的結果就沒有那麼有趣了——振幅降低的噪聲使得原圖和修改後的圖片用肉眼無法分辨。
圖片標題:從左到右:Sylvester Stallone, 對抗噪聲,Keanu Reeves
實際案例
接下來,讓我們一起來看看幾個對抗性攻擊的實際案例。(請勿模仿哦!)
列印一個「布滿躁點」的寫著$100的ATM支票-而用它取現$1000000.把一個路標換成一個稍微有幹擾性的,將限速設為200——這在自動駕駛的世界中是相當危險的。不要再等自動駕駛汽車了——重新畫你的車輛牌照,攝像頭永遠不會認出你的車。
安全性和性能的擔憂
現在我們已經知道如何成功執行一個攻擊,那麼讓我們來問問自己為什麼它們這麼危險。是的,每個人都可以使用FGSM,但有沒有防禦措施呢?
這裡我提兩個防禦策略:
被動型策略:訓練其他的分類器來檢測對抗輸入並抵制他們。主動型策略:實行對抗訓練程序。
主動型策略不僅可以幫助防止過度擬合,讓分類器的魯棒性變強,還可以讓你的模型加速收斂。但是根據最近的研究結果,這也不能消除所有對抗攻擊帶來的問題。
而且,增加一個分類器也會大大降低分類效率,實現這兩個分類器也要求你具備更多GANs的經驗。
有些人說既然GANs中的鑑別器能夠被訓練用來偵測對抗的案例(在不消除攻擊本身的情況下),攻擊的問題能夠通過抵制這種被破壞的樣本來解決。不論是從商業還是從科學角度來講,這種解決方案都不是最優的。除了沒有人願意承擔誤報(false positive)的風險這一因素,還有一個和機器學習本身同樣古老的論點:「人類能做的都可以教給一個機器做」。人類可以無障礙地正確解釋對抗案例,所以一定有方法讓這件事自動化。
最後,遷移學習也非常適合被應用到這種攻擊中。即使攻擊者沒辦法接觸原模型, 針對一個足夠好的分類器所生成的樣例也能夠騙過很多其他作用相同的模型。
研究方向
最後,我想提幾個針對對抗性攻擊未來研究的幾個研究方向。解決其中的一個或許就能讓你揚名立萬哦。
我們如何在分類器上實行對抗訓練呢?如果我們可以訓練出一個不僅能預測標籤,還能辨別你是不是在騙他的網絡,那可就太棒了。
對於大多數的類別來講,決策邊界到底長什麼樣子呢?我們知道他們是幾乎線性的。但到什麼程度呢?類群邊界的確切形式(或者換一個準確高端的術語「拓撲」)可以讓我們深入了解最有效的攻擊/防禦。
我們可以如何檢測出對抗案例的出現呢?當你看到一個受損的圖片時,比如一隻大象的圖,你很可能通過圖上的彩色噪點識別出來。但對於機器來說,它非常確信這就是一架飛機,而不是一張有噪點的大象圖。
論文資源Explaining and Harnessing Adversarial Examples:解釋並治理對抗案例:https://research.google.com/pubs/pub43405.htmlThe Space of Transferable Adversarial Examples:對抗案例的遷移空間:https://research.google.com/pubs/pub46153.htmlAdversarial Autoencoders:對抗自編碼:https://research.google.com /pubs/pub44904.htmlAdversarial examples in the physical world:現實世界中國的對抗案例:https://research.google.com/pubs/pub45471.htmlTutorials教程:Tutorial by Ian Goodfellow:Ian Goodfellow的教程:http://www.iro.umontreal.ca /~memisevr/dlss2015/goodfellow_adv.pdfLecture from Stanford course:斯坦福課程:https://www.youtube.com /watch?v=CIfsB_EYsVIOpenAI tutorial:OpenAI的教程https://blog.openai.com/adversarial-example- research/Repositories and tools資料庫和工具:Cleverhans is a great TensorFlow-based library for adversarial attacks and defences:Cleverhans是一個很好的基於TensorFlow的對抗攻擊和防禦的文庫https://github.com/tensoreow/cleverhansFoolBox — another collection of attacks that you can use with a framework of your preferenceFoolBox——另一個你可以結合你喜歡的的框架運用攻擊的集合:https://foolbox.readthedocs.io /en/latest/Competitions比賽Non-targeted attacks:無目標攻擊:https://www.kaggle.com/c/nips-2017-non- targeted-adversarial-attackTargeted attacks:目標攻擊:https://www.kaggle.com/c/nips-2017-targeted- adversarial-attackDefences:防禦:https://www.kaggle.com/c/nips-2017-defense-against- adversarial-attack