mxnet的模块gluon组合layer层的容器
mxnet将所有的layer都看作Block,自定义的神经网络结构也是继承自gluon.Block。和pytorch中有ModuleList和module两种堆叠layer的容器。在mxnet中,只有一种Sequential。
NDArray转换成numpy
使用asnumpy,这和pytorch中的一致。不过对于单个元素的NDArray,mxnet可以使用asscalar直接转成普通类型的数值,可以少些一些代码。
数据组织的格式
也是batch*channel*height*weight
mxnet.gluon是如何建立计算图的
mxnet有两种模式,可以像tensorFlow一样预先建立网络图结构,是symbol模块。也可以像pytorch一样,动态的建立网络图结构,属于gluon模块。
mxnet在建立动态图结构的时候,在with autograd.record()之下的网络层计算,据此建立的计算图用于后向传播。
说明这一点的关键是:如果有时候我们会遇到只需要变量(NDArray)的一小部分。比如只需要第一个batch传入多分类中的其中一个分支;或者更复杂的情况,只使用波段(或channel通道)的部分元素。这种情况不过通过单纯的slicing 的情况,计算图会出错。
对于需要slicing索引的情况,即只取得有限的元素的情况:
with autograd.record():
val1 = val * 2
a = [nd.dot(val1[0, :], w1), nd.dot(val1[1, :], w1)]
a[1] = val1[1, :]
res = nd.stack(*a)
对于某些属性元素的情况,我这儿也没有想到太好的可以自由选取元素的办法,只有下面的方式:
threshold = top_k_values.pick(idx) # top_k_values是配合用去取不同channel下的某个阈值
threshold = threshold.reshape((-1, 1, 1, 1))
seeds = (x > threshold) * 5.0 # 我的方法就是选取大于某个阈值下的元素
但是不管是什么样的操作,必须是要变量级别的运算,这样才能在后向传播的时候将梯度反传递到前面。
softmax的参数
这本来不是一个问题,是没有看官网的结构。mxnet默认的softmaxLoss为label的标签,是一个序号。如果是像我一样,预先准备好了onehot矩阵,可以在softmaxLoss中指定超参sparse_label=False
mxnet运行时出现segment error
这个也是某种可以避免的错误,但是刚遇到还是有点慌。mxnet不知为什么,当程序出错的一些情况时,放到显存里面的程序不会停止运行,这部分僵尸进程仍占据计算资源。没有注意的话,再次运行程序会出现显存爆掉的情况,出现segment error!所哟,有此错误是,大概率是因为现场的 原因,可以使用kill杀一杀了。
mxnet在计算后向传播时出错
其中一种错误是
mxnet.base.MXNetError: src/imperative/imperative.cc:299: Check failed: !ndinputs.back()->is_none() node_37 0
这是自定义某些操作时,出现了上面所说的违反建立计算图原则的情况,需要设置bypass的方式,逐一定位错误出现的地方。
其中一种错误是 mxnet.gluon.parameter.DeferredInitializationError,mxnet一些网络层是可以自动的推算输入输出,如FC层,可以不需要指定输入的大小,所以需要先经历一次forward前传,建立计算图,mxnet才能后向传播。可是有些情况,比如多分类会有多个分支,可能训练时不会所有的分支都用到,就会出现这种错误了。对于这种错误,给的建议还是比较明了的,比如我的:Parameter dense0_weight has not been initialized yet because initialization was deferred. Actual initialization happens during the first forward pass. Please pass one batch of data through the network before accessing Parameters. You can also avoid deferred initialization by specifying in_units, num_features, etc., for network layers.是说第一个FC层没有指定输入大小,如果还想反向传播,可以指定它的输入层数。
需要处理某一或某些Block网络块中的参数的情况
自定义的网络结构,可能需要自定义一些层的网络参数。比如比fine-tune的冻结操作更复杂的情况时,可能会有这样的需求。
刚开始我想到的办法比较笨,因为在mxnet中nn.Sequential()可以定义namescope,所以对选定的层(网络块单元)使用特别定义的命名空间。但是这种方式,在保存和重加载网络参数的时候会出现没办法使用已有网络参数的错误。
比较聪明的方法,在定义网络结构的时候,将所需要的网络单元指定为一个self类变量,比如net.base.collect_params()就可以取得想要网络单元的参数了。下面是我用到的处理代码
for k, v in net.base_2.collect_params().items():
parmas_dict[k] = v
a = [v.grad(ctx=c) for c in v._ctx_list]
b = nd.mean(nd.stack(*a), axis=0)
v.set_data(b)
mxnet多gpu
多gpu处理按照官方文档来就好了,例子比较明了。我想补充的是,在使用多个gpu中的数据进行处理时,可以直接的按照普通的方式来,mxnet这一点还是非常赞的。