Li-JT

线性回归的从零实现(借助pytorch)

import torch
from torch import nn
import random
net=nn.Linear(2,1)
print(net.type)
print(torch.__version__)

za=[3,4,5,6,7,8,9,10]
random.shuffle(za)#把za打乱顺序
bt=torch.tensor(za[1:7])
mt=list(range(20))
mt=torch.tensor(mt)#注意此处只有转化为torch.tensor()后
#才能在后续的mt(bt运行)
print(bt,bt.type())
print(mt,type(mt))
print(mt[bt])#可继续参考下面模块的代码

  

# %matplotlib inline #显示图示默认嵌入jupyter notebook中来显示
import random
import torch
from d2l import torch as d2l
#import d2lzh_pytorch as d2l #有网友这样说
#如果没有d2l可以用pip安装,或者在jupyter notebook中安装的话用!pip install d2l命令安装

 

\'\'\'
torch.normal(A, B ,size(C, D), requires_grad=True)
A表示均值,B表示标准差 ,C代表生成的数据行数,D表示列数,requires_grad=True表示对导数开始记录,不需要记录的话可以忽略。默认是False
\'\'\'
def synthetic_data(w,b,num_examples):
    """生成y=Xw+b+噪声"""
    X=torch.normal(0,1,(num_examples,len(w)))#X为1000行2列的矩阵,0是均值,1是标准差。
    y=torch.matmul(X,w)+b#X与w相乘,并加上b,可以用广播机制来加b,结果是1000行1列的列向量矩阵
    y+=torch.normal(0,0.01,y.shape)
#     print(y.shape,y.reshape(-1,1).shape)#torch.Size([1000]),torch.Size([1000, 1])说明y本身就是一个列向量,reshape(-1,1)后变成了若干行1列的二维矩阵
#     print(y.shape,y.shape[0],sep=\'\n\')#torch.Size([1000]),1000,如果是y.shape[1]就报错了,因为y只有行这个维度。
#     print(y.size())#torch.Size([1000])
#     print(y.reshape(-1,1).shape)#torch.Size([1000, 1])
#     print(y.reshape((-1,1)).shape)#torch.Size([1000, 1])
    return X,y.reshape((-1,1))

true_w=torch.tensor([2,-3.4]) #true_w是个2行1列的矩阵,是个列向量
true_b=4.2
features,labels=synthetic_data(true_w,true_b,1000)
# print(len(features),len(labels))
print(features.shape,labels.shape)
print(\'features:\',features[0],\'\nlabel:\',labels[0])

  

d2l.set_figsize()
d2l.plt.scatter(features[:,1].detach().numpy(),labels.detach().numpy(),1)

  

\'\'\'每次从所给的样本中选取batch个\'\'\'
def data_iter(batch_size,features,labels):
    num_examples=len(features)
    indices=list(range(num_examples))
    #这些样本是随机读取的,没有特定的顺序
    random.shuffle(indices)#打乱顺序后得到一个有打乱下标的list
    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

  

num_examples=15
indices=list(range(15))
#这些样本是随机读取的,没有特定的顺序
random.shuffle(indices)
for i in range(0,15,10):
    batch_indices=torch.tensor(indices[i:min(i+10,15)])
    print(batch_indices)


w=torch.normal(0,0.01,size=(2,1),requires_grad=True)
b=torch.ones(1,requires_grad=True)

def linreg(X,w,b):
    """线性回归模型"""
    return torch.matmul(X,w)+b
# print(w.size(),w.shape)

  

def squared_loss(y_hat,y):
    "均方误差"
    return (y_hat-y.reshape(y_hat.shape))**2/2

  

def sgd(params,lr,batch_size):#params里面包括w和b参数
    """小批量随机梯度下降"""
    with torch.no_grad():
        for param in params:
            param-=lr*param.grad/batch_size#这个param又可能是w,也有可能是b;
            #此处的除以batch_size.是因为之前的loss没有求均值,此处求均值。因为乘法对梯度来说是一个线性关系,
            #所以,除以batch_size除在上面和下面效果一样。也因为我们计算的梯度是一个批量样本的总和,所以用批量大小
            #来归一化步长,这样步长就不会取决于我们对批量大小的选择。
            param.grad.zero_()#pytorch会不断累加变量的梯度,故每更新一次参数,就要让其对应的梯度清零。

  

lr=0.03
num_epochs=3
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)#X和y的小批量损失
        #因为1 形状是(batch_size,1),而不是一个标量。1中的所有元素被加到
        #并一次计算关于[w,b]的梯度
        l.sum().backward()#求和之后算梯度;求和本身让l以标量的形式变现出来;求梯度对于l中的每一个分量都是单独求的;
        #求和之后后面会除batch_size可以计算均值。因为向量求梯度得矩阵;要同通过sum()转化为标量,然后再求梯度。
        #不求和的话是个向量,梯度算下来就变成矩阵了,形状没法对应。这里点backward()之后,你在sgd优化算法里就可以用
        #相应参数的点grad计算。
        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(\'w的估计误差:{}\'.format({true_w-w.reshape(true_w.shape)}))
print(\'b的估计误差:{}\'.format({true_b-b}))

 

python打印的时候print(f"*******") 的括号里的 f\' \' 的意思 ?

python的print字符串前面加f表示格式化字符串,加f后可以在字符串里面使用用花括号括起来的变量和表达式,如果字符串里面没有表达式,那么前面加不加f输出应该都一样.Python3.6新增了一种f-字符串格式化.

格式化的字符串文字前缀为’f’和接受的格式字符串相似str.format()。它们包含由花括号包围的替换区域。替换字段是表达式,在运行时进行评估,然后使用format()协议进行格式化。

formatted string literals, 以 f 开头,包含的{}表达式在程序运行时会被表达式的值代替。

分类:

技术点:

相关文章:

  • 2021-10-27
  • 2021-12-02
  • 2021-08-30
  • 2021-09-30
  • 2021-07-08
  • 2022-12-23
  • 2021-06-21
  • 2022-12-23
猜你喜欢
  • 2022-01-01
  • 2021-06-07
  • 2022-12-23
  • 2021-10-20
  • 2022-12-23
  • 2022-01-26
相关资源
相似解决方案