使用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工程师面试题 与Python基础语法相关
Jan 14 Python
浅谈Python的异常处理
Jun 19 Python
python 获取文件下所有文件或目录os.walk()的实例
Apr 23 Python
Python+pyplot绘制带文本标注的柱状图方法
Jul 08 Python
Python Pandas中根据列的值选取多行数据
Jul 08 Python
如何基于Python批量下载音乐
Nov 11 Python
用python的turtle模块实现给女票画个小心心
Nov 23 Python
Scrapy框架实现的登录网站操作示例
Feb 06 Python
Keras实现支持masking的Flatten层代码
Jun 16 Python
pycharm中使用request和Pytest进行接口测试的方法
Jul 31 Python
python3实现飞机大战
Nov 29 Python
Python抖音快手代码舞(字符舞)的实现方法
Feb 07 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获取域名的google收录示例
2014/03/24 PHP
php使用fputcsv()函数csv文件读写数据的方法
2015/01/06 PHP
利用Fix Rss Feeds插件修复WordPress的Feed显示错误
2015/12/19 PHP
php图片添加水印例子
2016/07/20 PHP
详解将数据从Laravel传送到vue的四种方式
2019/10/16 PHP
js constructor的实际作用分析
2011/11/15 Javascript
JS对象转换为Jquery对象示例
2014/01/26 Javascript
Node.js 服务器端应用开发框架 -- Hapi.js
2014/07/29 Javascript
jQuery选择器源码解读(三):tokenize方法
2015/03/31 Javascript
javascript关于运动的各种问题经典总结
2015/04/27 Javascript
jQuery实现控制文字内容溢出用省略号(…)表示的方法
2016/02/26 Javascript
微信小程序 Image API实例详解
2016/09/30 Javascript
基于React实现表单数据的添加和删除详解
2017/03/14 Javascript
AugularJS从入门到实践(必看篇)
2017/07/10 Javascript
vue-cli中打包图片路径错误的解决方法
2017/10/26 Javascript
axios发送post请求,提交图片类型表单数据方法
2018/03/16 Javascript
[18:32]DOTA2 HEROS教学视频教你分分钟做大人-谜团
2014/06/12 DOTA
PyQt5每天必学之单行文本框
2018/04/19 Python
Python面向对象之静态属性、类方法与静态方法分析
2018/08/24 Python
tensorflow 实现数据类型转换
2020/02/17 Python
python使用信号量动态更新配置文件的操作
2020/04/01 Python
Django数据结果集序列化并展示实现过程
2020/04/22 Python
python except异常处理之后不退出,解决异常继续执行的实现
2020/04/25 Python
Django实现前台上传并显示图片功能
2020/05/29 Python
python 解决mysql where in 对列表(list,,array)问题
2020/06/06 Python
解决pytorch多GPU训练保存的模型,在单GPU环境下加载出错问题
2020/06/23 Python
python 绘制场景热力图的示例
2020/09/23 Python
意大利巧克力店:Chocolate Shop
2019/07/24 全球购物
会计电算化专业应届大学生求职信
2013/10/22 职场文书
中青班党性分析材料
2014/02/16 职场文书
民生工程实施方案
2014/03/22 职场文书
2014年度安全工作总结
2014/12/04 职场文书
感谢信格式范文
2015/01/22 职场文书
golang 实现时间戳和时间的转化
2021/05/07 Golang
python数字转对应中文的方法总结
2021/08/02 Python
Mybatis 一级缓存和二级缓存原理区别
2022/09/23 Java/Android