[Pytorchフレームワーク] 2.5リカレントニューラルネットワーク

import torch
torch.__version__
'1.4.0'

2.5リカレントニューラルネットワーク

2.5.1RNNの概要

私たちの脳と機械を区別する最大の特徴の1つは、私たちには記憶があり、私たち自身の記憶に基づいて未知の事柄を推測できることです。私たちの思考は永続的です。ただし、このチュートリアルで現在紹介されているニューラルネットワーク構造の要素は互いに独立しており、入力と出力は独立しています。

RNNの原因

現実の世界では、多くの要素が相互に関連しています。たとえば、屋外の気温は気候変動に伴って周期的に変化し、私たちの言語も文脈を通じて表現された意味を確認する必要があります。しかし、マシンがこのステップを実行することは非常に困難です。したがって、現在の循環ニューラルネットワークがあります。その本質は、記憶する能力があり、これらの記憶の内容に基づいて推論を行うことです。したがって、彼の出力は現在の入力とメモリに依存します。

なぜRNNが必要なのですか

RNNの背後にある考え方は、シーケンシャル情報を使用することです。従来のニューラルネットワークでは、すべての入力(および出力)が互いに独立していると想定しています。文中の次の単語を予測したい場合は、その前にある単語を知る必要があります。また、正しい答えを出すには、次の単語を確認する必要があります。
RNNは、シーケンスの各要素で同じタスクを実行し、すべての出力が以前の計算に依存するため、ループと呼ばれます。
別の見方をすれば、RNNには「メモリ」があり、これまでに計算された情報をキャプチャできます。理論的には、RNNは任意の長さのシーケンスで情報を使用できますが、実際には、いくつかのステップを確認することに限定されています。
サイクリックニューラルネットワークの提案は、メモリモデルのアイデアに基づいています。ネットワークは、前に出現した特徴を記憶し、その特徴に基づいて後続の結果を推測することができ、ネットワーク構造全体が循環し続けることが期待されますサイクリックニューラルネットワークという名前のため。

RNNでできること

RNNは、多くのNLPタスクで大きな成功を収めています。この時点で、最も一般的に使用されるタイプのRNNはLSTMであり、これは長期的な依存関係のキャプチャにおいてRNNよりもはるかに優れています。ただし、心配しないでください。LSTMは基本的にこのチュートリアルで開発するRNNと同じであり、隠された状態を計算するために異なる方法を使用するだけです。LSTMについては後で詳しく説明します。以下は、NLPでのRNNの例です。
言語モデリングとテキスト生成

言語モデリングを通じて、人間が与えられた単語から理解できる偽のテキストと本物のテキストを生成できます。

機械翻訳

機械翻訳は言語モデリングに似ています。ソース言語で一連の単語を入力し、モデルの計算を通じて、ターゲット言語に対応するコンテンツを出力できます。

音声認識

音波からの音響信号の入力シーケンスが与えられると、一連の音声フラグメントとその確率を予測し、音声をテキストに変換できます。

画像の説明を生成する

畳み込みニューラルネットワークとともに、RNNはラベルのない画像の記述を生成できます。

2.5.2RNNネットワークの構造と原理

RNN

サイクリックニューラルネットワークの基本構造は特に単純です。つまり、ネットワークの出力はメモリユニットに格納され、このメモリユニットは次の入力とともにニューラルネットワークに入ります。ネットワークは、入力時に入力としてメモリユニットと結合されることがわかります。ネットワークは、結果を出力するだけでなく、結果をメモリユニットに保存します。次の図は、最も単純なリカレントニューラルの概略図です。入力時のネットワーク。画像ソース

RNNは、同じニューラルネットワークの複数の割り当てと見なすことができます。各ニューラルネットワークモジュールは、メッセージを次のモジュールに渡します。このグラフの構造を拡張します。

このネットワークは、サイクリックニューラルネットワークの名前の由来であるサイクリック構造を持っています。同時に、サイクリックニューラルネットワークの構造によれば、シーケンスタイプのデータの処理に自然な利点があることがわかります。 。ネットワーク自体はシーケンス構造であるため、これはすべてのリカレントニューラルネットワークの最も重要な構造でもあります。

サイクリックニューラルネットワークは特に優れたメモリ特性を備えており、メモリの内容を現在の状況に適用できますが、ネットワークのメモリ容量は想像したほど効果的ではありません。記憶の最大の問題は、物忘れがあることです。私たちは常に最近の出来事をより明確に覚えており、ずっと前に起こった出来事を忘れています。リカレントニューラルネットワークにもこの問題があります。

pytorchはnn.RNNクラスを使用して、シーケンスベースのリカレントニューラルネットワークを構築します。そのコンストラクターには、次のパラメーターがあります。

  • input_size:入力データXの特徴値の数。
  • hidden_​​size:隠れ層のニューロンの数、つまり、隠れ層の特徴の数。
  • num_layers:リカレントニューラルネットワークの層の数。デフォルト値は1です。
  • バイアス:デフォルトはTrueです。falseの場合、ニューロンはバイアスパラメータを使用しません。
  • batch_first:Trueに設定されている場合、入力データのディメンションの最初のディメンションはバッチ値であり、デフォルトはFalseです。デフォルトでは、最初の次元はシーケンスの長さ、2番目の次元は--batch、3番目の次元は特徴の数です。
  • ドロップアウト:空でない場合は、最後のドロップアウトレイヤーがデータの一部を破棄し、破棄されたデータの割合がこのパラメーターで指定されることを意味します。

RNNで最も重要なパラメーターはinput_sizeとhidden_​​sizeであり、これら2つのパラメーターを明確にする必要があります。残りのパラメータは通常設定する必要はなく、デフォルト値を使用するだけです。

rnn = torch.nn.RNN(20,50,2)
input = torch.randn(100 , 32 , 20)
h_0 =torch.randn(2 , 32 , 50)
output,hn=rnn(input ,h_0) 
print(output.size(),hn.size())
torch.Size([100, 32, 50]) torch.Size([2, 32, 50])

上記の紹介を見た初心者は間違いなく途方に暮れていますが、これらのことと実際の使い方は何ですか?
次に、pytorchを使用してRNNの実装を記述します。このようにして、独自の実装を通じて、RNNの構造をより深く理解することができます。

実装の前に、RNNの動作メカニズムを詳細に紹介し続けます。RNNは、履歴情報を保存するための追加のhidden_​​stateがあることを除いて、実際には通常のニューラルネットワークです。このhidden_​​stateの機能は、前の状態を保存することです。RNNに保存されるメモリ状態情報はこのhidden_​​stateであるとよく言われます。

RNNの場合、次の式で生活する必要があります。

ht =tanh⁡(W ihxt + bih + W hhh(t − 1)+ bhh)h_t = \ tanh(W_ {ih} x_t + b_ {ih} + W_ {hh} h _ {(t-1)} + b_ {hh}) hトン=tanh W。およびhバツトン+bおよびh+W時間時間hT - 1 +b時間時間)。

この式は公式ウェブサイトから来ています:
https //pytorch.org/docs/stable/nn.html?highlight = rnn#torch.nn.RNN

この式のXtx_tバツトン現在の状態の入力値h(t − 1)h _ {(t-1)}hT - 1 上記のように渡されるのは、メモリ部分である前の状態のhidden_​​stateです。
トレーニングされるネットワーク全体の一部はWih W_ {ih}です。Wおよびh現在の状態の入力値の重みWhh W_ {hh}W時間時間hidden_​​stateは、前の状態と2つの入力オフセット値の重みです。これらの4つの値を合計すると、アクティベーションにtanhが使用されます。Pytorchはデフォルトでアクティベーションとしてtanhを使用しますが、設定することでアクティベーション関数としてreluを使用できます。

上記の手順は、赤い枠で囲まれた計算プロセスです。

このステップは通常のニューラルネットワークと同じであり、RNNはより多くのシーケンス次元を持っているため、同じモデルでn回順伝播を実行する必要があります。このnはシーケンス設定の数です。
RNNの手動実装を始めましょう:Karpathyの記事を参照してください:https://karpathy.github.io/2015/05/21/rnn-effectiveness/

class RNN(object):
    def __init__(self,input_size,hidden_size):
        super().__init__()
        self.W_xh=torch.nn.Linear(input_size,hidden_size) #因为最后的操作是相加 所以hidden要和output 的shape一致
        self.W_hh=torch.nn.Linear(hidden_size,hidden_size)
        
    def __call__(self,x,hidden):
        return self.step(x,hidden)
    def step(self, x, hidden):
        #前向传播的一步
        h1=self.W_hh(hidden)
        w1=self.W_xh(x)
        out = torch.tanh( h1+w1)
        hidden=self.W_hh.weight
        return out,hidden
rnn = RNN(20,50)
input = torch.randn( 32 , 20)
h_0 =torch.randn(32 , 50) 
seq_len = input.shape[0]
for i in range(seq_len):
    output,hn= rnn(input[i, :], h_0)
print(output.size(),h_0.size())
torch.Size([32, 50]) torch.Size([32, 50])

LSTM

LSTMは、Long Short Term Memory Networksの略語であり、文字通りLong Short Term MemoryNetworksとして翻訳されています。LSTMのネットワーク構造は、1997年にHochreiterとSchmidhuberによって提案され、その後、このネットワーク構造は非常に人気がありました。
LSTMは短期依存の問題のみを解決し、長期依存を回避するために慎重な設計を使用しますが、このアプローチは実際のアプリケーションで非常に効果的であることが証明されており、多くの人々が多くの実際の問題を解決するために関連作業をフォローアップしています。 、したがって、現在でもLSTMは広く使用されています。画像ソース
ここに画像の説明を挿入します

標準のリカレントニューラルネットワークには単純な層構造しかありませんが、LSTMには4つの層構造があります。

最初の層は忘却層です:状態で破棄する情報を決定します

2番目のtanh層は、更新された値の候補を生成するために使用されます。これは、状態をいくつかの次元で強化し、いくつかの次元で弱める必要があることを示します。

シグモイド層の3番目の層(入力ゲート層)では、その出力値に、スケーリングの役割を果たすtanh層の出力を掛ける必要があります。極端な場合、シグモイド出力0は、対応する次元の状態を示します。更新する必要はありません

最後のレイヤーが何を出力するかを決定し、出力値は状態に関連しています。候補のどの部分が最終的に出力されるかは、シグモイド層によって決定されます。

pytorchはnn.LSTMクラスを使用して、シーケンスベースのリカレントニューラルネットワークを構築します。そのパラメーターは基本的にRNNに似ているため、ここではリストしません。

lstm = torch.nn.LSTM(10, 20,2)
input = torch.randn(5, 3, 10)
h0 =torch.randn(2, 3, 20)
c0 = torch.randn(2, 3, 20)
output, hn = lstm(input, (h0, c0))
print(output.size(),hn[0].size(),hn[1].size())
torch.Size([5, 3, 20]) torch.Size([2, 3, 20]) torch.Size([2, 3, 20])

タワークレーン

GRUは、ゲート付き回帰ユニットの略語であり、2014年にChoによって提案されました。GRUとLSTMの最大の違いは、GRUが忘却ゲートと入力ゲートを「更新ゲート」に結合することです。同時に、ネットワークは追加のメモリ状態を提供せず、代わりに出力結果をメモリ状態として使用します。継続的に逆方向に通過するために、ネットワークの入力と出力は特に単純になりました。

rnn = torch.nn.GRU(10, 20, 2)
input = torch.randn(5, 3, 10)
h_0= torch.randn(2, 3, 20)
output, hn = rnn(input, h0)
print(output.size(),hn.size())
torch.Size([5, 3, 20]) torch.Size([2, 3, 20])

2.5.3サイクリックネットワーク(BPTT)の後方伝搬

順伝播の場合、RNNの入力はタイムステップごとに進みます。バックプロパゲーションの場合、重みを変更するために「時間を遡る」ので、それをバックプロパゲーションスルータイム(BPTT)と呼びます。

通常、シーケンス全体(単語)をトレーニングサンプルとして扱うため、合計エラーは各タイムステップ(文字)のエラーの合計になります。重みは各タイムステップで同じです(したがって、合計エラーを計算した後で一緒に更新できます)。

  1. 予測出力と実際の出力を使用してクロスエントロピーエラーを計算します
  2. ネットワークはタイムステップで完全に展開されます
  3. 拡張されたネットワークの場合、各練習ステップの重みの勾配を計算します
  4. 重みはすべてのタイムステップで同じであるため、(ニューラルネットワークのように異なる隠れ層に対して異なる勾配を取得するのではなく)すべてのタイムステップで勾配を一緒に取得できます。
  5. 次に、循環ニューロンの重みをアップグレードします

RNNによって展開されるネットワークは、通常のニューラルネットワークのように見えます。バックプロパゲーションも通常のニューラルネットワークと似ていますが、すべての時間ステップの勾配を一度に取得する点が異なります。100のタイムステップがある場合、展開後にネットワークは非常に巨大になるため、この問題を解決するために、LSTMやGRUなどの構造が表示されます。

リカレントニューラルネットワークは現在、自然言語処理で最も人気があるため、次のコンテンツでは、リカレントニューラルネットワークがNLPを処理するときに使用する必要があるその他の知識を紹介します。

2.5.4単語の埋め込み

私たちの人間のコミュニケーションの過程で、特徴付け語彙は英語の単語で直接表されますが、コンピューターの場合、単語を直接認識することは不可能です。コンピューターが私たちの言語をよりよく理解し、より良い言語モデルを構築するために、私たちは語彙を特徴づける必要があります。

ワンホットエンコーディングは、画像分類の問題で使用されます。たとえば、LeNetには0〜9の数字が10個あります。この数字が2の場合、そのコードは(0,0,1,0,0,0,0,0,0,0)であり、これは分類の場合です。問題。表現は非常に明確ですが、自然言語処理では、単語数が多すぎるため、たとえば10,000の異なる単語があるため、ワンホットを使用してそれを定義する効率は特に低く、各単語は特に低くなります。 10,000次元のベクトルです。そのうちの1つだけが1で、残りは0です。これはメモリを消費し、単語の品詞を反映できません。これは、すべての単語がワンホットであるためですが、セマンティクスが近い単語もあります。この特性を反映するには、別の方法で各単語を定義する必要があります。

各語彙を特徴づけるためにさまざまな機能が使用されます。さまざまな機能と比較して、さまざまな単語の値が異なります。これは単語の埋め込みです。下の写真は、ウー・エンダ先生のコースのスクリーンショットです。

単語の埋め込みは、異なる単語の特徴的な表現を実現するだけでなく、単語間の類似性も計算します。実際、多次元空間では、単語ベクトル間の各次元の距離の類似性を見つけることができます。夏や暑さ、冬と寒さはすべて関連しています。

PyTorchでは、nn.Embeddingレイヤーを使用して埋め込みワードバッグモデルを実行します。Embeddingレイヤーの最初の入力は単語の数を示し、2番目の入力は各単語が使用するベクトル表現の次元数を示します。

# an Embedding module containing 10 tensors of size 3
embedding = torch.nn.Embedding(10, 3)
# a batch of 2 samples of 4 indices each
input = torch.LongTensor([[1,2,4,5],[4,3,2,9]])
output=embedding(input)
print(output.size())
torch.Size([2, 4, 3])

2.5.5その他の重要な概念

ビームサーチ

最初の単語の分布を生成した後、欲張り検索を使用して、条件付き言語モデルに従って出力される可能性が最も高い最初の単語を選択できますが、欲張り検索アルゴリズムの場合、単語ライブラリには数百の単語があります。数百万の単語の場合、単語の各組み合わせの可能性を計算することは不可能です。したがって、単語ではなく、近似検索方法を使用して、文の最大条件付き確率を最大化または近似します。

ビーム探索(クラスター探索)は、ヒューリスティックなグラフ探索アルゴリズムであり、通常、グラフの解空間が比較的大きい場合に使用されます。探索に占める空間と時間を削減するために、それぞれの深さである程度の品質がカットされます。ステップが拡張されます。劣ったノード、いくつかのより高品質のノードを保持します。ビームサーチアルゴリズムは不完全ですが、より大きなスペースを持つシステムを理解するために使用すると、スペースの占有と時間を削減できます。

ビーム検索は、制約付き最適化を使用した幅優先探索と見なすことができます。最初に、幅優先戦略を使用して探索木を構築します。ツリーの各レベルで、ノードはヒューリスティックコストに従って並べ替えられ、次にのみ所定の数(ビーム幅-クラスター幅)のノード。これらのノードのみが次のレベルで拡張を続け、他のノードは切断されます。

  1. 最初のノードをリストに挿入します
  2. ノードはヒープから外れます。ノードがターゲットノードの場合、アルゴリズムは終了します。
  3. それ以外の場合、ノードは展開され、クラスター幅のノードがパイルに取り込まれます。次に、2番目のステップに進んでサイクルを続行します。
  4. アルゴリズムが終了するための条件は、最適な解を見つけるか、ヒープが空であることです。

使用時には、クラスター幅を事前に指定または可変にすることができ、実際のシーンに応じて特定の設定を調整できます。

注意モデル

エンコードとデコードを使用するRNNモデルの場合、比較的正確な機械翻訳の結果を得ることができます。短い文の場合、パフォーマンスは非常に良好ですが、非常に長い文の場合、翻訳結果は悪化します。
私たち人間が手動翻訳を行う場合、部分的に翻訳します。導入された注意メカニズムは、長い文を部分的に翻訳する人間の翻訳プロセスと非常によく似ています。

具体的な内容はここでは詳しく紹介しません

おすすめ

転載: blog.csdn.net/yegeli/article/details/113688200