前面我们介绍了NumPy、Tensor的基础内容,对如何用NumPy、Tensor操作数组有了一定认识。为了加深大家对PyTorch的谅解,本章剩余章节将分别用NumPy、Tensor、autograd、nn及optimal实现同一个机器学习任务,比较它们的异同及优缺点,从而加深对PyTorch的理解。
首先,我们用最原始的NumPy实现一个有关回归的机器学习任务,不用PyTorch中的包或类。这种方法的代码可能会多一点,但每一步都是透明的,有利于理解每步的工作原理。
主要步骤分析如下。
首先,是给出一个数组x,然后基于表达式:,加上一些噪声数据到达另一组数据y。
然后,构建一个机器学习模型,学习表达式的两个参数w,b。利用数组x,y的数据训练模型。
最后,采用梯度下降法,通过多次迭代,学习到w、b的值。
1)导入需要的库。
# -*- coding: utf-8 -*-
import numpy as np
%matplotlib inline
from matplotlib import pyplot as plt
2)生成输入数据x及目标数据y。设置随机数种子,生成同一个份数据,以便用多种方法进行比较。
np.random.seed(100)
x = np.linspace(-1, 1, 100).reshape(100,1)
y = 3*np.power(x, 2) +2+ 0.2*np.random.rand(x.size).reshape(100,1)
3)查看x,y数据分布情况。
# 画图
plt.scatter(x, y)
plt.show()
运行结果如图2-12所示。
图2-12 NumPy实现的源数据
4)初始化权重参数。
# 随机初始化参数
w1 = np.random.rand(1,1)
b1 = np.random.rand(1,1)
5)训练模型。
定义损失函数,假设批量大小为100:
用代码实现上面这些表达式:
lr =0.001 # 学习率
for i in range(800):
# 正向传播
y_pred = np.power(x,2)*w1 + b1
# 定义损失函数
loss = 0.5 * (y_pred - y) ** 2
loss = loss.sum()
#计算梯度
grad_w=np.sum((y_pred - y)*np.power(x,2))
grad_b=np.sum((y_pred - y))
#使用梯度下降法,是loss最小
w1 -= lr * grad_w
b1 -= lr * grad_b
6)查看可视化结果。
plt.plot(x, y_pred,'r-',label='predict',linewidth=4)
plt.scatter(x, y,color='blue',marker='o',label='true') # true data
plt.xlim(-1,1)
plt.ylim(2,6)
plt.legend()
plt.show()
print(w1,b1)
运行结果如图2-13所示。
图2-13 可视化NumPy学习结果
[[2.98927619]] [[2.09818307]]
从结果看来,学习效果还是比较理想的。
2.6节可以说是纯手工完成一个机器学习任务,数据用NumPy表示,梯度学习是自己定义并构建学习模型。这种方法适合于比较简单的情况, 如果稍微复杂一些, 代码量将几何级增加。 是否有更方便的方法呢? 这节我们将使用PyTorch的自动求导的一个
包——autograd,利用这个包及对应的Tensor, 便可利用自动反向传播来求梯度,无须手工计算梯度。以下是具体实现代码。
1)导入需要的库。
import torch
%matplotlib inline
from matplotlib import pyplot as plt
2)生成训练数据,并可视化数据分布情况。
torch.manual_seed(100)
dtype = torch.float
#生成x坐标数据,x为tenor,形状为100x1
x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1)
#生成y坐标数据,y为tenor,形状为100x1,另加上一些噪声
y = 3*x.pow(2) +2+ 0.2*torch.rand(x.size())
# 画图,把tensor数据转换为numpy数据
plt.scatter(x.numpy(), y.numpy())
plt.show()
运行结果如图2-14所示。
图2-14 可视化输入数据
3)初始化权重参数。
# 随机初始化参数,参数w,b为需要学习的,故需requires_grad=True
w = torch.randn(1,1, dtype=dtype,requires_grad=True)
b = torch.zeros(1,1, dtype=dtype, requires_grad=True)
4)训练模型。
lr =0.001 # 学习率
for ii in range(800):
# forward:计算loss
y_pred = x.pow(2).mm(w) + b
loss = 0.5 * (y_pred - y) ** 2
loss = loss.sum()
# backward:自动计算梯度
loss.backward()
# 手动更新参数,需要用torch.no_grad()更新参数
with torch.no_grad():
w -= lr * w.grad
b -= lr * b.grad
# 因通过autigrad计算的梯度,会累加到grad中,故每次循环需把梯度清零
w.grad.zero_()
b.grad.zero_()
5)查看可视化训练结果。
plt.plot(x.numpy(), y_pred.detach().numpy(),'r-',label='predict',linewidth=4)#predict
plt.scatter(x.numpy(), y.numpy(),color='blue',marker='o',label='true') # true data
plt.xlim(-1,1)
plt.ylim(2,6)
plt.legend()
plt.show()
print(w, b)
运行结果如图2-15所示。
图2-15 使用 autograd的结果
tensor([[2.9645]], requires_grad=True) tensor([[2.1146]], requires_grad=True)。
这个结果与使用NumPy机器学习的差不多。
使用PyTorch内置的损失函数、优化器和自动微分机制等,可大大简化整个机器学习过程。梯度更新可简化为optimizer.step(),梯度清零可使用optimizer.zero_grad()。详细代码如下。导入模块与生成数据代码与2.7小节的基本相同,只需添加导入nn模块(这个模块第3章将介绍),这里就重写了。
1)定义损失函数及优化器。
loss_func = nn.MSELoss()
optimizer = torch.optim.SGD([w,b],lr = 0.001)
2)训练模型。
for ii in range(10000):
# forward:计算loss
y_pred = x.pow(2).mm(w) + b
loss=loss_func(y_pred,y)
# backward:自动计算梯度
loss.backward()
# 更新参数
optimizer.step()
# 因通过autigrad计算的梯度,会累加到grad中,故每次循环需把梯度清零
optimizer.zero_grad()
3)查看可视化运行结果。
plt.plot(x.numpy(), y_pred.detach().numpy(),'r-',label='predict',linewidth=4)#predict
plt.scatter(x.numpy(), y.numpy(),color='blue',marker='o',label='true') # true data
plt.xlim(-1,1)
plt.ylim(2,6)
plt.legend()
plt.show()
print(w, b)
运行结果如图2-16所示。
图2-16 使用优化器及自动微分(autograd)的结果
tensor([[2.6369]], requires_grad=True) tensor([[2.2360]], requires_grad=True)
由此可知,使用内置损失函数、优化器及自动微分实现机器学习比较简洁,这也是深度学习普遍采用的方式。
把数据集转换为带批量的迭代器,这样训练时就可进行批量处理。如果数据量比较大,采用批量处理可提升训练模型的效率及性能。
1)构建数据迭代器。
import numpy as np
# 构建数据迭代器
def data_iter(features, labels, batch_size=4):
num_examples = len(features)
indices = list(range(num_examples))
np.random.shuffle(indices) #样本的读取顺序是随机的
for i in range(0, num_examples, batch_size):
indexs = torch.LongTensor(indices[i: min(i + batch_size, num_examples)])
yield features.index_select(0, indexs), labels.index_select(0, indexs)
2)训练模型。
for ii in range(1000):
for features, labels in data_iter(x,y,10):
# forward:计算loss
y_pred = features.pow(2).mm(w) + b
loss=loss_func(y_pred,labels)
# backward:自动计算梯度
loss.backward()
# 更新参数
optimizer.step()
# 因通过autigrad计算的梯度,会累加到grad中,故每次循环需把梯度清零
optimizer.zero_grad()
3)查看可视化运行结果。
y_p=x.pow(2).mm(w).detach().numpy() + b.detach().numpy()
plt.plot(x.numpy(), y_p,'r-',label='predict',linewidth=4)#predict
plt.scatter(x.numpy(), y.numpy(),color='blue',marker='o',label='true') # true data
plt.xlim(-1,1)
plt.ylim(2,6)
plt.legend()
plt.show()
print(w, b)
运行结果如图2-17所示。
图2-17 使用数据迭代器、优化器和自动微分(autograd)的结果
tensor([[2.6370]], requires_grad=True) tensor([[2.2360]], requires_grad=True)
2.6节用NumPy实现了回归分析,2.7节用PyTorch的autograd及Tensor实现了这个任务。这节我们用深度学习的另一个框架TensorFlow实现该回归分析任务,大家可比较一下不同架构之间的区别。为便于比较,这里使用TensorFlow 2实现这个任务。
1)导入库及生成训练数据。
import tensorflow as tf
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline
2)生成训练数据,并初始化参数。
#生成训练数据
np.random.seed(100)
x = np.linspace(-1, 1, 100).reshape(100,1)
y = 3*np.power(x, 2) +2+ 0.2*np.random.rand(x.size).reshape(100,1)
# 创建权重变量w和b,并用随机值初始化.
# TensorFlow 的变量在整个计算图保存其值.
w = tf.Variable(tf.random.uniform([1], 0, 1.0))
b = tf.Variable(tf.zeros([1]))
3)构建模型。
# 定义模型
class CustNet:
#正向传播
def __call__(self,x):
return np.power(x,2)*w + b
# 损失函数
def loss_func(self,y_true,y_pred):
return tf.reduce_mean((y_true - y_pred)**2/2)
model=CustNet()
4)训练模型。
epochs=14000
for epoch in tf.range(1,epochs):
with tf.GradientTape() as tape:
predictions = model(x)
loss = model.loss_func(y, predictions)
# 反向传播求梯度
dw,db = tape.gradient(loss,[w,b])
# 梯度下降法更新参数
w.assign(w - 0.001*dw)
b.assign(b - 0.001*db)
5)查看可视化运行结果。
# 可视化结果
plt.figure()
plt.scatter(x,y,color='blue',marker='o',label='true')
plt.plot (x, b + w*x**2,'r-',label='predict',linewidth=4)
运行结果如图2-18所示。
图2-18 使用Tensorflow的结果
本章主要介绍PyTorch的基础知识,这些内容是后续章节的重要支撑。首先介绍了PyTorch的安装配置,然后介绍了PyTorch的重要数据结构Tensor。Tensor类似于NumPy的数据结构,但Tensor提供GPU加速及自动求导等技术。最后分别用NumPy、Tensor、autograd、Optimizer和TensorFlow2等技术分别实现同一个机器学习任务。