最近,訓練過程中遇到了一些問題,所有回頭看了一些原理性的內容,學習過程做了簡單記錄,如果有不準確的點,歡迎大家指正。
梯度下降(gradient descent)
梯度下降法的基本思想可以類比爲一個下山的過程。假設這樣一個場景:一個人被困在山上,需要從山上下來(i.e. 找到山的最低點,也就是山谷)。但此時山上的濃霧很大,導致可視度很低。因此,下山的路徑就無法確定,他必須利用自己周圍的信息去找到下山的路徑。這個時候,他就可以利用梯度下降算法來幫助自己下山。具體來說就是,以他當前的所處的位置爲基準,尋找這個位置最陡峭的地方,然後朝着山的高度下降的地方走,同理,如果我們的目標是上山,也就是爬到山頂,那麼此時應該是朝着最陡峭的方向往上走。然後每走一段距離,都反覆採用同一個方法,最後就能成功的抵達山谷。
Cost function (loss function, objective function): 目標函數
- C: cost
- w: weight 權重
- b: bias 偏向
- n: 訓練數據集實例個數
- x: 輸入值
- a: 輸出值 (當x是輸入時)
- ||v||: 向量的length function
C(w,b) 越小越好,輸出的預測值和真實值差別越小,因此我們在訓練過程的目標是最小化C(w,b)
最小化問題可以用梯度下降解決(gradient descent),假設目標函數C有兩個參數v1和v2,通常可以用微積分解決,如果v包含的變量過多,無法用微積分解決.
對於一個變量,我們可以抽象成一個小球在曲面上的某一點,滾動到最低點,假設y在mininum的右側,每點的導數>0 ,假設每次移動 ,結果仍然>0 ,其中代表學習率(每次我們移動的步長),當y在mininum左側 結果仍然大於0,仍然向下移動。
梯度下降的特點
1、可能會陷入局部最優 2、前提是目標函數要是凸函數convex 3、learning rate自動會減小
對於多個變量,每個變量的更新方法如下
推導過程:
1,總的cost方程變化量和各個變量偏導方向的變化和大概相同
2,我們假設
3,多個對於單個變量 梯度指這個變量的導數,對於多個變量 梯度只多個變量組成向量的轉置如下
可以推出
4,由前面的單變量,我們假設
可以推出: <=0
所以對於變量,可以使目標函數逐漸降低。
5,對於平均cost函數 可以推出
== >
==>
隨機梯度下降算法(stochastic gradient descent)
對於一個訓練過程,一般實例都有幾萬或者幾十萬,對於人臉項目都有數百萬的訓練集,如果等都訓練一遍在更新不太現實。
基本思想:從所有訓練實例中隨機取一個採樣(sample):X1,X2,...,Xm (mini-batch),來估計▽T,大大提高學習效率。
可以推斷出
w和b的更新方程如下:
然後重新選擇下一個mini_batch 進行訓練。
代碼實現如下:
def SGD(self,train_data,epoches,mini_size,eta,test_data):
if test_data: n_test = len(test_data)
n = len(train_data) #表示 訓練樣本數量
for epoch in range(epoches):
random.shuffle(train_data)
mini_batches = [train_data[k:k+mini_size] for k in xrange(0,n,mini_size)] #xrange 返回的是生成器
for mini_batch in mini_batches:
self.update_minibatch(mini_batch,eta)
if test_data:
print "epoches {0} acc {1}/{2} ".format(epoch,self.cal_acc(test_data),n_test)
else:
print "no test data"
# mini_batch 代表mini_size 個元組(x,y) 其中x是輸入的維度 ,輸出是class的種類
def update_minibatch(self,mini_batch,eta):
nabla_b = [np.zeros(b.shape) for b in self.biases] #隨機梯度下降算法,用於存儲我們指定的minibatch中的數據的bias的總和
nabla_w = [np.zeros(w.shape) for w in self.weights]
for x,y in mini_batch:
new_nabla_b ,new_nabla_w = self.back(x,y)
nabla_w = [nw+w for nw,w in zip(new_nabla_w,nabla_w)]
nabla_b = [nb+b for nb,b in zip(new_nabla_b,nabla_b)]
self.weights = [w-((eta/len(mini_batch))*nabla_w) for w,nabla_w in zip(self.weights,nabla_w)]
self.biases = [b-((eta/len(mini_batch))*nabla_b) for b,nabla_b in zip(self.biases,nabla_b)]