Hybrid

摘要:
HybridBlock将声明式编程与命令式编程无缝结合,从而提供了两者的优点。Hybridize加快执行速度并节省内存。如果网络的顶层不是HybridBlock,则仍可使用。hybride()来象征,而gluon将试图象征他的所有孩子。Hybridize还可以接受一些参数来调整性能:net。混合#ornet。混合串行化训练模式用于部署。作为HybridBlock,它在大多数情况下都可以很容易地序列化。序列化模型将来可以部署在多种语言中,包括C、C++和Scala。在混合之前,F是mxnet。nd,然后变成mxnet.sym。
Hybrid - Faster training and easy deployment

相关内容:

深度学习框架大致可以分为两类:declarative和imperative。对于declarative框架(包括Tensorflow、Theano等),用户首先声明一个固定的计算图,然后端到端地执行它。固定计算图的优点是它的可移植性和运行效率。但是,它不太灵活,因为任何逻辑都必须作为特殊运算符(如scan、while_loop和cond)编码到图中。这也很难调试。
imperative框架(包括PyTorch、Chainer等)正好相反:它们像老式的Matlab和Numpy一样逐个执行命令。这种风格更灵活,更容易调试,但效率较低。
HybridBlock无缝地结合了声明式编程和命令式编程,从而提供了两者的优点。用户可以通过命令式编程快速开发和调试模型,并通过调用以下命令切换到高效的声明式执行:

HybridBlock.hybridize().

HybridBlock

HybridBlock类似于Block但是有一些限制:

  • HybridBlock的所有子层也必须是HybridBlock。
  • 只能使用同时为NDArray和Symbol实现的方法。例如,不能使用.asnumpy()、.shape等。
  • 运行时操作无法更改。例如,不能对每个迭代执行if x:if x。

想利用混合编程,就需要子类化HybridBlock:

import mxnet as mx
from mxnet import gluon
from mxnet.gluon import nn

mx.random.seed(42)

class Net(gluon.HybridBlock):
    def __init__(self, **kwargs):
        super(Net, self).__init__(**kwargs)
        with self.name_scope():
            # layers created in name_scope will inherit name space
            # from parent layer.
            self.conv1 = nn.Conv2D(6, kernel_size=5)
            self.pool1 = nn.MaxPool2D(pool_size=2)
            self.conv2 = nn.Conv2D(16, kernel_size=5)
            self.pool2 = nn.MaxPool2D(pool_size=2)
            self.fc1 = nn.Dense(120)
            self.fc2 = nn.Dense(84)
            # You can use a Dense layer for fc3 but we do dot product manually
            # here for illustration purposes.
            self.fc3_weight = self.params.get('fc3_weight', shape=(10, 84))

    def hybrid_forward(self, F, x, fc3_weight):
        # Here `F` can be either mx.nd or mx.sym, x is the input data,
        # and fc3_weight is either self.fc3_weight.data() or
        # self.fc3_weight.var() depending on whether x is Symbol or NDArray
        print(x)       
        x = self.pool1(F.relu(self.conv1(x)))
        x = self.pool2(F.relu(self.conv2(x)))
        # 0 means copy over size from corresponding dimension.
        # -1 means infer size from the rest of dimensions.
        x = x.reshape((0, -1))
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.dot(x, fc3_weight, transpose_b=True)
        return x

⚠️注意上面的前向函数中有F,x;对于pytorch而言这里只有x代表输入数据。下面分析这种情况。

Hybridize

默认情况下,HybridBlock会像标准的Block那样执行(也像pytorch那样),每次调用都会forward起来:

net = Net()
net.initialize()
x = mx.nd.random_normal(shape=(16, 1, 28, 28))
net(x)
x = mx.nd.random_normal(shape=(16, 1, 28, 28))
net(x)

注意上面hybrid_forward中的print(x),这里调用两次net(x),所以会打印两次输出,一切看起来都很normal。可是当调用.hybridize()时就会发生:

net.hybridize()
x = mx.nd.random_normal(shape=(16, 1, 28, 28))
net(x)
x = mx.nd.random_normal(shape=(16, 1, 28, 28))
net(x)

在调用hybridize()之后,只有第一次前向时会打印一个symbol,之后的前向操作都不会调用hybrid_forward函数,所以前向时不会有任何输出。

hybridize会加速执行并节省内存。如果网络顶层不是HybridBlock,你仍然可以使用.hybridize()来符号化,这时gluon就会试着符号化所有他的孩子。

hybridize也可以接受一些参数来调整performance:

net.hybridize(static_alloc=True)
# or
net.hybridize(static_alloc=True, static_shape=True)

Serializing trained model for deployment

作为HybridBlock,大多情况是可以很容易序列化的,序列化的模型可在以后用许多语言部署,C,C++和Scala。为此,利用export和SymbolBlock.imports来保存和载入:

# 保存
net(x) net.export(
'model', epoch=1)

此时将会生成两个文件:model-symbol.json and model-0001.params 。可用任何语言进行载入,当然也可用SymbolBlock进行载入:

import warnings

with warnings.catch_warnings():
    warnings.simplefilter("ignore")
    net2 = gluon.SymbolBlock.imports('model-symbol.json', ['data'], 'model-0001.params')

Operators that do not work with hybridize

如果想混合编程,必须在“hybrid_forward”函数中使用F.some_operator,说白了就是用一些特定的操作符。在hybridize之前F为mxnet.nd,之后就会变为mxnet.sym。虽然大多数api在NDArray和Symbol中是相同的,但它们之间存在一些差异。编写F.some_operator和调用hybrize可能不会一直工作。这里列出了一些常用的不能hybridize的NDArray api,并提供了解决方法。

Element-wise Operators

在NDArray api中,如果输入的NDArray具有不同的形状,则会自动广播以下算术和比较api。但是Symbol API不是这样的。它不会自动广播,必须手动指定对预期具有不同形状的符号使用另一组广播运算符。

Hybrid第1张

目前的解决方法是使用相应的广播运算符进行运算和比较,以避免在输入形状不同时可能出现的hybridize失败。

Hybrid第2张

例如,如果想给你的输入加一个ndarray,那么应当利用broadcast_add而非 + :

def hybrid_forward(self, F, x):
    # avoid writing: return x + F.ones((1, 1))
    return F.broadcast_add(x, F.ones((1, 1)))

如果用的是➕,那么在hubridize之前是没问题的,而之后就可能导致形状不匹配。

 

Shape

Gluon的命令式交互非常灵活,允许打印NDArray的形状。但是,symbol没有形状属性。因此要避免在hubrid_forward中打印shape。否则,将出现以下错误:

AttributeError: 'Symbol' object has no attribute 'shape'

Slice

NDArray中索引很正常,而Symbol中的索引【】是得到grouped symbol的输出。在hybrid前后会得到不同的输出:

def hybrid_forward(self, F, x):
    return x[0]

Not implemented operators

一些在NDArray中常用的operators并没有在Symbol中实现,可能会导致错误:

NDArray.asnumpy:symbol中没这个操作,在hybrid_forward中不要用这个。

mx.nd.array():symbol中没有array的API,目前只有F.onesF.zeros, or F.full

 

免责声明:文章转载自《Hybrid》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇织梦dede批量替换文章标题、关键词、正文内容等解决办法介绍VirtualBox下Win7下CPU高占用的一次故障解决下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

VLAN-3.3 理解Hybrid接口的应用

实验目的: 掌握配置Hybrid接口的方法; 理解Hybrid接口处理Untagged数据帧的过程; 理解Hybrid接口处理Tagged数据帧过程; 理解Hybrid接口的应用场景; 实验拓扑: 一、基本配置:PC配置IP 地址,测试能ping通; 使用display port vlan 查看接口的默认类型; 使用display vlan 查看接口和所...

hybrid接口

SW1配置 vlan batch 2 to 3 100 interface GigabitEthernet0/0/1port hybrid tagged vlan 2 to 3 100# interface GigabitEthernet0/0/2port hybrid pvid vlan 2port hybrid untagged vlan 2 100...

eNSP——Hybrid接口的应用

原理: Hybrid接口既可以连接普通终端的接入链路又可以连接交换机间的干道链路,它允许多个VLAN的帧通过,并可以在出接口方向将某些VLAN帧的标签剥掉。 Hybrid接口处理VLAN帧的过程如下: (1)收到一个二层帧,判断是否有VLAN标签。没有标签,则标记上Hybrid接口的PVID,进行下一-步处理;有标签,判断该Hybrid接口是否允许该VLA...

centos6.4 安装wireless驱动

安装完centos6.4之后,目测只有有线的驱动,没有无线驱动。 一、检测网卡 [root@centos ~]# lspci | grep Net 04:00.0 Network controller: Broadcom Corporation BCM4312 802.11b/g LP-PHY (rev 01) 07:00.0 Ethernet contr...