- 12.3 - 环境及seq2seq教程
- 12.9~10 - 阅读教程
- 12.11 - 阅读项目源码
- 12.13
- 12.14
- 12.18 - 阅读论文
- 12.23
- 12.29
- 12.30
- 12.31
- 1.1
This is my note taken in Chinese.
12.3 - 环境及seq2seq教程
- 今天搭配好了pycharm连接服务器并进行本地与服务器自动同步上传的配置,完成了新建本地的服务器interpreter,也完成了pytorch以及CUDA环境的搭建。
- 下午和晚上看了pytorch的官方seq2seq教程并试着用GPU跑了一下它的代码。
- 关于网络的基本思路是掌握了,但是具体的参数细节还需要再加掌握。
- 参数的具体含义可以参考官网的文档。
- Variable的用法或许要从头再看一遍pytorch的教程。
- 关于训练,attention模型的具体流程不是很明白,以及train和trainIter要分清楚,随机梯度下降也要搞明白。
- 如果搞明白了decoder部分的输入,那我觉得就可以对对话进行建模了。
- 关于网络的基本思路是掌握了,但是具体的参数细节还需要再加掌握。
12.9~10 - 阅读教程
神经网络的相关预备知识
- 激活函数:activation function
- 掰弯利器(非线性函数) relu,sigmoid,tanh,softpuls
- 确保激励函数可以微分,这样才能误差反向传递
- 当使用多层神经网络的时候要注意激活函数的使用,不然可能会有梯度爆炸、梯度消失等问题
- 对于激活函数的选择:
- 当神经网络层数不多的时候,激活函数可以是多种选择,都可以尝试一下
- 当是CNN的时候,建议使用relu。
- 当是RNN的时候,建议使用relu或者tanh。
- 神经网络的每一层的结果都用激励函数去做一个映射(非线性化的转化),再传入下一层。
- 注:softmax也是一个激励函数,但是用于做概率的计算的,使用softmax的话对于分类问题的计算算概率比较好。
- 优化方法:
- 牛顿法 最小二乘法
- 梯度下降法
- 注意 局部最优 不是 全局最优
-
误差方程:cost function
-
防止过拟合:
-
加大数据量
-
增加regularization
- 对于过大的W加一个惩罚项。
-
dropout regularization
- 在训练的时候,随机切断一些神经元与神经网络的连接,使得这个神经网络不完整。
- 相当于每一次的训练结果都不会那么依赖于每一个神经元。
-
-
批标准化:
- 将分散数据统一化,解决激活函数tanh的“饱和”现象
- 将数据分成小批小批的进行SGD处理,在每一层的时候都做normalization(添加在全连接层和激活函数的层之间)。
- 让每一层的值在有效的范围内传递下去就是批标准化的好处。
What is tensor?
- tensor可以用于GPU加速计算,就是一个n维向量
-
初始化:
torch.rand(5,3)
- 任何会改变tensor的内容的操作会在方法名后面加一个下划线,比如:
y.add_(x)
- 注意的是numpy和torch的数组的转换中,他们会共享一个内存地址,改变一个就会带动改变另一个。
- tensor可以在CPU和GPU之间相互转换,使用CUDA函数来将tensor移动到GPU上,当CUDA可用的时候就会进行GPU运算
- 一般可以在一开始的地方写一个
use_cuda = torch.cuda.is_available()
- 一般可以在一开始的地方写一个
- Pytorch是动态建立图的过程,适合处理不同长度不同形式的图纸,比如:RNN。
Pytorch中的Variable自动求导
- autograd包可以提供所有操作的自动求导。
- 神经网络里的参数都是Variable变量形式,用变量来更新。requires_grad参数是参不参与误差反向传播,要不要计算梯度。
- 如果你想要进行求导计算,你可以在Variable上调用.backward(),需要制定一个和tensor形状相匹配的grad_output参数。反向传播之后,可用variable.grad()来访问梯度值(此处涉及:矩阵求梯度)。
- 方向传播的自动求导是根据你的代码运行的方式来定义的,因此每一轮迭代的时候都可以各不相同。
- 时刻记住,Variable 计算时,它在背景幕布后面一步步默默地搭建着一个庞大的系统,叫做计算图,computational graph。这个图将所有的计算步骤 (节点) 都连接起来,最后进行误差反向传递的时候,一次性将所有 variable 里面的修改幅度 (梯度) 都计算出来,而 tensor 是没有这个能力的。
- 与numpy的转换:
- 先转化到tensor再到numpy
- variable.data.numpy()
Pytorch搭建神经网络
- net要从torch.nn.module继承过来
- 一个典型的神经网络的训练过程是这样的:
- 定义一个有着可学习的参数(或者权重)的神经网络
- 对着一个输入的数据集进行迭代
- 用神经网络对输入进行处理
- 计算代价值 (对输出值的修正到底有多少)
- 将梯度传播回神经网络的参数中
- 更新网络中的权重
- 通常使用简单的更新规则: weight = weight + learning_rate * gradient
- class net
- init函数
- 搭建层所需要的一些参数信息
- 继承nn的init
- 对于hidden隐藏层,定义一开始输入的特征值,定义该层的神经元的个数
- 对于predict输出层,定义层隐藏层传进来的输入值的个数,定义输出值的个数
- forward函数
- 神经网络前向传递输入值,一层一层分析出输出值的过程
- 对隐藏层进行激活函数的非线性转化
- 可以直接用print(net)来看网络的结构
- init函数
- 训练
- 优化器
- 传入net的所有参数和学习率
- 注意学习率不要太大也不要过小
- loss_func
- 预测值和真实值的误差计算公式
- 参数的话记得把prediction写在真实值y的前面
- 回归:用MSELoss
- 分类:CrossEntropyLoss
- 输出值并不是预测值
- 输出之后需要利用softmax来转化成概率
prediction = torch.max(F.softmax(output), 1)[1]
- 预测值和真实值的误差计算公式
- 清空上一步的残余更新参数值
optimizer.zero_grad()
- 误差反向传播,计算参数更新值
loss.backward()
- 将参数的更新值施加到net的参数上
optimizer.step()
- 优化器
-
网络的快速搭建法:
-
net2 = torch.nn.Sequential( torch.nn.Linear(1, 10), torch.nn.ReLU(), torch.nn.Linear(10, 1) )
-
-
保存网络:
- 保留整个神经网络
torch.save(net, 'net.pkl')
- 只保留参数:
torch.save(net.state_dict(),'net_para.pkl')
- 保留整个神经网络
- 提取网络:
- 提取整个网络:
net = torch.load('net.pkl')
- 如果是提取参数的话:
- 要先建立一个完全一样的net
- 再把参数load进来
net.load_state_dict(torch.load('net_para.pkl'))
- 提取整个网络:
加速神经网络训练
- 优化器:
- 随机梯度下降(SGD)
- 每次使用批量数据传入NN
- 其他方法:
- Momentum:惯性方向上的原则
- AdaGrad:对错误方向上的阻力
- RMSProp:结合前两种但还少了一个部分
- Adam:结合前两种(大多数时候是最好的
- 随机梯度下降(SGD)
- 关于批数据训练
- 超参数:
batch_size
: 每次训练的数据数量epoch
: 轮数
- 准备数据:
Data.TensorDataset, DataLoader
- 可以shuffle数据,让每一次训练都打乱数据,且一般shuffle都会带来更好的效果
- num_workers:可以多线程,效率更高
- 注意: torch.nn 只接受小批量的数据
- 整个torch.nn包只接受那种小批量样本的数据,而非单个样本。
- 如果你拿的是单个样本,使用input.unsqueeze(0)来加一个假维度就可以了。
- 超参数:
卷积神经网络
- 卷积:
- 神经网络不再对单个像素的输入信息做处理,而是对图片上每一小块像素区域进行处理,。这种做法加强了图片信息的连续性,使得神经网络能看到图形,而非一个点。
- 批量过滤器持续不断的在图片上滚动收集图片里的信息,每一次收集的时候都只是收集一小块像素区域,然后把收集来的信息进行整理。
- 池化:
- 在每一次卷积的时候,神经层可能会无意地丢失一些信息。这时,池化 (pooling) 就可以很好地解决这一问题。
- 池化是一个筛选过滤的过程,能将 layer 中有用的信息筛选出来,给下一个层分析。
- 一般采用maxpooling。
循环神经网络
- “记住之前发生的事情的能力”
-
在$t+1$时刻,分析得到的$Y(t+1)$是由$X(t+1)$和$S(t)$一起分析得到的。
- LSTM
- 为了解决RNN的误差在反向传播的时候可能造成的梯度爆炸或者梯度消失的情况(所以RNN没有久远的记忆
自编码
- 是一种神经网络形式,由于并没有用到“标签”信息,所以为非监督学习。只是用training data压缩后然后与原始的traing data相对比,来计算误差。
- 压缩输入的信息,总结出原数据的精髓(压缩的精髓特征集)。之后再创造一个小的神经网络来对精髓进行学习,可以提高效率。
- 自编码和PCA一样可以用于给特征属性降维,表现还比PCA好。
12.11 - 阅读项目源码
预处理
- 语料在处理的时候保存的格式为;
- 一组语料的形式:上文(大概三句对话) tab 目标说话者(一个名字) tab 说话者回复(一句话)
- 每一组这样的语料之间是’\n’区分
- 训练的时候再手动根据tab去区分出来 上文,说话者,说话者回复,给回复加上
当作decoder的第一个输入,相当于 ,在nlp里叫go token. - word的index是先统计了所有的单词,然后用词典一一对应出来,高频词优先。在这里把文字中的词语变成index向量。
- 训练的时候把上文传到encoder中,把目标说话者(s向量)和说话者回复传到decoder中。
- speaker是一个小维度的embedding。
attention_model
- encoder:
- input_seqs:此时还是词在词汇表中的index的状态,用embedding去利用单词的index查表之后就能转换成一个200维度的向量(转换为200维的hidden representation)
- 此处的embedding也就是各个单词hidden表示有优劣之分,可以直接用nn.Embedding,也可以用glove(是在billion级别的数据集训练的 所以当做pretain的embedding很好)
- input_lengths
- 多加了一个embed_size,与hidden_size区分
- 目前的参数都比较粗略,encoder和decoder只有一层GRU。
- input_seqs:此时还是词在词汇表中的index的状态,用embedding去利用单词的index查表之后就能转换成一个200维度的向量(转换为200维的hidden representation)
- decoder:
- decoder中多加了一个speaker的属性进来,目前的speaker的s向量只是32维。
- 输入维度为:hidden_size + embed_size + speaker_embed_size,分别是上一次的输出+attention+人物的s标签。将三者拼成一个大向量传进去。
关于下一步的想法
- 第一个:
- 在encoder部分变成两个分支,一个分支是目标说话者说的上文,另一个分支是非目标说话者说的上文。然后合并后传入decoder。
- 问题:
- 说话者与非说话者的对话,仍然没有交互的关系,只是单纯的分开了而已。
- 先分开再合并成一起传进decoder的话其实跟之前的整个上文一起传进来的做法没有什么区别。(这里可以类似在 decoder的每个输入是 上一个状态的output + attention + speaker 合并起来,因为学到的权重是一样的,所以没什么意义。如果用其他方法来学习权重可能会有用
- 问题:
- 在encoder部分变成两个分支,一个分支是目标说话者说的上文,另一个分支是非目标说话者说的上文。然后合并后传入decoder。
- 第二个:
- 一个encoder接一个decoder 再接encoder…(循环进行)
- 比如第一个人说的一句话 进 encoder 下一个人回答他的话 进 decoder 再下一个回复 又进一个encoder
- 本质:相当于把decoder的最后一个状态的hidden state用作encoder的初始state。
- 第三个:
- 一个直观的想法就是,现在的encoder是对于输入进来的句子的每一个单词计算output,我希望在这里对于每一个句子进行一个output操作。
- 只要让每一个句子对应一个向量,就可用与word一样的处理方法来处理(因为现在的模型就是对于每个词对应的向量来处理的)。
- 一个直观的方法就是把这个句子的所有word的向量以某种线性方式结合起来,就得到了句子的表示向量。
- 对于每一步的输入除了一个句子以外还可以加入一个类似decoder中加入的s向量,这样就完成了人物tag+说话语句的建模。
- 或许这里对于每一步可以加入强化学习,不断给说话者的回复一个人物标签的反馈?
12.13
Screen命令控制多服务器运行
- 今天学会了用远程服务器在你电脑关闭的时候继续训练网络!
- 主要用到的一个叫screen的命令行
- 在终端通过
screen
命令可以创建一个新的桌面 - 在桌面用命令跑文件
python model.py
- 退出(但不结束)的时候用
screen -d
- 退出并彻底结束的时候用
exit
- 在服务器界面想要恢复之前在后台运行的桌面用
screen -r
- 恢复了终端之后,使用
control+a+{
即可转入copy mode,然后就进入了vim模式,可以使用control+f/b
进行上下翻页查看之前的输入输出!退出这个模式只需要用esc
。 - 查看服务器的占用情况可以用命令
nvidia-smi
,可以查询显卡信息,查看GPU显存、温度、功率使用,然后选择合适的GPU。 - 感谢占魁教学,非常酷 ^ ^
Jupyter notebook用于学习
- 今天本来想用jupyter notebook来跑代码,方便理解。但是一直不能用服务器来跑jupyter,配置了半天也不行 TAT,感觉解决办法可以是 用本地的jupyter来看数据维度,输入输出,学习代码,再用远程服务器来训练。
- jupyter notebook –no-browser
12.14
与魏老师讨论
- 对比试验
- 传统机器学习模型的对比实验需要更正
- (或许需要重新处理数据集
- 关于模型推荐的第一步想法:
- 分开成目标人物和非目标人物之后可以将两者RNN出来的output再过一次gru,之后传入decoder,此思路和之前的将前文当成一个段落来处理有所不同。
- 关于第三种方法的实现:
- 应阅读论文熟悉模型:
- 两种方法:
- 先是简单的去分成两层,对于每个句子的词进行一层RNN,对于句子与句子之间再进行一次RNN。同时要加入s的表达。
- 通过encoder(A1,B1,A2,B2)与decoder出来的(B2,A2,B1,A1)去pretrain一个s的表示,再接入decoder去做实验。
12.18 - 阅读论文
A Persona-Based Neural Conversation Model
- 参考阅读:
- handling the issue of speaker consistency
- 这里的consistency主要代表的是前后chat bot说的不一致
- evaluation: perplexity and BLEU
- related work:
- One major issue for these data-driven systems is their propensity to select the response with greatest likelihood
- neural models of conversation gen- eration (Sordoni et al., 2015; Shang et al., 2015; Vinyals and Le, 2015; Li et al., 2016) provide a straightforward mechanism for incorporating personas as embeddings
- learning generation rules from a minimal set of authored rules or labels
- Long Short-Term Memory (LSTM) (Hochreiter and Schmidhuber, 1997) to learn from unaligned data in order to reduce the heuristic space of sentence planning and surface realization
- two models:
- 论文针对对话系统前后不一致的问题,将user identity(比如 background facts、user profile,age,country等信息)考虑到model中,构建出一个富含用户特色的 seq2seq 模型,为不同的 user,以及同一个user对不同的对象对话生成不同风格的response。
- single-speaker SPEAKER MODEL
- integrates a speaker-level vector representation into the target part of the SEQ2SEQ model
- a dyadic SPEAKER-ADDRESSEE MODEL
- encodes the interaction patterns of two interlocutors by constructing an interaction representation from their individual embeddings and incorporating it into the SEQ2SEQ model
- 这是一个典型的 seq2seq 模型,不同的地方在于在 decoding 部分增加了一个speaker embedding。因为无法对用户的信息显式地进行建模,所以用了一种 embedding 的方法,这个 embedding 中编码了 speaker 的信息,通过训练来得到 speaker 向量。
Our work
- For present purposes, we will define PERSONA as the character that an artificial agent, as actor, plays or performs during conversational interactions. A persona can be viewed as a composite of elements of identity (background facts or user profile), language behavior, and interaction style.
- 上文可能是多人多轮对话,也就是Addressee model。
- decoder我不想要他生成单词序列,我只需要倒推回概率p。
12.23
关于定题报告魏老师的反馈
-
对了,现在大家的定题报告基本都给我了。我也反馈了一些建议。除了我给的建议,大家需要增加现在的具体进度内容以及在下个报告结点前的进度预期。
-
12.23 实验室框架:Baseline 和 Evaluation 的选定,Introduction的初稿
12.30 清理完熙森代码,Hierarchical模型完成,Pretrain模型搭建完成
1.3 NLP final PJ report
1.6 实验室第一次进度汇报
1.15 争取把实验跑完,可以着手写论文赶IJCAI
1.24 NLP final PJ
1.25 IJCAI Abstract Submission
1.28 完成IJCAI论文
1.31 如果此时才跑完实验,则赶ACL论文
2.10 实验室第三次进度汇报
2.13 ACL END
2.22 ACL Paper Submission
-
-
大家的定题报告,实际上是给自己这个文章准备做成什么样子,有一个大概得框架。报告的整个流程思路,基本上就是你们写文章时候introduction的框架。
-
另外两个重心是,模型和实验设置。模型现在应该都有基本思路了,但具体怎么做,大家可以慢慢摸索。实验设置方面,需要把实验对比如果进行,用哪些baseline,对于每一组的对比实验大概想说明什么问题。这些都是要思考的点。
论文阅读
Dilated Recurrent Nerual Network
- 问题:
- 原始的RNN长的时候可能会梯度爆炸、梯度消失等等问题
- Related Work:
- Clockwork RNN
- 重点:
- 点与点之间 跳跃连接
- 概括:
- 本文提出的 dilated RNN,解决了长程依赖的问题,同时可提高并行率,提高计算速度;提出 Mean Recurrent Length 指标,衡量 RNN 可记忆的时间长度,仅用普通的 RNN 模块在多项任务上达到 state of art 效果。
- 本文由IBM T. J. Watson研究中心和伊利诺伊大学香槟分校合作完成。传统递归神经网络在学习长串行数据时通常遇到很大的困难,主要表现在复杂的长时序跨度记忆和中短期记忆难以同时处理,用反向传播 (BP) 算法训练递归神经网络容易出现梯度消失和梯度爆炸的问题,与前向和反向传播需要串行进行,导致训练非常费时。本文提出了一种dilated RNN来解决上述训练难题。这种网络基於一种创新的多分辨率dilated递归skip连接,能够自由地和不同种类RNN单元结合。这种dilated递归神经网络结构显着减少了网络参数,提高了训练的高效性,同时还能取得与标准的递归神经网络相似的效果。为了理论地量化该网络结构的优势,本文还提出了一种记忆容量衡量标准,即平均递归长度,比已有的标準更适合具有长skip的递归神经网络。
Reinforcement learning for relation classification from noisy data
- 原来的缺陷:
- 知识库+实体 = 确定关系
- 这样的硬标注会导致噪声比较大
- 解决:
- 把bag level降为sentence level
- 相关解读可以参考理解
论文定题报告的反馈和反思
- 分类人物性格,可不可以直接用分类模型做?用生成对话的模型做再倒推概率会不会表现不好?
- 第一个问题:对的,所以我们要去实现传统分类模型去对比分类效果(很有可能我们的模型还比不过传统模型)
- 那么现在是不是,只要生成对话的模型好,我们加上s向量,就能让我们的分类效果好?
- 第二个问题:对的,直观上对话模型越好,加了s的效果就越好,但是也要注意看s在decode过程中信号的强度。
- 虽然一个对话模型很好,但是它完全不考虑s这个输入,那用这种模型分类就很糟。
- 所以之后可以考虑看一些conversation modeling的方法,去看怎么样才能让对话建模更好,怎样让句子表示成一个向量,以及思考怎么样加入s。以及再到之后,不行的话,论文的方向可以改成基于性格的对话模型的改进。
- 模型的评估:
- 只要你是直观的在模型上作出改变并且直接进行对比,逻辑上顺畅,那么自己与自己比较也可以,直观的表现出来了差距,而且对比是合理的公平的。
12.29
和魏老师汇报进度
- 今天主要说了discriminative的model的部分
- 一种是直接对于response过一个RNN(相当于之前的decoder不用加s向量的部分),将输出的hidden加一个softmax和全连接直接进行分类。
- 另一种是 content+response一起,在这里上文的建模可以用到s向量,将上文和response的回复生成的hidden一起传进全连接成进行分类。
- generative的model部分可以继续原来的思路做。
- 还提到了一下reinforcement learning的部分,魏老师说这应该是明年ACL的重点(不过还没有想得更细致,还需要继续思考细节部分。
关于虚拟环境的建立
- 先利用
pip freeze > requirements.txt
把当前环境的所有配置生成到requirements.txt文件里- 用命令
conda create -n CarolinePy2.7
生成一个名为CarolinePy2.7的文件夹在anaconda2/envs下,利用source activate CarolinePy2.7
即可激活,进入虚拟环境内部。 - 利用
pip install -r requirements.txt
这个命令可以一键安装requirements.txt的所有配置 - 或者利用
conda install anaconda
命令一键安装常用的包
- 用命令
- 之后即可先激活进入虚拟环境内部,在此即可运行各种安装好的包,也可以直接用命令
python run.py
跑文件,用完记得source deactivate
一下。 - 嫌刚才的命令太复杂?可以先开一个
screen
,之后用alias c2='source activate CarolinePy2.7'
来修改命令,之后就可以直接输入c2
代替啦! - 终端运行脚本
bash xxx.sh
- 以上:感谢占魁的教学 ^ ^
12.30
关于season代码中train的过程
-
首先load进已经处理好的vocab和speaker数据,这里主要用到的是
load_vocab_and_speaker
这个函数-
index_to_word
{0: '<pad>', 1: '<unk>', 2: '<GO>', 3: '</s>'}
-
word_to_index
{'<GO>': 2, '<pad>': 0, '</s>': 3, '<unk>': 1}
-
word_freq
defaultdict(<type 'int'>, {'<GO>': 1, '<pad>': 1, '</s>': 1, '<unk>': 1})
-
以上三个全是字典,是事先处理好之后存在本地里的一个字典。
-
同样的,对于人物,也是完全一致的处理方法:
-
index_to_word
{0: 'Sheldon', 1: 'Leonard', 2: 'Penny', 3: 'Howard', 4: 'Raj', 5: 'Amy'}
-
-
然后初始化encoder,decoder,并将其转到CUDA上
-
此时可以加载已经pretrain好的glove embedding
- glove的形式是一个大文件,每一行存一个单词加这个单词对应的向量,以空格分开。
- 先读进来这个单词和对应的词向量,然后利用
word_to_index
去找到这个词对应的index,更新vec_array
矩阵中对应的行。 - 这一步要做的就是把
vocab_size
里面的20000个词的embedding都取出来。
-
对于模型进行初始化,指定learning rate,优化器,loss。
-
之后开始迭代:
- 对于一次训练,应有 上文context, 人物response,回复response。
- 这里用到了一个函数
data_iterator
,其中的iter_time
就是整个数据集完整的过几遍的意思,即epoch。 - 这个
data_iterator
是为了先处理数据,为了encoder和decoder的输入做准备。 - 读入的形式为:
<type 'list'>: ['seriously , let him go . </s> sheldon , if you really need to do this , i'm not gon na stand in your way . </s> i do . </s>', 'Leonard', 'okay . good luck . </s>\n']
- 这里忽略掉了特别短的回复句子(长度小于7
- 这里还直接忽略掉了speaker不是目标人物的情况(
if speaker not in self.characters.word_to_index.keys()
- 在保存的时候,先将对应的单词转化成embedding,注意此处的转换是
word_to_index
,而不是直接成词向量,这一步完了之后就是将一句话里所有的单词转化成了index然后存进了列表里。 - 对于人物是一样的处理方法,不过人物对应的多存了一个p,也就是公式中的$p(s)$。
- 然后就是用了一个叫
really_magical_sorting_by_first_entry
的函数将这个处理好的context,speaker,response打包成了batch的形式(但仍然为ndarray的形式)。单个batch中的所有数据按照sequence length降序排序,长度不够的部分用0填充,一个batch里面sequence长度看起来都得是一样的。最后context_batches的维度为(x, 64),这里的64为batch_size,x为这64个句子里面最长的一个句子的长度,其他的句子不足这么长的部分就用0来代替。 - 然后就将batch传入训练呗,还能咋地(这里调用了train_iter这个函数
- 一开始的时候传进来的是np.array的形式,会在这里转成tensor,然后又转成variable,再转到CUDA上
- 清零encoder和decoder的优化器的梯度
- 让上文的words顺着encoder运行
- 将上文的encoder的输出做一些链接,传入decoder
- 把输出全部转到CUDA上
- 开始顺着decoder一个时间戳一个时间戳的运行,在这里的时候涉及到了一个speaker_input
- 计算loss然后反向传播
- 更新优化器的参数
- 迭代到一定次数之后存一下checkpoint
12.31
关于IBM的seq2seq中的模型和season的模型的区别
EncoderRNN
- 继承于一个自己写的基类
BaseRNN
- 基类中主要是在
init
的部分定义了一些参数,对于RNNcell定义了lstm和gru两种,forward
并没有implement
- 基类中主要是在
init
的部分其实和season的是等价的,不过是多了一个选择rnn_cell是gru还是lstm的部分。同样的是先定义参数们,然后定义embedding,再是定义rnn的网络结构部分。- 参数这里,season把其中一个hidden_size用embed_size来作代替了,他说是为了体现一个区分。其他参数表示上区别也不算很大。
forward
的部分也可以说是“等价”的吧,IBM的语句更加简洁一点,season要求要传入input_lengths
,而IBM的则是默认其为None
,经过一个判断再决定要不要对data进行一个packed。- 至此,encoder结束,需要改变的可能只是一些参数上的对应,模型本身没有太大的差别。
DecoderRNN
- 同样继承于基类baseRNN
- IBM的attention部分是“合进来”一起写的,用了一个
use_attention
的判断是否调用attention的部分,而season的是两个模型分开的,一个是普通的Decoder一个是AttenDecoder。 - season多了一个
speaker_embedding
和speaker_out
,以及在每一个GRUcell中season传入的都是上一次的output单词和上一次的隐藏状态还有人物向量,所以他的input_size
是self.hidden_size + self.embed_size + self.speaker_embed_size
,而IBM的则为hidden_size
,我想应该是没有用到前面的output单词的。 - 关于forward的部分,拆成了forward_step和forward两个。step的话就是进一个cell,与season在train中写的“循环”作用类似。而season的decoder更像是IBM的forward_step,一次只有一个GRU cell。season的“循环”在IBM的forward部分有类似的循环代码。
- 不是很明白他的symbols,ret_dict是拿来干什么的。还有就是双向的RNN我也不是很懂,但是season和IBM都写的双向的。
- 在改动的时候可以注意添加speaker的部分,以及一些参数维度的更改。
seq2seq
- 跟season的不一样的地方在于seq2seq把encoder和decoder包装了起来。
- 不是很懂为什么这里会多一个
decode_function
,default设置成了log_softmax,个人觉得这个应该是为了用于“判别模型”,过一个softmax之后可以用来分类。 - 不是很懂
flatten_parameters
是拿来干嘛的。
SUM
- season和IBM定义的loss是一样的,虽然训练的时候s在变,但是并没有把s加入到loss的考量中,还是在算 生成的句子和target的差距,只是顺带一起更新s。
- 在复现的时候只需要在decoder加入s的变化,以及evaluate的部分改一下。
1.1
GPU的调用
-
直接在终端中设定:
CUDA_VISIBLE_DEVICES=1 python my_script.py
-
Python代码中设定:
import os os.environ["CUDA_VISIBLE_DEVICES"] = "2"
-
使用函数 set_device
import torch torch.cuda.set_device(id)
判别模型需要更改的地方
trainer
-
_train_epoches
-
loss = self._train_batch(input_variables, input_lengths.tolist(), target_variables, model, teacher_forcing_ratio)
Checkpoint
- 目前我的做法是全部去掉了
output_vocab