Task01
线性回归
基本要素
*在进行矩阵计算时,采用向量的计算来提高计算效率。
相关代码段(非pytorch)
模型:
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
数据集的读取:
def data_iter(batch_size, features, labels):
num_examples = len(features) #特征
indices = list(range(num_examples))
random.shuffle(indices) # 随机
for i in range(0, num_examples, batch_size):
j = torch.LongTensor(indices[i: min(i + batch_size, num_examples)]) # the last time may be not enough for a whole batch
yield features.index_select(0, j), labels.index_select(0, j)
均方误差损失函数的定义:
def squared_loss(y_hat, y):
return (y_hat - y.view(y_hat.size())) ** 2 / 2
优化函数的定义:
def sgd(params, lr, batch_size):
for param in params:
param.data -= lr * param.grad / batch_size # ues .data to operate param without gradient track
softmax
概念
图像分类预测中得到的多个离散值,将其变换为正且和为1的概率分布:
y
^
1
,
y
^
2
,
y
^
3
=
softmax
(
o
1
,
o
2
,
o
3
)
\hat{y}_1, \hat{y}_2, \hat{y}_3 = \text{softmax}(o_1, o_2, o_3)
y^1,y^2,y^3=softmax(o1,o2,o3)
*易得softmax不改变输出类别
*函数不变性
softmax函数的常数不变性,即softmax(x)=softmax(x+c),推导如下:
s o f t m a x ( x i ) = e x p ( x i ) ∑ j e x p ( x j ) softmax(x_i)=\frac{exp(x_i)}{\sum_jexp(x_j)} softmax(xi)=∑jexp(xj)exp(xi)
( s o f t m a x ( x + c ) ) i = e x p ( x i + c ) ∑ j e x p ( x j + c ) = e x p ( c ) e x p ( x i ) e x p ( c ) ∑ j e x p ( x j ) = e x p ( x i ) ∑ j e x p ( x j ) = ( s o f t m a x ( x ) ) i (softmax(x+c))_i=\frac{exp(x_i+c)}{\sum_j exp(x_j+c)}=\frac{exp(c)exp(x_i)}{exp(c)\sum_jexp(x_j)}=\frac{exp(x_i)}{\sum_jexp(x_j)}=(softmax(x))_i (softmax(x+c))i=∑jexp(xj+c)exp(xi+c)=exp(c)∑jexp(xj)exp(c)exp(xi)=∑jexp(xj)exp(xi)=(softmax(x))i
上面的exp©之所以可以消除,是因为exp(a+b)=exp(a)*exp(b)这个特性将exp©提取出来了。在计算softmax概率的时候,为了保证数值稳定性(numerical stability),我们可以选择给输入项减去一个常数,比如x的每个元素都要减去一个x中的最大元素。当输入项很大的时候,如果不减这样一个常数,取指数之后结果会变得非常大,发生溢出的现象,导致结果出现inf。
交叉熵损失函数
使用平方损失估计并不需要预测概率完全等于标签概率,即在分类正确的情况下,其他的预测概率则不影响预测。因此采用交叉熵(cross entropy)是一个常用的衡量方法:
H
(
y
(
i
)
,
y
^
(
i
)
)
=
−
∑
j
=
1
q
y
j
(
i
)
log
y
^
j
(
i
)
,
H\left(\boldsymbol y^{(i)}, \boldsymbol {\hat y}^{(i)}\right ) = -\sum_{j=1}^q y_j^{(i)} \log \hat y_j^{(i)},
H(y(i),y^(i))=−j=1∑qyj(i)logy^j(i),
详见:详解机器学习中的熵、条件熵、相对熵和交叉熵
预测与输出
预测概率最大的类别作为输出类别。如果它与真实类别(标签)一致,说明这次预测是正确的。
相关代码块
softmax定义
def softmax(X):
X_exp = X.exp()
partition = X_exp.sum(dim=1, keepdim=True)
# print("X size is ", X_exp.size())
# print("partition size is ", partition, partition.size())
return X_exp / partition # 这里应用了广播机制
回归模型
def net(X):
return softmax(torch.mm(X.view((-1, num_inputs)), W) + b)
损失函数
y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])
y = torch.LongTensor([0, 2])
y_hat.gather(1, y.view(-1, 1))
*准确性的定义
def accuracy(y_hat, y):
return (y_hat.argmax(dim=1) == y).float().mean().item()
多层感知机
概念:**多层感知机就是含有至少一个隐藏层的由全连接层组成的神经网络,且每个隐藏层的输出通过激活函数进行变换。**加入了隐藏层(Hidden Layer),隐藏层输出直接作为输出层的输入,直接公式可得:
O
=
(
X
W
h
+
b
h
)
W
o
+
b
o
=
X
W
h
W
o
+
b
h
W
o
+
b
o
.
\boldsymbol{O} = (\boldsymbol{X} \boldsymbol{W}_h + \boldsymbol{b}_h)\boldsymbol{W}_o + \boldsymbol{b}_o = \boldsymbol{X} \boldsymbol{W}_h\boldsymbol{W}_o + \boldsymbol{b}_h \boldsymbol{W}_o + \boldsymbol{b}_o.
O=(XWh+bh)Wo+bo=XWhWo+bhWo+bo.
即只是做了简单的映射工作,因此加入激活函数(进行非线性变换):
ReLU
(
x
)
=
max
(
x
,
0
)
.
\text{ReLU}(x) = \max(x, 0).
ReLU(x)=max(x,0).
*激活函数根据所需网络功能进行选择,sigmoid,tanh,ReLu。
*梯度消失问题,有时要避免使用sigmoid和tanh函数。 ReLU在x<0部分会有梯度消失问题,但只有一半;所以后续有Leaky ReLU来缓解这个问题,绝大多数情况下使用ReLu
相关代码块
获取训练集
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size,root='/home/kesci/input/FashionMNIST2065')
定义模型参数
num_inputs, num_outputs, num_hiddens = 784, 10, 256
W1 = torch.tensor(np.random.normal(0, 0.01, (num_inputs, num_hiddens)), dtype=torch.float)
b1 = torch.zeros(num_hiddens, dtype=torch.float)
W2 = torch.tensor(np.random.normal(0, 0.01, (num_hiddens, num_outputs)), dtype=torch.float)
b2 = torch.zeros(num_outputs, dtype=torch.float)
params = [W1, b1, W2, b2]
for param in params:
param.requires_grad_(requires_grad=True)
定义激活函数
def relu(X):
return torch.max(input=X, other=torch.tensor(0.0))
定义网络
def net(X):
X = X.view((-1, num_inputs))
H = relu(torch.matmul(X, W1) + b1)
return torch.matmul(H, W2) + b2
定义损失函数
loss = torch.nn.CrossEntropyLoss()
Task02
文本预处理(基本方法)
-
文本读入。将文本预设为单词的序列。
-
分词。讲句子划分为若干个词[token],文本即变成词的序列。
*特殊的token:pad:使得短句子和长的相同,在sgd的时候批次的句子一样长; bos/eos 为开始结束 ;unk未知字符,比如无论use_special_token参数是否为真,都会使用的特殊token是unk。
-
建立字典。讲文本转换为数字(可处理),每个词映射到一个唯一的索引编号。
-
词转为索引。原文本中的句子从单词序列转换为索引序列。
*在这种粗略的规则下,标点符号在句中隐含的语义信息被忽略,如"doesn’t",“Mr.”。
*中文存在词的语义比英文更为复杂,词表和无关词表方式(?)
*中文的分词工具目前大多数使用的是jieba
语言模型
概念
一段自然语言文本可以看作是一个离散时间序列,语言模型的目标就是评估该序列是否合理,即计算该序列的概率。
词的概率可以通过该词在训练数据集中的相对词频来计算,概率的计算:
P
^
(
w
1
)
=
n
(
w
1
)
n
\hat P(w_1) = \frac{n(w_1)}{n}
P^(w1)=nn(w1)
n为语料库中文本总的数量。
n元语法
序列长度增加,计算和存储多个词共同出现的概率的复杂度会呈指数级增加。n元语法通过马尔可夫假设简化模型,马尔科夫假设是指一个词的出现只与前面n个词相关,即n阶马尔可夫链(Markov chain of order nn),如果n=1n=1,那么有P(w3∣w1,w2)=P(w3∣w2)P(w3∣w1,w2)=P(w3∣w2)。基于n−1n−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=1∏TP(wt∣wt−(n−1),…,wt−1).
以上也叫n元语法(n-grams),它是基于n−1阶马尔可夫链的概率语言模型。例如,当n=2n=2时,含有4个词的文本序列的概率就可以改写为:
当n分别为1、2和3时,我们将其分别称作一元语法(unigram)、二元语法(bigram)和三元语法(trigram)。例如,长度为4的序列w1,w2,w3,w4w1,w2,w3,w4在一元语法、二元语法和三元语法中的概率分别为
当n较小时,n元语法往往并不准确。例如,在一元语法中,由三个词组成的句子“你走先”和“你先走”的概率是一样的。然而,当n较大时,n元语法需要计算并存储大量的词频和多词相邻频率。(需要靠大量文本经验积累)
循环神经网络
基于循环神经网络实现语言模型。我们的目的是基于当前的输入与过去的输入序列,预测序列的下一个字符。循环神经网络引入一个隐藏变量H,用Ht表示H在时间步t的值。Ht的计算基于Xt和Ht−1,可以认为Ht记录了到当前字符为止的序列信息,利用Ht对序列的下一个字符进行预测。
输出:
*one-hot向量:假设词典大小是N,每次字符对应一个从0到N−1的唯一的索引,则该字符的向量是一个长度为N的向量,若字符的索引是i,则该向量的第i个位置为1,其他位置为0。
*裁剪梯度:循环神经网络中较容易出现梯度衰减或梯度爆炸,这会导致网络几乎无法训练。裁剪梯度(clip gradient)是一种应对梯度爆炸的方法。假设我们把所有模型参数的梯度拼接成一个向量 g,并设裁剪的阈值是θ。裁剪后的梯度的L2范数不超过θ
min
(
θ
∥
g
∥
,
1
)
g
\min\left(\frac{\theta}{\|\boldsymbol{g}\|}, 1\right)\boldsymbol{g}
min(∥g∥θ,1)g
*困惑度:评价模型
-
W_xh: 状态-输入权重
-
W_hh: 状态-状态权重
-
W_hq: 状态-输出权重
-
b_h: 隐藏层的偏置
-
b_q: 输出层的偏置循环
-
神经网络的参数就是上述的三个权重和两个偏置,并且在沿着时间训练(参数的更新),参数的数量没有发生变化,仅仅是上述的参数的值在更新。循环神经网络可以看作是沿着时间维度上的权值共享。