IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 动手学深度学习笔记(二) -> 正文阅读

[人工智能]动手学深度学习笔记(二)

1. 线性回归

简化模型房价预测的模型可以理解为用一些能够表示房子特点的因素如卧室个数、卫生间个数、面积等 n n n 个属性组成的特征向量:
x = [ x 1 x 2 ? x n ] \mathbf{x}=\left[ \begin{matrix} x_1 \\ x_2 \\ \vdots \\ x_n \end{matrix}\right] x=??????x1?x2??xn????????

房价的预测是这些属性的加权和:
y = w 1 x 1 + w 2 x 2 + ? + w n x n + b y=w_1x_1+w_2x_2+\cdots+w_nx_n + b y=w1?x1?+w2?x2?+?+wn?xn?+b

用向量表示为:
y = ? w , x ? + b y=\langle\mathbf{w},\mathbf{x}\rangle+b y=?w,x?+b

这个线性模型可以看为一个单层神经网络,如下图所示,之所以称为单层是因为我们只将带权重的层记为一层。
在这里插入图片描述

有了模型后,就可以用来比较模型的效果怎么样,通过该样本预测值和真实值之间的差距衡量模型的效果,如下,这个表达式也称为平方损失
l ( y , y ^ ) = 1 2 ( y ? y ^ ) 2 l(y,\hat{y})=\frac{1}{2}(y-\hat{y})^2 l(y,y^?)=21?(y?y^?)2

为了获取其中的权重参数 w \mathbf{w} w 我们可以收集 m m m 个训练集样本,数据集和对应的标签可以表示如下:
X = [ x 1 x 2 ? x m ] , y = [ y 1 y 2 ? y n ] \mathbf{X}= \left[ \begin{matrix} \mathbf{x}_1 \\ \mathbf{x}_2 \\ \vdots \\ \mathbf{x}_m \end{matrix} \right],\quad \mathbf{y}=\left[ \begin{matrix} y_1 \\ y_2 \\ \vdots \\ y_n \end{matrix} \right] X=??????x1?x2??xm????????,y=??????y1?y2??yn????????

通过这些数据,我们可以通过最小化损失函数的形式求解模型中的参数 w \mathbf{w} w b \mathbf{b} b,即:
w ? , b ? = arg ? min ? w , b l ( X , y , w , b ) \mathbf{w}^*,\mathbf{b}^* = \arg\min_{\mathbf{w},b}l(\mathbf{X},\mathbf{y},\mathbf{w},b) w?,b?=argw,bmin?l(X,y,w,b)

为了简化计算,我们将偏差移入权重矩阵中,记 X → [ X , 1 ] \mathbf{X}\rightarrow \left[\begin{matrix}\mathbf{X}, \mathbf{1}\end{matrix}\right] X[X,1?] w ← [ w b ] \mathbf{w} \leftarrow \left[\begin{matrix}\mathbf{w} \\ b\end{matrix}\right] w[wb?],那么所有样本的损失函数可以表示为:
l ( X , y , w ) = 1 2 ∥ y ? X w ∥ 2 l(\mathbf{X},\mathbf{y},\mathbf{w})= \frac{1}{2}\|\mathbf{y}-\mathbf{Xw}\|^2 l(X,y,w)=21?y?Xw2

对于线性回归,上式的损失是凸函数,所以我们可以直接通过梯度的方式求解 w ? \mathbf{w}^* w? 的最优解,
? ? w l ( X , y , w ) = 1 n ( y ? X w ) T X \begin{aligned} \frac{\partial}{\partial \mathbf{w}}l(\mathbf{X},\mathbf{y},\mathbf{w})= \frac{1}{n}\left(\mathbf{y}-\mathbf{Xw}\right)^T\mathbf{X} \end{aligned} ?w??l(X,y,w)=n1?(y?Xw)TX?

令梯度为 0 0 0 时满足的 w ? \mathbf{w}^* w? 即可,如下所示:
? ? w l ( X , y , w ) = 0 ? 1 n ( y ? X w ) T X = 0 ? w ? = ( X T X ) ? 1 X T y \begin{aligned} \frac{\partial}{\partial \mathbf{w}}l(\mathbf{X},\mathbf{y},\mathbf{w})=0 \\ \Leftrightarrow \frac{1}{n}\left(\mathbf{y}-\mathbf{Xw}\right)^T\mathbf{X} = 0 \\ \Leftrightarrow \mathbf{w}^* = \left(\mathbf{X}^T\mathbf{X}\right)^{-1}\mathbf{X}^T\mathbf{y} \end{aligned} ?w??l(X,y,w)=0?n1?(y?Xw)TX=0?w?=(XTX)?1XTy?

只有线性模型才能直接通过梯度方式直接找到最优解,但是这种方式因为比较简单,所以不能处理复杂的问题。

2. 线性回归基础优化算法

最常见的对参数优化的算法就是梯度下降算法,其基本过程如下:

  1. 对其中的一个参数 w \mathbf{w} w,首先随机初始为任意值 w 0 \mathbf{w}_0 w0?

  2. 重复迭代更新参数 t = 1 , 2 , 3 , ? t=1,2,3,\cdots t=1,2,3,?
    w t = w t ? 1 ? η ? l ? w t ? 1 \mathbf{w}_t = \mathbf{w}_{t-1}-\eta\frac{\partial l}{\partial \mathbf{w}_{t-1}} wt?=wt?1??η?wt?1??l?

    梯度表示函数值增加最快的方向,减去梯度的值就是向函数值减少最快的方向移动; η \eta η学习率,表示沿梯度方向走多远。

在整个训练集计算梯度太浪费资源,所以一般采用 小批量随机梯度下降 方法,通过随机采样 b b b 个样本 i 1 , i 2 , ? ? , i b i_1,i_2,\cdots,i_b i1?,i2?,?,ib? 来近似损失更新参数,如下所示,这样就可以减少计算量。
1 b ∑ i ∈ I b l ( x i , y i , w ) \frac{1}{b}\sum_{i\in I_b}l(\mathbf{x}_i,y_i,\mathbf{w}) b1?iIb??l(xi?,yi?,w)

批量不能太小,太小会使每次的计算量太小,不适合并行最大化利用计算资源。也不能太大,太大会增大内存的消耗,浪费资源。

学习率和批量大小是小批量梯度下降的两个最重要的超参数。

3. 从零开始实现线性回归

  1. 根据带有噪声的线性模型构造一个人造数据集,数据集用于后面的回归。这里使用包含参数 w = [ 2 , ? 3.4 ] T 、 b = 4.2 \mathbf{w}=\left[\begin{matrix}2,-3.4\end{matrix}\right]^T、b=4.2 w=[2,?3.4?]Tb=4.2 的线性模型:
    y = X w + b + ? \mathbf{y}=\mathbf{Xw}+b+\epsilon y=Xw+b+?
    来生成数据集,其中 ? \epsilon ? 表示噪声项。

    代码实现为:

    import random
    import torch
    import matplotlib.pyplot as plt
    
    def synthetic_data(w,b,num_examples):
        """生成 y = Xw + b + 噪音  的数据"""
        X = torch.normal(0, 1, (num_examples, len(w)))  # X 表示真实的数据
        y = torch.matmul(X,w) + b
        y += torch.normal(0, 0.01, y.shape)   #噪音
        
        return X, y.reshape((-1, 1))          #y作为每行对应的真实结果返回
    
    true_w = torch.tensor([2, -3.4])
    true_b = 4.2
    features, labels = synthetic_data(w,b,1000)
    
    plt.scatter(features[:,(1)].numpy(),labels.numpy(),1) #将 features 的第二列作为横轴,对应 labels 作为纵轴做散点图
    

    在这里插入图片描述

  2. 将数据划分为大小 batch_size 的批量数据

    def data_iter(batch_size, features, labels):
    	"""将 features 和 labels 分为大小为 batch_size 的批数据"""
        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_indieces 列表中指定位置的元素取出
    
  3. 初始化模型参数

    因为上面我们创建的数据 X 的特征维度为 2 2 2,所以这里随机初始化权重 w 的维度为 2 2 2

    w = torch.normal(0, 0.01, size=(2, 1), requires_grad = True)
    b = torch.zeros(1,requires_grad = True)
    
  4. 定义模型

    def linreg(X, w, b):
        """线性回归模型"""
        return torch.matmul(X, w) + b
    
  5. 定义损失函数和优化算法

    这里选择均方差损失函数:

    def squared_loss(y_hat, y):
        """均方差损失函数
        y_hat : 表示预测值
        y     : 表示真实值
        """
        return (y_hat - y.reshape(y_hat.shape))**2 / 2
    

    优化算法选择随机梯度下降算法,注意,在更新参数时会出现新的表达式,为了避免 backward() 时相对该表达式计算梯度,将这些过程使用 with torch.no_grad() 包围。

    def sgd(params, lr, batch_size):
        """小批量随机梯度下降"""
        with torch.no_grad():   #表示在以下的参数更新过程中不要计算梯度
            for param in params:
                param -= lr * param.grad / batch_size  #param.grad 表示该参数自动计算的梯度,这里把损失函数除以batch_size在这里实现
                param.grad.zero_()     #手动将梯度置为 0 
    
  6. 训练模型

    训练的过程主要为:

    • 根据现有参数计算损失
    • 用当前得到的损失求相对于每个参数的梯度
    • 用梯度更新参数
    # 训练过程
    lr = 0.03
    num_epochs = 3
    net = linreg
    loss = squared_loss
    batch_size = 10
    
    for epoch in range(num_epochs):
        for X, y in data_iter(batch_size, features, labels): #将真实数据分为小 batch
            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}')
    """
    epoch 1, loss0.000120
    epoch 2, loss0.000051
    epoch 3, loss0.000050
    """
    
    print(f'w 的估计误差:{true_w - w.reshape(true_w.shape)}')
    print(f'b 的估计误差:{true_b - b}')
    """
    w 的估计误差:tensor([-0.0003,  0.0007], grad_fn=<SubBackward0>)
    b 的估计误差:tensor([-6.9618e-05], grad_fn=<RsubBackward1>)
    """
    

在以上的训练过程中,我们可以通过改变 学习率、批的大小等不同参数的值来得到不同的训练结果。

4. 简洁实现

通过使用 PyTorch 深度学习框架简洁实现线性回归模型,生成数据集。

import torch
from torch.utils import data   #包含处理数据的一些模块
from torch import nn           #nn是神经网络的缩写,包含很多神经网络相关的工具

def synthetic_data(w,b,num_examples):
    """生成 y = Xw + b + 噪音  的数据"""
    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))          #y作为列向量返回


def load_array(data_arrays, batch_size, is_train=True):
    """构造一个PyTorch数据迭代器"""
    dataset = data.TensorDataset(*data_arrays)    #把输入的两组数据一一对应,*表示对列表解构
    return data.DataLoader(dataset, batch_size, shuffle=is_train)

true_w = torch.tensor([2, -3.4])
true_b = 4.2
#生成参数指定的数据
features, labels = synthetic_data(true_w,true_b,1000)

batch_size = 10
#加载生成的数据
data_iter = load_array((features, labels), batch_size)

#创建线性模型
net = nn.Sequential(nn.Linear(2, 1))    #nn.Linear(2, 1) 创建一个 2*1 的线性层
                    #nn.Sequential 用于将多层神经网络按顺序排列,后面使用时会按照放入顺序依次通过


#模型参数初始化
net[0].weight.data.normal_(0, 0.01)  #用指定的正态分布初始化,如果不这样指定会有默认的值
net[0].bias.data.fill_(0)            #对偏置项全部置 0


#指定均方误差
loss = nn.MSELoss()

#创建随机梯度下降公式
trainer = torch.optim.SGD(net.parameters(), lr = 0.03)  #net.parameters()会取出网络中的所有参数

#开始训练
num_epochs = 3
for epoch in range(num_epochs):
    for X, y in data_iter:
        l = loss(net(X), y)
        trainer.zero_grad()   #梯度清零
        l.backward()          #其中会自动做 sum 操作
        trainer.step()        #使用 step 进行模型的更新
        
    l = loss(net(features), labels)
    print(f'epoch {epoch + 1}, loss{l:f}')
  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-08-05 17:21:26  更:2021-08-05 17:21:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/7 18:51:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码