旷视MegEngine基本概念
旷视MegEngine基本概念
MegEngine 是基于计算图的深度神经网络学习框架。 本文简要介绍计算图及其相关基本概念,以及它们在 MegEngine 中的实现。
计算图(Computational Graph)
下面通过一个简单的数学表达式 y=(w∗x)+by=(w∗x)+b 来介绍计算图的基本概念,如下图所示:

图1
从中可以看到,计算图中存在:
- 数据节点(图中的实心圈):如输入数据 xx 、 ww 、 bb ,运算得到的中间数据 pp ,以及最终的运算输出 yy ;
- 计算节点(图中的空心圈):图中 * 和 + 分别表示计算节点 乘法 和 加法,是施加在数据节点上的运算;
- 边(图中的箭头):表示数据的流向,体现了数据节点和计算节点之间的依赖关系;
如上,便是一个简单的计算图示例。计算图是一个包含数据节点和计算节点的有向图(可以是有环的,也可以是无环的), 是数学表达式的形象化表示。在深度学习领域,任何复杂的深度神经网络本质上都可以用一个计算图表示出来。
前向传播
计算由计算图表示的数学表达式的值的过程。在图1中,变量 xx 和 ww ,从左侧输入,首先经过乘法运算得到中间结果 pp , 接着,pp 和输入变量 bb 经过加法运算,得到右侧最终的输出 yy ,这就是一个完整的前向传播过程。
在 MegEngine 中,用张量(Tensor)表示计算图中的数据节点,用算子(Operator)实现数据节点之间的运算。
张量(Tensor)
与 PyTorch,TensorFlow 等深度学习框架类似,MegEngine 使用张量(Tensor)来表示计算图中的数据。 张量(Tensor)可以看做 NumPy 中的数组,可以是标量、向量、矩阵或者多维数组。 可以通过 NumPy 或者 Python List 来创建一个 Tensor 。
import numpy as np
import megengine as mge
# 初始化一个维度为 (2, 5) 的 ndarray,并转化成 MegEngine 的 Tensor
# 注:目前 MegEngine Tensor 不支持 float64 数值类型,所以这里显式指定了 ndarray 的数值类型
a = mge.tensor(np.random.random((2,5)).astype('float32'))
print(a)
# 初始化一个长度为3的列表,并转化成 Tensor
b = mge.tensor([1., 2., 3.])
print(b)
输出:
Tensor([[0.2976 0.4078 0.5957 0.3945 0.9413]
[0.7519 0.3313 0.0913 0.3345 0.3256]], device=xpux:0)
Tensor([1. 2. 3.], device=xpux:0)
通过 dtype 属性,可以获取 Tensor 的数据类型;
通过 astype() 方法可以拷贝,创建一个指定数据类型的新Tensor ,原Tensor 不变。
print(a.dtype)
d = a.astype("float16")
print(d.dtype)
输出:
<class 'numpy.float32'>
<class 'numpy.float16'>
通过 shape 属性,可以获取 Tensor 的形状:
print(a.shape)
输出为一个Tuple:
(2, 5)
通过 numpy() 方法,可以将 Tensor 转换为 numpy.ndarray:
a = mge.tensor(np.arange(12)).reshape(2, 6).astype("float32")
print(a)
b = a.numpy()
print(b)
输出:
Tensor([[ 0. 1. 2. 3. 4. 5.]
[ 6. 7. 8. 9. 10. 11.]], device=xpux:0)
[[ 0. 1. 2. 3. 4. 5.]
[ 6. 7. 8. 9. 10. 11.]]
通过 device 属性,可以查询当前 Tensor 所在的设备。创建的 Tensor 可以位于不同 device,这根据当前的环境决定。一般地,如果在创建 Tensor 时不指定 device,其 device 属性默认为 xpux,表示当前任意一个可用的设备。如果存在 GPU 则优先使用 GPU,否则为 CPU。
print(a.device)
输出:
xpux:0
可以在创建 Tensor 时,指定 device 为 cpu0, cpu1, …, gpu0, gpu1, … ,也可以是 cpux 或 gpux,表示当前任意一个可用的 CPU 或 GPU。
通过 to() 方法可以在另一个 device 上生成当前 Tensor 的拷贝,比如将刚刚创建的 Tensor a 迁移到 CPU 上,再迁移到 GPU 上:
# 下面代码是否能正确执行取决于你当前所在的环境
b = a.to("cpu0")
print(b.device)
c = b.to("gpu0")
print(c.device)
输出:
cpu0:0
gpu0:0
GPU 和 CPU 切换
MegEngine 在 GPU 和 CPU 同时存在时默认使用 GPU 进行训练。用户可以调用 set_default_device() 来根据自身需求设置默认计算设备。
如下代码设置默认设备为 CPU:
import megengine as mge
# 默认使用 CPU
mge.set_default_device('cpux')
如下代码设置默认设备为GPU:
# 默认使用 GPU
mge.set_default_device('gpux')
如果不想修改代码,用户也可通过环境变量 MGE_DEFAULT_DEVICE 来设置默认计算设备:
# 默认使用 CPU
export MGE_DEFAULT_DEVICE='cpux'
# 默认使用 GPU
export MGE_DEFAULT_DEVICE='gpux'
算子(Operator)
MegEngine 中通过算子 (Operator) 来表示运算。 类似于 NumPy,MegEngine 中的算子支持基于 Tensor 的常见数学运算和操作。 下面介绍几个简单示例:
Tensor 的加法:
a = mge.tensor([[1., 2., 2.], [5., 1., 8.]])
print(a)
b = mge.tensor([[1., 9., 1.], [1., 7., 9.]])
print(b)
print(a + b)
输出:
Tensor([[1. 2. 2.]
[5. 1. 8.]], device=xpux:0)
Tensor([[1. 9. 1.]
[1. 7. 9.]], device=xpux:0)
Tensor([[ 2. 11. 3.]
[ 6. 8. 17.]], device=xpux:0)
Tensor 的切片:
print(a[1, :])
输出:
Tensor([5. 1. 8.], device=xpux:0)
Tensor 形状的更改:
a.reshape(3, 2)
输出:
Tensor([[1. 2.]
[2. 5.]
[1. 8.]], device=xpux:0)
reshape() 的参数允许存在单个维度的缺省值,用 -1 表示。此时,reshape 会自动推理该维度的值:
# 原始维度是 (2, 3),当给出 -1 的缺省维度值时,可以推理出另一维度为 6
a = a.reshape(1, -1)
print(a.shape)
输出:
(1, 6)
MegEngine 的 functional 提供了更多的算子,比如深度学习中常用的矩阵乘操作、卷积操作等。
Tensor 的矩阵乘:
import megengine as mge
import megengine.functional as F
a = mge.tensor(np.arange(6).reshape(2, 3)).astype('float32')
print(a)
b = mge.tensor(np.arange(6, 12).reshape(3, 2)).astype('float32')
print(b)
c = F.matmul(a, b)
print(c)
输出:
Tensor([[0. 1. 2.]
[3. 4. 5.]], device=xpux:0)
Tensor([[ 6. 7.]
[ 8. 9.]
[10. 11.]], device=xpux:0)
Tensor([[ 28. 31.]
[100. 112.]], device=xpux:0)
更多算子可以参见 functional 部分的文档。
求导器(Grad Manager)
神经网络的优化,通常通过随机梯度下降来进行。需要根据计算图的输出,通过链式求导法则,对所有的中间数据节点求梯度,这一过程被称之为 “反向传播”。 例如,为了得到图1中 yy 关于输入 ww 的梯度,反向传播的过程如下图所示:

图2
首先 y=p+by=p+b ,因此 ∂y/∂p=1∂y/∂p=1 ; 接着,反向追溯,p=w∗xp=w∗x ,因此,∂p/∂w=x∂p/∂w=x 。 根据链式求导法则,∂y/∂w=(∂y/∂p)∗(∂p/∂w)∂y/∂w=(∂y/∂p)∗(∂p/∂w) , 因此最终 yy 关于输入 ww 的梯度为 xx 。
MegEngine 为计算图中的张量提供了自动求导功能,以上图的例子说明: 假设图中的 xx 是 shape 为 (1, 3) 的张量, ww 是 shape 为 (3, 1) 的张量, bb 是一个标量。 利用MegEngine 计算 y=x∗w+by=x∗w+b 的过程如下:
import megengine as mge
import megengine.functional as F
from megengine.autodiff import GradManager
x = mge.tensor([1., 3., 5.]).reshape(1, 3)
w = mge.tensor([2., 4., 6.]).reshape(3, 1)
b = mge.tensor(-1.)
gm = GradManager().attach([w, b]) # 新建一个求导器,绑定需要求导的变量
with gm: # 开始记录计算图
p = F.matmul(x, w)
y = p + b
gm.backward(y) # 计算 y 的导数
print(w.grad)
print(b.grad)
输出:
Tensor([[1.]
[3.]
[5.]], device=xpux:0)
Tensor([1.], device=xpux:0)
可以看到,求出的梯度本身也是 Tensor。
with 代码段中的前向运算都会被求导器记录。可以用 record() 和 release() 来替代 with,分别控制求导器的开启和关闭(不推荐),代码如下所示。
gm = GradManager().attach([w, b]) # 新建一个求导器,绑定需要求导的变量
gm.record() # 开始记录计算图
p = F.matmul(x, w)
y = p + b
gm.backward(y) # 计算 y 的导数
gm.release() # 停止记录计算图并释放资源
此外,可以使用 detach 方法,把 Tensor 当作一个常量,这样求导器将不会对其求导。如下所示:
gm = GradManager().attach([w, b]) # 新建一个求导器,绑定需要求导的变量
with gm: # 开始记录计算图
p = F.matmul(x, w)
y = p + b.detach() # 停止对 b 求导
gm.backward(y) # 计算 y 的导数
print(b.grad)
输出:
None
旷视MegEngine基本概念的更多相关文章
- 旷视MegEngine网络搭建
旷视MegEngine网络搭建 在 基本概念 中,介绍了计算图.张量和算子,神经网络可以看成一个计算图.在 MegEngine 中,按照计算图的拓扑结构,将张量和算子连接起来,即可完成对网络的搭建.M ...
- 旷视MegEngine核心技术升级
旷视MegEngine核心技术升级 7 月 11 日,旷视研究院在 2020 WAIC · 开发者日「深度学习框架与技术生态论坛」上围绕 6 月底发布的天元深度学习框架(MegEngine)Beta ...
- 旷视MegEngine数据加载与处理
旷视MegEngine数据加载与处理 在网络训练与测试中,数据的加载和预处理往往会耗费大量的精力. MegEngine 提供了一系列接口来规范化这些处理工作. 利用 Dataset 封装一个数据集 数 ...
- ECCV 2018 | 旷视科技提出统一感知解析网络UPerNet,优化场景理解
全球计算机视觉三大顶会之一 ECCV 2018(European Conference on Computer Vision)即将于 9 月 8 -14 日在德国慕尼黑拉开帷幕.届时,旷视首席科学家孙 ...
- 入职9月,旷视孙剑106分钟讲述CV创业科研的5大区别
雷锋网按:本文为旷视科技首席科学家孙剑日前在 CCF-ADL上做的题为<如何在大公司和创业公司做好计算机视觉研究>的分享,主要介绍了近期计算机视觉的发展现状,ResNet基本原理和设计,旷 ...
- 旷视研究院Detection组负责人
http://www.skicyyu.org/ https://zhuanlan.zhihu.com/p/61910297 俞刚,旷视研究院Detection组负责人.2014年博士毕业于新加坡南洋理 ...
- 旷视科技 -- Face++ 世界最大的人脸识别技术平台
旷视科技 -- Face++ 世界最大的人脸识别技术平台: https://www.megvii.com/
- 旷视等Oral论文提出GeoNet:基于测地距离的点云分析深度网络
基于网格曲面的几何拓扑信息可以为物体语义分析和几何建模提供较强的线索,但是,如此重要的连接性信息在点云中是缺失的.为此,旷视西雅图研究院首次提出一种全新的深度学习网络,称之为 GeoNet,可建模点云 ...
- ECCV 2018 | 旷视科技提出GridFace:通过学习局部单应变换实现人脸校正
全球计算机视觉三大顶会之一 ECCV 2018(European Conference on Computer Vision)即将于 9 月 8 -14 日在德国慕尼黑拉开帷幕,旷视科技有多篇论文被此 ...
随机推荐
- php抽象类,接口,特性的比较
php抽象类 抽象方法必须被子类继承实现,所以不能为私有,只能是受保护的或公有的; 抽象类子类的方法访问控制级别必须和抽象类相等或更宽松.例如,父类的抽象方法是受保护的,子类实现时则必须为受保护的或者 ...
- 关于YiII框架的扩展memcache中set设置时间就get查询失效的解决方案(版本是1.1.20)
0x01 前言 在使用Yii框架的扩展memcache缓存的时候,存储数据有一个set方法,来看一下set方法的原型: public boolean set(string $id, mixed $va ...
- SSH后门万能密码
当我们在获得一台Linux服务器的 root 权限后,我们第一想做的就是如何维持这个权限,维持权限肯定想到的就是在目标服务器留下一个后门.但是留普通后门,肯定很容易被发现.我们今天要讲的就是留一个SS ...
- 记一次 .NET 医院CIS系统 内存溢出分析
一:背景 1. 讲故事 前几天有位朋友加wx求助说他的程序最近总是出现内存溢出,很崩溃,如下图: 和这位朋友聊下来,发现他也是搞医疗的,哈哈,.NET 在医疗方面还是很有市场的,不过对于内存方面出的问 ...
- SSM整合大体步骤
SSM整合步骤: 1. 导入jar spring: springMVC: mybatis: 第三方支持:log4j,pageHelper,AspectJ,jackson,jstl 2. 搭建sprin ...
- 电脑进入bios和u盘启动快捷键
参考:http://www.jb51.net/os/78638.html 一:联想系列 1:联想笔记本电脑 Thinkpad idea 520 :关机状态下,在左下角用回形针捅小孔,知道出现bios ...
- Django(17)orm查询操作
前言 查找是数据库操作中一个非常重要的技术.查询一般就是使用filter.exclude以及get三个方法来实现.我们可以在调用这些方法的时候传递不同的参数来实现查询需求.在ORM层面,这些查询条件都 ...
- Shell $?获取函数返回值或者上一个命令的退出状态
Shell $?获取函数返回值或者上一个命令的退出状态 来自:互联网 时间:2021-01-12 阅读:2 $? 是一个特殊变量,用来获取上一个命令的退出状态,或者上一个函数的返回值. 所谓退出状态, ...
- elasticksearch分词,导致kibana的url出现问题
在Kibana的展示页面中,我们点击Table的左侧栏,发现Elasticsearch中的数据在展示中是正确的数据,比如:agent中www.baidu.com/test,该界面中会正确的显示为www ...
- Ansible_使用文件模块将修改文件复制到受管主机
一.描述常用文件模块 1.常用文件模块 模块名称 模块说明 blockinfile 插入.更新或删除由可自定义标记线包围的多行文本块 copy 将文件从本地或远程计算机复制到受管主机上的某个位置.类似 ...