深層学習 - ニューラル ネットワークとリカレント ニューラル ネットワークの基本原理

順伝播 (順方向)

なぜアクティベーション関数があるのか

ここでは例として多層ニューラルネットワークを2層で表します。1層目の出力が2層目の入力になります。MMのW*X行列乗算、ADDはバイアスを加えるベクトル加算です。各層が線形変換だけであれば、何層を1層にまとめても(上図左側の式を参照)、層数に意味がないので、各層に非線形関数、つまり活性化関数を追加する必要があります。各層に独自の役割があることを確認ます

連鎖法則 

逆方向伝播 (逆方向) 

  

x が前層の出力の場合は、これも計算する必要がありますが、このとき、前層の出力 z に相当します。

損失 L から z への偏導関数は逆伝播から渡され、z から x への偏導関数は順伝播中に関数 f が計算されるときに計算される局所勾配です。

具体的な例を次に示します。

たとえば、順伝播では、関数 f=x*w の場合、z から x への偏導関数は w、z から w への偏導関数は x になります。x=2 と w=3 が渡されると、z=x*w=6 が出力されます。

次に、バックプロパゲーションで損失を取得し、L から z への偏微分を 5 として計算し、次に L から x への偏微分を 5*w として計算し、つまり 5*3=15 とします。同様に、L から w への偏微分は 10 となり、L から x への偏微分結果が引き続き上位層に渡されるため、各層は w の偏微分を通じて重み w を更新できます。

以上が順方向と逆方向の全体的なプロセスであり、w に対する損失の偏導関数を計算した後、勾配降下アルゴリズムを使用して w を更新できます。

上記は、勾配降下法アルゴリズムの公式導出です。

上記は確率的勾配降下法アルゴリズムの式です。 

コードデモ:

リカレント ニューラル ネットワーク (RNN)

一般に、ニューラル ネットワークでは順序関係のあるデータを扱うことはできません。たとえば、畳み込みニューラル ネットワークを使用して画像を作成し、その画像のカテゴリを出力します。この出力は入力された画像にのみ関連しており、前の入力画像とは何の関係もありません。これは順序関係のないデータです。たとえば、自然言語と同様に、単語と文の間には明らかな文脈上の関係があり、それを処理するにはリカレント ニューラル ネットワークを使用する必要があります。

RNN セルは線形変換層です。上の図の右側にある 4 つの RNN セルはすべて同じ RNN セルを参照します。ここで、 h は hidden とも呼ばれます。各入力は前の出力とともに RNN セルに入力され、次のシーケンスのデータも一緒に取得されます。これが延々と続くため、各入力は前のシーケンスの結果を結合しデータx_{i}h_{i-1}やあ}シーケンス関係x_{i+1}反映ますやあ}h_{i+1}

たとえば、上図には 3 つの層があり、最初の層の RNN セルは元のデータ x と前のシーケンスの出力 h を受け取り、2 番目の層の RNN セルは前の層のシーケンスの出力 h と前のシーケンスの出力 h を受け取り、3 番目の層は 2 番目の層と同じです。

実践例

ここでは、hello->ohlol の法則を学ぶ必要があります。Seq はシーケンスの略です。

具体的な実装コード 

import torch

input_size = 4
hidden_size = 3
batch_size = 1

#构建输入输出字典
idx2char_1 = ['e', 'h', 'l', 'o']
idx2char_2 = ['h', 'l', 'o']
x_data = [1, 0, 2, 2, 3]
y_data = [2, 0, 1, 2, 1]
# y_data = [3, 1, 2, 2, 3]
one_hot_lookup = [[1, 0, 0, 0],
                  [0, 1, 0, 0],
                  [0, 0, 1, 0],
                  [0, 0, 0, 1]]
#构造独热向量,此时向量维度为(SeqLen*InputSize)
x_one_hot = [one_hot_lookup[x] for x in x_data]
#view(-1……)保留原始SeqLen,并添加batch_size,input_size两个维度
inputs = torch.Tensor(x_one_hot).view(-1, batch_size, input_size)
#将labels转换为(SeqLen*1)的维度
labels = torch.LongTensor(y_data).view(-1, 1)

class Model(torch.nn.Module):
    def __init__(self, input_size, hidden_size, batch_size):
        super(Model, self).__init__()
        self.batch_size = batch_size
        self.input_size = input_size
        self.hidden_size = hidden_size

        self.rnncell = torch.nn.RNNCell(input_size = self.input_size,
                                        hidden_size = self.hidden_size)

    def forward(self, input, hidden):
        # RNNCell input = (batchsize*inputsize)
        # RNNCell hidden = (batchsize*hiddensize)
        hidden = self.rnncell(input, hidden)
        return hidden

    #初始化零向量作为h0,只有此处用到batch_size
    def init_hidden(self):
        return torch.zeros(self.batch_size, self.hidden_size)

net = Model(input_size, hidden_size, batch_size)

criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.1)

for epoch in range(15):
    #损失及梯度置0,创建前置条件h0
    loss = 0
    optimizer.zero_grad()
    hidden = net.init_hidden()

    print("Predicted string: ",end="")
    #inputs=(seqLen*batchsize*input_size) labels = (seqLen*1)
    #input是按序列取的inputs元素(batchsize*inputsize)
    #label是按序列去的labels元素(1)
    for input, label in zip(inputs, labels):
        hidden = net(input, hidden)
        #序列的每一项损失都需要累加
        loss += criterion(hidden, label)
        #多分类取最大
        _, idx = hidden.max(dim=1)
        print(idx2char_2[idx.item()], end='')

    loss.backward()
    optimizer.step()

    print(", Epoch [%d/15] loss = %.4f" % (epoch+1, loss.item()))

おすすめ

転載: blog.csdn.net/weixin_61725823/article/details/130568173