使用Pytorch来拟合函数方式


Posted in Python onJanuary 14, 2020

其实各大深度学习框架背后的原理都可以理解为拟合一个参数数量特别庞大的函数,所以各框架都能用来拟合任意函数,Pytorch也能。

在这篇博客中,就以拟合y = ax + b为例(a和b为需要拟合的参数),说明在Pytorch中如何拟合一个函数。

一、定义拟合网络

1、观察普通的神经网络的优化流程

# 定义网络
net = ...
# 定义优化器
optimizer = torch.optim.Adam(net.parameters(), lr=0.001, weight_decay=0.0005)
# 定义损失函数
loss_op = torch.nn.MSELoss(reduction='sum')
# 优化
for step, (inputs, tag) in enumerate(dataset_loader):
 # 向前传播
 outputs = net(inputs)
 # 计算损失
 loss = loss_op(tag, outputs)
 # 清空梯度
 optimizer.zero_grad()
 # 向后传播
 loss.backward()
 # 更新梯度
 optimizer.step()

上面的代码就是一般情况下的流程。为了能使用Pytorch内置的优化器,所以我们需要定义一个一个网络,实现函数parameters(返回需要优化的参数)和forward(向前传播);为了能支持GPU优化,还需要实现cuda和cpu两个函数,把参数从内存复制到GPU上和从GPU复制回内存。

基于以上要求,网络的定义就类似于:

class Net:
  def __init__(self):
    # 在这里定义要求的参数
    pass

  def cuda(self):
    # 传输参数到GPU
    pass

  def cpu(self):
    # 把参数传输回内存
    pass

  def forward(self, inputs):
   # 实现向前传播,就是根据输入inputs计算一遍输出
    pass

  def parameters(self):
   # 返回参数
    pass

在拟合数据量很大时,还可以使用GPU来加速;如果没有英伟达显卡,则可以不实现cuda和cpu这两个函数。

2、初始化网络

回顾本文目的,拟合: y = ax + b, 所以在__init__函数中就需要定义a和b两个参数,另外为了实现parameters、cpu和cuda,还需要定义属性__parameters和__gpu:

def __init__(self):
    # y = a*x + b
    self.a = torch.rand(1, requires_grad=True) # 参数a
    self.b = torch.rand(1, requires_grad=True) # 参数b
    self.__parameters = dict(a=self.a, b=self.b) # 参数字典
    self.___gpu = False # 是否使用gpu来拟合

要拟合的参数,不能初始化为0! ,一般使用随机值即可。还需要把requires_grad参数设置为True,这是为了支持向后传播。

3、实现向前传播

def forward(self, inputs):
    return self.a * inputs + self.b

非常的简单,就是根据输入inputs计算一遍输出,在本例中,就是计算一下 y = ax + b。计算完了要记得返回计算的结果。

4、把参数传送到GPU

为了支持GPU来加速拟合,需要把参数传输到GPU,且需要更新参数字典__parameters:

def cuda(self):
    if not self.___gpu:
      self.a = self.a.cuda().detach().requires_grad_(True) # 把a传输到gpu
      self.b = self.b.cuda().detach().requires_grad_(True) # 把b传输到gpu
      self.__parameters = dict(a=self.a, b=self.b) # 更新参数
      self.___gpu = True # 更新标志,表示参数已经传输到gpu了
    # 返回self,以支持链式调用
    return self

参数a和b,都是先调用detach再调用requires_grad_,是为了避免错误raise ValueError("can't optimize a non-leaf Tensor")(参考:ValueError: can't optimize a non-leaf Tensor?)。

4、把参数传输回内存

类似于cuda函数,不做过多解释。

def cpu(self):
    if self.___gpu:
      self.a = self.a.cpu().detach().requires_grad_(True)
      self.b = self.b.cpu().detach().requires_grad_(True)
      self.__parameters = dict(a=self.a, b=self.b)
      self.___gpu = False
    return self

5、返回网络参数

为了能使用Pytorch内置的优化器,就要实现parameters函数,观察Pytorch里面的实现:

def parameters(self, recurse=True):
    r"""...
    """
    for name, param in self.named_parameters(recurse=recurse):
      yield param

实际上就是使用yield返回网络的所有参数,因此本例中的实现如下:

def parameters(self):
    for name, param in self.__parameters.items():
      yield param

完整的实现将会放在后面。

二、测试

1、生成测试数据

def main():
  # 生成虚假数据
  x = np.linspace(1, 50, 50)
  # 系数a、b
  a = 2
  b = 1
  # 生成y
  y = a * x + b
  # 转换为Tensor
  x = torch.from_numpy(x.astype(np.float32))
  y = torch.from_numpy(y.astype(np.float32))

2、定义网络

# 定义网络
  net = Net()
  # 定义优化器
  optimizer = torch.optim.Adam(net.parameters(), lr=0.001, weight_decay=0.0005)
  # 定义损失函数
  loss_op = torch.nn.MSELoss(reduction='sum')

3、把数据传输到GPU(可选)

# 传输到GPU
  if torch.cuda.is_available():
    x = x.cuda()
    y = y.cuda()
    net = net.cuda()

4、定义优化器和损失函数

如果要使用GPU加速,优化器必须要在网络的参数传输到GPU之后在定义,否则优化器里的参数还是内存里的那些参数,传到GPU里面的参数不能被更新。 可以根据代码来理解这句话。

# 定义优化器
  optimizer = torch.optim.Adam(net.parameters(), lr=0.001, weight_decay=0.0005)
  # 定义损失函数
  loss_op = torch.nn.MSELoss(reduction='sum')

5、拟合(也是优化)

# 最多优化20001次
  for i in range(1, 20001, 1):
   # 向前传播
    out = net.forward(x)
 # 计算损失
    loss = loss_op(y, out)
 # 清空梯度(非常重要)
    optimizer.zero_grad()
 # 向后传播,计算梯度
    loss.backward()
 # 更新参数
    optimizer.step()
 # 得到损失的numpy值
    loss_numpy = loss.cpu().detach().numpy()
    if i % 1000 == 0: # 每1000次打印一下损失
      print(i, loss_numpy)

    if loss_numpy < 0.00001: # 如果损失小于0.00001
     # 打印参数
     a = net.a.cpu().detach().numpy()
     b = net.b.cpu().detach().numpy()
      print(a, b)
      # 退出
      exit()

6、完整示例代码

# coding=utf-8
from __future__ import absolute_import, division, print_function
import torch
import numpy as np


class Net:
  def __init__(self):
    # y = a*x + b
    self.a = torch.rand(1, requires_grad=True) # 参数a
    self.b = torch.rand(1, requires_grad=True) # 参数b
    self.__parameters = dict(a=self.a, b=self.b) # 参数字典
    self.___gpu = False # 是否使用gpu来拟合

  def cuda(self):
    if not self.___gpu:
      self.a = self.a.cuda().detach().requires_grad_(True) # 把a传输到gpu
      self.b = self.b.cuda().detach().requires_grad_(True) # 把b传输到gpu
      self.__parameters = dict(a=self.a, b=self.b) # 更新参数
      self.___gpu = True # 更新标志,表示参数已经传输到gpu了
    # 返回self,以支持链式调用
    return self

  def cpu(self):
    if self.___gpu:
      self.a = self.a.cpu().detach().requires_grad_(True)
      self.b = self.b.cpu().detach().requires_grad_(True)
      self.__parameters = dict(a=self.a, b=self.b) # 更新参数
      self.___gpu = False
    return self

  def forward(self, inputs):
    return self.a * inputs + self.b

  def parameters(self):
    for name, param in self.__parameters.items():
      yield param


def main():

  # 生成虚假数据
  x = np.linspace(1, 50, 50)

  # 系数a、b
  a = 2
  b = 1

  # 生成y
  y = a * x + b

  # 转换为Tensor
  x = torch.from_numpy(x.astype(np.float32))
  y = torch.from_numpy(y.astype(np.float32))

  # 定义网络
  net = Net()

  # 传输到GPU
  if torch.cuda.is_available():
    x = x.cuda()
    y = y.cuda()
    net = net.cuda()

  # 定义优化器
  optimizer = torch.optim.Adam(net.parameters(), lr=0.001, weight_decay=0.0005)

  # 定义损失函数
  loss_op = torch.nn.MSELoss(reduction='sum')

  # 最多优化20001次
  for i in range(1, 20001, 1):
    # 向前传播
    out = net.forward(x)
    # 计算损失
    loss = loss_op(y, out)
    # 清空梯度(非常重要)
    optimizer.zero_grad()
    # 向后传播,计算梯度
    loss.backward()
    # 更新参数
    optimizer.step()
    # 得到损失的numpy值
    loss_numpy = loss.cpu().detach().numpy()
    if i % 1000 == 0: # 每1000次打印一下损失
      print(i, loss_numpy)

    if loss_numpy < 0.00001: # 如果损失小于0.00001
      # 打印参数
      a = net.a.cpu().detach().numpy()
      b = net.b.cpu().detach().numpy()
      print(a, b)
      # 退出
      exit()


if __name__ == '__main__':
  main()

以上这篇使用Pytorch来拟合函数方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python性能优化的20条建议
Oct 25 Python
Python中Random和Math模块学习笔记
May 18 Python
Python中random模块用法实例分析
May 19 Python
总结网络IO模型与select模型的Python实例讲解
Jun 27 Python
Python3实现带附件的定时发送邮件功能
Dec 22 Python
Python内置函数reversed()用法分析
Mar 20 Python
使用Python制作简单的小程序IP查看器功能
Apr 16 Python
Python3.5面向对象程序设计之类的继承和多态详解
Apr 24 Python
10行Python代码计算汽车数量的实现方法
Oct 23 Python
浅析python,PyCharm,Anaconda三者之间的关系
Nov 27 Python
Django更新models数据库结构步骤
Apr 01 Python
Python脚本实现监听服务器的思路代码详解
May 28 Python
pytorch 模拟关系拟合——回归实例
Jan 14 #Python
PyTorch实现AlexNet示例
Jan 14 #Python
Pytorch 实现focal_loss 多类别和二分类示例
Jan 14 #Python
Python实现钉钉订阅消息功能
Jan 14 #Python
Python Tensor FLow简单使用方法实例详解
Jan 14 #Python
Python利用全连接神经网络求解MNIST问题详解
Jan 14 #Python
基于pytorch的lstm参数使用详解
Jan 14 #Python
You might like
POST一个JSON格式的数据给Restful服务实例详解
2017/04/07 PHP
PHP实现绘制二叉树图形显示功能详解【包括二叉搜索树、平衡树及红黑树】
2017/11/16 PHP
PHP命名空间简单用法示例
2018/12/28 PHP
javascript StringBuilder类实现
2008/12/22 Javascript
WEB 浏览器兼容 推荐收藏
2010/05/14 Javascript
Javascript面向对象之四 继承
2011/02/08 Javascript
Document.location.href和.replace的区别示例介绍
2014/03/04 Javascript
JS基础随笔(菜鸟必看篇)
2016/07/13 Javascript
node koa2实现上传图片并且同步上传到七牛云存储
2017/07/31 Javascript
Vue Transition实现类原生组件跳转过渡动画的示例
2017/08/19 Javascript
angularjs实现天气预报功能
2020/06/16 Javascript
webpack-dev-server自动更新页面方法
2018/02/22 Javascript
Node.js引入UIBootstrap的方法示例
2018/05/11 Javascript
javascript中函数的写法实例代码详解
2018/10/28 Javascript
vue开发环境配置跨域的方法步骤
2019/01/16 Javascript
浅谈Express.js解析Post数据类型的正确姿势
2019/05/30 Javascript
深入理解JavaScript 箭头函数
2019/05/30 Javascript
jQuery+Ajax+js实现请求json格式数据并渲染到html页面操作示例
2020/06/02 jQuery
uniapp开发小程序实现滑动页面控制元素的显示和隐藏效果
2020/12/10 Javascript
[52:02]完美世界DOTA2联赛PWL S2 FTD.C vs SZ 第一场 11.27
2020/11/30 DOTA
在Python的Django框架中显示对象子集的方法
2015/07/21 Python
Python Queue模块详细介绍及实例
2016/12/27 Python
python使用tornado实现简单爬虫
2018/07/28 Python
10 行 Python 代码教你自动发送短信(不想回复工作邮件妙招)
2018/10/11 Python
浅谈python 导入模块和解决文件句柄找不到问题
2018/12/15 Python
Python子类继承父类构造函数详解
2019/02/19 Python
详解Python函数式编程—高阶函数
2019/03/29 Python
python-docx文件定位读取过程(尝试替换)
2020/02/13 Python
程序设计HTML5 Canvas API
2013/04/08 HTML / CSS
英国珠宝和手表专家:Pleasance & Harper
2020/10/21 全球购物
房产销售经理职责
2013/12/20 职场文书
《花瓣飘香》教学反思
2014/04/15 职场文书
企业党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
奖学金感谢信
2015/01/21 职场文书
学习nginx基础知识
2021/09/04 Servers
Python Pandas 删除列操作
2022/03/16 Python