第2章 PyTorch基础(2/2)

2.6 使用NumPy实现机器学习

前面我们介绍了NumPy、Tensor的基础内容,对如何用NumPy、Tensor操作数组有了一定认识。为了加深大家对PyTorch的谅解,本章剩余章节将分别用NumPy、Tensor、autograd、nn及optimal实现同一个机器学习任务,比较它们的异同及优缺点,从而加深对PyTorch的理解。
首先,我们用最原始的NumPy实现一个有关回归的机器学习任务,不用PyTorch中的包或类。这种方法的代码可能会多一点,但每一步都是透明的,有利于理解每步的工作原理。
主要步骤分析如下。
首先,是给出一个数组x,然后基于表达式:y=3x^2+2,加上一些噪声数据到达另一组数据y。
然后,构建一个机器学习模型,学习表达式y=wx^2+b的两个参数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章 PyTorch基础(2/2)_第1张图片

 图2-12 NumPy实现的源数据
4)初始化权重参数。

# 随机初始化参数
w1 = np.random.rand(1,1)
b1 = np.random.rand(1,1) 

5)训练模型。
定义损失函数,假设批量大小为100:

第2章 PyTorch基础(2/2)_第2张图片

用代码实现上面这些表达式:

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章 PyTorch基础(2/2)_第3张图片

 

图2-13 可视化NumPy学习结果
[[2.98927619]] [[2.09818307]]
从结果看来,学习效果还是比较理想的。

2.7 使用Tensor及Autograd实现机器学习

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章 PyTorch基础(2/2)_第4张图片

 图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章 PyTorch基础(2/2)_第5张图片

图2-15 使用 autograd的结果
tensor([[2.9645]], requires_grad=True) tensor([[2.1146]], requires_grad=True)。
这个结果与使用NumPy机器学习的差不多。

2.8 使用优化器及自动微分

使用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章 PyTorch基础(2/2)_第6张图片

图2-16 使用优化器及自动微分(autograd)的结果
tensor([[2.6369]], requires_grad=True) tensor([[2.2360]], requires_grad=True)
由此可知,使用内置损失函数、优化器及自动微分实现机器学习比较简洁,这也是深度学习普遍采用的方式。

2.9 把数据集转换带批量的迭代器

把数据集转换为带批量的迭代器,这样训练时就可进行批量处理。如果数据量比较大,采用批量处理可提升训练模型的效率及性能。
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章 PyTorch基础(2/2)_第7张图片

图2-17 使用数据迭代器、优化器和自动微分(autograd)的结果
tensor([[2.6370]], requires_grad=True) tensor([[2.2360]], requires_grad=True)

2.10 使用TensorFlow2架构实现机器学习

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章 PyTorch基础(2/2)_第8张图片

图2-18 使用Tensorflow的结果

2.11 小结

本章主要介绍PyTorch的基础知识,这些内容是后续章节的重要支撑。首先介绍了PyTorch的安装配置,然后介绍了PyTorch的重要数据结构Tensor。Tensor类似于NumPy的数据结构,但Tensor提供GPU加速及自动求导等技术。最后分别用NumPy、Tensor、autograd、Optimizer和TensorFlow2等技术分别实现同一个机器学习任务。

 

你可能感兴趣的:(pytorch,python,numpy)