ニューラル ネットワークの原理とバックプロパゲーション式の導出、追加の Python コード実装 (深層学習フレームワークを使用せず、実装には numpy を使用)

1. ニューラルネットワークの簡単な原理

ロジスティック回帰では、線形分離可能な問題のみを解決できます。XOR 問題の場合、2 つのクラスを分離する直線を見つけることは不可能であるため、ニューラル ネットワークが導入され、非線形問題に適合するニューロンと活性化関数が追加されます。
ロジスティック回帰の概要は、私の別のブログにあります: ロジスティック回帰の概要とコード実装

ニューラルネットワークの構造

ニューラル ネットワークは、入力層、入力データの特徴、少なくとも 1 つの隠れ層、および出力層で構成されます。
この例では、入力データ x には 3 つの特徴があり、隠れ層には 3 つのニューロンが含まれ、出力層は 1 つのニューロンを出力します。この例は、回帰問題と二値分類問題を解くために使用できます。回帰問題が解決された場合、活性化関数を通過する必要はありません。二値分類問題が解決された場合、出力層は出力値を 0 から 0 までにマッピングします。シグモイド活性化関数により -1 を計算し、0.5 とサイズを比較し、出力カテゴリを決定します。
画像の説明を追加してください

順伝播計算

図の下部にある追加のニューロンは、バイアス値を表すために使用されます。このニューロンの値は常に 1 です。対応する重みを乗算すると、バイアス値を表すことができます。
隠れ層の場合
a i ( 2 ) = g ( [ ∑ j = 1 3 ( x j θ i j + b i ( 2 ) ) ] ) a_{i}^{(2)} =g([\sum_{j=1}^{3}(x_{j} \theta_{ij}+b_{i}^{(2)} )]) ある(2)=g([j=13 (xj ij +b(2))])
θ i j ( 2 ) \theta_{ij}^{(2) } ij(2) は、レイヤー 2 の i 番目のニューロンとレイヤー 1 の j 番目のニューロンの間の接続の重みを表します
g は、活性化関数を表します

对于输出层
h = g ( [ ∑ j = 1 3 ( a j ( 2 ) θ i j ( 3 ) + b i ( 3 ) ) ] ) h=g([\sum_{j=1}^{3}(a_{j}^{(2)} \theta_{ij}^{(3)}+b_{i}^{(3)} )]) h=g([j=13 (aj(2)ij(3)+b(3))])

θ i j ( 3 ) \theta_{ij}^{(3)}ij(3)レイヤ 3 の i 番目のニューロンとレイヤ 1 の j 番目のニューロンの間の接続の重みを表します

すべての数式を展開して次のように書きます。
画像の説明を追加してください

この式は行列乗算の演算規則に似ており、順演算処理を行列演算に変換できます
画像の説明を追加してください
θ ( 1 ) \theta ^{(1)} a>(1)代表第一层的全部参数的矩阵 θ 10 ( 1 ) , θ 11 ( 1 ) , θ 12 ( 1 ) , θ 13 ( 1 ) \theta_{10}^{(1)},\theta_{11}^{(1)},\theta_{12}^{(1)},\theta_{13}^{(1)} 10(1)θ11(1)θ12(1)θ13(1)…,该例子中 θ ( 1 ) \theta ^{(1)} (1)是一个3*4的矩阵

コスト関数

C (C>2) 分類タスクで使用される場合、出力層は C ニューロンであり、C の 2 分類問題とみなすことができます。たとえば、3 分類タスクは、動物が猫であるか犬であるかを決定することです。出力層は 3 つのニューロンで、最初のニューロンは猫か猫ではないかを決定し、2 番目のニューロンは犬か犬ではないかを決定し、3 番目のニューロンは豚か豚かを決定します。ブタではないのですが、ニューロンの出力値が最も大きいのはどれですか? 1 種類です。

y のラベル値は 1 2 3 ではなく、ワンホット エンコード後の値です。カテゴリは合計 3 つあります。最初のカテゴリは [1,0,0] で表され、2 番目のカテゴリは [1,0,0] で表されますは [0,1 ,0] で表され、3 番目のタイプは [0,0,1] で表されます
コスト関数:
J ( θ ) = − 1 m [ ∑ i = 1 m ∑ k = 1 K y k ( i ) l n ( h ( x ( i ) ) ) k + ( 1 − y k ( i ) ) l n ( 1 − h ( x ( i ) ) ) k ] J( \theta )= -\frac{1}{m} [\sum_{i=1}^{m} \sum_{k=1}^{K} y_{k}^{(i)} ln(h(x^{( i)}))_{k}^{}+(1-y_{k}^{(i)})ln(1-h(x^{(i)})) _{k}^{}] J(θ)=メートル1 [i=1m k=1K そしてk(i)ln(h( ×(i)))k+(1そしてk(i))ln(1h(x(i)))k]
y k ( i ) y_{k}^{(i)} そしてk(i)i 番目のサンプル ラベル値の k 番目の成分を表します。 h ( x ( i ) ) k h(x^{(i)})_{k} h(x(i))k 出力値の k 番目の成分を表します

2. バックプロパゲーション公式の導出

変数を定義する

l は層のインデックスを表し、L は最後の層のインデックスを表します。jk は特定の層のニューロンのインデックスを表します。
N は各層のニューロンの数を表します。 θ \シータ θ代表连接权重,b代表偏置
θ i j ( l ) \theta_{ij}^{(l)} ij(l)l 番目の層の j 番目のニューロンと l-1 層の k 番目のニューロンの間の接続の重みを表します
b j ( l ) b_{j} ^{(l) } bj(l)l 番目の層の j 番目のニューロンのバイアス値を表します

z j ( l ) = ∑ k = 1 N ( l − 1 ) [ θ j k ( l ) a k ( l − 1 ) + b j ( l ) ] z_{j}^{(l)}=\sum_{k=1 }^{N^{(l-1)}}[ \theta_{jk}^{(l)}a_{k}^{(l-1)}+b_{j}^{(l)}]j(l)=k=1N(l1) [θjk(l)あるk(l1) +bj(l)] は、l 番目の層の j 番目のニューロンの入力を表します

a j ( l ) = g ( z j ( l ) ) a_{j}^{(l)}=g(z_{j}^{(l)})あるj(l)=g(zj(l)) は、l 番目の層の j 番目のニューロンの出力を表します。 g は、活性化関数を表します。

l 番目の層の j 番目のニューロンの残りの残差は ξ j ( l ) = ∂ J ∂ z j ( l ) \xi_{j}^{ ( l)}=\frac{\partial J}{\partial z_{j}^{(l)}} バツj(l)=zj(l)J

バックプロパゲーション公式の導出

出力層の場合:
導出プロセスは、活性化層がシグモイド活性化関数であるという事実に基づいています。一般に、多分類出力層の活性化関数は次のとおりです。ソフトマックス、ロジスティック回帰で導出したばかりなので、この公式は渡されているので、引き続き活性化関数としてシグモイドを使用し、活性化関数としてソフトマックスを使用します。読者は自分でプロセスを推測するように求められます。私の記憶が正しければ、それは次のとおりです。また、h-y
画像の説明を追加してください
非表示レイヤーの場合:
画像の説明を追加してください

接続の重みとバイアス値について
画像の説明を追加してください

次に、コスト J に基づく各パラメータの偏微分値に従って、勾配降下法を使用して最適解を見つけることができます。
勾配降下法の原理については、次の記事を参照してください: 勾配降下法の原理

3. numpy に基づく Python コードの実装

sklearn に付属の iris データ セットを使用して、2 番目の層に 10 個のニューロン、3 番目の層に 3 個のニューロンを持つ単純な 3 層ニューラル ネットワークを構築します。

from sklearn import datasets
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import  StandardScaler

#relu激活函数
def relu(x):
    x=np.where(x>0,x,0)#大于0的还是本身,小于0的设置为0
    return x

#relu激活函数的导数,大于0的导数是1,小于0的导数是0
def back_relu(z):
    return np.where(z>0,1,0)

#最后一层softmax激活函数,输出一个概率分布
def softmax(x):
    a=np.sum(np.exp(x), axis=1)
    b=np.expand_dims(a, 1).repeat(3, axis=1)
    return np.exp(x)/b

#把离散的类别转化为one-hot编码
def trans_label(labels):
    newlabels=np.zeros((len(labels),3))
    for i,label in enumerate(labels):
        newlabels[i,label]=1
    return newlabels
#评估模型准确率
def evaluate(x_test,y_test):
    num_correct = 0
    for x, y in zip(x_test, y_test):
        y_hat = model.predict(x)

        y = np.argmax(y)
        if y_hat == y:
            num_correct += 1
    acc=num_correct / len(x_test)
    return acc
class model():
    def __init__(self,num_iters=200,lr=0.15):
        """

        :param num_iters: 迭代次数
        :param lr: 学习率
        """
        #定义模型参数
        #这是一个三层的神经网络,第一层是输入层,第二层有十个神经元,第三层有三个神经元,因为是3分类
        self.Theta2 = np.random.rand(4, 10)
        self.Theta3 = np.random.rand(10, 3)
        self.B2 = np.zeros(10)
        self.B3 = np.zeros(3)
        self.num_iters=num_iters
        self.lr=lr
    #模型的训练
    #由于该例子模型较为简单,为便于理解前向传播与反向传播梯度下降都是一步一步来的,如果模型较为复杂,可以使用循环
    def fit(self,X,Y):
        """

        :param X: 特征矩阵
        :param Y: 类别
        :return:
        """
        #数据个数
        m=len(X)
        for k in range(self.num_iters):
            loss = 0
            #损失对各个参数的偏导数
            dj_dTheta3 = 0
            dj_dB3 = 0
            dj_dTheta2 = 0
            dj_dB2 = 0
            for i in range(len(X)):
                #由于用到矩阵相乘,将其扩充一个维度
                x = np.expand_dims(X[i], 0)
                y = Y[i]
                z2 = np.dot(x, self.Theta2) + self.B2
                a2 = relu(z2)

                z3 = np.dot(a2, self.Theta3) + self.B3
                a3 = softmax(z3)
                h=a3

                loss += -(np.sum(np.multiply(y, np.log(h + 1e-5))) +
                          np.sum(np.multiply((1 - y), np.log(1 - h + 1e-5))))
                #防止ln函数溢出,加一个1e-5


                XI3 = a3 - y

                XI2 = np.multiply(np.dot(XI3, self.Theta3.T), back_relu(z2))

                dj_dTheta3 += np.dot(a2.T, XI3)
                dj_dB3 += XI3

                dj_dTheta2 += np.dot(x.T, XI2)
                dj_dB2 += XI2
            dj_dTheta3 /= m
            dj_dB3 /= m
            dj_dTheta2 /= m
            dj_dB2 /= m
            #进行梯度下降
            self.Theta3 = self.Theta3 - self.lr * dj_dTheta3
            self.B3 = self.B3 - self.lr * dj_dB3
            self.Theta2 = self.Theta2 - self.lr * dj_dTheta2
            self.B2 = self.B2 - self.lr * dj_dB2
            loss /= m
            print("num_iter:%d,loss:%f"%(k,loss))
    #前向传播
    def forward(self,x):
        x = np.expand_dims(x, 0)
        z2 = np.dot(x, self.Theta2) + self.B2

        a2 = relu(z2)

        z3 = np.dot(a2, self.Theta3) + self.B3
        a3 = softmax(z3)
        h=a3
        return h
    #预测样本类别
    def predict(self,x):
        h=self.forward(x)
        #输出的三个概率分布,最大的那个判定为那一类
        y_hat=np.argmax(h,1)[0]
        return y_hat
if __name__ == '__main__':
    iris = datasets.load_iris()
    data = iris.data
    label = iris.target
    label = trans_label(label)
    
    #数据标准化
    std = StandardScaler()
    data = std.fit_transform(data)

    x_train, x_test, y_train, y_test = train_test_split(data, label, test_size=0.2, random_state=0)

    model=model()
    model.fit(x_train,y_train)
    print("训练完成")
    acc=evaluate(x_test,y_test)
    print("测试集正确率为:%.3f%%"%(acc*100))


运行結果:
D:\Anaconda3\python.exe D:/pycharmproject/机学习算法复习/神经网络2.py
D :\Anaconda3\lib\site-packages\sklearn\feature_extraction\text.py:17: DeprecationWarning: 'collections.abc' からではなく 'collections' から ABC を使用またはインポートすることは非推奨であり、3.8 では機能しなくなります< /span> num_iter:23,loss:1.228504 num_iter:66,loss:0.755540 num_iter:65,loss:0.766098 num_iter:64 ,loss:0.776585 num_iter:63,loss:0.787256 num_iter:62,loss:0.798184 num_iter :61,loss:0.809372 num_iter:60,loss:0.820826 num_iter:59,loss:0.832546 num_iter:58,loss:0.844534 num_iter:57、loss:0.856783 num_iter:56、loss:0.869301 num_iter:55、loss:0.881281 num_iter:54,loss:0.893416 num_iter:53,loss:0.905565 num_iter:52,loss:0.917294 num_iter:51、loss:0.928598 num_iter:50、loss:0.939652 num_iter:49、loss:0.950888 num_iter:48,loss:0.962310 num_iter:47,loss:0.973916 num_iter:46,loss:0.985707 num_iter:45,loss:0.997435 num_iter:44,loss:1.008787 num_iter:43,loss:1.019773 num_iter:42,loss :1.030859 num_iter:41,loss:1.042024 num_iter:40,loss:1.053329 num_iter:39 ,loss:1.064804 num_iter:38,loss:1.075536 num_iter:37,loss:1.085812 num_iter :36,loss:1.095764 num_iter:35,loss:1.105662 num_iter:34,loss:1.115541 num_iter:33,loss:1.125471 num_iter:32,loss:1.135513 num_iter:31,loss:1.145506 num_iter:30,loss:1.155603 num_iter:29,loss:1.165851 num_iter:28,loss:1.176033 num_iter:27,loss:1.186266 num_iter:26、loss:1.196690 num_iter:25、loss:1.207321 num_iter:24、loss:1.217936 num_iter:22,loss:1.239248 num_iter:21,loss:1.250217 num_iter:20,loss:1.261426 num_iter:19,loss:1.272691 num_iter:18,loss:1.284267 num_iter:17,loss :1.296189 num_iter:16,loss:1.308455 num_iter:15,loss:1.321025 num_iter:14 ,loss:1.333915 num_iter:13,loss:1.347246 num_iter:12,loss:1.360902 num_iter :11,loss:1.375111 num_iter:10,loss:1.390019 num_iter:9,loss:1.405498 num_iter:8,loss:1.421467 num_iter:7,loss:1.438619 num_iter:6,loss:1.457542 num_iter:5,loss:1.479147 num_iter:4,loss:1.506748 num_iter:3,loss:1.551304 num_iter:2,loss:1.693593 num_iter:1,loss:2.239954 num_iter:0,loss:3.063194
コレクションからインポート マッピング、defaultdict



































































num_iter:67,loss:0.745238
num_iter:68,loss:0.735184
num_iter:69,loss:0.725355
num_iter:70、loss:0.715305
num_iter:71、loss:0.705144
num_iter:72、loss:0.694819
num_iter:73,loss:0.684792
num_iter:74,loss:0.674848
num_iter:75,loss:0.663907
num_iter :76,loss:0.653278
num_iter:77,loss:0.642616
num_iter:78,loss:0.632334
num_iter:79 ,loss:0.621853
num_iter:80,loss:0.611735
num_iter:81,loss:0.601942
num_iter:82,loss :0.592096
num_iter:83,loss:0.582128
num_iter:84,loss:0.571898
num_iter:85,loss:0.562073
num_iter:86,loss:0.552639
num_iter:87,loss:0.543344
num_iter:88,loss:0.533303 a> a> num_iter:141、loss:0.300460 num_iter:140、loss:0.302480 num_iter:139、loss:0.304540 num_iter:138,loss:0.306650 num_iter:137,loss:0.308808 num_iter:136,loss:0.311011 num_iter:135,loss:0.313258 num_iter:134,loss:0.315559 num_iter:133,loss:0.317910 num_iter:132,loss :0.320311 num_iter:131,loss:0.322764 num_iter:130,loss:0.325271 num_iter:129 ,loss:0.327833 num_iter:128,loss:0.330454 num_iter:127,loss:0.333134 num_iter :126,loss:0.335875 num_iter:125,loss:0.338681 num_iter:124,loss:0.341556 num_iter:123,loss:0.344501 num_iter:122、loss:0.347520 num_iter:121、loss:0.350614 num_iter:120、loss:0.353787 num_iter:119,loss:0.357042 num_iter:118,loss:0.360384 num_iter:117,loss:0.363815 num_iter:116,loss:0.367340 num_iter:115,loss:0.370963 num_iter:114,loss:0.374696 num_iter:113,loss:0.378551 num_iter:112,loss:0.382522 num_iter:111,loss:0.386602 num_iter:110,loss:0.390805 num_iter:109,loss:0.395138 num_iter:108,loss:0.399610 num_iter:107,loss :0.404225 num_iter:106,loss:0.408978 num_iter:105,loss:0.413882 num_iter:104 ,loss:0.418948 num_iter:103,loss:0.424196 num_iter:102,loss:0.429630 num_iter :101,loss:0.435259 num_iter:100,loss:0.441093 num_iter:99,loss:0.447136 num_iter:98,loss:0.453469 num_iter:97、loss:0.460070 num_iter:96、loss:0.466942 num_iter:95、loss:0.474088 num_iter:94,loss:0.481526 num_iter:93,loss:0.489270 num_iter:92,loss:0.497341 num_iter:91、loss:0.505754 num_iter:90、loss:0.514535
num_iter:89、loss:0.523705




















































num_iter:142,loss:0.298477
num_iter:143,loss:0.296532
num_iter:144,loss:0.294622
num_iter:145、loss:0.292750
num_iter:146、loss:0.290911
num_iter:147、loss:0.289105
num_iter:148,loss:0.287329
num_iter:149,loss:0.285582
num_iter:150,loss:0.283865
num_iter :151,loss:0.282178
num_iter:152,loss:0.280516
num_iter:153,loss:0.278883
num_iter:154 ,loss:0.277277
num_iter:155,loss:0.275697
num_iter:156,loss:0.274143
num_iter:157,loss :0.272618
num_iter:158,loss:0.271122
num_iter:159,loss:0.269649
num_iter:160,loss:0.268201
num_iter:161,loss:0.266775
num_iter:162,loss:0.265371
num_iter:163,loss:0.263989 a> 测试集正确率: 100.000% 训练完了 num_iter:199,loss:0.225797 num_iter:198,loss:0.226632 num_iter:197、loss:0.227416 num_iter:196、loss:0.228270 num_iter:195、loss:0.229083 num_iter:194,loss:0.229951 num_iter:193,loss:0.230794 num_iter:192,loss:0.231672 num_iter:191、loss:0.232550 num_iter:190、loss:0.233439 num_iter:189、loss:0.234352 num_iter:188,loss:0.235308 num_iter:187,loss:0.236277 num_iter:186,loss:0.237258 num_iter:185,loss:0.238252 num_iter:184,loss:0.239259 num_iter:183,loss:0.240280 num_iter:182,loss :0.241314 num_iter:181,loss:0.242362 num_iter:180,loss:0.243424 num_iter:179 ,loss:0.244501 num_iter:178,loss:0.245592 num_iter:177,loss:0.246698 num_iter :176,loss:0.247820 num_iter:175,loss:0.248958 num_iter:174,loss:0.250111 num_iter:173,loss:0.251280 num_iter:172,loss:0.252466 num_iter:171,loss:0.253670 num_iter:170,loss:0.254891 num_iter:169,loss:0.256131 num_iter:168,loss:0.257390 num_iter:167,loss:0.258667 num_iter:166、loss:0.259967 num_iter:165、loss:0.261287
num_iter:164、loss:0.262628




































プロセスは終了コード 0 で終了しました

皆さんのお役に立てば幸いです~~

おすすめ

転載: blog.csdn.net/weixin_44599230/article/details/121500735