• pytorch深度学习实战lesson9


    第九课 线性回归

    理论部分

    线性回归

    案例:美国房价预测

    系统估价和自己实际付的钱要保持差不多的关系才能使自己赚到,那怎么样才能赚到呢,那就得有一个量良好的预估手段。

    下面做出两个假设:

    线性模型可以看做是单层的神经网络

    每个箭头代表一个权重,输出是o1,输入是xn

    神经网络其实源于神经科学,下图是真实的神经元:

    有了模型之后,就要对其进行预测了,放在上面的案例里面讲也就是比较房价的真实值和预估值。

    这个相当于是神经网络里面的损失函数。

    有了模型和损失后,下一步就是参数的学习。

    可以收集一些数据点来决定参数值(权重和偏差),比如过去六个月卖的房子,这些数据就被称为是训练数据,通常来讲,训练数据越多越好。

    X是列向量,每个x一排一排的排好然后做转置。然后y是列向量有n个样本,每个y是实数样本。

    目标是找到一个w和b使得损失函数的结果最小。

    总结

    1、线性回归是对n维输入的加权,外加偏差。

    2、使用平方损失来衡量预测值和真实值的差异。

    3、线性回归有显示解。

    4、线性回归可以看做是单层神经网络。

    基础优化方法

    优化方法最常用的是梯度下降算法。

    这里的学习率不能太大也不能太小,因为太小的话耗费资源很多,太大的话就错过最优值了。

    总结:

    1、梯度下降通过不断沿着反梯度方向更新参数求解

    2、小批量随机梯度下降是深度学习默认的求解算法

    3、两个重要的超参数是批量大小和学习率

    实践部分

    线性回归从零开始实现:

    1. #¥¥¥¥¥<<<<<+++++-----线性回归从零开始实现-----+++++>>>>>¥¥¥¥¥#
    2. #从零开始实现整个方法,包括流水线、模型、损失函数和小批量随机梯度下降优化器
    3. #%matplotlib_inline #用于随机梯度下降和初始化权重
    4. import matplotlib.pyplot as plt
    5. import torch
    6. import random
    7. from d2l import torch as d2l
    8. #根据带有噪声的线性模型构造一个人造数据集,我们使用线性模型参数w=[2,-3,4]T、b=4.2和噪声e生成数据集及其标签:
    9. #y=Xw+b+e
    10. def synthetic_data(w,b,num_examples): #构造人造数据集,num_examples是要生成的样本数量
    11. '''生成 y=Xw+b+e'''
    12. X=torch.normal(0,1,(num_examples,len(w))) #构造x是方差为零均值为1的随机数,它的大小是样本数,它的列数是w的长度
    13. y=torch.matmul(X,w)+b #构造y
    14. y+=torch.normal(0,0.01,y.shape) #又让y加上了一个噪音。噪音是方差为0,均值为0.01,形状与y一样
    15. return X,y.reshape((-1,1)) #把x和y做出列向量返回
    16. true_w=torch.tensor([2,-3.4]) #定义真实的w和真实的b
    17. true_b=4.2
    18. features,labels=synthetic_data(true_w,true_b,1000) #然后通过函数计算出特征和标注
    19. #看一下训练样本的样子以及样本分布图
    20. print('features:',features[0],'\nlable:',labels[0]) #输出:features: tensor([0.4727, 0.1651]) lable: tensor([4.5845])
    21. #可见,第零个样本是长为2的一个向量,其标号是标量
    22. print('########################################################')
    23. d2l.set_figsize()
    24. d2l.plt.scatter(features[:,(1)].detach().numpy(),labels.detach().numpy(),1)#detach的作用是在pytorch的一些版本中,
    25. # 需要从计算图中detach处来才能转到numpy中
    26. plt.show() #画完后我们可以看到是个线性相关的样本集
    27. #定义一个data_iter 函数, 该函数接收批量大小、
    28. def data_iter(batch_size, features, labels):
    29. # 特征矩阵和标签向量作为输入,生成大小为batch_size的小批量
    30. num_examples = len(features)
    31. indices = list(range(num_examples)) #生成每个样本的索引(每个样本是随机读取的,没有特定顺序)
    32. random.shuffle(indices) #打乱下标
    33. for i in range(0, num_examples, batch_size): #从0开始到num_examples,每次走batch_size个
    34. batch_indices = torch.tensor(
    35. indices[i:min(i +batch_size, num_examples)]) #这里要获取批量索引,把索引存入张量中,后面的min操作是防止超过总量,所以要取最小的
    36. yield (features[batch_indices], #通过indices生成特征和标号。yield相当于是Python中的重复操作,
    37. labels[batch_indices]) #每次都生成一个x一个y,生成完后再调用函数,直到全部完成为止。
    38. batch_size = 10
    39. for X, y in data_iter(batch_size, features, labels):#给我一些样本标号,每次随机选取b个样本返回出来
    40. print(X, '\n', y)
    41. break
    42. print('########################################################')
    43. #定义初始化模型参数
    44. w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)#w是2*1的,2表示特征,1表示标签,0表示方差,0.02表示均值
    45. b = torch.zeros(1, requires_grad=True) #b初始赋为零,1表示它是1维的标量
    46. #w和b的requires_grad都是true表示它们要计算梯度,实时更新
    47. #定义模型
    48. def linreg(X, w, b): #-----线性回归模型
    49. return torch.matmul(X, w) + b
    50. #定义损失函数
    51. def squared_loss(y_hat, y): #-----均方损失
    52. return (y_hat - y.reshape(y_hat.shape))**2 / 2 #y_hat是预测值,y是真实值,要保证两者形状统一,差先按元素平方然后按元素除二
    53. #定义优化算法
    54. def sgd(params, lr, batch_size): #-----小批量随机梯度下降,params是个列表,里面包含w和b
    55. with torch.no_grad(): #它不需要计算梯度
    56. for param in params: #每一个w和b
    57. param -= lr * param.grad / batch_size #param=param-lr*param.grad/batch_size除以batch_size的操作是求均值操作,
    58. #由于是线性关系,所以在此求均值也可。
    59. param.grad.zero_() #梯度置零
    60. #开始训练
    61. #先定义超参数
    62. lr = 0.03 #学习率
    63. num_epochs = 3 #把整个数据扫三遍,也就是进行三轮训练
    64. net = linreg #模型就是之前定义的linreg
    65. loss = squared_loss #损失还是之前的定义的
    66. for epoch in range(num_epochs): #每一次对数据扫一遍
    67. for X, y in data_iter(batch_size, features, labels):#每次拿出一组x和y
    68. l = loss(net(X, w, b), y) #把预测的y和真实的y做损失,出来的损失是长为批量大小的向量
    69. l.sum().backward() #求和之后算梯度
    70. sgd([w, b], lr, batch_size) #更新参数
    71. with torch.no_grad():
    72. train_l = loss(net(features, w, b), labels) #计算损失,不用算梯度
    73. print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
    74. print('########################################################')
    75. #比较真实参数和通过训练学到的参数来评估训练的成功程度
    76. print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')
    77. print(f'b的估计误差: {true_b - b}')
    78. #可以实验一下梯度很大或梯度很小时的情况,看看其损失有什么变化
    79. #梯度很大时
    80. '''#先定义超参数
    81. lr = 10 #学习率
    82. num_epochs = 10 #把整个数据扫三遍,也就是进行三轮训练
    83. net = linreg #模型就是之前定义的linreg
    84. loss = squared_loss #损失还是之前的定义的
    85. for epoch in range(num_epochs): #每一次对数据扫一遍
    86. for X, y in data_iter(batch_size, features, labels):#每次拿出一组x和y
    87. l = loss(net(X, w, b), y) #把预测的y和真实的y做损失,出来的损失是长为批量大小的向量
    88. l.sum().backward() #求和之后算梯度
    89. sgd([w, b], lr, batch_size) #更新参数
    90. with torch.no_grad():
    91. train_l = loss(net(features, w, b), labels) #计算损失,不用算梯度
    92. print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')'''
    93. #梯度很小时,可以通过增加学习轮次得到好一些的损失值,但是成本有点大
    94. '''#梯度很大时
    95. #先定义超参数
    96. lr = 0.001 #学习率
    97. num_epochs = 3 #把整个数据扫三遍,也就是进行三轮训练
    98. net = linreg #模型就是之前定义的linreg
    99. loss = squared_loss #损失还是之前的定义的
    100. for epoch in range(num_epochs): #每一次对数据扫一遍
    101. for X, y in data_iter(batch_size, features, labels):#每次拿出一组x和y
    102. l = loss(net(X, w, b), y) #把预测的y和真实的y做损失,出来的损失是长为批量大小的向量
    103. l.sum().backward() #求和之后算梯度
    104. sgd([w, b], lr, batch_size) #更新参数
    105. with torch.no_grad():
    106. train_l = loss(net(features, w, b), labels) #计算损失,不用算梯度
    107. print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')'''

    features: tensor([ 0.3840, -0.3376]) 
    lable: tensor([6.1121])
    ########################################################
    tensor([[-1.1147e+00, -8.3294e-01],
            [-6.0542e-04,  2.1474e-02],
            [ 9.3246e-01,  1.4499e+00],
            [ 4.7537e-01, -2.9177e-01],
            [ 1.8271e+00,  1.3387e-01],
            [-3.8728e-01, -1.7065e+00],
            [-2.3963e+00, -1.5596e-01],
            [-1.7679e+00, -6.3735e-01],
            [ 4.8884e-01,  1.1035e+00],
            [-6.9350e-01,  2.9550e-01]]) 
     tensor([[ 4.7953],
            [ 4.1320],
            [ 1.1461],
            [ 6.1476],
            [ 7.3970],
            [ 9.2280],
            [-0.0416],
            [ 2.8342],
            [ 1.4362],
            [ 1.8041]])
    ########################################################
    epoch 1, loss 0.026386
    epoch 2, loss 0.000093
    epoch 3, loss 0.000046
    ########################################################
    w的估计误差: tensor([0.0001, 0.0004], grad_fn=)
    b的估计误差: tensor([0.0007], grad_fn=)

    线性回归简洁实现:

    1. #所谓的简洁实现就是通过使用深度学习框架来简洁地实现 线性回归模型 生成数据集
    2. import numpy as np
    3. import torch
    4. from torch.utils import data #处理数据的模块
    5. from d2l import torch as d2l
    6. true_w = torch.tensor([2, -3.4]) #真实的w
    7. true_b = 4.2 #真实的b
    8. features, labels = d2l.synthetic_data(true_w, true_b, 1000) #生成特征和标签
    9. #调用框架中现有的API来读取数据
    10. def load_array(data_arrays, batch_size, is_train=True):
    11. """构造一个PyTorch数据迭代器。"""
    12. dataset = data.TensorDataset(*data_arrays) #先将x,y变成dataset数据集
    13. return data.DataLoader(dataset, batch_size, #然后调用dataloader,每次挑b个样本出来
    14. shuffle=is_train) #如果在训练过程中的话就要随机打乱顺序
    15. batch_size = 10
    16. data_iter = load_array((features, labels), batch_size)
    17. next(iter(data_iter)) #得到一个x和一个y
    18. #使用框架的预定义好的层
    19. from torch import nn
    20. net = nn.Sequential(nn.Linear(2, 1)) #要指定输入输出维度,linear是个线性层,
    21. # 把他放在sequential里的话就相当于把每层给罗列起来了
    22. #初始化模型参数
    23. net[0].weight.data.normal_(0, 0.01) #把权重初始化
    24. net[0].bias.data.fill_(0) #把偏重初始化
    25. #计算均方误差使用的是MSELoss类,也称为平方 L2 范数
    26. loss = nn.MSELoss() #均方误差的调用
    27. #实例化 SGD 实例
    28. trainer = torch.optim.SGD(net.parameters(), lr=0.03) #梯度下降的调用,要传入所有参数(w,b),和学习参数
    29. #训练过程代码与我们从零开始实现时所做的非常相似
    30. num_epochs = 3
    31. for epoch in range(num_epochs):
    32. for X, y in data_iter:
    33. l = loss(net(X), y) #net自己带模型参数了
    34. trainer.zero_grad() #先梯度清零
    35. l.backward() #pytorch已经做sum了
    36. trainer.step() #模型更新
    37. l = loss(net(features), labels)
    38. print(f'epoch {epoch + 1}, loss {l:f}')
    39. #比较生成数据集的真实参数和通过有限数据训练获得的模型参数
    40. w = net[0].weight.data
    41. print('w的估计误差:', true_w - w.reshape(true_w.shape))
    42. b = net[0].bias.data
    43. print('b的估计误差:', true_b - b)

    epoch 1, loss 0.000369
    epoch 2, loss 0.000104
    epoch 3, loss 0.000105
    w的估计误差: tensor([-0.0004, -0.0009])
    b的估计误差: tensor([-5.7220e-06])

  • 相关阅读:
    通用接口平台开源版正式发布2.0版本
    Linux Day16 多线程的一些常见问题
    Python正则表达式
    SpringBoot Kafka生产者 多kafka配置
    从云AK泄露利用看企业特权管理
    js正则表达式
    计算机毕业论文选题推荐|软件工程|系列十一
    提高采购效率,采购管理的五大原则及实现方法
    Qt6.3学习笔记 QFrame::HLine与QFrame::VLine 改变线条颜色
    Postman抓包网页请求
  • 原文地址:https://blog.csdn.net/weixin_48304306/article/details/127773206