旷视MegEngine网络搭建

在 基本概念 中,介绍了计算图、张量和算子,神经网络可以看成一个计算图。在 MegEngine 中,按照计算图的拓扑结构,将张量和算子连接起来,即可完成对网络的搭建。MegEngine 提供了基于 functional 和基于 Module 的两种方式搭建网络。 functional 仅提供最基本的算子功能,数据连接的工作完全由用户完成; Module 对网络模块(包含若干算子及其参数的基本单元)进行了进一步的封装,代码更易复用和维护。

基于 functional 搭建网络

functional 包提供了常用的算子函数(如 conv2d() 、 batch_norm() 等)。这些函数接受参与计算的张量并返回计算结果。参与计算的张量通常包括两类:输入数据和算子自身的参数,其中后者是网路中需要学习的变量。比如,二维卷积( conv2d() )接受多通道的二维图像作为输入数据,把卷积核作为参数,输出经卷积操作后的多通道二维图像。

算子的输入和输出数据都是 Tensor 类型。算子的参数通常由 Parameter 类表示。 Parameter 是 Tensor 的子类,其对象(即网络参数)可以被优化器更新。更多内容参见 网络的训练和测试 。

下面的例子实现了一个两层卷积网络(使用 ReLU 作为激活函数):

import megengine as mge

import megengine.functional as F

import numpy as np

def two_layer_conv(x):

# (8, 3, 3, 3) 代表(输出信道数,输入信道数,卷积核高度,卷积核宽度)

conv_weight = mge.Parameter(np.random.randn(8, 3, 3, 3).astype(np.float32))

# 对于 8 个卷积核,提供 8 bias

conv_bias = mge.Parameter(np.zeros((1, 8, 1, 1), dtype=np.float32))

x = F.conv2d(x, conv_weight, conv_bias)

x = F.relu(x)

conv_weight = mge.Parameter(np.random.randn(16, 8, 3, 3).astype(np.float32))

conv_bias = mge.Parameter(np.zeros((1, 16, 1, 1), dtype=np.float32))

x = F.conv2d(x, conv_weight, conv_bias)

x = F.relu(x)

return x

# 输入形状为 (2, 3, 32, 32) 的张量

x = mge.tensor(np.random.randn(2, 3, 32, 32).astype(np.float32))

out = two_layer_conv(x)

print(out.shape)

输出:

(2, 16, 28, 28)

基于 Module 搭建网络

在上面的代码中,对于每一个需要参数的算子,需要单独定义其网络参数。由于“ conv + relu ”这样的组合出现了两次,代码显得臃肿。对于更加复杂的网络,这样的写法可读性、可复用性和可维护性会比较差。

为了更好的封装和复用算子, MegEngine 在 functional 基础上提供了 module 包。

megengine.module 包定义了抽象的网络模块基类 Module 。它是构造网络的基本单元,可以被组合和叠加。它定义了网络模块的基本接口和属性,如“前向传播”等。所有 Module 子类都需要实现 Module 定义的两个抽象方法,介绍如下:

  • __init__() :在构造方法中创建这个模块,包括定义网络参数、构造和连接其子模块等工作。
  • forward() : 该方法定义前向传播计算流程。接受输入数据并返回前向传播的计算结果。注意, Module 对象是可被调用的 ( callable ),其实现就是 forward() 。

megengine.module 包提供了常用的网络基本模块,如 Conv2d 、Linear 等。以 Conv2d 为例,该类的 __init__() 方法定义并初始化卷积核参数,其 forward() 方法执行卷积操作。

基于各种常用的网络模块,可以方便地搭建非常复杂的网络。例如,上一个例子的网络定义可以简化成如下写法:

import megengine.module as M

# 为了演示,在这里定义了一个简单的卷积模块。注意: MegEngine 已经提供了更为通用的 Conv2d 模块。

class ConvReLU(M.Module):

def __init__(self, in_channels, out_channels):

# 先调用父类的初始化

super().__init__()

# 定义卷积权重和 bias ,作为模块参数

self.conv_weight = mge.Parameter(np.random.randn(out_channels, in_channels, 3, 3).astype(np.float32))

self.conv_bias = mge.Parameter(np.zeros((1, out_channels, 1, 1), dtype=np.float32))

# 将激活函数 ReLU 作为子模块

self.relu = M.ReLU()

def forward(self, x):

x = F.conv2d(x, self.conv_weight, self.conv_bias)

x = self.relu(x)

return x

# 基于 ConvReLU ,定义一个两层卷积网络

class TwoLayerConv(M.Module):

def __init__(self):

super().__init__()

self.conv_relu1 = ConvReLU(3, 8)

self.conv_relu2 = ConvReLU(8, 16)

def forward(self, x):

x = self.conv_relu1(x)

x = self.conv_relu2(x)

return x

# 输入形状为 (2, 3, 32, 32) 的张量

x = mge.tensor(np.random.randn(2, 3, 32, 32).astype(np.float32))

two_layer_conv_module = TwoLayerConv()

out = two_layer_conv_module(x)

print(out.shape)

输出:

(2, 16, 28, 28)

使用 Module 定义的网络比使用 functional 进一步封装了内部实现,更易复用,统一的接口使得代码更易维护。推荐使用 Module 搭建网络。

此外, Module 其它常用的方法如下:

  • parameters() : 该方法返回包含网络参数的迭代器。
  • named_parameters() : 该方法返回包含参数名称及对应网络参数的迭代器。
  • state_dict():返回以参数名称和网络参数为键值对的有序字典,可用于保存训练好的模型。比如,对于上面定义的 ConvReLU 模块,打印它的一个实例的 state_dict :

conv_relu = ConvReLU(2, 3)

print(conv_relu.state_dict())

输出的参数信息有卷积的权重项 'conv_weight' 和偏置项 'conv_bias' :

OrderedDict([('conv_bias', array([[[[0.]],

[[0.]],

[[0.]]]], dtype=float32)), ('conv_weight', array([[[[-0.53457755,  0.2799128 , -0.6624546 ],

[-0.9222688 ,  1.2226251 , -0.5591961 ],

[-0.45538583, -0.95166504,  1.1570141 ]],

[[-0.89926094,  0.09956062, -0.7329557 ],

[-0.67284465,  0.34817234,  0.6731445 ],

[ 0.61970276,  1.8007269 ,  1.6130987 ]]],

[[[ 1.7108068 , -1.7188625 , -0.52539474],

[-0.04049037,  0.03099988, -1.4271212 ],

[-0.9138133 ,  0.3976046 , -1.1582668 ]],

[[-1.2193677 ,  0.24107741, -0.50833786],

[ 0.9088649 , -0.2747458 , -0.1261102 ],

[ 0.00594431,  0.65737075,  1.5280651 ]]],

[[[ 0.24874896, -1.3824748 ,  2.2161844 ],

[-0.6629168 ,  1.0220655 , -0.53007567],

[ 0.37829646,  1.1993718 ,  1.0667052 ]],

[[-0.66264534, -0.6392335 , -0.41280702],

[ 1.7417566 ,  0.75295806, -0.4228349 ],

[-0.94973356,  2.4136777 , -0.06665667]]]], dtype=float32))])

最后,来搭建更加复杂的、经典的 LeNet 网络,其结构如下图:

图1 LeNet ( http://yann.lecun.com/exdb/publis/pdf/lecun-01a.pdf )

使用 Module 搭建 LeNet 的代码如下:

class LeNet(M.Module):

def __init__(self):

super(LeNet, self).__init__()

# 单信道图片, 两层  5x5 卷积 + ReLU + 池化

self.conv1 = M.Conv2d(1, 6, 5)

self.relu1 = M.ReLU()

self.pool1 = M.MaxPool2d(2, 2)

self.conv2 = M.Conv2d(6, 16, 5)

self.relu2 = M.ReLU()

self.pool2 = M.MaxPool2d(2, 2)

# 两层全连接 + ReLU

self.fc1 = M.Linear(16 * 5 * 5, 120)

self.relu3 = M.ReLU()

self.fc2 = M.Linear(120, 84)

self.relu4 = M.ReLU()

# 分类器

self.classifier = M.Linear(84, 10)

def forward(self, x):

x = self.pool1(self.relu1(self.conv1(x)))

x = self.pool2(self.relu2(self.conv2(x)))

# F.flatten 将原本形状为 (N, C, H, W) 的张量x从第一个维度(即C)开始拉平成一个维度,

# 得到的新张量形状为 (N, C*H*W) 等价于 reshape 操作: x = x.reshape(x.shape[0], -1)

x = F.flatten(x, 1)

x = self.relu3(self.fc1(x))

x = self.relu4(self.fc2(x))

x = self.classifier(x)

return x

# 输入形状为 (2, 1, 32, 32) 的张量

x = mge.tensor(np.random.randn(2, 1, 32, 32).astype(np.float32))

le_net = LeNet()

# 调用网络,即执行 le_net forward 成员方法,返回网络处理结果

out = le_net(x)

print(out.shape)

输出:

(2, 10)

旷视MegEngine网络搭建的更多相关文章

  1. 旷视MegEngine核心技术升级

    旷视MegEngine核心技术升级 7 月 11 日,旷视研究院在 2020 WAIC · 开发者日「深度学习框架与技术生态论坛」上围绕 6 月底发布的天元深度学习框架(MegEngine)Beta ...

  2. 旷视MegEngine数据加载与处理

    旷视MegEngine数据加载与处理 在网络训练与测试中,数据的加载和预处理往往会耗费大量的精力. MegEngine 提供了一系列接口来规范化这些处理工作. 利用 Dataset 封装一个数据集 数 ...

  3. 旷视MegEngine基本概念

    旷视MegEngine基本概念 MegEngine 是基于计算图的深度神经网络学习框架. 本文简要介绍计算图及其相关基本概念,以及它们在 MegEngine 中的实现. 计算图(Computation ...

  4. 旷视等Oral论文提出GeoNet:基于测地距离的点云分析深度网络

    基于网格曲面的几何拓扑信息可以为物体语义分析和几何建模提供较强的线索,但是,如此重要的连接性信息在点云中是缺失的.为此,旷视西雅图研究院首次提出一种全新的深度学习网络,称之为 GeoNet,可建模点云 ...

  5. ECCV 2018 | 旷视科技提出统一感知解析网络UPerNet,优化场景理解

    全球计算机视觉三大顶会之一 ECCV 2018(European Conference on Computer Vision)即将于 9 月 8 -14 日在德国慕尼黑拉开帷幕.届时,旷视首席科学家孙 ...

  6. ECCV 2018 | 旷视科技提出GridFace:通过学习局部单应变换实现人脸校正

    全球计算机视觉三大顶会之一 ECCV 2018(European Conference on Computer Vision)即将于 9 月 8 -14 日在德国慕尼黑拉开帷幕,旷视科技有多篇论文被此 ...

  7. 入职9月,旷视孙剑106分钟讲述CV创业科研的5大区别

    雷锋网按:本文为旷视科技首席科学家孙剑日前在 CCF-ADL上做的题为<如何在大公司和创业公司做好计算机视觉研究>的分享,主要介绍了近期计算机视觉的发展现状,ResNet基本原理和设计,旷 ...

  8. 旷视研究院Detection组负责人

    http://www.skicyyu.org/ https://zhuanlan.zhihu.com/p/61910297 俞刚,旷视研究院Detection组负责人.2014年博士毕业于新加坡南洋理 ...

  9. 旷视科技 -- Face++ 世界最大的人脸识别技术平台

    旷视科技 -- Face++ 世界最大的人脸识别技术平台: https://www.megvii.com/

随机推荐

  1. Think5之删除单条数据功能

    //删除单条学员信息 public function deleteStu(Request $request){ $stu_id = $request->param('id'); $result ...

  2. vim 中文乱码解决

    问题如下: 在vim中编辑一个中文文本时 出现中文乱码情况 问题解决: 修改vimrc的脚本配置 编辑~/.vimrc文件,加上如下几行即可: set fileencodings=utf-8,ucs- ...

  3. 【SpringBoot】SpringBoot集成jasypt数据库密码加密

    一.为什么要使用jasypt库? 目前springboot单体应用项目中,甚至没有使用外部配置中心的多服务的微服务架构的项目,开发/测试/生产环境中的密码往往是明文配置在yml或properties文 ...

  4. hdu4280 最大流DINIC

    题意:       x最小的到x最大的点同一时间的最大运输量. 思路:       裸的最大流,不解释,注意一点,记得加上防爆栈. #pragma comment(linker, "/STA ...

  5. hdu4876 深搜+(随机枚举剪枝)

    题意:       给你n个数,让你从选择k个数,然后排成一个环(k个数的顺序随意,但是排成一个环后就不能变了),然后可以在这个环上任意的找连续w个数(w<=k),可以找多次,得到一个值等于当前 ...

  6. PE文件附加数据感染之Worm.Win32.Agent.ayd病毒分析

    一.基本信息 样本名称:1q8JRgwDeGMofs.exe 病毒名称:Worm.Win32.Agent.ayd 文件大小:165384 字节 文件MD5:7EF5D0028997CB7DD3484A ...

  7. hdu2158 最短区间版大家来找碴

    题意:                  最短区间版大家来找碴 Problem Description 给定一个序列,有N个整数,数值范围为[0,N).有M个询问,每次询问给定Q个整数,可能出现重复值 ...

  8. hdu5108枚举因子求最小的m

    题意:      给一个n(<=10Y),然后让找到一个最小的m使得n/m是一个素数. 思路:       先用sqrt(n)的时间把所有的因子都求出来,然后在排序,枚举,就行了,这个题目这么做 ...

  9. ExtJS4中Ext.onReady、Ext.define、Ext.create

    1.Ext.onReady 说明:onReady内的语句块会在页面上下文加载后再执行. 2.Ext.define 说明:创建类,可以继承其他类,也可以被继承. 例子1: 1 <script ty ...

  10. Sublime text3 的破解

    下载sublimeText3的安装包并安装(已经安装的可以忽略) 在hosts文件中添加:127.0.0.1 license.sublimehq.com(hosts文件地址:C:\Windows\Sy ...