第三章 线性神经网络
介绍神经?络的整个训练过程,包括:定义简单的神经?络架构、数据处理、指定损失函数和如何训练模型。
3.1 线性回归
回归regression是能为一个或多个自变量与因变量之间关系建模的一类方法。回归经常用来表示输入和输出之间的关系,与预测任务有关
3.1.1 线性回归linear regression的基本元素
线性回归在回归的各种标准?具中最简单而且最流?。 线性回归基于的简单假设:?先,假设?变量x和因变量y之间的关系是线性的,即y可以表?为x中元素的加权和,这?通常允许包含观测值的?些噪声;其次,我们假设任何噪声都?较正常,如噪声遵循正态分布。 专有名词: 为了开发?个能预测房价的模型,我们需要收集?个真实的数据集。这个数据集包括了房屋的销售价格、?积和房龄。在机器学习的术语中,该数据集称为训练数据集(training data set)或训练集(training set)。 每?数据(?如?次房屋交易相对应的数据)称为样本(sample),也可以称为数据点(data point)或数据样本(data instance)。 我们把试图预测的?标(?如预测房屋价格)称为标签(label)或?标(target)。 预测所依据的?变量(?积和房龄)称为特征(feature)或协变量(covariate)。
线性模型
在开始寻找最好的模型参数(model parameters)w和b之前,我们还需要两个东西:(1)?种模型质量的度量?式;(2)?种能够更新模型以提?模型预测质量的?法。
损失函数
解析解
随机梯度下降
即使在我们?法得到解析解的情况下,我们仍然可以有效地训练模型。弄清楚如何训练这些难以优化的模型。
梯度下降(gradient descent)这种?法?乎可以优化所有深度学习模型。它通过不断地在损失函数递减的?向上更新参数来降低误差。
梯度下降最简单的?法是计算损失函数(数据集中所有样本的损失均值)关于模型参数的导数(在这?也可以称为梯度)。但实际中的执?可能会?常慢:因为在每?次更新参数之前,我们必须遍历整个数据集。因此,我们通常会在每次需要计算更新的时候随机抽取?小批样本,这种变体叫做小批量随机梯度下降(minibatch stochastic gradient descent)。
用模型进行预测
3.1.2 矢量化加速
在训练我们的模型时,我们经常希望能够同时处理整个小批量的样本。为了实现这?点,需要我们对计算进??量化,从而利?线性代数库,而不是在Python中编写开销?昂的for循环。
import math
import time
import numpy as np
import torch
class Timer:
def __init__(self):
self.times = []
self.tik = None
self.start()
def start(self):
self.tik = time.time()
def stop(self):
self.times.append(time.time() - self.tik)
return self.times[-1]
def avg(self):
return sum(self.times) / len(self.times)
def sum(self):
return sum(self.times)
def cumsum(self):
return np.array(self.times).cumsum().tolist()
n = 10000
a = torch.ones(n)
b = torch.ones(n)
c = torch.zeros(n)
timer = Timer()
for i in range(n):
c[i] = a[i] + b[i]
print(f'{timer.stop(): .5f} sec')
timer.start()
d = a + b
print(f'{timer.stop(): .5f} sec')
?量化代码通常会带来数量级的加速 将更多的数学运算放到库中,而?须??编写那么多的计算,从而减少了出错的可能性
3.1.3 正态分布与平方损失
正态分布 改变均值会产?沿x轴的偏移,增加?差将会分散分布、降低其峰值。
import math
import numpy as np
import matplotlib.pyplot as plt
def normal(x, mu, sigma):
p = 1 / math.sqrt(2 * math.pi * sigma ** 2)
return p * np.exp(-0.5 / sigma ** 2 * (x - mu) ** 2)
x = np.arange(-7, 7, 0.01)
params = [(0, 1), (0, 2), (3, 1)]
for mu, sigma in params:
plt.plot(x, normal(x, mu, sigma), label=f'mean {mu}, std {sigma}')
plt.xlabel("x")
plt.ylabel("p(x)")
plt.legend()
plt.show()
均方误差损失函数(均方损失) 解释均方误差可以用于线性回归的原因: 假设观测中包含噪声,噪声服从正态分布 在高斯噪声的假设下,最小化均方误差等价于对线性模型的极大似然估计
3.1.4 从线性回归到深度网络
神经网络图
生物学
当今?多数深度学习的研究?乎没有直接从神经科学中获得灵感。如今在深度学习中的灵感同样或更多地来?数学、统计学和计算机科学。 小结 ? 机器学习模型中的关键要素是训练数据、损失函数、优化算法,还有模型本?。 ? ?量化使数学表达上更简洁,同时运?的更快。 ? 最小化?标函数和执?极?似然估计等价。 ? 线性回归模型也是?个简单的神经?络。
3.2 线性回归的从零开始实现
3.2.1 生成数据集
?成?个包含1000个样本的数据集,每个样本包含从标准正态分布中采样的2个特征。 合成数据集是?个矩阵X ∈ R1000×2。 detach() detach_() data区别
3.2.2 读取数据集
训练模型时要对数据集进?遍历,每次抽取?小批量样本,并使?它们来更新我们的模型。由于这个过程是训练机器学习算法的基础,所以有必要定义?个函数,该函数能打乱数据集中的样本并以小批量?式获取数据。 random.shuffle python for range 循环 python yield
3.2.3 初始化模型参数
在初始化参数之后,我们的任务是更新这些参数,直到这些参数?够拟合我们的数据。每次更新都需要计算损失函数关于模型参数的梯度。有了这个梯度,我们就可以向减小损失的?向更新每个参数。 因为?动计算梯度很枯燥而且容易出错,所以没有?会?动计算梯度。我们使? 2.5节中引?的?动微分来计算梯度。
3.2.4 定义模型
定义模型,将模型的输?和参数同模型的输出关联起来
3.2.5 定义损失函数
3.2.6 优化算法:小批量随机梯度下降方法
在每?步中,使?从数据集中随机抽取的?个小批量,然后根据参数计算损失的梯度。接下来,朝着减少损失的?向更新我们的参数。 torch.no_grad()
3.2.7 训练过程
训练过程是具有共性的。深度学习几乎相同的训练过程 .backward .sum 梯度为1不影响结果 只有标量才能backward 在每次迭代中,读取一小批量训练样本,并通过模型来获得一组预测。计算完损失后,开始反向传播,存储每个参数的梯度。最后调用优化算法来更新模型参数。 我们不应该想当然地认为我们能够完美地求解参数。在机器学习中,我们通常不太关?恢复真正的参数,而更关?如何?度准确预测参数。幸运的是,即使是在复杂的优化问题上,随机梯度下降通常也能找到?常好的解。其中?个原因是,在深度?络中存在许多参数组合能够实现?度精确的预测。
import random
import torch
import matplotlib.pyplot as plt
def synthetic_data(w, b, num_examples):
X = torch.normal(0, 1, (num_examples, len(w)))
y = torch.matmul(X, w) + b
y += torch.normal(0, 0.01, y.shape)
return X, y.reshape((-1, 1))
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
print('features:', features[0], '\nlabel:', labels[0])
plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1)
plt.show()
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):
batch_indices = torch.tensor(indices[i: min(i + batch_size, num_examples)])
yield features[batch_indices], labels[batch_indices]
batch_size = 10
for X, y in data_iter(batch_size, features, labels):
print(X, '\n', y)
break
w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
def linreg(X, w, b):
return torch.matmul(X, w) + b
def squared_loss(y_hat, y):
return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2
def sgd(params, lr, batch_size):
with torch.no_grad():
for param in params:
param -= lr * param.grad / batch_size
param.grad.zero_()
lr = 0.03
num_epochs = 5
net = linreg
loss = squared_loss
for epoch in range(num_epochs):
for X, y in data_iter(batch_size, features, labels):
l = loss(net(X, w, b), y)
l.sum().backward()
sgd([w, b], lr, batch_size)
with torch.no_grad():
train_l = loss(net(features, w, b), labels)
print(f'epoch {epoch + 1}, loss {float(train_l.mean()): f}')
print(f'error in estimating w: {true_w - w.reshape(true_w.shape)}')
print(f'error in estimating b: {true_b - b}')
小结 ? 我们学习了深度?络是如何实现和优化的。在这?过程中只使?张量和自动微分,不需要定义层或复杂的优化器。 ? 这?节只触及到了表?知识。在下面的部分中,我们将基于刚刚介绍的概念描述其他模型,并学习如何更简洁地实现其他模型。
|