RNNの導入:時系列をどう表現するか?
畳み込みニューラルネットワークは位置の特徴を抽出します 例えば音声と翻訳は時間的に絡み合っています 時系列の特徴を抽出する方法
シーケンスの問題に関する研究: テキストをデータ型または値にプログラムする方法については、この研究計画は埋め込みです。
単一の株価の表現方法であり、各時点が対応する価格値となります。
複数の株価の表現。
この考え方を絵に当てはめた場合も同様で、列ごとの値を配列の特徴として読み取ってください。
ワンホット表現法。
具体的な質問を通して分析し、評価が肯定的か否定的かを判断してみましょう。「この退屈な映画は嫌いです」と入力すると、Embedding が単語であることがわかります。
各単語は入力であり、単語の数と同じ数の全結合層があり、各全結合層が単語を処理し、各単語の現在の意味情報が全結合層を通じて抽出され、その後、分類が行われます。 、現在のレビューが肯定的か否定的か。この方法は比較的直感的ですが、問題があります。比較的長いコメントの場合、100 単語で 100 の全結合層を導入する必要がありますが、より重要なことは、各単語の意味情報しか取得できないことです。100 単語の場合、全体的な意味上の関連性はありません。100 個の単語をスクランブルした場合、結果には影響しませんが、結果は全体的な意味の関連性に影響します。
全体を統合して全体的に分析する必要がありますが、この問題に対処するにはどうすればよいでしょうか。
畳み込みネットワーク内の大量のパラメータをどのように解決するかは、畳み込みカーネルを使用します。畳み込みカーネルのサイズは変更されず、内部値が変化することで解決されます。解決には 1 つのニューラル ネットワークのみを使用し、一定の入力と出力を使用します。パラメータは w と b のみです。パラメーターが多すぎる問題を解決します。
意味情報の全体的な分析をどのように解決するか?
メモリ層または状態状態層を追加します。つまり、完全に接続された層が通過するたびに、後者は以前の情報を記録します。このようにして、すべての情報を記録した文全体の最後の記憶を取得し、最後に取得した情報を処理するだけですべての意味情報を取得できます。
サンプルは時間軸上にあるだけあり、必要なだけあり、サンプリングは時間に関係します。初期状態を h0 として週を折り畳み、継続的に情報を集計します。現在の入力が最後のコンテキスト情報です。このようにして、継続的な集約を通じて、最後の集約にはすべてのコンテキスト情報が含まれます。これが最も単純な RNN サイクル ネットワークの原理です。総合すると、これはニューラル ネットワークの継続的な集合の結果です。
RNN の数学的表現は次のとおりです: コードデモ
# _*_ coding =utf-8 _*_
import tensorflow as tf
from tensorflow.keras import layers,optimizers,datasets,Sequential
import os
#Xt@Wxh + ht@Whh
cell =layers.SimpleRNNCell(3)
#[b,embeding]4输入的维度
cell.build(input_shape=(None,4))
#打印cell的参数
print(cell.trainable_variables)
#kernel:0表示Wxh,recurrent_kernel:0表示Whh
# [<tf.Variable 'kernel:0' shape=(4, 3) dtype=float32, numpy=
# array([[ 0.87822306, 0.8071407 , -0.20742077],
# [-0.5177747 , -0.0864749 , 0.87705004],
# [-0.8141298 , 0.32291627, -0.329014 ],
# [-0.05522245, -0.5882717 , 0.74687743]], dtype=float32)>, <tf.Variable 'recurrent_kernel:0' shape=(3, 3) dtype=float32, numpy=
# array([[ 0.29745793, 0.9037314 , 0.30787772],
# [-0.9194169 , 0.35804993, -0.16270511],
# [-0.25727728, -0.23467004, 0.9374105 ]], dtype=float32)>, <tf.Variable 'bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>]
Wxh は前回の重み、Whh は今回の重みで次の新しい Yt を生成します、Ht は前のコンテキスト情報の活性化であり、勾配は継続的に導出可能であることが保証されています。
出力が [b,64] の場合、[b,100]@[100,64] +[b,64]@[64,64]=[b,64]
Xt@Wxh + ht@Whh これは SampleRNNCell (LSTM や GRU とは異なります) です
# #获取4个句子,每个句子80个单词,每个单子100位向量
# x = tf.random.normal([4,80,100])
# #获取第一个单词
# xt0 = x[:,0,:]
# #中间维度是64
# cell = tf.keras.layers.SimpleRNNCell(64)
# #初始状态xt0,返回俩个相同的状态[b,64] 输出
# out,xt1 = cell(xt0,[tf.zeros([4,64])])
#
# print(out.shape,xt1[0].shape)
勾配拡散と勾配爆発:
Whh の k 倍では、Whh>1 の場合、結果は無限大に近づき、勾配爆発が発生します。Whh
<1 の場合、結果は 0 に近づき、勾配分散が発生します。
実際の RNN センチメント分析: 単層 RNN
import os
import tensorflow as tf
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers
from keras.preprocessing.sequence import pad_sequences
tf.random.set_seed(22)
np.random.seed(22)
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
assert tf.__version__.startswith('2.')
embedding_len=100#表示100个句子
batchsz = 128
#
total_words = 10000
max_review_len = 80 #80个单词
(x_train,y_train),(x_test,y_test) = keras.datasets.imdb.load_data(num_words=total_words)
# x_train[b,80] 每个句子80个单词
# x_test[b,80]
x_train = keras.preprocessing.sequence.pad_sequences(x_train,maxlen=max_review_len)
x_test = keras.preprocessing.sequence.pad_sequences(x_test,maxlen=max_review_len)
db_train = tf.data.Dataset.from_tensor_slices((x_train,y_train))
#最后一个bach给drop掉
db_train = db_train.shuffle(1000).batch(batchsz,drop_remainder=True)
db_test = tf.data.Dataset.from_tensor_slices((x_test,y_test))
db_test = db_test.batch(batchsz,drop_remainder=True)
print('x_train shape:',x_train.shape,tf.reduce_max(y_train),tf.reduce_min(y_train))
print('x_test:',x_test.shape)
class MyRNN(keras.Model):
def __init__(self,units):
super(MyRNN, self).__init__()
#初始化状态[b,64],b个句子,每个句子64维的状态
self.state0 = [tf.zeros([batchsz,units])]
#网络总共三层,第一层就是把数字编码转换为embedding编码,b个句子,每个句子80个单词,每个单词100维向量来表示
# [b,80] => [b,80,100]
#total_words输入维度10000,embedding_len 输出是100维,input_length每个句子的长度是80
self.embedding = layers.Embedding(total_words,embedding_len,input_length=max_review_len)
#[b,80,100],h_dim:units(100维进行转换为64)
#RNN:cell0,cell1,cell2
#SimpleRNN
#第二层是语义提取,就是利用SimapleRNN提取语义,dropout防止过拟合
self.rnn_cell0 = layers.SimpleRNNCell(units,dropout=0.2)
#fc,[b,80,100] => [b,64] => [b,1]
self.outlayer = layers.Dense(1)
def call(self,inputs,training=None):
"""
net(x),net(x, training=True)
:param inputs: [b,80]
:param training:
:return:
"""
#[b,80]
x = inputs
#embedding:[b,80] => [b,80,100]
x = self.embedding(x)
#rnn cell compute
# [b,80,100] =>[b,64]
state0 = self.state0
#x在第一维上进行展开
for word in tf.unstack(x,axis=1):# word [b,100]
# x*wxh + h*whh #上一个状态会获取下一个状态
out,state1 = self.rnn_cell0(word,state0)
#新的state赋值给上一个state
state0 = state1
# out: [b,64]=>[b,1]二分类转换为b和1
x = self.outlayer(out)
#p(y is pos|x) 计算概率
prob = tf.sigmoid(x)
return prob #完成了前向计算的信息
def main():
units =64
epochs =4
model =MyRNN(units)
model.compile(optimizer = keras.optimizers.Adam(0.001),
loss = tf.losses.BinaryCrossentropy(),
metrics = ['accuracy'])
model.fit(db_train,epochs=epochs,validation_data=db_test)
model.evaluate(db_test)
if __name__ =='__main__':
main()
多層 RNN:
import os
import tensorflow as tf
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers
from keras.preprocessing.sequence import pad_sequences
tf.random.set_seed(22)
np.random.seed(22)
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
assert tf.__version__.startswith('2.')
embedding_len=100#表示100个句子
batchsz = 128
#
total_words = 10000
max_review_len = 80 #80个单词
(x_train,y_train),(x_test,y_test) = keras.datasets.imdb.load_data(num_words=total_words)
# x_train[b,80] 每个句子80个单词
# x_test[b,80]
x_train = keras.preprocessing.sequence.pad_sequences(x_train,maxlen=max_review_len)
x_test = keras.preprocessing.sequence.pad_sequences(x_test,maxlen=max_review_len)
db_train = tf.data.Dataset.from_tensor_slices((x_train,y_train))
#最后一个bach给drop掉
db_train = db_train.shuffle(1000).batch(batchsz,drop_remainder=True)
db_test = tf.data.Dataset.from_tensor_slices((x_test,y_test))
db_test = db_test.batch(batchsz,drop_remainder=True)
print('x_train shape:',x_train.shape,tf.reduce_max(y_train),tf.reduce_min(y_train))
print('x_test:',x_test.shape)
#以单个层训练,现在再增加一个层,提高训练准确度
class MyRNN(keras.Model):
def __init__(self,units):
super(MyRNN, self).__init__()
#初始化状态[b,64],b个句子,每个句子64维的状态
self.state0 = [tf.zeros([batchsz,units])]
self.state1 = [tf.zeros([batchsz,units])]
#网络总共三层,第一层就是把数字编码转换为embedding编码,b个句子,每个句子80个单词,每个单词100维向量来表示
# [b,80] => [b,80,100]
#total_words输入维度10000,embedding_len 输出是100维,input_length每个句子的长度是80
self.embedding = layers.Embedding(total_words,embedding_len,input_length=max_review_len)
#[b,80,100],h_dim:units(100维进行转换为64)
#RNN:cell0,cell1,cell2
#SimpleRNN
#第二层是语义提取,就是利用SimapleRNN提取语义,dropout防止过拟合
self.rnn_cell0 = layers.SimpleRNNCell(units,dropout=0.2)
self.rnn_cell1 = layers.SimpleRNNCell(units,dropout=0.2)
#fc,[b,80,100] => [b,64] => [b,1]
self.outlayer = layers.Dense(1)
def call(self,inputs,training=None):
"""
net(x),net(x, training=True)
:param inputs: [b,80]
:param training:
:return:
"""
#[b,80]
x = inputs
#embedding:[b,80] => [b,80,100]
x = self.embedding(x)
#rnn cell compute
# [b,80,100] =>[b,64]
state0 = self.state0
state1 = self.state1
#x在第一维上进行展开
for word in tf.unstack(x,axis=1):# word [b,100]
# x*wxh + h*whh #上一个状态会获取下一个状态
out0,state0 = self.rnn_cell0(word,state0)
out1,state1 = self.rnn_cell1(out0,state1)
# out: [b,64]=>[b,1]二分类转换为b和1
x = self.outlayer(out1)
#p(y is pos|x) 计算概率
prob = tf.sigmoid(x)
return prob #完成了前向计算的信息
def main():
units =64
epochs =4
model =MyRNN(units)
model.compile(optimizer = keras.optimizers.Adam(0.001),
loss = tf.losses.BinaryCrossentropy(),
metrics = ['accuracy'])
model.fit(db_train,epochs=epochs,validation_data=db_test)
model.evaluate(db_test)
if __name__ =='__main__':
main()
結果の表示: