RNNLM

RNNLM

基于RNN的语言模型称为RNNLM(Language Model)。

在这里插入图片描述

Embedding 层:将单词ID转化为单词的分布式表示(单词向量)。

RNN层:向下一层(上方)输出隐藏状态,同时也向下一时刻的RNN层(右边)输出隐藏状态。

对于“you say goodbye and i say hello.”如果模型学习顺利。

输入的数据是单词ID列表,输入单词ID为0的you,Softmax层输出的概率分布P0中,say的概率最高。这说明预测出了you后面出现的单词为say。

输入单词ID为1的say,Softmax层输出的概率分布P1中,goodbye和hello的概率最高。RNN层记忆了you say这一上下文。RNN将you say这一过去的信息保存成隐藏状态向量。

RNNLM可以记忆目前为止输入的单词,并以此为基础预测接下来会出现的单词。

在这里插入图片描述

如果整体处理时序数据,神经网络就如下图所示。整体处理含有T个时序数据的层称为Time xx层。

在这里插入图片描述

Time Affine 层:使用T个Affine层分别处理各个时刻的数据。代码使用矩阵运算实现整体处理。

class TimeAffine:def __init__(self, W, b):#接收权重参数和偏置参数self.params = [W, b]#参数设置为列表类型的成员变量paramsself.grads = [np.zeros_like(W), np.zeros_like(b)]self.x = Nonedef forward(self, x):#x包含T个时序数据N, T, D = x.shape#批大小是 N,输入向量的维数是 D,x形状为(N,T,D)W, b = self.paramsrx = x.reshape(N*T, -1)out = np.dot(rx, W) + b#使用矩阵运算实现整体处理self.x = xreturn out.reshape(N, T, -1)def backward(self, dout):x = self.xN, T, D = x.shapeW, b = self.paramsdout = dout.reshape(N*T, -1)rx = x.reshape(N*T, -1)db = np.sum(dout, axis=0)dW = np.dot(rx.T, dout)dx = np.dot(dout, W.T)dx = dx.reshape(*x.shape)self.grads[0][...] = dWself.grads[1][...] = dbreturn dx

Time Softmax with Loss 层:

x表示从下方的层传来的得分(正规化为概率之前的值);t表示正确解标签;T个Softmax with Loss层各自算出损失,相加并求平均,得到的值作为最终的损失。

在这里插入图片描述

class TimeSoftmaxWithLoss:def __init__(self):self.params, self.grads = [], []self.cache = Noneself.ignore_label = -1def forward(self, xs, ts):N, T, V = xs.shapeif ts.ndim == 3:  # 在监督标签为one-hot向量的情况下ts = ts.argmax(axis=2)mask = (ts != self.ignore_label)# 按批次大小和时序大小进行整理(reshape)xs = xs.reshape(N * T, V)ts = ts.reshape(N * T)mask = mask.reshape(N * T)ys = softmax(xs)ls = np.log(ys[np.arange(N * T), ts])ls *= mask  # 与ignore_label相应的数据将损失设为0loss = -np.sum(ls)loss /= mask.sum()self.cache = (ts, ys, mask, (N, T, V))return lossdef backward(self, dout=1):ts, ys, mask, (N, T, V) = self.cachedx = ysdx[np.arange(N * T), ts] -= 1dx *= doutdx /= mask.sum()dx *= mask[:, np.newaxis]  # 与ignore_label相应的数据将梯度设为0dx = dx.reshape((N, T, V))return dx

RNNLM学习与评价

将RNNLM使用的网络实现为SimpleRnnlm类,结构如下。

在这里插入图片描述

class SimpleRnnlm:def __init__(self, vocab_size, wordvec_size, hidden_size):V, D, H = vocab_size, wordvec_size, hidden_sizern = np.random.randn# 初始化权重,对各个层使用的参数(权重和偏置)进行初始化embed_W = (rn(V, D) / 100).astype('f')rnn_Wx = (rn(D, H) / np.sqrt(D)).astype('f')rnn_Wh = (rn(H, H) / np.sqrt(H)).astype('f')rnn_b = np.zeros(H).astype('f')affine_W = (rn(H, V) / np.sqrt(H)).astype('f')affine_b = np.zeros(V).astype('f')'''使用 Truncated BPTT 进行学习,将 Time RNN 层的 stateful设置为 TrueTime RNN 层就可以继承上一时刻的隐藏状态RNN 层和 Affine 层使用了Xavier 初始值'''# 生成层Time RNN 层就可以继承上一时刻的隐藏状态self.layers = [TimeEmbedding(embed_W),TimeRNN(rnn_Wx, rnn_Wh, rnn_b, stateful=True),TimeAffine(affine_W, affine_b)]self.loss_layer = TimeSoftmaxWithLoss()self.rnn_layer = self.layers[1]# 将所有的权重和梯度整理到列表中self.params, self.grads = [], []for layer in self.layers:self.params += layer.paramsself.grads += layer.gradsdef forward(self, xs, ts):for layer in self.layers:xs = layer.forward(xs)loss = self.loss_layer.forward(xs, ts)return lossdef backward(self, dout=1):dout = self.loss_layer.backward(dout)for layer in reversed(self.layers):dout = layer.backward(dout)return doutdef reset_state(self):self.rnn_layer.reset_state()

常使用困惑度(perplexity)评价语言模型。

困惑度是概率的倒数(数据量为1时),因为预测出的正确单词的概率越大越好,所以困惑度越小越好。

困惑度可以解释为分叉度,表示下一个可以选择的选项的数量(下一个可能出现单词的候选个数)。

输入数据为多个的情况,困惑度计算:

L是神经网络的损失,数据量为N个,tn是one-hot向量形式正确解标签,tnk表示第n个数据的第k个值,ynk是概率分布(神经网络Softmax的输出)。

在这里插入图片描述

RNNLM的学习和评价的代码如下。

# 设定超参数
batch_size = 10
wordvec_size = 100
hidden_size = 100
time_size = 5  # Truncated BPTT的时间跨度大小
lr = 0.1
max_epoch = 100# 读入训练数据(缩小了数据集)
corpus, word_to_id, id_to_word = ptb.load_data('train')
corpus_size = 1000
corpus = corpus[:corpus_size]
vocab_size = int(max(corpus) + 1)xs = corpus[:-1]  # 输入
ts = corpus[1:]  # 输出(监督标签)
data_size = len(xs)
print('corpus size: %d, vocabulary size: %d' % (corpus_size, vocab_size))# 学习用的参数
max_iters = data_size // (batch_size * time_size)
time_idx = 0
total_loss = 0
loss_count = 0
ppl_list = []# 生成模型
model = SimpleRnnlm(vocab_size, wordvec_size, hidden_size)
optimizer = SGD(lr)'''
使用 Truncated BPTT 进行学习,因此数据需要按顺序输入.
mini-batch 的各批次要平移读入数据的开始位置。'''# 计算读入mini-batch的各笔样本数据的开始位置
jump = (corpus_size - 1) // batch_size
offsets = [i * jump for i in range(batch_size)]#offsets 的各个元素中存放了读入数据的开始位置for epoch in range(max_epoch):for iter in range(max_iters):# 获取mini-batch,按顺序读入数据batch_x = np.empty((batch_size, time_size), dtype='i')batch_t = np.empty((batch_size, time_size), dtype='i')for t in range(time_size):#for i, offset in enumerate(offsets):#各批次增加偏移量batch_x[i, t] = xs[(offset + time_idx) % data_size]#将time_idx 处的数据从语料库中取出,将当前位置除以语料库大小后的余数作为索引使用batch_t[i, t] = ts[(offset + time_idx) % data_size]#取余数为的是:读入语料库的位置超过语料库大小时,回到语料库的开头time_idx += 1# 计算梯度,更新参数loss = model.forward(batch_x, batch_t)model.backward()optimizer.update(model.params, model.grads)total_loss += lossloss_count += 1# 各个epoch的困惑度评价ppl = np.exp(total_loss / loss_count)#计算每个 epoch 的平均损失,然后计算困惑度print('| epoch %d | perplexity %.2f'% (epoch+1, ppl))ppl_list.append(float(ppl))total_loss, loss_count = 0, 0# 绘制图形
x = np.arange(len(ppl_list))
plt.plot(x, ppl_list, label='train')
plt.xlabel('epochs')
plt.ylabel('perplexity')
plt.show()

结果如下。困惑度逐渐减小。

| epoch 78 | perplexity 16.30
| epoch 79 | perplexity 15.07
| epoch 80 | perplexity 14.23
| epoch 81 | perplexity 13.74
| epoch 82 | perplexity 13.12
| epoch 83 | perplexity 12.36
| epoch 84 | perplexity 11.58
| epoch 85 | perplexity 11.16
| epoch 86 | perplexity 10.23
| epoch 87 | perplexity 10.12
| epoch 88 | perplexity 9.08
| epoch 89 | perplexity 8.71
| epoch 90 | perplexity 8.29
| epoch 91 | perplexity 8.24
| epoch 92 | perplexity 7.79
| epoch 93 | perplexity 7.41
| epoch 94 | perplexity 6.99
| epoch 95 | perplexity 7.17
| epoch 96 | perplexity 6.36
| epoch 97 | perplexity 5.98
| epoch 98 | perplexity 5.78
| epoch 99 | perplexity 5.55
| epoch 100 | perplexity 5.48Process finished with exit code 0

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/560182.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用c#制作赛尔号登录器

使用c#制作赛尔号登录器 需求: 打开赛尔号官网,发现我的chrome浏览器无法运行Flash。这是因为Adobe 公司放弃了对 Flash Player 的支持。 那么如果我想要玩游戏,又不想下载别的浏览器,只好自己写一个登陆器了。 创建项目 首先…

普通RNN的缺陷—梯度消失和梯度爆炸

之前的RNN,无法很好地学习到时序数据的长期依赖关系。因为BPTT会发生梯度消失和梯度爆炸的问题。 RNN梯度消失和爆炸 对于RNN来说,输入时序数据xt时,RNN 层输出ht。这个ht称为RNN 层的隐藏状态,它记录过去的信息。 语言模型的任…

LSTM的结构

RNN和LSTM 简略表示RNN层:长方形节点中包含了矩阵乘积、偏置的和、tanh函数的变换。将下面这个公式表示成一个tanh节点。 LSTM:Long Short-Term Memory(长短期记忆),长时间维持短期记忆。 LSTM与RNN的接口(输入输出)…

STM32 USART 补充

串口通讯的数据包:发送设备通过自身的TXD接口传输到接收设备的RXD接口。 串口通讯的协议层中,规定了数据包的内容,由起始位、主体数据、校验位、停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据。 异步通讯&#xf…

ROS TF变换

静态坐标转换:机器人本体中心到雷达中心的转换。因为激光雷达可能没安装到机器人的中心。 动态坐标转换:机器人中心和里程计坐标的变换。机器人从起点出发后,里程计坐标相对于本体就会产生一个偏移,这个偏移随着机器人的运动不断…

ROS底盘控制节点 源码分析

先在机器人端通过launch文件启动底盘控制。 robot:~$ roslaunch base_control base_control.launch ... logging to /home/jym/.ros/log/3e52acda-914a-11ec-beaa-ac8247315e93/roslaunch-robot-8759.log Checking log directory for disk usage. This may take a while. Pres…

ROS + OpenCV

视觉节点测试 先进行一些测试。并记录数据。 圆的是节点,方的是话题。 1.robot_camera.launch robot:~$ roslaunch robot_vision robot_camera.launch ... logging to /home/jym/.ros/log/bff715b6-9201-11ec-b271-ac8247315e93/roslaunch-robot-8830.log Check…

ROS+雷达 运行数据记录

先测试一下雷达,记录数据。方便接下来分析源码。 1.roslaunch robot_navigation lidar.launch robot:~$ roslaunch robot_navigation lidar.launch ... logging to /home/jym/.ros/log/7136849a-92cc-11ec-acff-ac8247315e93/roslaunch-robot-9556.log Checking l…

ROS 找C++算法源码的方法

在gmapping的launch文件中看到,type“slam_gmapping”,这里的slam_gmapping是c编译后的可执行文件。 如果想要修改gmapping算法,就需要找到slam_gmapping的c源码。 但是这是用apt下载的包,是二进制类型的,没有下载出…

ros 雷达 slam 导航 文件分析

ros 雷达 slam 导航 文件分析robot_slam_laser.launchrobot_lidar.launchlidar.launchraplidar.launchkarto.launchgmapping.launchcartographer.launchrobot_navigation.launchmap.yamlmap.pgmamcl_params.yamlmove_base.launchcostmap_common_params.yamllocal_costmap_param…

Apprentissage du français partie 1

Apprentissage du franais partie 1 键盘转换图: 字母:26个 元音字母:a、e、i、o、u、y b浊辅音(声带)-p清辅音 d-t 音符 音符:改变字母发音。 :闭音符 [e] :开音符 /ε/ :长音符 /ε/…

stm32基本定时器

定时器分类 stm32f1系列,8个定时器,基本定时器(TIM6,7)、通用定时器(TIM2,3,4,5)、高级定时器(TIM1,8)。 基本定时器:16位,只能向上计数的定时器,只能定时,没有外部IO 通用定时器:16位&#…

stm32高级定时器 基础知识

stm32高级定时器 高级定时器时基单元: 包含一个16位自动重装载寄存器 ARR 一个16位的计数器CNT,可向上/下计数 一个16位可编程预分频器PSC,预分频器时钟源有多种可选,有内部的时钟、外部时钟。 一个8位的重复计数器 RCR&…

stm32 PWM互补输出

stm32高级定时器例子—stm32 PWM互补输出 定时器初始化结构体 TIM_TimeBaseInitTypeDef 时基结构体,用于定时器基础参数设置,与TIM_TimeBaseInit函数配合使用,完成配置。 typedef struct { TIM_Prescaler /*定时器预分频器设置&…

stm32 输入捕获 测量脉宽

选用通用定时器TIM5的CH1。 PA0接一个按键,默认接GND,当按键按下时,IO口被拉高,此时,可利用定时器的输入捕获功能,测量按键按下的这段高电平的时间。 宏定义方便程序升级、移植,举个例子&#…

stm32 PWM输入捕获

普通的输入捕获,可使用定时器的四个通道,一路捕获占用一个捕获寄存器. PWM输入,只能使用两个通道,通道1和通道2。 一路PWM输入占用两个捕获寄存器,一个捕获周期,一个捕获占空比。 这里,用通用…

直流有刷减速电机结构及其工作原理

寒假无聊拆了个直流有刷减速电机。下面介绍一下它的结构和工作原理 直流电机 直流电机和直流减速电机: 构造上相差的是一个减速齿轮组。 普通的直流电机当空载时,电机的转速由电压决定,直流减速电机的转速由齿轮组和电压决定。 齿轮组作…

数据库基础概念

postgreSQL设置只允许本地机器连接 在D:\program files\PostgreSQL\14\data里面设置postgresql.conf: listen_addresses ‘localhost’ 然后在服务窗口重新启动postgresql。 PostgreSQL执行SQL语句 PostgreSQL的psql工具可通过命令行执行SQL语句。 psql -U po…

电机和驱动的种类

电机种类 直流电机 分为普通的直流电机、直流减速电机、有刷、无刷。 直流有刷减速电机参数: 空载转速,正常工作电压,电机不带任何负载的转速。 空载电流,正常工作电压,电机不带任何负载的工作电流。单位mA。 负载…

Linux shell基础知识

Shell简介 Shell是一个应用程序,接收用户输入的命令,根据命令做出相应动作。 Shell负责将应用层或者用户输入的命令,传递给系统内核。由操作系统内核,来完成相应的工作。然后将结果反馈给应用层或者用户。 shell命令格式&#…