本篇文章7881字,读完约20分钟

雷锋。这篇文章的作者是刘冲。原文包含在作者的个人博客中。雷锋。com已被授权。

最近,我们正在研究rnn模型。为简单起见,本文采用简单的二进制序列作为训练数据,而不是实现特定的纸张模拟。主要目的是理解rnn的原理以及如何在张量流中构造一个简单的基本模型结构。代码指的是这个博客。

数据集首先,让我们看看实验数据的结构:

输入数据x:在时间t,xt的值有50%的概率为1,50%的概率为0;

输出数据y:在实践t中,yt的值有50%的概率为1,50%的概率为0。此外,如果“XT-3 = = 1 ”, yt为1的概率增加50%,如果“XT-8 = = 1 ”, yt为1的概率减少25%。如果同时满足上述两个条件,。

可以看出,y和x有两个依赖性,一个是t-3,另一个是t-8。我们实验的目的是测试rnn是否能够捕捉到Y和x之间的这两种依赖关系。以交叉熵作为评价标准,实验得到了以下三个理想的实验结果:

如果rnn没有学习到任何相关性,那么yt为1的概率是0.625(0.5+0.5*0.5-0.5*0.25),因此所获得的交叉熵应该是0.66(-(0.625 * NP . log(0.625)+0.375 * NP . log(0.375)

如果rnn知道第一个相关性,也就是说,当xt-3为1时,yt必须为1。那么,最终的交叉熵应该是0.52(-0.5 *(0.875 * NP . log(0.875)+0.125 * NP . log(0.125))-0.5 *(0.625 * NP . log(0.625)+0.375 * NP。

如果rnn学习了两个依赖项,那么概率为0.25,0.5的概率为75%,0.25的概率为0.5。因此,交叉熵为0.45(-0.50 *(0.75 * NP . log(0.75)+0.25 * NP . log(0.25))-0.25 *(2 * 0.50 * NP . log(0.50))-0.25 *(0))

数据预处理的主要部分是生成实验数据,实验数据根据rnn模型的输入格式进行分段和批处理。代码输入:

1、生成实验数据:

def gen_data(大小=100000):

x = np.array(np.random.choice(2,size=(size,))

y = []

对于范围内的I(尺寸):

阈值= 0.5

#判断x[i-3]和x[i-8]是否为1,并修改阈值

如果x[i-3] == 1:

阈值+= 0.5

如果x[i-8] == 1:

阈值-= 0.25

#生成随机数,并以阈值为阈值分配yi

如果NP . rand . rand()>阈值:

y.append(0)

否则:

y.append(1)

返回x,np.array(y)

接下来,根据模型参数设置分割生成的数据。这里需要的参数主要包括:批量大小和步数,即RNN每层的批量数据大小和rnn信元周期数,即下图中sn中N的大小。代码输入:

def gen_batch(原始数据、批次大小、步骤数):

#raw_data是使用gen_data()函数生成的数据,分别为x和y

原始x,原始y =原始数据

data _ len = len(raw _ x)

#首先,将数据分成批次大小,0-批次大小,批次大小-2 *批次大小。。。

批处理分区长度=数据长度//批处理大小

data _ x = NP . zeross([batch _ size,batch_partition_length],dt type = NP . int 32)

data _ y = NP . zeross([batch _ size,batch_partition_length],dt type = NP . int 32)

对于范围内的I(批次大小):

data _ x[I]= raw _ x[batch _ partition _ length * I:batch _ partition _ length *(I+1)]

data _ y[I]= raw _ y[batch _ partition _ length * I:batch _ partition _ length *(I+1)]

#因为rnn模型一次只处理num_steps数据,所以每个batch_size都被划分为epoch_size,并且每个批处理都有num_steps数据。注意,这里的历元大小不同于模型训练过程中的历元。

epoch _ size = batch _ partition _ length//num _ steps

#x是0-num_steps,batch _ partition _ length-batch _ partition _ length+num _ steps。。。总批量_大小

对于范围内的I(纪元大小):

x = data_x[:,i * num_steps:(i + 1) * num_steps]

y = data_y[:,i * num_steps:(i + 1) * num_steps]

产量(x,y)

# n这里是训练过程中使用的历元,即样本尺度上的周期数

定义世代(n,num_steps):

对于范围(n)中的I:

生成gen_batch(gen_data(),批次大小,步骤数)

根据上面的代码,我们可以看到,这里的数据划分并不完全遵循原始的数据顺序,而是每隔一段时间取num_steps数据,因此该批被训练= =是为了省事还是为了其他原因,这有待在后面的研究中验证。

我们不再重复用该模型构建rnn的具体原理,主要是计算新的隐藏层状态,并将隐藏层状态与输入连接后输出。这里使用单层rnn。公式和原理图如下:

st=tanh(w(xt @ st?1)+bs)

pt=softmax(ust+bp)

对于用张量流构造rnn模型,主要是定义rnn_cell类型并重用它。代码如下:

x = tf.placeholder(tf.int32,[batch_size,num_steps],name= input_placeholder)

y = tf.placeholder(tf.int32,[batch_size,num_steps],name= labels_placeholder)

#rnn初始化状态,全部设置为零。请注意,状态与输入是一致的,接下来是连接操作,所以这里应该有批处理的维度。也就是说,每个样本必须有一个隐藏层状态

init _ state = TF . zeross([batch _ size,state_size])

#将输入转换为一个热门代码,两个类别。[批处理大小,步骤数,类数]

x_one_hot = tf.one_hot(x,num _ classes)

#输入unstack,即unbind num_steps,这对于每个周期单位都很方便。这里可以看到,rnn的每个单元处理一个批处理输入(即批处理二进制样本输入)

rnn _ inputs = TF . un stack(x _ one _ hot,axis=1)

#定义rnn_cell的权重参数,

使用tf.variable_scope( rnn_cell):

w = tf.get_variable( w,[num _ class+state _ size,state_size])

b = tf.get_variable( b,[state_size],初始值设定项= tf.constant _初始值设定项(0.0))

#将其定义为重用模式,回收它,并保持参数不变

定义rnn_cell(rnn_input,state):

tf.variable_scope( rnn_cell,重用=true):

w = tf.get_variable( w,[num _ class+state _ size,state_size])

b = tf.get_variable( b,[state_size],初始值设定项= tf.constant _初始值设定项(0.0))

#定义rnn_cell的具体操作。这里使用最简单的rnn,而不是lstm

返回TF . tanh(TF . mat mul(TF . concat([rnn _ input,state],1),w) + b)

状态= init_state

rnn_outputs = []

#循环次数_步次,即输入一个序列到rnn模型

对于rnn_inputs中的rnn_input:

状态= rnn_cell(rnn_input,state)

rnn_outputs.append(状态)

final_state = rnn_outputs[-1]

#定义softmax层

使用tf.variable_scope( softmax):

w = tf.get_variable( w,[state_size,num _ classes)

b = tf.get_variable( b,[num _ class],初始值设定项= tf.constant _初始值设定项(0.0))

#注意,这里我们将分别计算所有的num_steps输出,然后使用softmax进行预测

logit =[TF . mat mul(rnn_output,w)+b(rnn _ output中的rnn _ output)

预测=[TF . nn . soft max(logit)for logit in logit]

#将我们的y占位符变成标签列表

y_as_list = tf.unstack(y,num=num_steps,axis=1)

#损失和训练_步骤

loss =[TF . nn . sparse _ soft max _ cross _熵_ with _ logit(labels = label,logit = logit)for \

logit,zip中的标签(logit,y_as_list)]

total_loss = tf.reduce_mean(损失)

train _ step = TF . train . adagrad optimizer(学习速率)。最小化(总损失)

在模型训练定义了我们的模型之后,下一步是传入数据,然后训练并编码:

def train _ network(num _ epoch,num_steps,state_size=4,verbose=true):

tf.session()作为sess:

sess . run(TF . global _ variables _ initializer())

培训_损失= []

#获取数据,因为num _ epochs = =,所以外部循环只执行一次

对于idx,枚举中的纪元(gen _ epoch(num _ epoch,num_steps)):

培训_损失= 0

#保存每次执行后的最终状态,并将其分配给下一次执行

training _ state = NP . zeros((batch _ size,state_size))

如果冗长:

打印(idx)

#这是具体的数据采集部分,应该执行1000000//200//5 = 1000次,也就是说,在每次执行中要传输batch_size*num_steps (1000个),所以每个num _ epochs需要执行1000次。

对于枚举(纪元)中的步骤(x,y):

tr _ losses,training_loss_,training_state,_ = \

sess . run([损失,

全损,

最终状态,

train_step],

feed_dict={x:x,y:y,init_state:training_state})

培训_损失+=培训_损失\u

如果步骤% 100 == 0且步骤> 0:

如果冗长:

打印(“步骤平均损失”,步骤,

"对于最后250步:",training_loss/100)

培训_损失.追加(培训_损失/100)

培训_损失= 0

返回培训_损失

训练损失=训练网络(1,步数)

plt.plot(培训_损失)

plt.show()

实验结果如下:

从上图可以看出,交叉熵最终稳定在0。52.根据以上分析,我们可以知道rnn模型成功地学习了第一个依赖关系。因为我们的循环步长是5,他只能学习t-3的第一个依赖性,而不能学习t-8的第二个依赖性。

接下来,尝试num_steps==10来捕获第二个依赖项。最终结果如下:

从上图可以看出,我们的rnn模型已经成功地学习了两种依赖关系。最终的交叉熵不确定在0.46左右。

一些改进。首先,在上面的代码中,为了尽可能详细地解释张量流中rnn模型的构造方法,详细地编写了rnn_cell的定义。事实上,这些任务tf已经打包好了,我们只需要一行命令来实现它们,所以首先要改进的是简化rnn_cell定义和循环部分的代码:

#定义rnn_cell的权重参数,

使用tf.variable_scope( rnn_cell):

w = tf.get_variable( w,[num _ class+state _ size,state_size])

b = tf.get_variable( b,[state_size],初始值设定项= tf.constant _初始值设定项(0.0))

#将其定义为重用模式,回收它,并保持参数不变

定义rnn_cell(rnn_input,state):

tf.variable_scope( rnn_cell,重用=true):

w = tf.get_variable( w,[num _ class+state _ size,state_size])

b = tf.get_variable( b,[state_size],初始值设定项= tf.constant _初始值设定项(0.0))

#定义rnn_cell的具体操作。这里使用最简单的rnn,而不是lstm

返回TF . tanh(TF . mat mul(TF . concat([rnn _ input,state],1),w) + b)

状态= init_state

rnn_outputs = []

#循环次数_步次,即输入一个序列到rnn模型

对于rnn_inputs中的rnn_input:

状态= rnn_cell(rnn_input,state)

rnn_outputs.append(状态)

final_state = rnn_outputs[-1]

# -

cell = TF . contrib . rnn . basicrncell(state _ size)

rnn_outputs,final _ state = TF . contrib . rnn . static _ rnn(cell,rnn_inputs,initial_state=init_state)

2.使用动态rnn模型,在上面的模型中,我们以列表的形式表示输入,也就是说,rnn_inputs是一个具有num_steps长度的列表,其中每个元素都是[batch_size,features](即每个rnn_cell要处理的数据)的张量,这很难做到。我们还可以使用tf提供的dynamic_rnn函数,它不仅在使用dynamic_rnn时,我们可以将输入直接表示为[批量大小、步长数、特征]的三维张量。最终的动态rnn模型代码如下:

简单实用的 TensorFlow 实现 RNN 入门教程

x = tf.placeholder(tf.int32,[batch_size,num_steps],name= input_placeholder)

y = tf.placeholder(tf.int32,[batch_size,num_steps],name= labels_placeholder)

init _ state = TF . zeross([batch _ size,state_size])

rnn_inputs = tf.one_hot(x,num _ classes)

#请注意,这一行代码在这里已经被删除了,因为我们不需要将它表示为一个列表并使用循环来完成它。

# rnn _ inputs = TF . un stack(x _ one _ hot,axis=1)

cell = TF . contrib . rnn . basicrncell(state _ size)

#使用dynamic_rnn函数动态构建rnn模型

rnn_outputs,final _ state = TF . nn . dynamic _ rnn(cell,rnn_inputs,initial_state=init_state)

使用tf.variable_scope( softmax):

w = tf.get_variable( w,[state_size,num _ classes)

b = tf.get_variable( b,[num _ class],初始值设定项= tf.constant _初始值设定项(0.0))

logit = TF . resform(

TF . mat mul(TF . resform(rnn _ outputs,[-1,state_size]),w) + b,

[批处理大小,步数,类数]

预测= TF . nn . soft max(logit)

损耗= tf.nn .稀疏_ softmax _ cross _熵_ with _ logits(标签=y,logits = logits)

total_loss = tf.reduce_mean(损失)

train _ step = TF . train . adagrad optimizer(学习速率)。最小化(总损失)

至此,我们已经实现了一个非常简单的rnn模型的构建。在这个过程中,我们应该注意以下三点:

在将数据转换为rnn可接受的输入格式时,应注意批量大小和步数之间的关系。

为了定义rnn_cell,这里使用了以下命令:cell = TF . contrib . rnn . basicnncell(state _ size)

要定义rnn模型,可以使用以下两个命令静态和动态地构建它:

rnn_outputs,final _ state = TF . contrib . rnn . static _ rnn(cell,rnn_inputs,initial_state=init_state)

rnn_outputs,final _ state = TF . nn . dynamic _ rnn(cell,rnn_inputs,initial_state=init_state)

雷锋(公开号:雷锋)(公开号:雷锋)相关阅读:

从原则到实战,英伟达教你用pytorch(1)构建rnn

从原则到实战,英伟达教你用pytorch构建rnn(第二部分)

雷锋文章版权所有。严禁擅自转载。详情请参考转载说明。

来源:搜狐微门户

标题:简单实用的 TensorFlow 实现 RNN 入门教程

地址:http://www.shwmhw.com/shxw/63217.html