Issue 106
bug 定位及原因
在网络的前向计算过程中,中间有一步计算过程需要获取上一层 blob 作为输入,但是该 blob 却被释放了,代码可以定位到 src/mt_ncnn/mt_net_ncnn.cpp 的第 278 行.

在 forward 之后,这一层的 blob 被释放,释放代码在 ./src/net.cpp 的第 1431 行。

目前的任务是复现该 Issue 并且尝试在非释放的情况下实现接口策略。
首先分析下这里的释放原因
1 | auto it = mid_blob.find(bottom_blob_index); |
这里的 release 方法仅仅是减少了该 Mat 实际数据的引用计数,并没有将其回收。之后实现就地计算,如果其引用计数不为 1, 那么为防止对其他正在引用此 blob 的计算产生影响,需要深复制该 blob 然后实现 inplace 计算。
如果 layer 的 bottom_blob 不在当前的 mid_blob 中,那么就将其释放。向上查询到 mid_blob insert 方法调用的位置。
查询到 bool MTNetCNN::Forward 方法,在 ./src/mt_ncnn/mt_net_ncnn.cpp 第 263 行。

这个的 Forward 方法会根据参数中的 output_ 参数(common_middle_blob_info 类型)即将其 index 添加到 mid_blob 中。在前向计算前为避免返回上次计算结果,需要把 blob_mats[index] 释放。
当存在两个 layer 需要同一个 blob 时,当第一层读取输入后,会将输入释放掉,这时第二层计算时可能就读取不到输入。这时一种可能的网络结构。
我这里没有工程的完整代码,问题也一直无法复现,网络的模型也暂时无法从合并的 bin 分离(真是艰苦的环境)。今天 mentor 说网络的崩溃是使用了层融合的代码,这样网络的崩溃就不是 ncnn 的问题,而是在层融合之后没有调整相应的接口导致。在层融合之后的递归计算在向上传递到已经被融合的层时,被融合的层没有输入 blob, 所以会崩溃。
解决方式
这里修复方式是当计算传递到被融合层时,根据 blob 描述的网络信息递归到上一层,避免在被融合层计算和释放动作。
释放前添加如下代码。
1 | int layer_index =net_->blobs[index].producer; |
前向计算释放上一次结果前添加如下代码
1 | int layer_index =net_->blobs[index].producer; |