Apache MXNet - Python API autograd 和 initializer
MXNet Python API:Autograd 和 Initializer
Section titled “MXNet Python API:Autograd 和 Initializer”本章深入探讨 MXNet 的 autograd API 用于自动微分以及 initializer API 用于设置神经网络中的初始参数值。
mxnet.autograd
Section titled “mxnet.autograd”mxnet.autograd 模块提供用于对 NDArray 进行自动微分的工具。
类:mxnet.autograd.Function
Section titled “类:mxnet.autograd.Function”mxnet.autograd.Function 允许用户定义自定义的可微分操作。如果您需要 MXNet 内置运算符未覆盖的非标准梯度计算,您可以继承 Function 并实现自定义的 forward 和 backward 方法。
自定义 autograd 函数的工作流程:
- 在
forward方法中定义前向计算。此方法接受输入NDArray并返回输出NDArray。 - 在
backward方法中实现自定义的梯度计算。此方法接收后续函数输出的梯度(通常表示为dy或head_grads),并且必须返回相对于forward方法的每个输入的梯度。 - 在反向传播期间,
mxnet.autograd将调用您的自定义backward方法,而不是依赖于预定义操作的链式法则。 - 您可以在
forward中使用self.save_for_backward(*tensors)缓存backward计算所需的任何张量(Tensors),这些张量可以通过backward中的self.saved_tensors检索。
示例:定义一个具有自定义前向和反向传播的稳定 sigmoid 函数。
import mxnet as mxfrom mxnet import nd, autograd
class StableSigmoid(autograd.Function): def forward(self, x): # 数值稳定的 sigmoid: y = 1 / (1 + exp(-x)) y = 1 / (1 + nd.exp(-x)) self.save_for_backward(y) # 保存 y 以在反向传播中使用 return y
def backward(self, dy): # sigmoid 的梯度: dy * y * (1 - y) y, = self.saved_tensors # 检索保存的 y return dy * y * (1 - y)
# 使用自定义函数custom_sigmoid_op = StableSigmoid()
x_input = nd.random.uniform(shape=(5,))x_input.attach_grad() # 标记 x_input 以计算其梯度
with autograd.record(): output_y = custom_sigmoid_op(x_input)
# 从一个虚拟头部梯度(例如,全为 1)反向传播output_y.backward(nd.ones_like(output_y))
dx_gradient = x_input.grad
print("输入 x:")print(x_input.asnumpy())print("\n输出 y (sigmoid(x)):")print(output_y.asnumpy())print("\n梯度 dx (自定义):")print(dx_gradient.asnumpy())输出(值会因随机输入而异):
Input x:[0.6288061 0.03209561 0.9043807 0.07945406 0.3247892 ]
Output y (sigmoid(x)):[0.6521595 0.5080225 0.711851 0.5198517 0.58049846]
Gradient dx (custom):[0.22686191 0.24993561 0.20499429 0.2496056 0.24351722]核心 mxnet.autograd 方法
Section titled “核心 mxnet.autograd 方法”mxnet.autograd 中常用的函数和上下文管理器:
| 方法/上下文管理器 | 描述 |
|---|---|
| tagName | tds |
| tagName | tds |
| tagName | tds |
| tagName | tds |
| tagName | tds |
| tagName | tds |
实现示例:autograd.grad()
Section titled “实现示例:autograd.grad()”使用 mxnet.autograd.grad() 直接计算梯度:
x = nd.ones((2,))x.attach_grad() # 如果 x 是我们需要梯度的叶子变量,则需要为其附加梯度
with autograd.record(): # y = x * x # z = y + x # 我们来做类似于 z = exp(x) + x 的计算 z = nd.exp(x) + x
# 计算 dz/dxdx_grads_list = autograd.grad(heads=z, variables=[x], create_graph=False)dx_grad = dx_grads_list[0]
print("x:", x.asnumpy())print("z:", z.asnumpy())print("dz/dx:", dx_grad.asnumpy()) # 应该等于 exp(x) + 1。对于 x=1,e^1+1 ≈ 2.718+1 = 3.718输出:
x: [1. 1.]z: [3.7182817 3.7182817]dz/dx: [3.7182817 3.7182817]在推理(Inference)部分使用 predict_mode()(或在 record 或 pause 中使用 train_mode=False):
# model = 某个 Gluon 模型()# x_input = nd.random.normal(shape=(1,10))# with autograd.record(train_mode=True): # 训练模式,用于像 dropout/batchnorm 这样的部分# intermediate_y = model.feature_extractor(x_input)# with autograd.predict_mode(): # 推理模式,用于不需要梯度或特殊训练行为的部分# final_output_logits = model.classifier(intermediate_y)# # 或者如果只需要预测:# # with autograd.predict_mode():# # predictions = model(x_input)# # loss.backward() # 如果损失在 record() 作用域内计算print("predict_mode() 用于确保网络的部分在推理模式下运行。")mxnet.initializer(或 mx.init)
Section titled “mxnet.initializer(或 mx.init)”mxnet.initializer 模块(通常通过 mx.init 访问)提供了各种初始化神经网络层权重和偏置的方案。恰当的初始化对于有效训练至关重要。
常用 Initializer 类
Section titled “常用 Initializer 类”关键的 Initializer 类及其用途:
| Initializer 类 | 描述 |
|---|---|
| tagName | tds |
| tagName | tds |
| tagName | tds |
| tagName | tds |
| tagName | tds |
| tagName | tds |
| tagName | tds |
| tagName | tds |
| tagName | tds |
实现示例:使用 Initializers
Section titled “实现示例:使用 Initializers”在定义 Gluon 层或模型时应用 Initializer:
from mxnet import gluon, init
# 示例 1:使用 Xavier 初始化 Dense 层layer_xavier = gluon.nn.Dense(units=64, weight_initializer=init.Xavier(), bias_initializer=init.Zero())layer_xavier.initialize() # 实际的初始化在这里发生# print("Xavier 初始化后的权重示例:", layer_xavier.weight.data()[0,0:5].asnumpy())
# 示例 2:对 Sequential 模型使用 Mixed initializernet = gluon.nn.Sequential()with net.name_scope(): net.add(gluon.nn.Dense(256, activation='relu')) # 如果在 net.initialize 中未指定,将应用默认初始化 net.add(gluon.nn.Dense(10))
# 定义混合 Initializer:偏置为零,权重使用 Normal(0.02)mixed_init = init.Mixed( ['.*bias', '.*gamma', '.*beta', '.*running_mean', '.*running_var'], # 偏置、Batchnorm 缩放/偏移、运行统计量的模式 [init.Zero(), init.One(), init.Zero(), init.Zero(), init.One()] # 对应的 Initializer)# 可以为其他权重(例如,'.*weight')指定回退或使用默认值。# 为权重指定:net.initialize(init.Normal(0.02), ctx=mx.cpu())# 对于混合:net.initialize(mixed_init, ctx=mx.cpu())# 一个更常见的混合初始化模式:net.initialize(init.Mixed(['.*weight', '.*bias'], [init.Normal(0.02), init.Zero()]), ctx=mx.cpu())
print("已初始化的 net[0].bias(Dense 层 0 的偏置):")print(net[0].bias.data().asnumpy())print("\nnet[0].weight(Dense 层 0 的权重)示例 - 第一行的前 5 个值:")print(net[0].weight.data()[0,:5].asnumpy())输出(偏置应为零,权重将是小的随机数):
Initialized net[0].bias (Dense layer 0 bias):[0. 0. 0. ... 0. 0. 0.] (形状将是 (256,))
Sample of net[0].weight (Dense layer 0 weight) - first 5 values of first row:[-0.00890991 0.01314114 -0.00038932 0.02028422 0.0158705 ]