从零开始实现的代码如下:
import math import random #随机梯度下降 随机的权重 import time import numpy as np from d2l import torch as d2l #实现过的函数写在d2l包中 ''' 加这两句是为了能画出散点图,不然会报错 import os os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" ''' #定义一个函数生成数据集 def synthetic_data(w, b, num_examples): #生成 y = Xw + b + 噪声 #均值为0, 方差为1的随机数,有num_examples个样本,有len(w)列 x = torch.normal(0, 1, (num_examples, len(w))) y = torch.matmul(x, w) + b #加入随机噪音 均值为0,方差为0.01 y += torch.normal(0, 0.01, y.shape) return x, y.reshape((-1, 1)) #-1指行数未知由电脑推断 1指的是1列 true_w = torch.tensor([2, -3.4]) true_b = 4.2 features, labels = synthetic_data(true_w, true_b, 1000) #用于生成特征与标号 print('features:', features[0], '\nlabel:', labels[0]) #生成散点图 d2l.set_figsize() d2l.plt.scatter(features[:, 0].detach().numpy(), labels.detach().numpy(), 1); #定义一个函数读取数据集 def data_iter(batch_size, features, labels): num_examples = len(features) indices = list(range(num_examples)) #这些样本是随机读取的,没有特定的顺序 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)]) 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 #定义初始化模型参数 w = torch.normal(0, 0.01, size = (2, 1), requires_grad = True) b = torch.zeros(1, requires_grad = True) def linreg(x, w, b): #线性回归模型 #这里会出现广播,即当我们用一个向量加一个标量时,标量会被加在向量的每个分量上 return torch.matmul(x, w) + b #定义损失函数 def squared_loss(y_hat, y): #均方损失 return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2 #除以2是求导时方便 #定义优化算法 def sgd(params, lr, batch_size): #小批量梯度下降 with torch.no_grad(): #不需要计算梯度 for param in params: param -= lr * param.grad / batch_size param.grad.zero_() #手动将梯度设为0(方便下一次计算梯度) #训练 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'的小批量损失 #因为l的形状是(batch_size, 1), 而不是一个标量 #l中的所有元素被加到一起,并以此计算关于[w, b]的梯度 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}') print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}') print(f'b的估计误差: {true_b - b}') '''
线性回归的简易实现如下:
import math import random #随机梯度下降 随机的权重 import time import numpy as np from d2l import torch as d2l #实现过的函数写在d2l包中 #线性回归的简洁实现 from torch.utils import data #定义一个函数生成数据集 def synthetic_data(w, b, num_examples): #生成 y = Xw + b + 噪声 #均值为0, 方差为1的随机数,有num_examples个样本,有len(w)列 x = torch.normal(0, 1, (num_examples, len(w))) y = torch.matmul(x, w) + b #加入随机噪音 均值为0,方差为0.01 y += torch.normal(0, 0.01, y.shape) return x, y.reshape((-1, 1)) #-1指行数未知由电脑推断 1指的是1列 true_w = torch.tensor([2, -3.4]) true_b = 4.2 features, labels = synthetic_data(true_w, true_b, 1000) #用于生成特征与标号 #读取数据集 def load_array(data_arrays, batch_size, is_train = True): #构造一个PyTorch数据迭代器 #TensorDataset:把输入的两类数据进行一一对应 #'*'是为了给元组解包 dataset = data.TensorDataset(*data_arrays) #DataLoader:重新排序 #布尔值is_train表示是否希望数据迭代器对象在每轮内打乱数据 return data.DataLoader(dataset, batch_size, shuffle = is_train) batch_size = 10 data_iter = load_array((features, labels), batch_size) #iter()用于产生迭代器,next()用于访问迭代器的下一个元素 print(next(iter(data_iter))) #定义模型 #'nn'是神经网络的缩写 from torch import nn #Sequential是一个有序的容器,神经网络模块将按照在传入构造器的顺序 #依次被添加到计算图中执行。同时以神经网络模块为元素的有序字典序也可以作为传入参数 net = nn.Sequential(nn.Linear(2, 1)) #指定输入维度为2,输出维度为1 #初始化模型参数 #net[0]访问网络的第一层 #weight.data和bias.data方法访问参数 #我们可以用normal_(正态分布)和fill_来重写参数值 net[0].weight.data.normal_(0, 0.01)#均值为0方差为0.01 net[0].bias.data.fill_(0) #定义损失函数 loss = nn.MSELoss() #计算均方误差使用MSELoss类 默认情况下他返回所有样本损失的均值 #定义优化算法 trainer = torch.optim.SGD(net.parameters(), lr = 0.03) #训练 ''' 1.调用net(x)生成预测并计算损失l(向前传播) 2.通过反向传播计算梯度 3.通过调用优化器来更新模型的参数 ''' 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() trainer.step() #进行模型的更新 l = loss(net(features), labels) print(f'epoch {epoch + 1}, loss {l:f}')
再补充一个向量化加速的小例子(导入的包就不改了,偷个懒)
import math import random #随机梯度下降 随机的权重 import time import numpy as np from d2l import torch as d2l #实现过的函数写在d2l包中 #向量化加速 #以两个10000维的向量相加为例 ''' n = 10000 a = torch.ones(n) b = torch.ones(n) #定义一个计时器 class Timer: #记录多次运行时间 def __init__(self): self.times = [] self.start() def start(self): #启动计时器 self.tik = time.time() def stop(self): #停止计时器并将时间记录在列表中 self.times.append(time.time() - self.tik) return self.times[-1] #-1代表列表中的最后一个元素的索引 def avg(self): #返回平均时间 return sum(self.times) / len(self.times) def sum(self): #返回时间总和 return sum(self.times) def cumsum(self): #返回累计时间 return np.array(self.times).cumsum().tolist() #第一种方案 利用for循环(慢) c = torch.zeros(n) timer = Timer() for i in range(n): c[i] = a[i] + b[i] print(f'{timer.stop():.5f} sec') #第二种方案 利用向量加法以达到加速(快) timer.start() d = a + b print(f'{timer.stop():.5f} sec') '''
这些内容有点难,看了好久都还很迷糊,继续加油吧
标签:灰灰,day8,self,torch,batch,从零开始,import,data,size From: https://www.cnblogs.com/fighting-huihui/p/17472767.html