在PyTorch中,Tensor(张量)>是基本单元,它包含参数和损失函数关于这个参数的导数。
下图的代码定义了一个,w 为 [1.0] 的Tensor,将requires_grad置为True表示这个参数需要计算梯度。默认为False。
如果w需要计算梯度,那么通过w计算得到的a也需要计算梯度,其中w和a都是Tensor。Tensor之间的乘法可以直接用*进行,已经被重载过了。
代码功能:使用pytorch实现线性回归
- 需要注意的是,一旦执行过一次backward,就会释放原有的计算图,下次计算时需要创建一个新的计算图。这样设定的目的是因为每次迭代都可能使用不同的计算图。
- 更新参数时一定记得要转换成标量后再去计算,否则会导致计算图的膨胀。
import torch
# 模拟训练集,这里 y = 2x
x_train = [1, 2, 3]
y_train = [2, 4, 6]
# 创建一个data为1.0的Tensor(张量)
w = torch.Tensor([1.0])
w.requires_grad = True
def forward(x, w):
# 这里的w和x都是Tensor
return w * x
def loss(x, y, w):
y_pred = forward(x, w)
return (y_pred - y) ** 2
# 训练100次
for epoch in range(100):
# 这里为了方便理解,不使用向量化
for x, y in zip(x_train, y_train):
cost = loss(x, y, w)
cost.backward()
# 这里假设学习率为0.01
# 须注意w.grad其实也是一个张量,更新参数时应该转换成标量来计算
# 否则张量间的计算会构建计算图,循环多次后,可能会因为计算图过于庞大导致程序崩溃
w.data = w.data - 0.01 * w.grad.data
# 手动将原来的导数清零,如果不清零,就会保留原有的值,下次使用时会是 旧值+新值
# 显然这样的设定是为了方便应用以后的各种优化方法
w.grad.data.zero_()
# cost.item()的返回值是一个int或float类型的数据
# 这里输出的是上个训练集中最后一组数据的cost,并非总的cost
# 如果要计算cost_total,应在上一个循环中使用sum += cost.item()
# 如果使用sum_tensor += cost,那么会构建计算图来计算,性能不如直接进行标量运算
# 但是sum == sum_tensor.item()为True
print("epoch: ", epoch, ",\tcost: ", cost.item())
print(type(w.item()),w.item()) # <class 'float'> 1.9999996423721313
print(type(w.data),w.data) # <class 'torch.Tensor'> tensor([2.0000])
print(type(w),w) # <class 'torch.Tensor'> tensor([2.0000], requires_grad=True)