書名: AI安全之對抗樣本入門作者名: 兜哥編著本章字數: 1900字更新時間: 2019-07-11 18:32:01
1.1.4 反向傳遞與優化器
深度學習訓練過程如圖1-7所示。
在深度學習模型里面,經常需要使用梯度算法,針對損失函數的反饋不斷調整各層的參數,使得損失函數最小化。在訓練階段,真實值就是樣本對應的真實標簽,預測值就是機器學習模型預測的標簽值,這些都是明確的,所以損失函數是可以定義和計算的。機器學習模型訓練的過程就是不斷調整參數追求損失函數最小的過程。梯度可以理解為多元函數的指定點上升的坡度,假設多元函數可以表示為f(x,y),那么對應的梯度的定義為:

可見梯度可以用偏導數來定義,通常損失函數就是這個多元函數,特征向量就可以看成這個多元函數的某個點。在訓練過程中,針對參數的調整可以使用梯度和學習率來定義,其中學習率也叫作學習步長,物理含義就是變量在梯度方向上移動的長度,學習率是一個非常重要的參數,學習率過大會導致損失函數的震蕩難以收斂,過小會導致計算緩慢,目前還沒有很成熟的理論來推倒最合適的學習率,經驗值是0.001~0.1。以表示學習率,那么迭代更新參數x的方法為:


圖1-7 深度學習訓練過程
在求函數的最大值時,我們會向梯度向上的方向移動,使用加號,也稱為梯度向上算法。如果我們想求函數的最小值,則需要向梯度向下的方向移動,使用減號,也稱為梯度下降算法,比如求損失函數最小值時,對應迭代求解的方法為:

我們通過一個非常簡單的例子演示這個過程,假設我們只有一個變量x,對應的損失函數定義為:

根據梯度的定義,可以獲得對應的梯度為:

我們隨機初始化x,將學習率設置為0.1,整個過程如下:
def demo(): import random a=0.1 x=random.randint(1,10) y = x * x + 2 index=1 while index < 100 and abs(y-2) > 0.01 : y=x*x+2 print "batch={} x={} y={}".format(index,x,y) x=x-2*x*a index+=1
整個迭代過程最多100步,由于我們預先知道函數的最小值為2,所以如果當計算獲得的函數值非常接近2,我們也可以提前退出迭代過程,比如絕對值相差不超過0.01。最后果然沒讓我們失望,在迭代20次后就找到了接近理論上的最小點:
batch=14 x=0.329853488333 y=2.10880332377 batch=15 x=0.263882790666 y=2.06963412721 batch=16 x=0.211106232533 y=2.04456584141 batch=17 x=0.168884986026 y=2.02852213851 batch=18 x=0.135107988821 y=2.01825416864 batch=19 x=0.108086391057 y=2.01168266793 batch=20 x=0.0864691128455 y=2.00747690748
Keras里面提供相應的工具返回loss函數關于variables的梯度,variables為張量變量的列表,這里的loss函數即損失函數:
from keras import backend as K k.gradients(loss, variables)
Keras也提供了function用于實例化一個Keras函數,inputs是輸入張量的列表,其元素為占位符或張量變量,outputs為輸出張量的列表:
k.function(inputs, outputs, updates=[])
常用的優化器包括SGD、RMSprop和Adam。
1.SGD
SGD即隨機梯度下降法,是最基礎的優化方法。普通的訓練方法需要重復不斷地把整套數據放入神經網絡中訓練,這會消耗大量計算資源。SGD則會把數據拆分后再分批不斷地放入神經網絡中來計算。每次使用批數據,雖然不能反映整體數據的情況,不過卻在很大程度上加速了神經網絡的訓練過程,而且也不會丟失太多準確率。
SGD支持動量參數,支持學習衰減率,函數的定義如下:
keras.optimizers.SGD(lr=0.01, momentum=0.0, decay=0.0, nesterov=False)
其中比較重要的參數如下:
·lr:學習率。
·momentum:動量參數。
·decay:每次更新后的學習率衰減值。
2.RMSprop
RMSprop是面對遞歸神經網絡時的一個良好選擇,函數的定義如下:
keras.optimizers.RMSprop(lr=0.001, rho=0.9, epsilon=1e-06)
其中比較重要的參數如下:
·lr:學習率。
·epsilon:大于或等于0的小浮點數,防止除0錯誤。
3.Adam
Adam是一種可以替代SGD的一階優化算法,它能基于訓練數據迭代地更新神經網絡權重,是目前最受歡迎的優化算法之一,定義如下:
keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08)
其中比較重要的參數如下:
·lr:學習率。
·epsilon:大于或等于0的小浮點數,防止除0錯誤。
下面我們以迭代生成對抗樣本的例子來感性認識一下不同優化器的計算收斂速度,代碼路徑為:
https://github.com/duoergun0729/adversarial_examples/code/1-case1-pytorch.ipynb
首先,定義全局變量,其中adam_original_loss、sdg_original_loss和RMSprop_original_loss分別代表迭代過程中不同優化算法對應的損失函數的值:
sdg_original_loss=[] RMSprop_original_loss=[] epoch_range=[]
加載測試圖片,并縮放到長和寬均為224:
#獲取計算設備,默認是CPU device = torch.device("cuda" if torch.cuda.is_available() else "cpu") #圖像加載以及預處理 image_path="../picture/cropped_panda.jpg" orig = cv2.imread(image_path)[..., ::-1] orig = cv2.resize(orig, (224, 224)) img = orig.copy().astype(np.float32)
對圖像數據進行標準化處理,由于攻擊的圖像分類模型是基于ImageNet2012數據集進行預訓練的,因此需要使用ImageNet2012數據集特有的均值mean和標準差std進行標準化:
mean = [0.485, 0.456, 0.406] std = [0.229, 0.224, 0.225] img /= 255.0 img = (img - mean) / std img = img.transpose(2, 0, 1) img=np.expand_dims(img, axis=0) img = Variable(torch.from_numpy(img).to(device).float())
實例化alexnet模型并加載預訓練的參數。在使用迭代優化的過程中,整個模型的參數不變化,反向傳遞僅調整原始圖像的內容:
#使用預測模式主要影響dropout和BN層的行為 model = models.alexnet(pretrained=True).to(device).eval() #獲取分類標簽 label=np.argmax(model(img).data.cpu().numpy()) print("label={}".format(label)) #圖像數據梯度可以獲取 img.requires_grad = True #設置為不保存梯度值,自然也無法修改 for param in model.parameters(): param.requires_grad = False
使用定向攻擊,攻擊目標的標簽值為288,最大迭代次數為100:
loss_func = torch.nn.CrossEntropyLoss() epochs=100 target=288 target=Variable(torch.Tensor([float(target)]).to(device).long())
迭代優化的計算過程中,根據預測結果與定向攻擊目標計算損失值,并通過手工調用反向傳遞過程,更新原始圖像:
for epoch in range(epochs): # 梯度清零 optimizer.zero_grad() # forward + backward output = model(img) loss = loss_func(output, target) label=np.argmax(output.data.cpu().numpy()) adam_original_loss+=[loss] epoch_range += [epoch] #手工調用反向傳遞計算,更新原始圖像 loss.backward() optimizer.step()
分別實例化不同的優化器,記錄100次迭代優化過程中損失值的變化,如圖1-8所示,當使用相同的學習速率對同一圖片進行迭代優化生成定向攻擊樣本時,RMSprop和Adam明顯快于SGD:
fig, ax = plt.subplots() ax.plot(np.array(epoch_range), np.array(adam_original_loss), 'b--', label='Adam') ax.plot(np.array(epoch_range), np.array(RMSprop_original_loss), 'b-', label='RMSprop') ax.plot(np.array(epoch_range), np.array(sdg_original_loss), 'b:', label='SGD') legend = ax.legend(loc='best', shadow=True, fontsize='large') legend.get_frame().set_facecolor('#FFFFFF') plt.xlabel('Iteration Step ') plt.ylabel('Loss') plt.show()

圖1-8 相同條件下不同優化算法的收斂速度