日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CS231n 学习笔记(3)——神经网络 part3 :最优化

發布時間:2025/5/22 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CS231n 学习笔记(3)——神经网络 part3 :最优化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

stanford的course note 近日在維護中,所以換了http://cs231n.stanford.edu/slides/網頁的lecture4作為最優化部分的學習資料。

訓練神經網絡的三要素是:1. 確定判別函數2. 確定損失函數3. 最優化

實踐中很少用像素的取值去直接訓練神經網絡。 我們采用的是圖像的特征,例如:直方圖、HOG特征、 Bag of Words

HOG提取算法:每次掃描圖像的一塊8*8的小區域,獲取邊緣方向。一共有9中方向。

將圖片塊的大小調整為32*32,在每個調整后的圖片塊(patch)上采用HOG算法。



絕大多數感知系統都采用下面這種結構:


損失函數可視化

最優化的目的就是要找到損失函數取最小值時,W的取值。如果我們能將損失函數可視化,找最小值就是輕而易舉的。但是,損失函數中包含高維向量W,將高維空間可視化的難度很大,所以首先我們需要采用某些方法來“降維”。回顧一下,SVM的損失函數:

不同取值W的L的值可以看作是超平面中的一個點,當然這個超平面是高維空間。如果我們選擇某一個特定的方向,這個方向用向量W1來表示。W1是一維的,可以用數組表示,它可以看作是超平面中的一個固定的點。新的損失函數就是原損失函數與這個固定點的差值。重新定義改寫一下損失函數:


α是一個可變參數。將α作為x軸自變量,新的損失函數作為y軸應變量。畫圖:

我們可以很容易找出改寫后的損失函數的最小值以及此時所對應的α。同樣,我們也可以用原損失函數減去兩個向量W1,W2。a,b分別對應x軸和y軸,新的損失函數可以用類似等高線的方式用顏色來表示。藍色部分對應的損失函數取值低,紅色部分取值高。

對于一個具體的樣本,損失函數的計算式如下所示:

這個式子的取值可能是正的(錯誤分類時),也可能是負的(正確分類時)假設現在有一個簡單的訓練集,包含三種類別的圖像(每個類別的樣本各一個),因此需要三種判別函數,W中會包含3行,對應的用不同下標表示。對于每一個樣本,要考慮單個的損失函數。整個SVM的損失函數是三個樣本的損失函數情況取平均:

繪圖之后的樣子:

從上圖可以看出,SVM的損失函數是凸函數,可以用凸函數求解最優化的一系列方法來求取最優解。但是在神經網絡中,損失函數并不是凸函數,情況會復雜許多。另外,從SVM損失函數的表達式來看,此函數并不是可微的。但是次梯度法( subgradient )仍舊是有效可用的。后面會有實際的例子。

最優化

最優化的目的是尋找最合適的W使得損失函數取值最小。方法一:隨機尋找W,作比較,直到找到最合適的。這種方法是“暴力破解”,并不推薦。方法二:首先隨機確定W,再通過迭代,每一次都尋找一個更合適的W。 這種方法的準確率達到21.4%。因為很多這種方法時間復雜度高,而且其中有很多計算并不是必須的,是存在浪費的。所以人就不推薦。方法三:沿著梯度的方向搜索。想象一下,如果你在山上,想要最快速度的下山,是不是應該選擇最陡峭的一條路而不是緩緩地盤山路。損失函數可視化之后可以看作是一座山,無論我們選取的初值W在山上的那個位置,我們的目標都是要去山腳(損失函數取得最小值的點)。所以現在我們要找到那條最陡峭的下山路,這條路就是梯度的方向。一維變量中,梯度的定義如下:


計算梯度有兩種算法:一種簡單但是比較慢,另一種比較快但是有較高的錯誤率,需要用算法修正。下例給出簡單的梯度算法:
首先定義每一個樣本的損失函數L_i_vectorized(x, y, W)

def L_i_vectorized(x, y, W):"""A faster half-vectorized implementation. half-vectorizedrefers to the fact that for a single example the implementation containsno for loops, but there is still one loop over the examples (outside this function)"""delta = 1.0scores = W.dot(x)# compute the margins for all classes in one vector operationmargins = np.maximum(0, scores - scores[y] + delta)# on y-th position scores[y] - scores[y] canceled and gave delta. We want# to ignore the y-th position and only consider margin on max wrong classmargins[y] = 0loss_i = np.sum(margins)return loss_i 然后計算所有訓練集樣本的總的損失函數的平均值。 def L(X, Y, W):"""fully-vectorized implementation :- X holds all the training examples as columns (e.g. 3073 x 50,000 in CIFAR-10)- y is array of integers specifying correct class (e.g. 50,000-D array)- W are weights (e.g. 10 x 3073)"""Loss_sum=0for i in range(50000):x=X[i]x=np.append(x,1)y=Y[i]loss_i=L_i_vectorized(x, y, W)#print loss_i#print "#####################"Loss_sum+=loss_i#print Loss_sumL=Loss_sum/50000#print i#print "L="#print L#print "#####################"return Ldef CIFAR10_loss_fun(W):return L(Xtr, Ytr, W) 計算梯度 def eval_numerical_gradient(f, x):""" a naive implementation of numerical gradient of f at x - f should be a function that takes a single argument- x is the point (numpy array) to evaluate the gradient at""" fx = f(x) # evaluate function value at original pointgrad = np.zeros(x.shape)h = 0.00001# iterate over all indexes in xit = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])while not it.finished:# evaluate function at x+hix = it.multi_indexold_value = x[ix]x[ix] = old_value + h # increment by hfxh = f(x) # evalute f(x + h)x[ix] = old_value # restore to previous value (very important!)# compute the partial derivativegrad[ix] = (fxh - fx) / h # the slopeit.iternext() # step to next dimensionreturn grad 調整,找到最合適的步長(step) W = np.random.rand(10, 3073) * 0.001 # random weight vector df = eval_numerical_gradient(CIFAR10_loss_fun, W) # get the gradientloss_original = CIFAR10_loss_fun(W) # the original loss print 'original loss: %f' % (loss_original, )# lets see the effect of multiple step sizes for step_size_log in [-10, -9, -8, -7, -6, -5,-4,-3,-2,-1]:step_size = 10 ** step_size_logW_new = W - step_size * df # new position in the weight spaceloss_new = CIFAR10_loss_fun(W_new)print 'for step size %f new loss: %f' % (step_size, loss_new) 上述程序運行之后,可以看出,在step選擇為6的時候,損失函數最小。這就引出了在神經網絡算法中最終要的參數選取問題————step的大小。step如果選的過小,整個運算會消耗很長時間。如果選的過大,運算過程會加速,但是有點冒險。其中細節將在以后討論。在上例中我們采用的是簡單的numerical gradient 來求取梯度,這種算法非常簡單但是計算復雜度大,消耗很多計算資源。另外一種更高效的算法是使用微積分( Calculus )來計算梯度。這種算法更快速高效,但是錯誤率高。在實踐中,我們經常通過比較 Calculus和numerical gradient 來修正Calculus計算出的梯度。這個過程被稱作“梯度矯正”。以SVM為例,若采用Calculus來計算梯度,我們使用下面的式子:


定義了梯度之后,就可以采用梯度下降算法來搜做最優解:

while True:weights_grad = evaluate_gradient(loss_fun, data, weights)weights += - step_size * weights_grad # perform parameter update 梯度搜索算法是適用范圍最廣的神經網絡損失函數最優化算法。但是對于容量較大的數據集,計算出全部的損失函數非常費時費力。計算成本太高,因此,我們可以采取Mini-batch 的方法,每次取出訓練集中的一部分樣本作為batch,用batch來計算和調整參數。例如,每次選取256個樣本作為一個batch: while True:data_batch = sample_training_data(data, 256) # sample 256 examplesweights_grad = evaluate_gradient(loss_fun, data_batch, weights)weights += - step_size * weights_grad # perform parameter update 小的batch計算出的損失函數,是整個樣本集損失函數的近似。Mini-batch的極端情況是每個batch只含有單個樣本。這種情況被稱為Stochastic Gradient Descent (SGD),實踐中并不常見,因為在實踐中,計算100個樣本的損失函數比計算1個樣本的損失函數100次的計算效率更高。batch的大小是一個超參數,但是我們很少用交叉驗證的方式來求取最優值。經常采用一些設定的值,如32,64,128等。

總結

以上是生活随笔為你收集整理的CS231n 学习笔记(3)——神经网络 part3 :最优化的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。