Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/_sources/第三章/3.6 损失函数.md.txt
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ print('TripletMarginLoss损失函数的计算结果为',output)
TripletMarginLoss损失函数的计算结果为 tensor(1.1667, grad_fn=<MeanBackward0>)


## 3.5.13 HingEmbeddingLoss
## 3.5.13 HingeEmbeddingLoss
```python
torch.nn.HingeEmbeddingLoss(margin=1.0, size_average=None, reduce=None, reduction='mean')
```
Expand Down Expand Up @@ -550,12 +550,12 @@ $
loss_f = nn.HingeEmbeddingLoss()
inputs = torch.tensor([[1., 0.8, 0.5]])
target = torch.tensor([[1, 1, -1]])
output = loss_f(inputs,target)
output = loss_f(inputs, target)

print('HingEmbeddingLoss损失函数的计算结果为',output)
print('HingeEmbeddingLoss损失函数的计算结果为',output)
```

HingEmbeddingLoss损失函数的计算结果为 tensor(0.7667)
HingeEmbeddingLoss损失函数的计算结果为 tensor(0.7667)


## 3.5.14 余弦相似度
Expand Down
34 changes: 17 additions & 17 deletions docs/_sources/第十章/LSTM解读及实战.md.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# 文章结构
# LSTM解读及实战

在[RNN详解及其实战](./RNN%E8%AF%A6%E8%A7%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0.md)中,我们简单讨论了为什么需要RNN这类模型、RNN的具体思路、RNN的简单实现等问题。同时,在文章结尾部分我们提到了RNN存在的梯度消失问题,及之后的一个解决方案:**LSTM**。因此,本篇文章主要结构如下:
在[RNN详解及其实现](./RNN%E8%AF%A6%E8%A7%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0.md)中,我们简单讨论了为什么需要RNN这类模型、RNN的具体思路、RNN的简单实现等问题。同时,在文章结尾部分我们提到了RNN存在的梯度消失问题,及之后的一个解决方案:**LSTM**。因此,本篇文章主要结构如下:

1. LSTM 理解及简单实现
2. LSTM 实战
3. 经典 RNN 与 LSTM 对比
4. 关于梯度消失

# LSTM 理解
## LSTM 理解

其实,我们将 LSTM 与 RNN 说成两个并不可取, LSTM 依然归属于 RNN 之下,相比于使用线性回归方式来处理序列问题, LSTM 其实是设计了一个模块来取代线性回归算法。

Expand All @@ -23,7 +23,7 @@ LSTM(Long Short-Term Memory),翻译过来是长短期记忆法,其核心思


我们在分析三个门之前,我们先了解 **门** 这一概念。
## 门
###

从简化图中可以看到, **门**的感觉类似于电路中的一个开关,当开关按下,信息通过,而开关抬起,信息不再通过。实际也如此类似,**门**是一个全连接层,输入为一个向量,输出为一个位于 [0,1] 之间的值。
我们来设计一个非常简单的遗忘门:每次学习状态之后,都遗忘一定的已学习内容,注意,这里的遗忘门与 LSTM 的遗忘门无关,单纯理解 **门** 这一概念。
Expand Down Expand Up @@ -67,7 +67,7 @@ final_out = gate * mid_out

在有了对门的基础知识后,接下来对遗忘门、记忆门、输出门进行分别分析。

## 遗忘门
### 遗忘门

遗忘门涉及部分如下图所示:
![LSTM-遗忘门](./figures/LSTM-gate_f.jpg)
Expand All @@ -84,7 +84,7 @@ $$

一部分的 $C_{t-1}$ 就这样被遗忘了。

## 记忆门
### 记忆门

记忆门涉及部分如下所示:
![LSTM记忆门](./figures/LSTM-gate_m.jpg)
Expand All @@ -108,7 +108,7 @@ $$

我们可以说 $\tilde{C_t'}$ 是保留了一定内容的短期状态

## 状态更新
### 状态更新

![LSTM-状态更新](./figures/LSTM-update.jpg)

Expand All @@ -118,7 +118,7 @@ $$
C_t = C_t' + \tilde{C_t'}
$$

## 输出门
### 输出门

![LSTM输出门](./figures/LSTM-gate_o.jpg)

Expand All @@ -133,7 +133,7 @@ $$



## 模型总结
### 模型总结

可以看到,所有公式的核心部分都是如此的相似:
$$
Expand All @@ -144,9 +144,9 @@ $$
最后总的来看,LSTM 其实就是一个升级版本的的 RNN,他额外初始化了一个状态 $C$, 用来保存长期的记忆,控制远距离上的参数权重。而输出也基本类似于此。


# LSTM 实战
## LSTM 实战

## 实验说明
### 实验说明

完整代码实现可以点击[这里](../../notebook/第十章%20常见网络代码的解读/LSTM实战.ipynb)下载。在完整代码中,我们共计使用了三个模型并对比了他们的效果,三个模型分别是:由我完全使用 `nn.Linear` 实现的 LSTM 模型、 使用 `nn.LSTM` 为基础的 LSTM 模型和使用 `nn.RNN` 为基础实现的 RNN 模型。

Expand All @@ -159,7 +159,7 @@ $$
为了证明模型真的有学习到一定的内容,所以对比实验中部分参数可能存在部分区别,可以在本地调整到同一参数进行细致的对比实验。


## 模型实现
### 模型实现

我们在这里分析一下由我实现的 LSTM 模型,并以此了解 LSTM 模型。(ps:个人能力有限,没能实现 `num_layers` 和 `Bi-LSTM` 两个特点,此外可能实现存在其他问题,欢迎给予反馈)
```python
Expand Down Expand Up @@ -210,9 +210,9 @@ class LSTM(nn.Module):
```


## 超参数及参数说明
### 超参数及参数说明

### MyLSTM 与 nn.LSTM
#### MyLSTM 与 nn.LSTM

名称 | 值
-- | --
Expand All @@ -231,7 +231,7 @@ nn.LSTM 参数量: 99328

另外在代码实现中 `nn.LSTM` 后面加了一个 `nn.Linear` 来实现二分类,参数量为 258, 所以 MyLSTM 和 LSTM 相差参数总量为 512。

### nn.RNN
#### nn.RNN

名称 | 值
-- | --
Expand All @@ -249,14 +249,14 @@ nn.RNN 参数量: 25090

举例来说,某学生学习阅读理解,要求根据文章内容回答文章的情感倾向,但是学生只喜欢看最后一句话,每次都根据最后一句话来回答问题,那么他基本上是等于瞎猜的,只能学到一点浅薄的知识。

## 实验结果
### 实验结果

MyLSTM | nn.LSTM | nn.RNN
-- | -- | --
0.86 | 0.80 | 0.67


# 关于梯度问题
## 关于梯度问题

- RNN问题中,**总的梯度是不会消失的**。即便梯度越传越弱,那也是远处的梯度逐渐消失,而近距离的梯度不会消失,因此,梯度总和不会消失。RNN 梯度消失的真正含义是:梯度被近距离梯度所主导,导致模型难以学到远距离的依赖关系。

Expand Down
10 changes: 5 additions & 5 deletions docs/_sources/第十章/RNN详解及其实现.md.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# 文章结构
# RNN详解及其实现
提及 RNN,绝大部分人都知道他是一个用于序列任务的神经网络,会提及他保存了时序信息,但是,为什么需要考虑时序的信息?为什么说 RNN 保存了时序的信息?RNN又存在哪些问题? 本篇内容将按照以下顺序逐步带你摸清 RNN 的细节之处,并使用 PyTorch 来完成一个自己的文本分类模型。

1. 为什么需要 RNN?
2. RNN 理解及其简单实现。
3. 用 RNN 完成文本分类任务。
4. RNN 存在的问题。

# 为什么需要 RNN?
## 为什么需要 RNN?
在现实生活的世界中,有很多的内容是有着前后关系的,比如你所阅读的这段文字,他并不是毫无理由的随机组合,而是我构思之后按顺序写下的一个个文字。除了文字之外,例如人的发音、物品的价格的曲线、温度变化等等,都是有着前后顺序存在的。

很明显,当知道了前面的信息,就可以对后面的信息进行合理的预测。比如,前十天温度都只有20度,明天的温度无论如何不可能零下;这个商品一年来价格都在30左右浮动,明天我去买他的时候,准备40就足够了;老师很好的表扬了你,紧跟着说了一个但是,你就知道他的内容要开始转折了。这就是隐藏在日常生活中的序列信息,因为已经知道了前面发生的内容,所以才可以推理后面的内容。
Expand All @@ -31,7 +31,7 @@ $$

上面提到的两个问题,使用多层感知机本身似乎难以解决,但是所幸,RNN 从一个更常规的思路出发来解决这个问题:**记住之前看到的内容,并结合当前看到的内容,来预测之后可能的内容。**

# RNN 理解及其简单实现
## RNN 理解及其简单实现
根据开篇的内容,相信你已经可以简单的理解为什么传统的多层感知机无法很好的解决序列信息,接下来我们开始理解,RNN 如何记忆之前的内容的。

在这里,我先放出 RNN 的公式,请将其与多层感知机公式进行对比:
Expand Down Expand Up @@ -95,7 +95,7 @@ class RNNDemo(nn.Module):

在理解了 RNN 来龙去脉之后,接下来开始从 RNN 的在实际文本分类中进行更深入的分析。(注:该样例源自 [Torch 官方教程](https://pytorch.org/tutorials/intermediate/char_rnn_classification_tutorial.html))。

# RNN 完成文本分类任务
## RNN 完成文本分类任务
完成一个基本的算法任务,有以下流程:数据分析、数据转换、构建模型、定义训练函数、执行训练、保存模型、评估模型。

这里摘取官方教程中部分关键代码进行讲解,可以直接[点击这里](https://pytorch.org/tutorials/_downloads/13b143c2380f4768d9432d808ad50799/char_rnn_classification_tutorial.ipynb)直接下载官方 notebook进行训练。训练所用数据位于[这里](https://download.pytorch.org/tutorial/data.zip)。
Expand Down Expand Up @@ -197,7 +197,7 @@ for iter in range(1, n_iters + 1):

再简单的举一反三,可以结合之前所学的 word2vec、Glovec 等模型将词语转为向量,将一句话转为一个序列,每个词转为序列中的一个值,这样的话,就可以对一句话进行文本分类了。

# RNN 存在的问题
## RNN 存在的问题

前面讲解了 RNN 是如何解决简单神经网络无法处理序列问题的,但是 RNN 是否就完美无缺?能应用于全部的序列任务了呢?答案当然是否定的。

Expand Down
8 changes: 7 additions & 1 deletion docs/_sources/第十章/Transformer 解读.md.txt
Original file line number Diff line number Diff line change
Expand Up @@ -439,18 +439,24 @@ def subsequent_mask(size):
​Attention 机制可以实现良好的并行计算,但同时,其注意力计算的方式也导致序列中相对位置的丢失。在 RNN、LSTM 中,输入序列会沿着语句本身的顺序被依次递归处理,因此输入序列的顺序提供了极其重要的信息,这也和自然语言的本身特性非常吻合。但从上文对 Attention 机制的分析我们可以发现,在 Attention 机制的计算过程中,对于序列中的每一个 token,其他各个位置对其来说都是平等的,即“我喜欢你”和“你喜欢我”在 Attention 机制看来是完全相同的,但无疑这是 Attention 机制存在的一个巨大问题。因此,为使用序列顺序信息,保留序列中的相对位置信息,Transformer 采用了位置编码机制,该机制也在之后被多种模型沿用。

​位置编码,即根据序列中 token 的相对位置对其进行编码,再将位置编码加入词向量编码中。位置编码的方式有很多,Transformer 使用了正余弦函数来进行位置编码,其编码方式为:

$$
PE(pos, 2i) = sin(pos/10000^{2i/d_{model}})\\
PE(pos, 2i+1) = cos(pos/10000^{2i/d_{model}})
$$
​上式中,pos 为 token 在句子中的位置,2i 和 2i+1 则是指示了 token 是奇数位置还是偶数位置,从上式中我们可以看出对于奇数位置的 token 和偶数位置的 token,Transformer 采用了不同的函数进行编码。我们以一个简单的例子来说明位置编码的计算过程:假如我们输入的是一个长度为 4 的句子"I like to code",我们可以得到下面的词向量矩阵$\rm x$,其中每一行代表的就是一个词向量,$\rm x_0=[0.1,0.2,0.3,0.4]$对应的就是“I”的词向量,它的pos就是为0,以此类推,第二行代表的是“like”的词向量,它的pos就是1:

​上式中,pos 为 token 在句子中的位置,2i 和 2i+1 则是指示了 token 是奇数位置还是偶数位置,从上式中我们可以看出对于奇数位置的 token 和偶数位置的 token,Transformer 采用了不同的函数进行编码。我们以一个简单的例子来说明位置编码的计算过程:假如我们输入的是一个长度为 4 的句子"I like to code",我们可以得到下面的词向量矩阵 $\rm x$,其中每一行代表的就是一个词向量,$\rm x_0=[0.1,0.2,0.3,0.4]$ 对应的就是"I"的词向量,它的pos就是为0,以此类推,第二行代表的是"like"的词向量,它的pos就是1:

$$
\rm x = \begin{bmatrix} 0.1 & 0.2 & 0.3 & 0.4 \\ 0.2 & 0.3 & 0.4 & 0.5 \\ 0.3 & 0.4 & 0.5 & 0.6 \\ 0.4 & 0.5 & 0.6 & 0.7 \end{bmatrix}
$$

​则经过位置编码后的词向量为:

$$
\rm x_{PE} = \begin{bmatrix} 0.1 & 0.2 & 0.3 & 0.4 \\ 0.2 & 0.3 & 0.4 & 0.5 \\ 0.3 & 0.4 & 0.5 & 0.6 \\ 0.4 & 0.5 & 0.6 & 0.7 \end{bmatrix} + \begin{bmatrix} \sin(\frac{0}{10000^0}) & \cos(\frac{0}{10000^0}) & \sin(\frac{0}{10000^{2/4}}) & \cos(\frac{0}{10000^{2/4}}) \\ \sin(\frac{1}{10000^0}) & \cos(\frac{1}{10000^0}) & \sin(\frac{1}{10000^{2/4}}) & \cos(\frac{1}{10000^{2/4}}) \\ \sin(\frac{2}{10000^0}) & \cos(\frac{2}{10000^0}) & \sin(\frac{2}{10000^{2/4}}) & \cos(\frac{2}{10000^{2/4}}) \\ \sin(\frac{3}{10000^0}) & \cos(\frac{3}{10000^0}) & \sin(\frac{3}{10000^{2/4}}) & \cos(\frac{3}{10000^{2/4}}) \end{bmatrix} = \begin{bmatrix} 0.1 & 1.2 & 0.3 & 1.4 \\ 1.041 & 0.84 & 0.41 & 1.49 \\ 1.209 & -0.016 & 0.52 & 1.59 \\ 0.541 & -0.489 & 0.895 & 1.655 \end{bmatrix}
$$

我们可以使用如下的代码来获取上述例子的位置编码:
```python
import numpy as np
Expand Down
Loading