2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

RNNまとめ(+Attention)

Last updated at Posted at 2023-04-13

はじめに

この記事はE資格の認定講座で提出したレポートをもとに、代表的なRNNモデルとAttentionについてまとめた記事です。

再帰的ニューラルネットワーク(RNN)とは

 RNNとは、時系列データに対して有効なニューラルネットワークの一つ。従来のニューラルネットワークとは異なり、自己回帰的な構造を持ち、主に音声認識、自然言語処理で使用される。
 TensorFlowにSimpleRNNレイヤーがあります。

import tensorflow as tf
from tensorflow.keras.layers import SimpleRNN, Dense
from tensorflow.keras.models import Sequential

# RNNモデルを定義
def rnn_model(input_shape):
    model = Sequential()
    model.add(SimpleRNN(50, activation='tanh', input_shape=input_shape))
    model.add(Dense(1, activation='linear'))
    model.compile(optimizer='adam', loss='mse')
    return model

LSTM(Long Short-Term Memory)

LSTMとは

LSTMは、RNNの一種で、特に長期的な依存関係を扱うために設計されたニューラルネットワークのアーキテクチャ。LSTMにより時系列を遡れば遡ぼるほど勾配が消失していくというRNNの課題を解決することができる。

LSTMの構造

 LSTMには3つのゲートがある。
 忘却ゲート:現在の入力と前の状態を受け取り、どの情報を保持するかを決定するゲート
 入力ゲート:現在の入力と前の状態を受け取り、新しい情報をどの程度保持するかを決定するゲート
 出力ゲート:現在の入力と前の状態を受け取り、次の状態をどの程度出力するかを決定するゲート
LSTMの全体図

実装

TensorFlowにLSTMレイヤーがあります。

import tensorflow as tf
from tensorflow.keras.layers import LSTM, Dense
from tensorflow.keras.models import Sequential

# LSTMモデル
def lstm_model(input_shape):
    model = Sequential()
    model.add(LSTM(50, activation='tanh', input_shape=input_shape))
    model.add(Dense(1, activation='linear'))
    model.compile(optimizer='adam', loss='mse')
    return model

スクラッチ実装

# LSTMレイヤの実装
class LSTM:
    # 初期化メソッドの定義
    def __init__(self, Wx, Wh, b):
        self.params = [Wx, Wh, b] # パラメータ
        self.grads = [np.zeros_like(Wx), np.zeros_like(Wh), np.zeros_like(b)] # 勾配
        self.cache = None

    # 順伝播メソッドの定義
    def forward(self, x, h_prev, c_prev):
        # パラメータと変数の形状に関する値を取得
        Wx, Wh, b = self.params
        N, H = h_prev.shape

        # 結合したパラメータによる重み付き和の計算
        A = np.dot(x, Wx) + np.dot(h_prev, Wh) + b

        # 各ゲートの重み付き和を取得
        f = A[:, :H]      # forgetゲート
        g = A[:, H:2*H]   # 記憶セル
        i = A[:, 2*H:3*H] # inputゲート
        o = A[:, 3*H:]    # outputゲート

        # ゲート値に変換
        f = sigmoid(f)
        g = np.tanh(g)
        i = sigmoid(i)
        o = sigmoid(o)

        # 出力を計算
        c_next = f * c_prev + g * i  # 記憶セル
        h_next = o * np.tanh(c_next) # 出力データ

        # 逆伝播の計算用に変数を保存
        self.cache = (x, h_prev, c_prev, i, f, g, o, c_next)
        return h_next, c_next

    # 逆伝播メソッドの定義
    def backward(self, dh_next, dc_next):
        # 変数を取得
        Wx, Wh, b = self.params
        x, h_prev, c_prev, i, f, g, o, c_next = self.cache

        # 計算用に活性化記憶セルを計算
        tanh_c_next = np.tanh(c_next)

        # 現レイヤの記憶セルの勾配を計算
        ds = dc_next + (dh_next * o) * (1 - tanh_c_next ** 2)

        # 前レイヤの記憶セルの勾配を計算
        dc_prev = ds * f

        # 活性化後のゲートの勾配を計算
        di = ds * g
        df = ds * c_prev
        do = dh_next * tanh_c_next
        dg = ds * i

        # 活性化前のゲートの勾配を計算
        di *= i * (1 - i)
        df *= f * (1 - f)
        do *= o * (1 - o)
        dg *= (1 - g ** 2)

        # ゲートの勾配を結合
        dA = np.hstack((df, dg, di, do))

        # パラメータの勾配を計算
        dWh = np.dot(h_prev.T, dA)
        dWx = np.dot(x.T, dA)
        db = dA.sum(axis=0)

        # パラメータの勾配を格納
        self.grads[0][...] = dWx
        self.grads[1][...] = dWh
        self.grads[2][...] = db

        # 入力の勾配を計算
        dx = np.dot(dA, Wx.T)
        dh_prev = np.dot(dA, Wh.T)

        return dx, dh_prev, dc_prev

GRU

GRUとは

 GRUとは、深層学習における一種の再帰型ニューラルネットワーク。LSTMと同様に、シーケンスデータに対するモデリングに適していて、パラメータが多く計算負荷が大きかったLSTMの課題点を解決するために作られた。GRUはパラメータ量がLSTMよりも少ないが、精度はLSTM同等かそれ以上になった。

 GRUにはリセットゲート、更新ゲートの2つのゲートがある。
GRUの全体像

実装

TensorFlowにGRUレイヤーがあります。

import tensorflow as tf
from tensorflow.keras.layers import GRU, Dense
from tensorflow.keras.models import Sequential


def gru_model(input_shape):
    model = Sequential()
    model.add(GRU(50, activation='tanh', input_shape=input_shape))
    model.add(Dense(1, activation='linear'))
    model.compile(optimizer='adam', loss='mse')
    return model

スクラッチ実装

def gru(x, h, W_r, U_r, W_z, U_z, W, U):
  # ゲートを計算
  # リセットゲート
  r = _sigmoid(x.dot(W_r.T) + h.dot(U_r.T)) 
  # 更新ゲート
  z = _sigmoid(x.dot(W_z.T) + h.dot(U_z.T)) 

  # 次の状態を計算
  h_bar = np.tanh(x.dot(W.T) + (r * h).dot(U.T)) 
  h_new = (1-z) * h + z * h_bar  
  return h_new

参考

 ゼロから作るDeepLearning2 付録C GRU
 【脱初心者】GRUの数式とあの図を攻略!超絶分かりやすい図解でステップ解説【E資格合格者のノート公開】 https://i-main.net/emmanote-ai-gru/

双方向RNN(BiRNN)

BiRNNとは

 RNNを2つ組み合わせることで、未来から過去方向も含めて学習できるようにしたモデル。通常のRNNは過去から未来への一方向でしか学習をすることができないが、BiRNNによって未来の情報からの学習も可能になった。文章の推敲や機械翻訳に用いられている。

実装

def bindirectional_rnn_net(xs, W_f, U_f, W_b, U_b, V):
  # W_f, U_f:入力から中間層、前の中間層から今の中間層の順方向の重み
  # W_b, U_b:W_f, U_fの逆方向
  # V:順方向、逆方向の中間層から出力層の重み
  xs_f = np.zeros_like(xs)
  xs_b = np.zeros_like(xs)

  for i, x in enumerate(xs):
    xs_f[i] = x
    xs_b[i] = x[::-1]

  hs_f = _rnn(xs_f, W_f, U_f)
  hs_b = _rnn(xs_b, W_b, U_b)
  hs = [np.concatenate([h_f, h_b[::-1]], axis=0)] for h_f, h_b in zip(hs_f, hs_b)
  ys = hs.dot(V.T)
  return ys

参考

ゼロから作るDeepLearning2 8章 4-1 双方向RNN

Seq2Seq

Seq2Seqとは

自然言語処理において、入力と出力の長さが異なるシーケンスを扱うためのモデル。エンコーダとデコーダという2つのニューラルネットワークを使用している。

Encoder部分

 Encoder部分では、入力されたシーケンスデータを単語の埋め込み表現に変換し、RNNを使用してシーケンスを表す隠れ状態を生成する。隠れ状態は、最終的に固定長のベクトルに変換される。

Decoder部分

 Decoder部分では、エンコーダーが生成したベクトルを元に、出力となる文章を生成する。

Attention

Attentionとは

 入力された情報のうち、重要な情報に焦点を当てて処理するための仕組み。通常、Seq2SeqモデルやTransformerモデルなどの自然言語処理タスクで使用される。
 現在注目を浴びているChatGPTにもAttention機構が使用されている。

実装

def scaled_dot_product_attention(q, k, v, mask):
  matmul_qk = tf.matmul(q, k, transpose_b=True)  # (..., seq_len_q, seq_len_k)

  # matmul_qkをスケール
  dk = tf.cast(tf.shape(k)[-1], tf.float32)
  scaled_attention_logits = matmul_qk / tf.math.sqrt(dk)

  # マスクをスケール済みテンソルに加算
  if mask is not None:
    scaled_attention_logits += (mask * -1e9)  

  # softmax は最後の軸(seq_len_k)について
  # 合計が1となるように正規化
  attention_weights = tf.nn.softmax(scaled_attention_logits, axis=-1)  # (..., seq_len_q, seq_len_k)

  output = tf.matmul(attention_weights, v)  # (..., seq_len_q, depth_v)

  return output, attention_weights

参考

言語理解のためのTransformerモデル
https://www.tensorflow.org/tutorials/text/transformer?hl=ja#%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E6%B8%88%E3%81%BF%E5%86%85%E7%A9%8D%E3%82%A2%E3%83%86%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%B3

作って理解する Transformer / Attention
https://qiita.com/halhorn/items/c91497522be27bde17ce
より

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?