【李沐AI自学】线性神经网络

线性回归

在机器学习领域中的⼤多数任务通常都与预测(prediction)有关。当我们想预测⼀个数值时,就会涉及到回归问题。常⻅的例⼦包括:预测价格(房屋、股票等)、预测住院时间(针对住院病⼈等)、预测需求(零售销量等)。但不是所有的预测都是回归问题。在后⾯的章节中,我们将介绍分类问题。分类问题的⽬标是预测数据属于⼀组类别中的哪⼀个。

线性回归基本元素

为了解释线性回归,我们举⼀个实际的例⼦:我们希望根据房屋的⾯积(平⽅英尺)和房龄(年)来估算房屋价格(美元)。为了开发⼀个能预测房价的模型,我们需要收集⼀个真实的数据集。这个数据集包括了房屋的销售价格、⾯积和房龄。在机器学习的术语中,该数据集称为训练数据集(training data set)或训练集(training set)。每⾏数据(⽐如⼀次房屋交易相对应的数据)称为样本(sample),也可以称为数据点(data point)或数据样本(data instance)。我们把试图预测的⽬标(⽐如预测房屋价格)称为标签(label)或⽬标(target)。预测所依据的⾃变量(⾯积和房龄)称为特征(feature)或协变量(covariate)。

在这里插入图片描述在这里插入图片描述
由于平⽅误差函数中的⼆次⽅项,估计值yˆ(i)和观测值y(i)之间较⼤的差异将导致更⼤的损失。为了度量模型在整个数据集上的质量,我们需计算在训练集n个样本上的损失均值(也等价于求和)。

在这里插入图片描述
在训练模型时,我们希望寻找⼀组参数(w∗, b∗),这组参数能最⼩化在所有训练样本上的总损失。如下式:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
线性回归,前向传播的是计算得到的y‘值,然后根据y’-y计算loss,然后反向传播,每一个特征(相当于邻接矩阵的那些列)的loss分别对w和b求偏导,得到每一个特征的梯度,也就是3.1.10式子,以此来更新w和b。

⽮量化加速

在训练我们的模型时,我们经常希望能够同时处理整个⼩批量的样本。为了实现这⼀点,需要我们对计算进⾏⽮量化,从⽽利⽤线性代数库,⽽不是在Python中编写开销⾼昂的for循环。

%matplotlib inline
import math
import time
import numpy as np
import torch
from d2l import torch as d2l
	n = 10000
	a = torch.ones(n)
	b = torch.ones(n)

由于在本书中我们将频繁地进⾏运⾏时间的基准测试,所以我们定义⼀个计时器:

class Timer: #@save
"""记录多次运⾏时间"""
	def __init__(self):
		self.times = []
		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()

现在我们可以对⼯作负载进⾏基准测试。
⾸先,我们使⽤for循环,每次执⾏⼀位的加法。

	c = torch.zeros(n)
	timer = Timer()
	for i in range(n):
		c[i] = a[i] + b[i]
		f'{
     
     timer.stop():.5f} sec'
		'0.08976 sec'

或者,我们使⽤重载的+运算符来计算按元素的和。

timer.start()
d = a + b f'{
     
     timer.stop():.5f} sec'
'0.00027 sec'

正态分布和平方损失

接下来,我们通过对噪声分布的假设来解读平⽅损失⽬标函数。
正态分布和线性回归之间的关系很密切。正态分布(normal distribution),也称为⾼斯分布(Gaussian
distribution),最早由德国数学家⾼斯(Gauss)应⽤于天⽂学研究。简单的说,若随机变量x具有均值µ和⽅差σ2(标准差σ),其正态分布概率密度函数如下:
在这里插入图片描述
下⾯我们定义⼀个Python函数来计算正态分布。

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)

我们现在可视化正态分布。

# 再次使⽤numpy进⾏可视化
x = np.arange(-7, 7, 0.01) # 均值和标准差对
params = [(0, 1), (0, 2), (3, 1)]
d2l.plot(x, [normal(x, mu, sigma) for mu, sigma in params], xlabel='x',
ylabel='p(x)', figsize=(4.5, 2.5),
legend=[f'mean {
     
     mu}, std {
     
     sigma}' for mu, sigma in params])

在这里插入图片描述

线性回归的从零开始实现

⽣成数据集

为了简单起⻅,我们将根据带有噪声的线性模型构造⼀个⼈造数据集。我们的任务是使⽤这个有限样本的数据集来恢复这个模型的参数。我们将使⽤低维数据,这样可以很容易地将其可视化。在下⾯的代码中,我们⽣成⼀个包含1000个样本的数据集,每个样本包含从标准正态分布中采样的2个特征。我们的合成数据集是⼀个矩阵X ∈ R1000×2。我们使⽤线性模型参数w = [2, −3.4]⊤、b = 4.2 和噪声项ϵ⽣成数据集及其标签:
你可以将ϵ视为模型预测和标签时的潜在观测误差。在这⾥我们认为标准假设成⽴,即ϵ服从均值为0的正态分布。为了简化问题,我们将标准差设为0.01。下⾯的代码⽣成合成数据集。

%matplotlib inline
import random
import torch
from d2l import torch as d21
def synthetic_data(w, b, num_examples): #@save
    """生成 y = Xw + b + 噪声。"""
    X=torch.normal(0,1,(num_examples,len(w)))
    y=torch.matmul(X,w)+b#matmul所以矩阵向量乘法都可以通过广播机制实现
    y+=torch.normal(0,0.01,y.shape)
    return X,y.reshape(-1,1)
torch.normal(2,3,size=(1,4))
# tensor([[-1.3987, -1.9544,  3.6048,  0.7909]])
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features,labels=synthetic_data(true_w,true_b,1000)
features,labels
d2l.set_figsize()
d2l.plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1);

在这里插入图片描述

读取数据集

回想⼀下,训练模型时要对数据集进⾏遍历,每次抽取⼀⼩批量样本,并使⽤它们来更新我们的模型。由于这个过程是训练机器学习算法的基础,所以有必要定义⼀个函数,该函数能打乱数据集中的样本并以⼩批量⽅式获取数据。在下⾯的代码中,我们定义⼀个data_iter函数,该函数接收批量⼤⼩、特征矩阵和标签向量作为输⼊,⽣成⼤⼩为batch_size的⼩批量。每个⼩批量包含⼀组特征和标签。

def data_iter(batch_size, features, labels):
    num_examples = len(features)
    indices = list(range(num_examples))#0-999的数组列表
    # 这些样本是随机读取的,没有特定的顺序
    random.shuffle(indices)#打乱顺序
    for i in range(0, num_examples, batch_size):
        batch_indices = torch.tensor(
            indices[i: min(i + batch_size, num_examples)])#tensor([993, 616, 127, 509, 119, 167, 648, 486, 907,  27])前十个
        yield features[batch_indices], labels[batch_indices]
    #yield可以理解为一个return操作,但是和return又有很大的区别,执行完return,当前函数就终止了,函数内部的所有数据,所占的内存空间,全部都没有了。
    #而yield在返回数据的同时,还保存了当前的执行内容,当你再一次调用这个函数时,他会找到你在此函数中的yield关键字,然后从yield的下一句开始执行。

通常,我们利⽤GPU并⾏运算的优势,处理合理⼤⼩的“⼩批量”。每个样本都可以并⾏地进⾏模型计算,且每个样本损失函数的梯度也可以被并⾏计算。GPU可以在处理⼏百个样本时,所花费的时间不⽐处理⼀个样本时多太多。我们直观感受⼀下⼩批量运算:读取第⼀个⼩批量数据样本并打印。每个批量的特征维度显⽰批量⼤⼩和输⼊特征数。同样的,批量的标签形状与batch_size相等。

batch_size = 10
for X, y in data_iter
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值