1.RNN简介
人类并不是每时每刻都从一片空白的大脑开始他们的思考。在你阅读这篇文章时候,你都是基于自己已经拥有的对先前所见词的理解来推断当前词的真实含义。我们不会将所有的东西都全部丢弃,然后用空白的大脑进行思考。我们的思想拥有持久性。
传统的神经网络并不能做到这点,看起来也像是一种巨大的弊端。例如,假设你希望对电影中的每个时间点的时间类型进行分类。传统的神经网络应该很难来处理这个问题——使用电影中先前的事件推断后续的事件。
RNN 解决了这个问题。RNN 是包含循环的网络,允许信息的持久化。
2.基于imdb数据集的SimpleRNNCell实战
#RNN-情感分类实战
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers,datasets
tf.random.set_seed(1234)
np.random.seed(2345)
assert tf.__version__.startswith('2.')#判断tensorflow的类型是否开头是2.版本(写2/2.0都可以)
batchsize = 80
#假设常见单词有10000个,但是我们都知道,词库当中的单词有很多,肯定要超过一万个
total_words = 10000
#为了方便我们的网络训练和数据处理,我们把每个句子的单词个数统一设置成80,通过下面的padding操作处理
max_review_len = 80
#这样的话是说每个单词通过embedding_len这个方法用一百维的向量去表示
embedding_len = 100
(x_train,y_train),(x_test,y_test) = datasets.imdb.load_data(num_words=total_words)
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)
#经过padding之后,x_train:[b,80],x_test:[b,80]->b个句子,每个句子80个单词
db_train = tf.data.Dataset.from_tensor_slices((x_train,y_train))
db = db_train.shuffle(25000).batch(batchsize,drop_remainder=True)
#出现剩下的句子个数不足128的情况,这样我们就不再进行训练--定长训练RNN
db_test = tf.data.Dataset.from_tensor_slices((x_test,y_test))
db_test = db_test.shuffle(25000).batch(batchsize,drop_remainder=True)
#出现剩下的句子个数不足128的情况,这样我们就不再进行测试--定长测试RNN
print('x_train_shape:',x_train.shape,)#(25000, 80)--25k个句子
print('x_test-shape:',x_test.shape)#(25000, 80)
print('y_train_shape:',y_train.shape,)#(25000,)
print('y_test-shape:',y_test.shape)#(25000,)
print(tf.reduce_min(y_train),tf.reduce_max(y_train),#min-0差评Neg,max-1好评Pos
tf.reduce_min(y_test),tf.reduce_max(y_test))#min-0,max-1
class MyRNN(keras.Model):
def __init__(self,units):
super(MyRNN,self).__init__()
self.state0 = [tf.zeros([batchsize,units])]#一个batch一个batch的运算/训练/验证/测试
self.state1 = [tf.zeros([batchsize,units])]
#[b,80]->[b,80,100]
self.embedding = layers.Embedding(total_words,embedding_len,input_length=max_review_len)
#[b,80,100]->[b,64]
self.rnn1 = layers.SimpleRNNCell(units,dropout=0.2)
self.rnn2 = layers.SimpleRNNCell(units, dropout=0.2)
#units=64,但是我们可以在外边调用类时进行随便赋值定义
#[b,64]->[b]/[b,1]这俩一样
self.outlayer = layers.Dense(1)
def call(self,inputs,training=True):
#这里是训练模式,会有网络连接抛去两成连接的逻辑,但是测试时不会抛弃
#net(x)&net(x,training=True)都是训练模式
x = inputs
x = self.embedding(x)
state0 = self.state0
state1 = self.state1
for word in tf.unstack(x,axis=1):
out0,state0 = self.rnn1(word,state0)
out1,state1 = self.rnn2(out0,state1)
x = self.outlayer(out1)
#sigmoid将x压缩到一个(0,1)的范围
prob = tf.sigmoid(x)
return prob
def main():
units = 64
epochs = 5
model = MyRNN(units)
#特殊1:SimpleRNNCell没有build和summary属性所以不用写出
model.compile(optimizer=keras.optimizers.Adam(0.001),
loss=tf.losses.BinaryCrossentropy(),#二分类loss计算--一个输出或者两者输出都可以使用
#这里计算loss会自动将prob=0.72->1,然后再进行比较,但是我们不能手动在前面return就转化成1
metrics=['accuracy'],
experimental_run_tf_function = False)
#特殊二:在SimpleRNNCell中这一行如果不加就会报错
model.fit(db_train, epochs=epochs, validation_data=db_test,validation_freq=1)
model.evaluate(db_test)
if __name__ == '__main__':
main()
3.LSTM简介
LSTM 的核心概念在于细胞状态以及“门”结构。细胞状态相当于信息传输的路径,让信息能在序列连中传递下去。你可以将其看作网络的“记忆”。理论上讲,细胞状态能够将序列处理过程中的相关信息一直传递下去。
因此,即使是较早时间步长的信息也能携带到较后时间步长的细胞中来,这克服了短时记忆的影响。信息的添加和移除我们通过“门”结构来实现,“门”结构在训练过程中会去学习该保存或遗忘哪些信息。
Sigmoid
门结构中包含着 sigmoid 激活函数。Sigmoid 激活函数与 tanh 函数类似,不同之处在于 sigmoid 是把值压缩到 0~1 之间而不是 -1~1 之间。这样的设置有助于更新或忘记信息,因为任何数乘以 0 都得 0,这部分信息就会剔除掉。同样的,任何数乘以 1 都得到它本身,这部分信息就会完美地保存下来。这样网络就能了解哪些数据是需要遗忘,哪些数据是需要保存。
4.基于imdb的LSTMCell实战
#RNN-情感分类实战
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers,datasets
tf.random.set_seed(1234)
np.random.seed(2345)
assert tf.__version__.startswith('2.')#判断tensorflow的类型是否开头是2.版本(写2/2.0都可以)
batchsize = 80
#假设常见单词有10000个,但是我们都知道,词库当中的单词有很多,肯定要超过一万个
total_words = 10000
#为了方便我们的网络训练和数据处理,我们把每个句子的单词个数统一设置成80,通过下面的padding操作处理
max_review_len = 80
#这样的话是说每个单词通过embedding_len这个方法用一百维的向量去表示
embedding_len = 100
(x_train,y_train),(x_test,y_test) = datasets.imdb.load_data(num_words=total_words)
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)
#经过padding之后,x_train:[b,80],x_test:[b,80]->b个句子,每个句子80个单词
db_train = tf.data.Dataset.from_tensor_slices((x_train,y_train))
db = db_train.shuffle(25000).batch(batchsize,drop_remainder=True)
#出现剩下的句子个数不足128的情况,这样我们就不再进行训练--定长训练RNN
db_test = tf.data.Dataset.from_tensor_slices((x_test,y_test))
db_test = db_test.shuffle(25000).batch(batchsize,drop_remainder=True)
#出现剩下的句子个数不足128的情况,这样我们就不再进行测试--定长测试RNN
print('x_train_shape:',x_train.shape,)#(25000, 80)--25k个句子
print('x_test-shape:',x_test.shape)#(25000, 80)
print('y_train_shape:',y_train.shape,)#(25000,)
print('y_test-shape:',y_test.shape)#(25000,)
print(tf.reduce_min(y_train),tf.reduce_max(y_train),#min-0差评Neg,max-1好评Pos
tf.reduce_min(y_test),tf.reduce_max(y_test))#min-0,max-1
class MyRNN(keras.Model):
def __init__(self,units):
super(MyRNN,self).__init__()
#改成LSTM之后,state0和state1都是两个全零单元组成的列表,一个是h,一个是C
self.state0 = [tf.zeros([batchsize,units]),tf.zeros([batchsize,units])]
#一个batch一个batch的运算/训练/验证/测试
self.state1 = [tf.zeros([batchsize,units]),tf.zeros([batchsize,units])]
#[b,80]->[b,80,100]
self.embedding = layers.Embedding(total_words,embedding_len,input_length=max_review_len)
#[b,80,100]->[b,64]
self.rnn1 = layers.LSTMCell(units,dropout=0.2)
self.rnn2 = layers.LSTMCell(units,dropout=0.2)
#units=64,但是我们可以在外边调用类时进行随便赋值定义
#[b,64]->[b]/[b,1]这俩一样
self.outlayer = layers.Dense(1)
def call(self,inputs,training=True):
#这里是训练模式,会有网络连接抛去两成连接的逻辑,但是测试时不会抛弃
#net(x)&net(x,training=True)都是训练模式
x = inputs
x = self.embedding(x)
state0 = self.state0
state1 = self.state1
for word in tf.unstack(x,axis=1):
out0,state0 = self.rnn1(word,state0)
out1,state1 = self.rnn2(out0,state1)
x = self.outlayer(out1)
#sigmoid将x压缩到一个(0,1)的范围
prob = tf.sigmoid(x)
return prob
def main():
import time
units = 64
epochs = 5
t0 = time.time()#纪录时刻t0
model = MyRNN(units)
#特殊1:SimpleRNNCell没有build和summary属性所以不用写出
model.compile(optimizer=keras.optimizers.Adam(0.001),
loss=tf.losses.BinaryCrossentropy(),#二分类loss计算--一个输出或者两者输出都可以使用
#这里计算loss会自动将prob=0.72->1,然后再进行比较,但是我们不能手动在前面return就转化成1
metrics=['accuracy'],
experimental_run_tf_function = False)
#特殊二:在SimpleRNNCell中这一行如果不加就会报错
model.fit(db_train, epochs=epochs, validation_data=db_test,validation_freq=1)
model.evaluate(db_test)
t1 = time.time()#纪录时刻t1
print('Spending Time:',t1-t0)#训练和测试花费的时间
if __name__ == '__main__':
main()
5.GRU简介
GRU(Gated Recurrent Unit)神经网络是LSTM 的一个变体,GRU 在保持了LSTM 的效果同时又使结构更加简单,是一种非常流行RNN 神经网络,它只有两个门了,分别为更新门t z 和重置门tr 。更新门控制前一时刻的状态信息被带入到当前状态中的程度,值越大前一时刻的状态信息带入越多。重置门控制忽略前一时刻的状态信息的程度,值越小说明忽略得越多。
6.GRU—imdb实战
#RNN-情感分类实战
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers,datasets
tf.random.set_seed(1234)
np.random.seed(2345)
assert tf.__version__.startswith('2.')#判断tensorflow的类型是否开头是2.版本(写2/2.0都可以)
batchsize = 80
#假设常见单词有10000个,但是我们都知道,词库当中的单词有很多,肯定要超过一万个
total_words = 10000
#为了方便我们的网络训练和数据处理,我们把每个句子的单词个数统一设置成80,通过下面的padding操作处理
max_review_len = 80
#这样的话是说每个单词通过embedding_len这个方法用一百维的向量去表示
embedding_len = 100
(x_train,y_train),(x_test,y_test) = datasets.imdb.load_data(num_words=total_words)
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)
#经过padding之后,x_train:[b,80],x_test:[b,80]->b个句子,每个句子80个单词
db_train = tf.data.Dataset.from_tensor_slices((x_train,y_train))
db = db_train.shuffle(25000).batch(batchsize,drop_remainder=True)
#出现剩下的句子个数不足128的情况,这样我们就不再进行训练--定长训练RNN
db_test = tf.data.Dataset.from_tensor_slices((x_test,y_test))
db_test = db_test.shuffle(25000).batch(batchsize,drop_remainder=True)
#出现剩下的句子个数不足128的情况,这样我们就不再进行测试--定长测试RNN
print('x_train_shape:',x_train.shape,)#(25000, 80)--25k个句子
print('x_test-shape:',x_test.shape)#(25000, 80)
print('y_train_shape:',y_train.shape,)#(25000,)
print('y_test-shape:',y_test.shape)#(25000,)
print(tf.reduce_min(y_train),tf.reduce_max(y_train),#min-0差评Neg,max-1好评Pos
tf.reduce_min(y_test),tf.reduce_max(y_test))#min-0,max-1
class MyRNN(keras.Model):
def __init__(self,units):
super(MyRNN,self).__init__()
#改成LSTM之后,state0和state1都是两个全零单元组成的列表,一个是h,一个是C
self.state0 = [tf.zeros([batchsize,units])]
#一个batch一个batch的运算/训练/验证/测试
self.state1 = [tf.zeros([batchsize,units])]
#[b,80]->[b,80,100]
self.embedding = layers.Embedding(total_words,embedding_len,input_length=max_review_len)
#[b,80,100]->[b,64]
self.rnn1 = layers.GRUCell(units,dropout=0.2)
self.rnn2 = layers.GRUCell(units)
#units=64,但是我们可以在外边调用类时进行随便赋值定义
#[b,64]->[b]/[b,1]这俩一样
self.outlayer = layers.Dense(1)
def call(self,inputs,training=True):
#这里是训练模式,会有网络连接抛去两成连接的逻辑,但是测试时不会抛弃
#net(x)&net(x,training=True)都是训练模式
x = inputs
x = self.embedding(x)
state0 = self.state0
state1 = self.state1
for word in tf.unstack(x,axis=1):
out0,state0 = self.rnn1(word,state0)
out1,state1 = self.rnn2(out0,state1)
x = self.outlayer(out1)
#sigmoid将x压缩到一个(0,1)的范围
prob = tf.sigmoid(x)
return prob
def main():
import time
units = 64
epochs = 5
t0 = time.time()#纪录时刻t0
model = MyRNN(units)
#特殊1:SimpleRNNCell没有build和summary属性所以不用写出
model.compile(optimizer=keras.optimizers.Adam(0.001),
loss=tf.losses.BinaryCrossentropy(),#二分类loss计算--一个输出或者两者输出都可以使用
#这里计算loss会自动将prob=0.72->1,然后再进行比较,但是我们不能手动在前面return就转化成1
metrics=['accuracy'],
experimental_run_tf_function = False)
#特殊二:在SimpleRNNCell中这一行如果不加就会报错
model.fit(db_train, epochs=epochs, validation_data=db_test,validation_freq=1)
model.evaluate(db_test)
t1 = time.time()#纪录时刻t1
print('Spending Time:',t1-t0)#训练和测试花费的时间
if __name__ == '__main__':
main()
7.综合实验结果
RNN:50轮训练和测试—ACC0.9328—Time:312s
LSTM:35轮训练和测试—ACC0.8977—Time:243s
GRU:100轮训练和测试—ACC0.9714—Time:2349s
平台:TensorflowGPU—GTX1080Ti—11GB—官方公版
占用率和发热程度平均值:34.31%占用率 64.5摄氏度