Andrew Ng の 2 回目の深層学習コースの最初の週の概要

Andrew Ng の 2 回目の深層学習コースの最初の週の概要


まず目次に行きましょう: 目次
から 最初の週のディレクトリ
次に、コードを個別に説明して実装しましょう。

1. 勾配の消失・爆発とその解決

ニューラル ネットワークをトレーニングする場合、導関数または傾き (dW、db) が特に大きくなったり小さくなったりすることがあります。これは、勾配爆発または勾配消失と呼ばれるものです。その結果、勾配降下アルゴリズムの時間が長くなったり、トレーニングに失敗したりすることがあります。この状況を回避するには、W が 1 より大きくも 1 よりも大きくならないように重み初期化方法を使用できます。

これまでのコースでは、通常、 np.random.randn() メソッドを使用して重み行列 W を初期化しました。重み行列 W は、平均が 0 のユニット標準正規分布からサンプリングしますが、ニューラル ネットワーク内の特定の値をレイヤーの入力として使用します。が増加すると、出力データの分布の分散も増加するため、重みの初期化方法が改良されました。つまり、入力の平方根に従って重みベクトルをスケーリングすることにより、各ニューロンの出力分散は 1 から 1 に正規化されます。ネットワーク内のすべてのニューロンが最初にほぼ同じように分散されるようにし、経験的に収束速度を向上させます。

活性化関数が Tanh 関数の場合、式は次のようになります。これは Xavier 初期化と呼ばれます。

活性化関数が relu 関数の場合、式は次のようになります。これは Xavier 初期化と呼ばれます。

def init_parameters(layer_dims,initialization):
    np.random.seed(3)
    parameters = {}
    if initialization=='zeros':
        for i in range(1,len(layer_dims)):
            parameters['W'+str(i)] = np.zeros((layer_dims[i],layer_dims[i-1]))
            parameters['b'+str(i)] = np.zeros((layer_dims[i],1))
    elif initialization=='random':
        for i in range(1,len(layer_dims)):
            parameters['W'+str(i)] = np.random.randn(layer_dims[i],layer_dims[i-1])
            parameters['b'+str(i)] = np.zeros((layer_dims[i],1))
    elif initialization=='he':  #这是由He等人在所写的Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification论文中得到的结论
        for i in range(1,len(layer_dims)):
            parameters['W'+str(i)] = np.random.randn(layer_dims[i],layer_dims[i-1]) * np.sqrt(2/layer_dims[i-1])
            parameters['b'+str(i)] = np.zeros((layer_dims[i],1))
    else:
        print("错误的初始化参数!程序退出")
        exit()
            
    assert(parameters['W'+str(i)].shape == (layer_dims[i],layer_dims[i-1]))
    assert(parameters['b'+str(i)].shape == (layer_dims[i],1))
    
    return parameters

1.layer_dims = [train_X.shape[0],10,10,1],learning_rate=0.5

  • 初期化='ゼロ'
図1 コスト値変化曲線
図2 訓練結果
  • 初期化='ランダム'
図1 コスト変化曲線
図2 訓練結果
  • 初期化='彼'
図1 コスト変化曲線
図2 訓練結果

2.layer_dims = [train_X.shape[0],100,100,1],learning_rate=0.5

  • 初期化='ゼロ'
図1 コスト値変化曲線
図2 訓練結果
  • 初期化='ランダム'
図1 コスト変化曲線
図2 訓練結果
  • 初期化='彼'
図1 コスト変化曲線
図2 訓練結果

np.sqrt(2/layer_dims[n]) を掛けるかどうかの補正項が主に初期コスト値に影響を与えることが分かります. ネットワークの各層のニューロンの数が少ない場合、この項を掛けるかどうかは最終的な効果への影響は大きい 影響は小さい ニューロンの数が増加するにつれて、補正項なしの初期コスト値は徐々に増加し、トレーニング結果の非対称性がますます明らかになります ただし、ニューロンの数が増加するにつれて、補正項が増加しても、最終トレーニングの結果には特に影響はありません。

2. 正則化方法

ここで最初に理解すべきことは、機械学習におけるバイアスと分散の概念です。Ng Enda氏の説明によると、偏差はトレーニングセットの誤差サイズ、分散はトレーニングセットとテストセットの誤差サイズの比較とのこと。次の図は、同じトレーニング セットを示しています。

左側の図では、データ セットが十分に適合していません。トレーニング セットの適合効果が非常に低いため、テスト セットの精度があまり高くないと考えられます。これを高偏差と呼びます。これを「アンダーフィッティング」といいます。右の図では、トレーニング セットは基本的に 100% 適合しており、精度が非常に高いことがわかります。ただし、このトレーニング結果の適応性は非常に低いため、フィッティングは非常に悪いです。テスト セットの効果はテスト セットの効果と同じです。トレーニング セットは大きく異なり、分散が高くなります。つまり、トレーニング セットの精度は非常に高いですが、テスト セットは比較的低いです。これはこの状況を「過学習」といいます。真ん中は「中程度のフィッティング」で、トレーニングセットとテストセットの精度はほぼ同じです。

結論は:

トレーニング セットの精度が低く、偏差が高いです。
トレーニング セットのパフォーマンスを評価します。偏差が高すぎる場合は、新しいネットワークに置き換える必要がある場合があります。

トレーニング セットの精度は非常に高いですが、テスト セットの精度は低く、
1 つ目は独自のデータ セットを拡張すること、2 つ目は正則化です。

ラララ、本題にいきましょう!正則化によって過学習の問題を解決するにはどうすればよいでしょうか? ロジスティック回帰を例に挙げます。

1.L1/L2正則化

正則化とは、コスト関数 J に正則化項を追加することです。一般的に使用されるものには、L1 正則化と L2 正則化の 2 つがあります。

  • L1 正則化

    で:

  • L2 の正則化

    その中には、

    L1 と L2 の選択に関して、Ng Enda 教師からの引用があります。

L1 正則化が使用される場合、W は最終的にスパースになります。これは、W ベクトルに多くの 0 があることを意味します。セット内のパラメーターはすべて 0 であり、ストレージ モデルには時間がかかるため、これはモデルの圧縮に有益であると言う人もいます。メモリが少なくなります。実際、L1 正則化によってモデルはスパースになりますが、ストレージ メモリはあまり削減されないため、これは L1 正則化の目的ではなく、少なくともモデルを圧縮することではないと思います。 . L2 正則化を使用します。

ニューラル ネットワークのコスト関数に正則化項を追加します。

ここに画像の説明を挿入します
W は n [ l ] × n [ l − 1 ] n^{[l]}\times n^{[l-1]} であるためn[ l ]×n[ l 1 ] 、 n [ l ] n^{[l]}の行列n[ l ] は層lのニューロンの数を表しますn [ l − 1 ] n^{[l-1]}n[ l 1 ] は層l-1のニューロンの数を表すため

∑ i = 1 L ∥ W [ l ] ∥ F 2 = ∑ i = 1 n [ l ] ∑ j = 1 n [ l − 1 ] ( wij [ l ] ) 2 \sum_{i=1}^{L} \左\| W^{[l]} \right \|_{F}^{2}=\sum_{i=1}^{n^{[l]}}\sum_{j=1}^{n^{[ l-1]}}(w_{ij}^{[l]})^2i = 1LW[ l ]F2=i = 1n[ l ]j = 1n[ l 1 ]( w[ l ])2

つまり、行列内のすべての要素の合計を表します。このノルムを使用して勾配降下法を実装する場合、元の結果に基づいて、w の偏微分値を取得するために正規項を追加する必要があります。

d W [ l ] = ∂ L ∂ W [ l ] + λ m W [ l ] dW^{[l]}=\frac{\partial L}{\partial W^{[l]}}+\frac{ \lambda }{m}W^{[l]}dW _[ l ]=∂W _[ l ]∂L _+メートルW[ l ]

体重の更新:

W [ l ] = W [ l ] − α d W [ l ] = W [ l ] − α ( ∂ L ∂ W [ l ] + λ m W [ l ] ) = ( 1 − α λ m ) W [ l ] − α d W [ l ] W^{[l]}=W^{[l]}-\alpha dW^{[l]}=W^{[l]}-\alpha(\frac{\partial L}{\partial W^{[l]}}+\frac{\lambda }{m}W^{[l]})=(1-\frac{\alpha \lambda }{m})W^{ [l]}-\alpha dW^{[l]}W[ l ]=W[ l ]α d W[ l ]=W[ l ]( _∂W _[ l ]∂L _+メートルW[ l ] )=( 1メートルある_) W[ l ]α d W[ l ]

上の式からわかるように、正則化ではW [ l ] W^{[l]}を作成しようとします。W[ l ]には 1 未満の重み係数が乗算されて小さくなるため、L2 正則化は「重み減衰」とも呼ばれます。正則化が過学習の防止に有益である具体的な理由については、第 2 コースの最初の週のセクション 1.5 を参照してください (参考リンク: http://www.ai-start.com/dl2017/html/lesson2-week1.html#ヘッダー -n89)。

コードを使用して実装する方法とその効果を見てみましょう。
2 番目の分類を例に挙げると、効果をより明確にするために、別のデータセットに変更します (参考リンク: https://blog.csdn.net/weixin_42604446/article/details/81369224)。

図 1 トレーニングセット
図 2 テストセット

参照コード:

def datagen(m,lambd,is_plot):   
    np.random.seed(1)
    N = int(m/2)                            #分为两类
    D = 2                                   #样本的特征数或维度
    X = np.zeros((m,D))                     #初始化样本坐标
    Y = np.zeros((m,1))                     #初始化样本标签
    for j in range(2):
        ix = range(N*j,N*(j+1))
        t = np.random.randn(N)*lambd                          
        r = np.random.randn(N)*lambd
        if j==0:
            X[ix] = np.c_[t-0.4, r-0.4]
        else:
            X[ix] = np.c_[t+0.4, r+0.4]      
        Y[ix] = j #red or blue
    if is_plot:
        fig = plt.figure()
        plt.rcParams['figure.figsize']=(7.0,4.0)
        plt.rcParams['image.interpolation']='nearset'
        plt.rcParams['image.cmap']='gray'
        plt.title('training dataset')
        plt.scatter(X[:, 0], X[:, 1], c=np.squeeze(Y), s=40, cmap=plt.cm.Spectral)
        plt.show()
    return X.T,Y.T

正規化を追加した後にコードを更新しました。

  • コストの計算
def compute_cost_with_regulation(A,Y,parameters,lambd):
    m = Y.shape[1]
    sum = 0.
    cross_entropy_cost = compute_cost(A[len(A)-1],Y)
    for i in range(len(A)):
        sum += np.sum(np.square(parameters["W"+str(i+1)]))
    L2_regularization_cost = lambd * sum / (2 * m)
    cost = cross_entropy_cost + L2_regularization_cost
    
    return cost
  • 誤差逆伝播法
def backward_propagation_with_regulation(X,Y,Z,A,W,lambd,derivate_function):
    l = len(W)
    dZ = list(range(l))
    dA = list(range(l))
    dW = list(range(l))
    db = list(range(l))
    m = Y.shape[1]
    grads = {}
    
    dZ[l-1] = A[l-1] - Y
    for i in range(l-1,-1,-1):
        if i>0:
            dW[i] = (1/m)*np.dot(dZ[i],A[i-1].T) + ((lambd * W[i] / m))
        else:
            dW[i] = (1/m)*np.dot(dZ[i],X.T) + ((lambd * W[i] / m))
        db[i] = (1/m)*np.sum(dZ[i],axis=1,keepdims=True)
        dA[i-1] = np.dot(W[i].T,dZ[i])
        dZ[i-1] = np.multiply(dA[i-1],np.int64(A[i-1]>0))
    for i in range(len(dW)):
        grads["dW"+str(i+1)] = dW[i]
        grads["db"+str(i+1)] = db[i]
        
    return grads  

実験結果を見てみましょう:

  • 正則化は追加されていません
図 1 トレーニング セットの分類結果
図 2 テスト セットの分類結果
  • 正則化を追加します。λ = 0.5 \lambda =0.5=0 5
正則化を追加しない場合、明らかな過適合現象が発生し、分散が比較的大きいことがわかります。正則化を追加すると、過適合問題は解決されます。トレーニング セットの精度は低下しますが、精度は向上します。トレーニング セットとテスト セットの割合は近く、適度に適合しています。
図 1 トレーニング セットの分類結果
図 2 テスト セットの分類結果

2.ドロップアウト正則化
の原理は、ニューラル ネットワークの各層でノードを削除する確率を設定し、ドロップアウトがネットワークの各層を横断し、設定された確率で対応するノードをランダムに保持および削除し、最終的にノードを取得します。ノードが少なく、ネットワークが小さい。各ノードは削除される可能性が同じであるため、ニューラル ネットワークが特定のノードに依存することがなくなり、分散が減少し、重みが圧縮され、過学習が防止されます。

ドロップアウトを実装するために最も一般的に使用される方法は、反転ドロップアウト (逆ランダム非アクティブ化) です。この方法では、keep-prob で表される、ネットワークの各層の非アクティブ化確率を設定する必要があります。たとえば、keep-prob=0.8 とすると、隠れたものはすべて削除されます単位 確率は 0.2 です。3 層ネットワークを例にとります。
まずベクトル d を定義します。ドロップアウトがネットワークの 3 層目に実装されている場合は、次のようになります:
d 3 = np .random .rand ( A [ 3 ] .shape [ 0 ] , A [ 3 ] .shape [ 1 ] ) < keep − prob d3=np.random.rand(A^{[3]}.shape[0],A^{[3]}.shape[1])<キーププロブd3 _=np . _ ランダム_ _ _ _ _ rd ( A _[ 3 ]形状[0]____[ 3 ]形状[1])____<キープ_ _ _pro b A [ 3 ]
= np 。multiply ( A [ 3 ] , d 3 ) / keep − prob A^{[3]}=np.multiply(A^{[3]},d3)/keep-prob[ 3 ]=np . _ 乗算( A _ _ _ _ _ _ _[ 3 ]d 3 ) /キープ_ _ _p r o b1
行目の式で得られる d3 はブール配列で、値は True または False です。<keep-prob は、keep-prob より小さい場合は True に設定され、それ以下の場合は True に設定されることを意味します2行目 該当するノードを削除する式であり、削除した部分をkeep-probで割ることで補うことになるので、 A [ 3 ] A^{[ 3]}[ 3 ]の期待値は変わりません。

コードで実装する方法と実験結果を見てみましょう (L2 正則化のトレーニング セットを例として取り上げます)。

ドロップアウトは最後の層には実装されておらず、順伝播と逆伝播のコードは次のとおりです。

  • 順伝播
def forward_propagation_with_dropout(X,parameters,activate_fun,keep_prob):
    #retrieve parameters
    W = []
    b = []
    for i in range(1,len(parameters)//2+1):
        W.append(parameters["W"+str(i)])
        b.append(parameters["b"+str(i)])
    #compute forward_propagation
    Z = []
    A = []
    D = []
    for i in range(len(W)):
        if i==0:
            sZ = np.dot(W[i],X)+b[i]
        else:
            sZ = np.dot(W[i],A[i-1])+b[i]
        sA = activate_fun[i](sZ)
        if i<(len(W)-1):
            sD = np.random.rand(sA.shape[0],sA.shape[1]) < keep_prob
            sA = np.multiply(sA,sD) / keep_prob
        Z.append(sZ)
        A.append(sA)
        D.append(sD)
    return Z,A,W,D
  • 誤差逆伝播法
def backward_propagation_with_dropout(X,Y,Z,A,W,D,keep_prob):
    l = len(W)
    dZ = list(range(l))
    dA = list(range(l-1))
    dW = list(range(l))
    db = list(range(l))
    m = Y.shape[1]
    grads = {}
    
    dZ[l-1] = A[l-1] - Y

    for i in range(l-1,0,-1):
        if i>0:
            dW[i] = (1/m)*np.dot(dZ[i],A[i-1].T)
        else:
            dW[i] = (1/m)*np.dot(dZ[i],X.T)
        db[i] = (1/m)*np.sum(dZ[i],axis=1,keepdims=True)
        dA[i-1] = np.dot(W[i].T,dZ[i])*D[i-1]/keep_prob
        dZ[i-1] = np.multiply(dA[i-1],np.int64(A[i-1]>0))
    for i in range(len(dW)):
        grads["dW"+str(i+1)] = dW[i]
        grads["db"+str(i+1)] = db[i]
        
    return grads

トレーニング結果:

  • ドロップアウトを実装しない、つまり keep_prob=1
図 1 トレーニング セットの分類結果
図 2 テスト セットの分類結果
  • ドロップアウトを実装、keep_prob=0.6
図 1 トレーニング セットの分類結果
図 2 テスト セットの分類結果

上図から分かるように、ドロップアウト正則化を実装しないと過学習の問題が発生しますが、ドロップアウトを実装すると基本的に過学習は解消されます。

仕上げる!
関連リソースのダウンロード: https://download.csdn.net/download/weixin_42149550/11666926
****************************** **************************** これが境界線です****************** * ************************************************
添付:

  1. 最初のコースの 3 週目の課題の backward_propagation セクションを修正しました
def backward_propagation_with_regulation(X,Y,Z,A,W,lambd):
    l = len(W)
    dZ = list(range(l))
    dA = list(range(l-1)) #更正前为dA = list(range(l)),实际需要记录的dA不需要包括最后一层,因为代码直接算出了最后一层的dZ
    dW = list(range(l))
    db = list(range(l))
    m = Y.shape[1]
    grads = {}
    
    dZ[l-1] = A[l-1] - Y

    for i in range(l-1,0,-1):  #更正前为 range(l-1,-1,-1),后面计算的dA,dZ的索引值包括i-1,如果为-1,最后dA的索引就有负数了,显然不行
        if i>0:
            dW[i] = (1/m)*np.dot(dZ[i],A[i-1].T) + ((lambd * W[i] / m))
        else:
            dW[i] = (1/m)*np.dot(dZ[i],X.T) + ((lambd * W[i] / m))
        db[i] = (1/m)*np.sum(dZ[i],axis=1,keepdims=True)
        dA[i-1] = np.dot(W[i].T,dZ[i])
        dZ[i-1] = np.multiply(dA[i-1],np.int64(A[i-1]>0))
    for i in range(len(dW)):
        grads["dW"+str(i+1)] = dW[i]
        grads["db"+str(i+1)] = db[i]
        
    return grads
  1. Markdown エディターで複数の画像を中央に並べて配置するにはどうすればよいですか?
<table>
    <tr>
        <td ><center><img src="https://img-blog.csdnimg.cn/20190904211338386.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjE0OTU1MA==,size_16,color_FFFFFF,t_70" width=480 >图1   训练集分类结果</center></td>
        <td ><center><img src="https://img-blog.csdnimg.cn/2019090421135561.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjE0OTU1MA==,size_16,color_FFFFFF,t_70" width=480 >图2 测试集分类结果</center></td>
    </tr>

おすすめ

転載: blog.csdn.net/weixin_42149550/article/details/100528497