MXNet:nn.Activation 对比 nd.relu?
MXNet: nn.Activation vs nd.relu?
我是 MXNet 的新手(我在 Python3 中使用它)
他们的教程系列鼓励您定义自己的 gluon
blocks。
所以假设这是你的块(一个常见的卷积结构):
class CNN1D(mx.gluon.Block):
def __init__(self, **kwargs):
super(CNN1D, self).__init__(**kwargs)
with self.name_scope():
self.cnn = mx.gluon.nn.Conv1D(10, 1)
self.bn = mx.gluon.nn.BatchNorm()
self.ramp = mx.gluon.nn.Activation(activation='relu')
def forward(self, x):
x = mx.nd.relu(self.cnn(x))
x = mx.nd.relu(self.bn(x))
x = mx.nd.relu(self.ramp(x))
return x
这是他们示例结构的镜像。
mx.nd.relu
与 mx.gluon.nn.Activation
有什么区别?
应该是
x = self.ramp(x)
而不是
x = mx.nd.relu(self.ramp(x))
看来
mx.gluon.nn.Activation(activation=<act>)
是一个包装器,用于从 NDArray
模块调用大量底层激活。
因此 - 原则上 - 在前向定义中是否使用并不重要
x = self.ramp(x)
或
x = mx.nd.relu(x)
或
x = mx.nd.relu(self.ramp(x))
因为 relu 只是取最大值 0 和传递的值(因此除了运行时持续时间略有增加之外,多个应用程序不会比单个调用影响值更多)。
因此在这种情况下它并不重要。当然,与其他激活函数叠加多个调用可能会产生影响。
在 MXNets 文档中,他们在定义 gluon.Block
时在前向定义中使用 nd.relu
。这可能比使用 mx.gluon.nn.Activation(activation='relu')
带来的开销略少。
从风格上讲,gluon
模块意味着高级抽象。因此我认为在定义块时应该使用
ramp = mx.gluon.nn.Activation(activation=<act>)
而不是 nd.<act>(x)
,然后在前向定义中调用 self.ramp(x)
。
然而鉴于此时所有自定义 Block
教程/文档都坚持 relu
激活,这是否会产生持久的影响还有待观察。
一起使用 mx.gluon.nn.Activation
似乎是一种从 Gluon
模块调用 NDArray
模块激活函数的方法。
mx.gluon.nn.Activation wraps around mx.ndarray.Activation, see Gluon source code.
但是,当使用 Gluon 构建神经网络时,建议您使用 Gluon API 而不是随意分支使用较低级别的 MXNet API - 这可能会有问题随着 Gluon 的发展和潜在的变化(例如停止在幕后使用 mx.nd)。
我是 MXNet 的新手(我在 Python3 中使用它)
他们的教程系列鼓励您定义自己的 gluon
blocks。
所以假设这是你的块(一个常见的卷积结构):
class CNN1D(mx.gluon.Block):
def __init__(self, **kwargs):
super(CNN1D, self).__init__(**kwargs)
with self.name_scope():
self.cnn = mx.gluon.nn.Conv1D(10, 1)
self.bn = mx.gluon.nn.BatchNorm()
self.ramp = mx.gluon.nn.Activation(activation='relu')
def forward(self, x):
x = mx.nd.relu(self.cnn(x))
x = mx.nd.relu(self.bn(x))
x = mx.nd.relu(self.ramp(x))
return x
这是他们示例结构的镜像。
mx.nd.relu
与 mx.gluon.nn.Activation
有什么区别?
应该是
x = self.ramp(x)
而不是
x = mx.nd.relu(self.ramp(x))
看来
mx.gluon.nn.Activation(activation=<act>)
是一个包装器,用于从 NDArray
模块调用大量底层激活。
因此 - 原则上 - 在前向定义中是否使用并不重要
x = self.ramp(x)
或
x = mx.nd.relu(x)
或
x = mx.nd.relu(self.ramp(x))
因为 relu 只是取最大值 0 和传递的值(因此除了运行时持续时间略有增加之外,多个应用程序不会比单个调用影响值更多)。
因此在这种情况下它并不重要。当然,与其他激活函数叠加多个调用可能会产生影响。
在 MXNets 文档中,他们在定义 gluon.Block
时在前向定义中使用 nd.relu
。这可能比使用 mx.gluon.nn.Activation(activation='relu')
带来的开销略少。
从风格上讲,gluon
模块意味着高级抽象。因此我认为在定义块时应该使用
ramp = mx.gluon.nn.Activation(activation=<act>)
而不是 nd.<act>(x)
,然后在前向定义中调用 self.ramp(x)
。
然而鉴于此时所有自定义 Block
教程/文档都坚持 relu
激活,这是否会产生持久的影响还有待观察。
一起使用 mx.gluon.nn.Activation
似乎是一种从 Gluon
模块调用 NDArray
模块激活函数的方法。
mx.gluon.nn.Activation wraps around mx.ndarray.Activation, see Gluon source code.
但是,当使用 Gluon 构建神经网络时,建议您使用 Gluon API 而不是随意分支使用较低级别的 MXNet API - 这可能会有问题随着 Gluon 的发展和潜在的变化(例如停止在幕后使用 mx.nd)。