使用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+matplotlib绘制饼图散点图实例代码
Jan 20 Python
python如何在列表、字典中筛选数据
Mar 19 Python
实例讲解python中的协程
Oct 08 Python
Python爬虫设置代理IP(图文)
Dec 23 Python
Pyqt清空某一个QTreeewidgetItem下的所有分支方法
Jun 17 Python
Django之创建引擎索引报错及解决详解
Jul 17 Python
python自带tkinter库实现棋盘覆盖图形界面
Jul 17 Python
运用PyTorch动手搭建一个共享单车预测器
Aug 06 Python
Python+Redis实现布隆过滤器
Dec 08 Python
python读取Kafka实例
Dec 23 Python
pycharm 更改创建文件默认路径的操作
Feb 15 Python
浅谈keras中的keras.utils.to_categorical用法
Jul 02 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
php中使用Curl、socket、file_get_contents三种方法POST提交数据
2011/08/12 PHP
php中is_null,empty,isset,unset 的区别详细介绍
2013/04/28 PHP
PHP不使用递归的无限级分类简单实例
2016/11/05 PHP
php写一个函数,实现扫描并打印出自定目录下(含子目录)所有jpg文件名
2017/05/26 PHP
php变量与JS变量实现不通过跳转直接交互的方法
2017/08/25 PHP
PHP检测接口Traversable用法详解
2017/12/29 PHP
在laravel框架中实现封装公共方法全局调用
2019/10/14 PHP
window.open被浏览器拦截后的自定义提示效果代码
2007/11/19 Javascript
使用原生javascript创建通用表单验证——更锋利的使用dom对象
2011/09/13 Javascript
多种方法判断Javascript对象是否存在
2013/09/22 Javascript
关于jQuery判断元素是否存在的问题示例探讨
2014/07/21 Javascript
让IE8浏览器支持function.bind()方法
2014/10/16 Javascript
超实用的JavaScript代码段 附使用方法
2016/05/22 Javascript
JavaScript常用判断写法大全(推荐)
2016/05/30 Javascript
微信小程序 网络API发起请求详解
2016/11/09 Javascript
jQuery Validate设置onkeyup验证的实例代码
2016/12/09 Javascript
解决Window10系统下Node安装报错的问题分析
2016/12/13 Javascript
webpack配置之后端渲染详解
2017/10/26 Javascript
Puppeteer环境搭建的详细步骤
2018/09/21 Javascript
Vue源码解析之数据响应系统的使用
2019/04/24 Javascript
WebStorm中如何将自己的代码上传到github示例详解
2020/10/28 Javascript
利用Python操作消息队列RabbitMQ的方法教程
2017/07/19 Python
jupyter notebook实现显示行号
2020/04/13 Python
python 服务器运行代码报错ModuleNotFoundError的解决办法
2020/09/16 Python
python用tkinter实现一个gui的翻译工具
2020/10/26 Python
利用css3-animation实现逐帧动画效果
2016/03/10 HTML / CSS
html5实现完美兼容各大浏览器的播放器
2014/12/26 HTML / CSS
canvas 实现 github404动态效果的示例代码
2017/11/15 HTML / CSS
Vivo俄罗斯官方在线商店:中国智能手机品牌
2019/10/04 全球购物
应届大学生求职信
2014/07/20 职场文书
2014乡镇干部纪律作风整顿思想汇报
2014/09/13 职场文书
民间借贷被告代理词
2015/05/23 职场文书
教师个人工作总结范文2015
2015/10/14 职场文书
大学生心理健康教育心得体会
2016/01/12 职场文书
导游词之蓬莱长岛
2019/12/17 职场文书
python神经网络 使用Keras构建RNN训练
2022/05/04 Python