用RNN写诗
- 1. 背景
-
- 1.1 词向量
- 1.2 RNN
- 2. CharRNN
- 3. 用PyTorch实现CharRNN
- 4. 结果分析
- 参考资料
1. 背景
自然语言处理(Natural Language Processing, NLP)
是人工智能和语言学领域的分支学科,涉及研究方向宽泛,包括机器翻译、句法分析、信息检索等。 回顾两个基本概念:。
1.1 词向量
自然语言处理主要研究语言信息。语言由单词和单词组成,可以将语言转换为单词或单词的集合。常用于方便One-Hot该方法解决了分类器难以处理属性的问题(Categorical)数据问题的缺点是冗余过多,无法反映词与词之间的关系。而且在深度学习中,维度灾难经常发生,因此在深度学习中采用词向量的表现形式。
词向量(Word Vector)
,也被称为词嵌入(Word Embedding)
。从概念上讲,它是指将一个维数为所有单词数量的高维空间(数万个单词和数十万个单词)嵌入一个维数要低得多的连续向量空间(通常是128或256维),每个单词或短语都映射成实数域的向量。
词向量采用特殊的训练方法,如GloVe
。这里,词向量最重要的特点是相似词的词向量相似。每个单词的词向量维度是固定的,每个维度是连续的。
在PyTorch在中间,有一个特殊的词向量层nn.Embedding
,用来 注意:Embedding权重也可以训练,可以随机初始化,也可以预训练好的词向量初始化。
1.2 RNN
RNN, 通过每次使用前一个词的状态,可以解决词与词之间的依赖问题(hidden state)结合当前词计算新状态。网络结构如下图所示:
- x 1 , x 2 , x 3 , . . . , x T x_1,x_2,x_3,...,x_T x1,x2,x3,...,xT:输入词的序列(共有T个词),每个词都是一个向量,通常用词向量表示。
- S 0 , S 1 , S 2 , S 3 , . . . S T S_0,S_1,S_2,S_3,...S_T S0,S1,S2,S3,...ST:隐层元(共有T+1个),每个隐藏元都由之前的词计算得到,所以可以认为包含之前所有词的信息。 S 0 S_0 S0表示初始信息,一般采用全0的向量进行初始化。
- f f f:转换函数,根据当前输入 X t X_t Xt和前一个隐藏元的状态( S t − 1 S_{t-1} St−1),计算新的隐藏元状态 S t S_t St。可以认为 S t − 1 S_{t-1} St−1包含前 t − 1 t-1 t−1个词的信息,即 x 1 , x 2 , . . . , x t − 1 x_1,x_2,...,x_{t-1} x1,x2,...,xt−1,由 f f f利用 S t − 1 S_{t-1} St−1和 x t x_t xt计算得到的 S t S_t St,可以认为是包含前t个词的信息。需要注意的是,每一次计算 S t S_t St都用同一个 f f f。 f f f一般是一个矩阵乘法运算。
RNN最后会输出所有隐藏元的信息,一般只使用最后一个隐藏元的信息,可以认为它包含了整个句子的信息。
但是这种结构的RNN具有严重的梯度消失
和梯度爆炸
问题,难以训练。目前在深度学习中普遍使用的是一种称为LSTM的RNN结构。LSTM(Long Short Term Meomory Network, 长短期记忆网络),如下图所示: LSTM也是通过不断利用之前的状态和当前的输入来计算新的状态,但是其f函数更复杂,除了隐藏元状态(hidden state h),还有cell state c。每个LSTM单元的输出有两个,一个是下面的 h t h_t ht( h t h_t ht同时被创建分支引到上面去),一个是上面的 c t c_t ct。 c t c_t ct的存在能很好地抑制梯度消失和梯度爆炸等问题。
输入门
控制当前计算的新状态以多大程度更新到记忆单元中;遗忘门
控制前一步记忆单元中的信息有多大程度上被遗忘掉;输出门
控制当前的输出有多大程度上取决于当前的记忆单元。
经典的LSTM中,第t步的更新计算公式为: i t = σ ( W i x t + U i h t − 1 + b i ) i_t=\sigma (W_ix_t+U_ih_{t-1}+b_i) it=σ(Wixt+Uiht−1+bi) f t = σ ( W f x t + U f h t − 1 + b f ) f_t=\sigma (W_fx_t+U_fh_{t-1}+b_f) ft=σ(Wfxt+Ufht−1+bf) o t = σ ( W o x t + U o h t − 1 + b o ) o_t=\sigma (W_ox_t+U_oh_{t-1}+b_o) ot=σ(Woxt+Uoht−1+bo) c ~ t = T a n h ( W c x t + U c h t − 1 ) \widetilde{c}_t=Tanh(W_cx_t+U_ch_{t-1}) c t=Tanh(Wcxt+Ucht−1) c t = f t ⊙ c t − 1 + i t ⊙ c ~ t c_t=f_t\odot c_{t-1}+i_t\odot \widetilde{c}_t ct=ft⊙ct−1+it⊙c t h t = o t ⊙ T a n h ( c t ) h_t=o_t\odot Tanh(c_t) ht=ot⊙Tanh(ct) 其中, i t i_t it是通过输入 x t x_t xt和上一步的隐含层输出 h t − 1 h_{t-1} ht−1进行线性变换,在经过激活函数 σ \sigma σ得到的。输入门 i t i_t it的结果是向量,其中每个元素是0到1之间的实数,用于控制各维度流过阀门的信