<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                作者:[寒小陽](http://blog.csdn.net/han_xiaoyang?viewmode=contents) 時間:2016年1月。 出處:[http://blog.csdn.net/han_xiaoyang/article/details/50521072](http://blog.csdn.net/han_xiaoyang/article/details/50521072) 聲明:版權所有,轉載請聯系作者并注明出處 ### 1.引言 前面8小節,算從神經網絡的結構、簡單原理、數據準備與處理、神經元選擇、損失函數選擇等方面把神經網絡過了一遍。這個部分我們打算把知識點串一串,動手實現一個簡單的2維平面神經網絡分類器,去分割平面上的不同類別樣本點。為了循序漸進,我們打算先實現一個簡單的線性分類器,然后再拓展到非線性的2層神經網絡。我們可以看到簡單的淺層神經網絡,在這個例子上就能夠有分割程度遠高于線性分類器的效果。 ### 2.樣本數據的產生 為了凸顯一下神經網絡強大的空間分割能力,我們打算產生出一部分對于線性分類器不那么容易分割的樣本點,比如說我們生成一份螺旋狀分布的樣本點,如下: ~~~ N = 100 # 每個類中的樣本點 D = 2 # 維度 K = 3 # 類別個數 X = np.zeros((N*K,D)) # 樣本input y = np.zeros(N*K, dtype='uint8') # 類別標簽 for j in xrange(K): ix = range(N*j,N*(j+1)) r = np.linspace(0.0,1,N) # radius t = np.linspace(j*4,(j+1)*4,N) + np.random.randn(N)*0.2 # theta X[ix] = np.c_[r*np.sin(t), r*np.cos(t)] y[ix] = j # 可視化一下我們的樣本點 plt.scatter(X[:, 0], X[:, 1], c=y, s=40, cmap=plt.cm.Spectral) ~~~ 得到如下的樣本分布: ![螺旋樣本點集](https://box.kancloud.cn/2016-03-16_56e90ad70b30e.png "") 紫色,紅色和黃色分布代表不同的3種類別。 一般來說,**拿到數據都要做預處理**,包括之前提到的**去均值和方差歸一化**。不過我們構造的數據幅度已經在-1到1之間了,所以這里不用做這個操作。 ### 3.使用Softmax線性分類器 #### 3.1 初始化參數 我們先在訓練集上用softmax線性分類器試試。如我們在[之前的章節](http://blog.csdn.net/han_xiaoyang/article/details/49999583)提到的,我們這里用的softmax分類器,使用的是一個線性的得分函數/score function,使用的損失函數是互熵損失/cross-entropy loss。包含的參數包括得分函數里面用到的權重矩陣`W`和偏移量`b`,我們先隨機初始化這些參數。 ~~~ #隨機初始化參數 import numpy as np #D=2表示維度,K=3表示類別數 W = 0.01 * np.random.randn(D,K) b = np.zeros((1,K)) ~~~ #### 3.2 計算得分 線性的得分函數,將原始的數據映射到得分域非常簡單,只是一個直接的矩陣乘法。 ~~~ #使用得分函數計算得分 scores = np.dot(X, W) + b ~~~ 在我們給的這個例子中,我們有2個2維點集,所以做完乘法過后,矩陣得分`scores`其實是一個[300*3]的矩陣,每一行都給出對應3各類別(紫,紅,黃)的得分。 #### 3.3 計算損失 然后我們就要開始使用我們的損失函數計算`損失`了,我們之前也提到過,損失函數計算出來的結果代表著預測結果和真實結果之間的吻合度,我們的目標是最小化這個結果。直觀一點理解,我們希望對每個樣本而言,對應正確類別的得分高于其他類別的得分,如果滿足這個條件,那么損失函數計算的結果是一個比較低的值,如果判定的類別不是正確類別,則結果值會很高。我們[之前](http://blog.csdn.net/han_xiaoyang/article/details/49999583)提到了,softmax分類器里面,使用的損失函數是互熵損失。一起回憶一下,假設`f`是得分向量,那么我們的互熵損失是用如下的形式定義的: Li=?log(efyi∑jefj) 直觀地理解一下上述形式,就是Softmax分類器把類別得分向量`f`中每個值都看成對應三個類別的log似然概率。因此我們在求每個類別對應概率的時候,使用指數函數還原它,然后歸一化。從上面形式里面大家也可以看得出來,得到的值總是在0到1之間的,因此從某種程度上說我們可以把它理解成概率。如果判定類別是錯誤類別,那么上述公式的結果就會趨于無窮,也就是說損失相當相當大,相反,如果判定類別正確,那么損失就接近log(1)=0。這和我們直觀理解上要最小化`損失`是完全吻合的。 當然,當然,別忘了,完整的損失函數定義,一定會加上正則化項,也就是說,完整的損失`L`應該有如下的形式: L=1N∑iLidata loss+12λ∑k∑lW2k,lregularization loss 好,我們實現以下,根據上面計算得到的得分`scores`,我們計算以下各個類別上的概率: ~~~ # 用指數函數還原 exp_scores = np.exp(scores) # 歸一化 probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) ~~~ 在我們的例子中,我們最后得到了一個[300*3]的概率矩陣`prob`,其中每一行都包含屬于3個類別的概率。然后我們就可以計算完整的互熵損失了: ~~~ #計算log概率和互熵損失 corect_logprobs = -np.log(probs[range(num_examples),y]) data_loss = np.sum(corect_logprobs)/num_examples #加上正則化項 reg_loss = 0.5*reg*np.sum(W*W) loss = data_loss + reg_loss ~~~ 正則化強度λ在上述代碼中是reg,最開始的時候我們可能會得到`loss=1.1`,是通過`np.log(1.0/3)`得到的(假定初始的時候屬于3個類別的概率一樣),我們現在想最小化損失`loss` #### 3.4 計算梯度與梯度回傳 我們能夠用損失函數評估預測值與真實值之間的差距,下一步要做的事情自然是最小化這個值。我們用傳統的梯度下降來解決這個問題。多解釋一句,梯度下降的過程是:我們先選取一組隨機參數作為初始值,然后計算損失函數在這組參數上的梯度(負梯度的方向表明了損失函數減小的方向),接著我們朝著負梯度的方向迭代和更新參數,不斷重復這個過程直至損失函數最小化。為了清楚一點說明這個問題,我們引入一個中間變量p,它是歸一化后的概率向量,如下: pk=efk∑jefjLi=?log(pyi) 我們現在希望知道朝著哪個方向調整權重能夠減小損失,也就是說,我們需要計算梯度?Li/?fk。損失Li從p計算而來,再退一步,依賴于f。于是我們又要做高數題,使用鏈式求導法則了,不過梯度的結果倒是非常簡單: ?Li?fk=pk?1(yi=k) 解釋一下,公式的最后一個部分表示yi=k的時候,取值為1。整個公式其實非常的優雅和簡單。假設我們計算的概率p=[0.2, 0.3, 0.5],而中間的類別才是真實的結果類別。根據梯度求解公式,我們得到梯度df=[0.2,?0.7,0.5]。我們想想梯度的含義,其實這個結果是可解釋性非常高的:大家都知道,梯度是最快上升方向,我們減掉它乘以步長才會讓損失函數值減小。第1項和第3項(其實就是不正確的類別項)梯度為正,表明增加它們只會讓最后的損失/loss增大,而我們的目標是減小loss;中間的梯度項-0.7其實再告訴我們,增加這一項,能減小損失Li,達到我們最終的目的。 我們依舊記`probs`為所有樣本屬于各個類別的概率,記`dscores`為得分上的梯度,我們可以有以下的代碼: ~~~ dscores = probs dscores[range(num_examples),y] -= 1 dscores /= num_examples ~~~ 我們計算的得分`scores = np.dot(X, W)+b`,因為上面已經算好了`scores`的梯度`dscores`,我們現在可以回傳梯度計算W和b了: ~~~ dW = np.dot(X.T, dscores) db = np.sum(dscores, axis=0, keepdims=True) #得記著正則化梯度哈 dW += reg*W ~~~ 我們通過矩陣的乘法得到梯度部分,權重W的部分加上了正則化項的梯度。因為我們在設定正則化項的時候用了系數`0.5`(ddw(12λw2)=λw),因此直接用`reg*W`就可以表示出正則化的梯度部分。 #### 3.5 參數迭代與更新 在得到所需的所有部分之后,我們就可以進行參數更新了: ~~~ #參數迭代更新 W += -step_size * dW b += -step_size * db ~~~ #### 3.6 大雜合:訓練SoftMax分類器 ~~~ #代碼部分組一起,訓練線性分類器 #隨機初始化參數 W = 0.01 * np.random.randn(D,K) b = np.zeros((1,K)) #需要自己敲定的步長和正則化系數 step_size = 1e-0 reg = 1e-3 #正則化系數 #梯度下降迭代循環 num_examples = X.shape[0] for i in xrange(200): # 計算類別得分, 結果矩陣為[N x K] scores = np.dot(X, W) + b # 計算類別概率 exp_scores = np.exp(scores) probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) # [N x K] # 計算損失loss(包括互熵損失和正則化部分) corect_logprobs = -np.log(probs[range(num_examples),y]) data_loss = np.sum(corect_logprobs)/num_examples reg_loss = 0.5*reg*np.sum(W*W) loss = data_loss + reg_loss if i % 10 == 0: print "iteration %d: loss %f" % (i, loss) # 計算得分上的梯度 dscores = probs dscores[range(num_examples),y] -= 1 dscores /= num_examples # 計算和回傳梯度 dW = np.dot(X.T, dscores) db = np.sum(dscores, axis=0, keepdims=True) dW += reg*W # 正則化梯度 #參數更新 W += -step_size * dW b += -step_size * db ~~~ 得到結果: ~~~ iteration 0: loss 1.096956 iteration 10: loss 0.917265 iteration 20: loss 0.851503 iteration 30: loss 0.822336 iteration 40: loss 0.807586 iteration 50: loss 0.799448 iteration 60: loss 0.794681 iteration 70: loss 0.791764 iteration 80: loss 0.789920 iteration 90: loss 0.788726 iteration 100: loss 0.787938 iteration 110: loss 0.787409 iteration 120: loss 0.787049 iteration 130: loss 0.786803 iteration 140: loss 0.786633 iteration 150: loss 0.786514 iteration 160: loss 0.786431 iteration 170: loss 0.786373 iteration 180: loss 0.786331 iteration 190: loss 0.786302 ~~~ 190次循環之后,結果大致收斂了。我們評估一下準確度: ~~~ #評估準確度 scores = np.dot(X, W) + b predicted_class = np.argmax(scores, axis=1) print 'training accuracy: %.2f' % (np.mean(predicted_class == y)) ~~~ 輸出結果為49%。不太好,對吧?實際上也是可理解的,你想想,一份螺旋形的數據,你偏執地要用一個線性分類器去分割,不管怎么調整這個線性分類器,都非常非常困難。我們可視化一下數據看看決策邊界(decision boundaries): ![線性分類器與決策邊界](https://box.kancloud.cn/2016-03-16_56e90ad727e80.png "") ### 4.使用神經網絡分類 從剛才的例子里可以看出,一個線性分類器,在現在的數據集上效果并不好。我們知道神經網絡可以做非線性的分割,那我們就試試神經網絡,看看會不會有更好的效果。對于這樣一個簡單問題,我們用單隱藏層的神經網絡就可以了,這樣一個神經網絡我們需要2層的權重和偏移量: ~~~ # 初始化參數 h = 100 # 隱層大小(神經元個數) W = 0.01 * np.random.randn(D,h) b = np.zeros((1,h)) W2 = 0.01 * np.random.randn(h,K) b2 = np.zeros((1,K)) ~~~ 然后前向計算的過程也稍有一些變化: ~~~ #2層神經網絡的前向計算 hidden_layer = np.maximum(0, np.dot(X, W) + b) # 用的 ReLU單元 scores = np.dot(hidden_layer, W2) + b2 ~~~ 注意到這里,和之前線性分類器中的得分計算相比,多了一行代碼計算,我們首先計算第一層神經網絡結果,然后作為第二層的輸入,計算最后的結果。哦,對了,代碼里大家也看的出來,我們這里使用的是ReLU神經單元。 其他的東西都沒太大變化。我們依舊按照之前的方式去計算loss,然后計算梯度`dscores`。不過反向回傳梯度的過程形式上也有一些小小的變化。我們看下面的代碼,可能覺得和Softmax分類器里面看到的基本一樣,但注意到我們用`hidden_layer`替換掉了之前的`X`: ~~~ # 梯度回傳與反向傳播 # 對W2和b2的第一次計算 dW2 = np.dot(hidden_layer.T, dscores) db2 = np.sum(dscores, axis=0, keepdims=True) ~~~ 恩,并沒有完事啊,因為`hidden_layer`本身是一個包含其他參數和數據的函數,我們得計算一下它的梯度: ~~~ dhidden = np.dot(dscores, W2.T) ~~~ 現在我們有隱層輸出的梯度了,下一步我們要反向傳播到ReLU神經元了。不過這個計算非常簡單,因為r=max(0,x),同時我們又有drdx=1(x>0)。用鏈式法則串起來后,我們可以看到,回傳的梯度大于0的時候,經過ReLU之后,保持原樣;如果小于0,那本次回傳就到此結束了。因此,我們這一部分非常簡單: ~~~ #梯度回傳經過ReLU dhidden[hidden_layer <= 0] = 0 ~~~ 終于,翻山越嶺,回到第一層,拿到總的權重和偏移量的梯度: ~~~ dW = np.dot(X.T, dhidden) db = np.sum(dhidden, axis=0, keepdims=True) ~~~ 來,來,來。組一組,我們把整個神經網絡的過程串起來: ~~~ # 隨機初始化參數 h = 100 # 隱層大小 W = 0.01 * np.random.randn(D,h) b = np.zeros((1,h)) W2 = 0.01 * np.random.randn(h,K) b2 = np.zeros((1,K)) # 手動敲定的幾個參數 step_size = 1e-0 reg = 1e-3 # 正則化參數 # 梯度迭代與循環 num_examples = X.shape[0] for i in xrange(10000): hidden_layer = np.maximum(0, np.dot(X, W) + b) #使用的ReLU神經元 scores = np.dot(hidden_layer, W2) + b2 # 計算類別概率 exp_scores = np.exp(scores) probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) # [N x K] # 計算互熵損失與正則化項 corect_logprobs = -np.log(probs[range(num_examples),y]) data_loss = np.sum(corect_logprobs)/num_examples reg_loss = 0.5*reg*np.sum(W*W) + 0.5*reg*np.sum(W2*W2) loss = data_loss + reg_loss if i % 1000 == 0: print "iteration %d: loss %f" % (i, loss) # 計算梯度 dscores = probs dscores[range(num_examples),y] -= 1 dscores /= num_examples # 梯度回傳 dW2 = np.dot(hidden_layer.T, dscores) db2 = np.sum(dscores, axis=0, keepdims=True) dhidden = np.dot(dscores, W2.T) dhidden[hidden_layer <= 0] = 0 # 拿到最后W,b上的梯度 dW = np.dot(X.T, dhidden) db = np.sum(dhidden, axis=0, keepdims=True) # 加上正則化梯度部分 dW2 += reg * W2 dW += reg * W # 參數迭代與更新 W += -step_size * dW b += -step_size * db W2 += -step_size * dW2 b2 += -step_size * db2 ~~~ 輸出結果: ~~~ iteration 0: loss 1.098744 iteration 1000: loss 0.294946 iteration 2000: loss 0.259301 iteration 3000: loss 0.248310 iteration 4000: loss 0.246170 iteration 5000: loss 0.245649 iteration 6000: loss 0.245491 iteration 7000: loss 0.245400 iteration 8000: loss 0.245335 iteration 9000: loss 0.245292 ~~~ 現在的訓練準確度為: ~~~ #計算分類準確度 hidden_layer = np.maximum(0, np.dot(X, W) + b) scores = np.dot(hidden_layer, W2) + b2 predicted_class = np.argmax(scores, axis=1) print 'training accuracy: %.2f' % (np.mean(predicted_class == y)) ~~~ 你猜怎么著,準確度為98%,我們可視化一下數據和現在的決策邊界: ![神經網絡決策邊界](https://box.kancloud.cn/2016-03-16_56e90ad74dce1.png "") 看起來效果比之前好多了,這充分地印證了我們在[手把手入門神經網絡系列(1)_從初等數學的角度初探神經網絡](http://blog.csdn.net/han_xiaoyang/article/details/50100367)中提到的,神經網絡對于空間強大的分割能力,對于非線性的不規則圖形,能有很強的劃分區域和區分類別能力。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看