Press "Enter" to skip to content

动手学深度学习笔记-线性回归和softmax回归底层从零实现

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

文章目录

 

线性回归

 

理论部分:

 

唯一一个 有 显性最优解的模型

 

优化基础算法

 

线性回归的代码

 

d2l.plot的参数

 

这个代码的画折线图很不错,值得学习!

 

下面画图的构思很不错

 

import math
import os
import numpy as np
import torch
from d2l import torch as d2l
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
n = 10000
a = torch.ones(n)
b = torch.ones(n)
c = torch.zeros(n)
timer = d2l.Timer()
for i in range(n):
    c[i] = a[i] + b[i]
print(c)
print("{0:.5f} sec".format(timer.stop()))
timer.start()
d = a + b
print(d)
print("{0:.5f} sec".format(timer.stop()))
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)]
#figsize为图像尺寸,其他参数都好理解
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])
d2l.plt.show()

 

就像我们所看到的,改变均值会产生沿x轴的偏移,增加方差将会分散分布、降低其峰值。

 

想要深入研究的话, 去原网页 如上图,

 

线性回归的底层实现

 

对于底层实现的理解需要借助一点 数形结合的思想。

 

补充一个函数yield

 

矩阵乘法怎幺用在代码里面的详解(matmul)

 

注意代码里的一个细节

 

+=和-=的区别(内存的分配)。

 

知乎:关于梯度下降的原理

 

进阶一点的随机梯度下降 以及学习率衰减

 

如果数据大小不能被batch_size整除怎幺办?
1 reply
23 Jul▶ mi_Sot
qscgyx
(indices[i: min(i + batch_size, num_examples)]):不被整除,余数小于bitchsize,就把剩下的数组组成一个新的数据集进行迭代

 

剩下的知识补充在代码里面了。

 

代码和截图

 

import random
import torch
## with torch.no_grad() 则主要是用于停止autograd模块的工作,
## 以起到加速和节省显存的作用,具体行为就是停止gradient计算,从而节省了GPU算力和显存,但是并不会影响dropout和batchnorm层的行为。
## mm只能进行矩阵乘法,也就是输入的两个tensor维度只能是( n × m ) (n\times m)(n×m)和( m × p ) (m\times p)(m×p)
## bmm是两个三维张量相乘, 两个输入tensor维度是( b × n × m )和( b × m × p ), 第一维b代表batch size,输出为( b × n × p )
## matmul可以进行张量乘法, 输入可以是高维.
## python知识补充:
## Python3 range() 函数返回的是一个可迭代对象(类型是对象),而不是列表类型, 所以打印的时候不会打印列表。
## Python3 list() 函数是对象迭代器,可以把range()返回的可迭代对象转为一个列表,返回的变量类型为列表。
## Python3 range(start, stop[, step])
## Python3 shuffle() 方法将序列的所有元素随机排序。shuffle()是不能直接访问的,需要导入 random 模块。举例:random.shuffle (list)
## Python3 yield是python中的生成器
## 人造数据集
def create_data(w, b, nums_example):
    X = torch.normal(0, 1, (nums_example, len(w)))
    print(X)
    y = torch.matmul(X, w) + b
    print("y_shape:", y.shape)
    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 = create_data(true_w, true_b, 1000)
## 读数据集
def read_data(batch_size, features, lables):
    nums_example = len(features)
    indices = list(range(nums_example))  # 生成0-999的元组,然后将range()返回的可迭代对象转为一个列表
    random.shuffle(indices)  # 将序列的所有元素随机排序。
    for i in range(0, nums_example, batch_size):  # range(start, stop, step)
        index_tensor = torch.tensor(indices[i: min(i + batch_size, nums_example)])
        yield features[index_tensor], lables[index_tensor]  # 通过索引访问向量
batch_size = 10
for X, y in read_data(batch_size, features, labels):
    print("X:", X, "
y", y)
    break;
##初始化参数
w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
# 定义模型
def net(X, w, b):
    return torch.matmul(X, w) + b
# 定义损失函数
#沐神原视频有提到
def loss(y_hat, y):
    # print("y_hat_shape:",y_hat.shape,"
y_shape:",y.shape)
    return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2  # 这里为什幺要加 y_hat_shape: torch.Size([10, 1])  y_shape: torch.Size([10])
# 定义优化算法
def sgd(params, batch_size, lr):
    with torch.no_grad():  # with torch.no_grad() 则主要是用于停止autograd模块的工作,
        for param in params:
            param -= lr * param.grad / batch_size  ##  这里用param = param - lr * param.grad / batch_size会导致导数丢失, zero_()函数报错
            param.grad.zero_()  ## 导数如果丢失了,会报错‘NoneType’ object has no attribute ‘zero_’
# 训练模型
lr = 0.03
num_epochs = 3
for epoch in range(0, num_epochs):
    for X, y in read_data(batch_size, features, labels):
        f = loss(net(X, w, b), y)
        # 因为`f`形状是(`batch_size`, 1),而不是一个向量。`f`中的所有元素被加到一起,
        # 并以此计算关于[`w`, `b`]的梯度
        f.sum().backward()
        sgd([w, b], batch_size, lr)  # 使用参数的梯度更新参数
    with torch.no_grad():
        train_l = loss(net(features, w, b), labels)
        print("w {0} 
b {1} 
loss {2:f}".format(w, b, float(train_l.mean())))
print("w误差 ", true_w - w, "
b误差 ", true_b - b)

 

运行结果:

 

tensor([[ 1.8542, -0.3219],
        [ 1.0203, -0.7845],
        [-0.9824, -0.1772],
        ...,
        [ 1.5191,  0.1785],
        [-0.6120, -0.9020],
        [-0.7551, -0.1053]])
y_shape: torch.Size([1000])
X: tensor([[-1.7079, -0.1877],
        [ 0.2274,  0.6016],
        [-1.4346, -0.5391],
        [-0.0480,  0.9621],
        [-0.9212, -0.0900],
        [-1.4508,  0.2027],
        [-0.6889, -0.2055],
        [ 1.6016,  0.7179],
        [-0.2508, -1.6958],
        [-0.3766,  2.1676]]) 
y tensor([[ 1.4308],
        [ 2.6103],
        [ 3.1677],
        [ 0.8409],
        [ 2.6762],
        [ 0.6122],
        [ 3.4965],
        [ 4.9586],
        [ 9.4805],
        [-3.9394]])
w tensor([[ 1.8843],
        [-3.2100]], requires_grad=True) 
b tensor([4.0051], requires_grad=True) 
loss 0.042249
w tensor([[ 1.9935],
        [-3.3888]], requires_grad=True) 
b tensor([4.1908], requires_grad=True) 
loss 0.000167
w tensor([[ 1.9995],
        [-3.3989]], requires_grad=True) 
b tensor([4.1991], requires_grad=True) 
loss 0.000054
w误差  tensor([[ 4.9162e-04, -5.3995e+00],
        [ 5.3989e+00, -1.1227e-03]], grad_fn=<SubBackward0>) 
b误差  tensor([0.0009], grad_fn=<RsubBackward1>)

 

softmax回归

 

GitHub参考

 

求幂运算就是以e为底数,把预测值作为指数进行运算。

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注