1.线性回归
用神经网络的方式来表示一个线性回归:
这是一个没有隐藏层的神经网络,输入层的数据和网络参数计算的结果直接输出的输出层。多层感知机的网络结构其实就是有很多这样的线性回归模型组合而成。
向量相加的两种方法:
1.两个向量按元素逐一做标量加法(通过循环将每个标量对应相加)。
2.两个向量直接做矢量加法。
矢量计算的运算速度更快,因此在计算中应尽量使用矢量计算方式。
使用pytorch训练一个神经网络的基本步骤:
- 读取数据(使用pytorch中的读取数据模块utils.data)
import torch.utils.data as Data
# combine featues and labels of dataset
dataset = Data.TensorDataset(features, labels)
# put dataset into DataLoader
data_iter = Data.DataLoader(
dataset=dataset, # torch TensorDataset format
batch_size=10, # mini batch size
shuffle=True, # whether shuffle the data or not
num_workers=2, # read data in multithreading
)
#输出数据
for X, y in data_iter:
print(X, '\n', y)
break
- 定义模型
class LinearNet(nn.Module):
def __init__(self, n_feature):
super(LinearNet, self).__init__() # call father function to init
self.linear = nn.Linear(n_feature, 1) # function prototype: `torch.nn.Linear(in_features, out_features, bias=True)`
def forward(self, x):
y = self.linear(x)
return y
net = LinearNet(num_inputs)
print(net)
定义多层网络的三种方法:
# ways to init a multilayer network
# method one
net = nn.Sequential(
nn.Linear(num_inputs, 1)
# other layers can be added here
)
# method two
net = nn.Sequential()
net.add_module('linear', nn.Linear(num_inputs, 1))
# net.add_module ......
# method three
from collections import OrderedDict
net = nn.Sequential(OrderedDict([
('linear', nn.Linear(num_inputs, 1))
# ......
]))
print(net)
print(net[0])
- 初始化模型参数
from torch.nn import init
init.normal_(net[0].weight, mean=0.0, std=0.01)
init.constant_(net[0].bias, val=0.0) # or you can use `net[0].bias.data.fill_(0)` to modify it directly
#查看网络参数
for param in net.parameters():
print(param)
- 定义损失函数
loss = nn.MSELoss() # nn built-in squared loss function
# function prototype: `torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')`
- 定义优化算法
import torch.optim as optim
optimizer = optim.SGD(net.parameters(), lr=0.03) # built-in random gradient descent function
print(optimizer) # function prototype: `torch.optim.SGD(params, lr=, momentum=0, dampening=0, weight_decay=0, nesterov=False)`
- 训练模型
num_epochs = 3
for epoch in range(1, num_epochs + 1):
for X, y in data_iter:
output = net(X)
l = loss(output, y.view(-1, 1))
optimizer.zero_grad() # reset gradient, equal to net.zero_grad()
l.backward()
optimizer.step()
print('epoch %d, loss: %f' % (epoch, l.item()))
需要注意的是在每次反向传播之前先将上一次计算的梯度清零。
2.Softmax回归与分类模型
线性回归预测一个值,Softmax回归预测多个值。Softmax回归从结构上来看其实是由多个线性回归组成。 如下图所示:
Softmax回归与分类的关系就是:softmax回归输出值的个数等于分类的个数,softmax回归输出的值的大小表示分类的可能性,取值最大的类别为样本的预测类别。直接使用输出值作为类别的置信度会有两个问题:
1.由于输出层的输出值的范围不确定,我们难以直观上判断这些值的意义。(我们只是取相对最大值,实际上该相对最大值在给定的输出值范围上可能很小)
2.由于真实标签是离散值,这些离散值与不确定范围的输出值之间的误差难以衡量。
3.多层感知机(MLP)
多层感知机从结构上可以看成是一个个线性回归的结构组合起来。
多层感知机包含了隐藏层和激活函数。
输入层的输出作为隐藏层的输入,隐藏层的输出再作为输出层的输入。
常见激活函数:
- RELU函数
RELU函数对应的图像:
RELU函数的导数对应的图像:
- sigmoid函数
sigmoid函数对应的图像:
sigmoid函数的导数对应的图像:
- tanh(双曲正切)函数
tanh函数的图像:
tanh函数的导数的图像:
4.文本预处理
文本预处理是自然语言处理中重要的一步就是为了将自然的文本处理成计算机能够计算的状态。
简单的预处理包含以下几步:
- 读文本
- 分词(使用分词工具)
- 去重,建立字典(词-索引)
- 根据字典,转换文本为索引的形式
5.语言模型
一段自然语言文本可以看作是一个离散时间序列,给定一个长度为T的词的序列
w
1
,
w
2
,
…
,
w
T
w_1, w_2, \ldots, w_T
w1,w2,…,wT,语言模型的目标就是评估该序列是否合理,即计算该序列的概率:
P
(
w
1
,
w
2
,
…
,
w
T
)
=
∏
t
=
1
T
P
(
w
t
∣
w
1
,
…
,
w
t
−
1
)
=
P
(
w
1
)
P
(
w
2
∣
w
1
)
⋯
P
(
w
T
∣
w
1
w
2
⋯
w
T
−
1
)
\begin{aligned} P(w_1, w_2, \ldots, w_T) &= \prod_{t=1}^T P(w_t \mid w_1, \ldots, w_{t-1})\\ &= P(w_1)P(w_2 \mid w_1) \cdots P(w_T \mid w_1w_2\cdots w_{T-1}) \end{aligned}
P(w1,w2,…,wT)=t=1∏TP(wt∣w1,…,wt−1)=P(w1)P(w2∣w1)⋯P(wT∣w1w2⋯wT−1)
n元语法
序列长度增加,计算和存储多个词共同出现的概率的复杂度会呈指数级增加。n元语法通过马尔可夫假设简化模型,马尔科夫假设是指一个词的出现只与前面n个词相关,即n阶马尔可夫链(Markov chain of order n),如果n=1,那么有
P
(
w
3
∣
w
1
,
w
2
)
=
P
(
w
3
∣
w
2
)
P(w_3 \mid w_1, w_2) = P(w_3 \mid w_2)
P(w3∣w1,w2)=P(w3∣w2)。
基于n−1阶马尔可夫链,我们可以将语言模型改写为
P ( w 1 , w 2 , … , w T ) = ∏ t = 1 T P ( w t ∣ w t − ( n − 1 ) , … , w t − 1 ) P(w_1, w_2, \ldots, w_T) = \prod_{t=1}^T P(w_t \mid w_{t-(n-1)}, \ldots, w_{t-1}) P(w1,w2,…,wT)=∏t=1TP(wt∣wt−(n−1),…,wt−1)
以上也叫n元语法(n-grams),它是基于n−1阶马尔可夫链的概率语言模型。例如,当n=2时,含有4个词的文本序列的概率就可以改写为:
P ( w 1 , w 2 , w 3 , w 4 ) = P ( w 1 ) P ( w 2 ∣ w 1 ) P ( w 3 ∣ w 1 , w 2 ) P ( w 4 ∣ w 1 , w 2 , w 3 ) = P ( w 1 ) P ( w 2 ∣ w 1 ) P ( w 3 ∣ w 2 ) P ( w 4 ∣ w 3 ) \begin{aligned} P(w_1, w_2, w_3, w_4) &= P(w_1) P(w_2 \mid w_1) P(w_3 \mid w_1, w_2) P(w_4 \mid w_1, w_2, w_3)\\ &= P(w_1) P(w_2 \mid w_1) P(w_3 \mid w_2) P(w_4 \mid w_3) \end{aligned} P(w1,w2,w3,w4)=P(w1)P(w2∣w1)P(w3∣w1,w2)P(w4∣w1,w2,w3)=P(w1)P(w2∣w1)P(w3∣w2)P(w4∣w3)
当n分别为1、2和3时,我们将其分别称作一元语法(unigram)、二元语法(bigram)和三元语法(trigram)
n元语法缺陷:参数空间过大,数据稀疏
时序数据采样
-
随机采样
随机采样中的每个batch的样本之间是不连续的 -
相邻采样
相邻采样每个batch的样本之间是连续的
6.循环神经网络
循环神经网络公式描述:
H t = ϕ ( X t W x h + H t − 1 W h h + b h ) . \boldsymbol{H}_t = \phi(\boldsymbol{X}_t \boldsymbol{W}_{xh} + \boldsymbol{H}_{t-1} \boldsymbol{W}_{hh} + \boldsymbol{b}_h). Ht=ϕ(XtWxh+Ht−1Whh+bh).
其中, H t − 1 \boldsymbol{H}_{t-1} Ht−1是上一时刻的状态, W x h \boldsymbol{W}_{xh} Wxh是输入层权重, W h h \boldsymbol{W}_{hh} Whh是隐藏层之间的权重,在循环神经网络中,每个时间步共享参数 W x h \boldsymbol{W}_{xh} Wxh , W h h \boldsymbol{W}_{hh} Whh以及输出层权重 W q h \boldsymbol{W}_{qh} Wqh
所以
H
t
\boldsymbol{H}_t
Ht能够捕捉历史信息,就像拥有记忆一样。通过计算当前步的输出,就可以进行预测下一步的信息。
O
t
=
H
t
W
h
q
+
b
q
.
\boldsymbol{O}_t = \boldsymbol{H}_t \boldsymbol{W}_{hq} + \boldsymbol{b}_q.
Ot=HtWhq+bq.