學習筆記:斯坦福2017季CS231n深度視覺識別課程視頻(by Fei-Fei Li, Justin Johnson, Serena Yeung)最優化筆記

最優化(上)

簡介

對於圖像數據xi,如果基於參數集W做出的分類預測與真實情況比較一致,那麼計算出來的損失值L就很低。現在介紹第三個,也是最後一個關鍵部分:最優化Optimization。最優化是尋找能使得損失函數值最小化的參數W的過程。

損失函數可視化

最優化

策略#1:隨機搜索

核心思路:迭代優化。當然,我們肯定能做得更好些。核心思路是:雖然找到最優的權重W非常困難,甚至是不可能的(尤其當W中存的是整個神經網絡的權重的時候),但如果問題轉化爲:對一個權重矩陣集W取優,使其損失值稍微減少。那麼問題的難度就大大降低了。換句話說,我們的方法從一個隨機的W開始,然後對其迭代取優,每次都讓它的損失值變得更小一點。

我們的策略是從隨機權重開始,然後迭代取優,從而獲得更低的損失值。

矇眼徒步者的比喻:一個助於理解的比喻是把你自己想象成一個蒙着眼睛的徒步者,正走在山地地形上,目標是要慢慢走到山底。在CIFAR-10的例子中,這山是30730維的(因爲W是3073x10)。我們在山上踩的每一點都對應一個的損失值,該損失值可以看做該點的海拔高度。

策略#2:隨機局部搜索

第一個策略可以看做是每走一步都嘗試幾個隨機方向,如果某個方向是向山下的,就向該方向走一步。這次我們從一個隨機W開始,然後生成一個隨機的擾動dW ,只有當[公式]的損失值變低,我們纔會更新。這個過程的具體代碼如下:

W = np.random.randn(10, 3073) * 0.001 # 生成隨機初始W
bestloss = float("inf")
for i in xrange(1000):
  step_size = 0.0001
  Wtry = W + np.random.randn(10, 3073) * step_size # 有隨機擾動
  loss = L(Xtr_cols, Ytr, Wtry)
  if loss < bestloss:
    W = Wtry
    bestloss = loss
  print 'iter %d loss is %f' % (i, bestloss)

使用同樣的數據(1000),這個方法可以得到21.4%的分類準確率。這個比策略一好,但是依然過於浪費計算資源。

策略#3:跟隨梯度

前兩個策略中,我們是嘗試在權重空間中找到一個方向,沿着該方向能降低損失函數的損失值。其實不需要隨機尋找方向,因爲可以直接計算出最好的方向,==這就是從數學上計算出最陡峭的方向。這個方向就是損失函數的梯度(gradient)。==在矇眼徒步者的比喻中,這個方法就好比是感受我們腳下山體的傾斜程度,然後向着最陡峭的下降方向下山。

在一維函數中,斜率是函數在某一點的瞬時變化率。梯度是函數的斜率的一般化表達,它不是一個值,而是一個向量。在輸入空間中,梯度是各個維度的斜率組成的向量(或者稱爲導數derivatives)。(這是我理解梯度最深的一次 。對一維函數的求導公式如下:
在這裏插入圖片描述
當函數有多個參數的時候,我們稱導數爲偏導數。而梯度就是在每個維度上偏導數所形成的向量。

最優化(下)

梯度計算

計算梯度有兩種方法:一個是緩慢的近似方法(數值梯度法),但實現相對簡單。另一個方法(分析梯度法)計算迅速,結果精確,但是實現時容易出錯,且需要使用微分。現在對兩種方法進行介紹:

使用有限差值進行數值計算

上節中的公式已經給出數值計算梯度的方法。下面代碼是一個輸入爲函數f和向量x,計算f的梯度的通用函數,它返回函數f在點x處的梯度:

def eval_numerical_gradient(f, x):
  """  
  一個f在x處的數值梯度法的簡單實現
  - f是隻有一個參數的函數
  - x是計算梯度的點
  """ 
    fx = f(x) # 在原點計算函數值
	grad = np.zeros(x.shape)
	h = 0.00001
	
    # 對x中所有的索引進行迭代
    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
    while not it.finished:
        # 計算x+h處的函數值
  		ix = it.multi_index
    	old_value = x[ix]
    	x[ix] = old_value + h # 增加h
    	fxh = f(x) # 計算f(x + h)
    	x[ix] = old_value # 存到前一個值中 (非常重要)
    	
    # 計算偏導數
    grad[ix] = (fxh - fx) / h # 坡度
	it.iternext() # 到下個維度

   return grad

根據上面的梯度公式,代碼對所有維度進行迭代,在每個維度上產生一個很小的變化h,通過觀察函數值變化,計算函數在該維度上的偏導數。最後,所有的梯度存儲在變量grad中。

在梯度負方向上更新:在上面的代碼中,爲了計算W_new,要注意我們是向着梯度df的負方向去更新,這是因爲我們希望損失函數值是降低而不是升高。

步長的影響
效率的問題

微分計算梯度

使用有限差值近似計算梯度比較簡單,但缺點在於終究只是近似(因爲我們對於h值是選取了一個很小的數值,但真正的梯度定義中h趨向0的極限),且耗費計算資源太多。

第二個梯度計算方法是利用微分來分析,能得到計算梯度的公式(不是近似),用公式計算梯度速度很快,唯一不好的就是實現的時候容易出錯。爲了解決這個問題,在實際操作時常常將分析梯度法的結果和數值梯度法的結果作比較,以此來檢查其實現的正確性,這個步驟叫做梯度檢查。
在這裏插入圖片描述

梯度下降

現在可以計算損失函數的梯度了,程序重複地計算梯度然後對參數進行更新,這一過程稱爲梯度下降,他的普通版本是這樣的:

# 普通的梯度下降
while True:
  weights_grad = evaluate_gradient(loss_fun, data, weights)
  weights += - step_size * weights_grad # 進行梯度更新
在這裏插入代碼片

這個簡單的循環在所有的神經網絡核心庫中都有。雖然也有其他實現最優化的方法(比如LBFGS),但是到目前爲止,梯度下降是對神經網絡的損失函數最優化中最常用的方法。

課程中,我們會在它的循環細節增加一些新的東西(比如更新的具體公式),但是核心思想不變,那就是我們一直跟着梯度走,直到結果不再變化。

小節

在這裏插入圖片描述
參考來源:
https://zhuanlan.zhihu.com/p/21360434?refer=intelligentunit

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章