线性回归的从零开始实现(pytorch)

#1. 定义一个线性回归函数,返回值为自变量X和函数值y
def synthetic_data(w,b,num_examples):
  #******************1.1 定义1000x2大小的数据集X******************
  X = torch.normal(0,1,(num_examples,len(w)))
  #torch.normal(means, std, out=None),means(tensor)-均值,std(tensor)-标准差,out(tensor)-可选的输出张量
  #返回一个张量,包含从给定参数means,std的离散正态分布中抽取随机数。 
  #均值means是一个张量,包含每个输出元素相关的正态分布的均值。 
  #std是一个张量,包含每个输出元素相关的正态分布的标准差。
  #out的大小和数量可以被指定 
  #均值和标准差的形状不须匹配,但每个张量的元素个数须相同。
  
  #******************1.2 计算y=Xw+b******************
  y = torch.matmul(X,w)+b
  #torch,matmul(a,b) tensor的乘法,输入可以是高维的
  #输入有3维时,把多出的一维作为batch;大于3维,第0维作为batch,其余利用广播机制
  
  #*******************1.3 加入随机噪声0.01(假设误差服从均值为0的正态分布)***********
  y += torch.normal(0,0.01,y.shape)

  return X,y.reshape((-1,1)) #n行1列,即列向量
  #reshape函数,修改成m行n列的矩阵,
  #-1表示模糊控制,行或列为-1表示行数或列数不确定,另一维确定即可

#2. 生成真实的w和b,调用函数得到特征和标签
true_w = torch.tensor([2,-3.4])
true_b = 4.2
features,labels = synthetic_data(true_w,true_b,1000);


#3. 定义一个data_iter函数,用于分割批量。
    #接收批量大小、特征矩阵和标签向量作为输入
    #生成大小为batch_size的小批量
def data_iter(batch_size,features,labels):
  num_examples = len(features)
  indices = list(range(num_examples))#用range()函数从0到n-1计数,再通过list()返回列表
  #Python3 range() 函数返回的是一个可迭代对象(类型是对象),而不是列表类型, 所以打印的时候不会打印列表。
    #range(stop) 计数到stop结束
    #range(start,stop[,step]) 从start开始,step为步长
  #Python3 list() 函数是对象迭代器,可以把range()返回的可迭代对象转为一个列表,返回的变量类型为列表。
  
  #序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推。
  #列表的数据项不需要具有相同的类型
  #创建一个列表,只要把逗号分隔的不同的数据项使用方括号括起来即可

  random.shuffle(indices) #随机打乱
  for i in range(0,num_examples,batch_size):#从0开始,到num_examples结束,每次跳batch_size
    batch_indices = torch.tensor(indices[i:min(i+batch_size,num_examples)])
    #每次生成从i到i+batch_size大小的tensor,
    #min函数避免到最后一个batch数量不足size,取到num_examples即可
    yield features[batch_indices],labels[batch_indices]
    #一个带有 yield 的函数就是一个 generator,
    #它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,
    #直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。
    #虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,
    #下次执行时从 yield 的下一个语句继续执行。
    #看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,
    #每次中断都会通过 yield 返回当前的迭代值。

batch_size = 10


#4. 定义初始化模型参数
w = torch.normal(0,0.01,size=(2,1),requires_grad=True)
b = torch.zeros(1,requires_grad=True)

#5. 定义模型
def linreg(X,w,b):
  """线性回归模型"""
  return torch.matmul(X,w)+b

#6. 定义损失函数
def squared_loss(y_hat,y):
  """均方损失"""
  return (y_hat-y.reshape(y_hat.shape))**2/2

#7. 定义优化算法
def sgd(params,lr,batch_size):#params:参数w和b;lr:学习率;batch_size:批量大小
  """小批量随机梯度下降"""
  with torch.no_grad():
    for param in params:
      param -= lr*param.grad/batch_size
      param.grad.zero_() #手动设置梯度清零

#8. 训练过程
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)  #l是每个小批量损失
    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}')

你可能感兴趣的:(笔记,pytorch,深度学习,机器学习)