CNN(LeNet)以驻留在队列中的9层实现,计算按顺序执行.每个层都是单独计时的.
这是一个例子:
conv1 pool1 conv2 pool2 resh1 ip1 relu1 ip2 softmax nexus7 11.177 7.813 13.357 8.367 8.097 2.1 0.326 1.557 2.667 shield 13.219 1.024 1.567 1.081 0.988 14.588 13.323 14.318 40.347
时间的分布对于nexus来说是正确的,其中conv1和conv2(卷积层)占用大部分时间.但是在盾牌上,时间下降的方式超出了2-4层的合理范围,并且似乎朝着最后的方向聚集起来. softmax层是一个相对较小的工作,因此40ms太大了.我的计时方法必须是错误的,或者正在发生其他事情.
运行图层的代码如下所示:
double[] times = new double[layers.size()]; int layerindex = 0; for (Layer a : layers) { double t = SystemClock.elapsedRealtime(); //long t = System.currentTimeMillis(); // makes no difference blob = a.forward(blob); // here we call renderscript forEach_(),invoke_() etc //mRS.finish(); // makes no difference t = SystemClock.elapsedRealtime() - t; //t = System.currentTimeMillis() - t; // makes no difference times[layerindex] += t; // later we take average etc layerindex++; }
我的理解是,一旦forEach_()返回,该作业应该完成.无论如何,mRS.finish()应该提供最后的障碍.但从时代的角度来看,唯一合理的解释是,工作仍然在后台处理.
该应用程序非常简单,我只是从MainActivity运行测试并打印到logcat. Android Studio将应用程序构建为版本,并在通过USB连接的设备上运行.
(1)为RenderScript进程计时的正确方法是什么?
(2)当forEach_()返回时,脚本产生的线程是否可以保证完成?
(3)在我的测试应用程序中,我只是直接从MainActivity运行.这是一个问题(除了阻止UI线程并使应用程序无响应)?如果这会影响时间或导致奇怪,那么设置这样的测试应用程序的正确方法是什么?
解决方法
通常,绝对确保对真正运行的内核有某种控制的唯一方法是在层之间显式读取RS内核的输出,例如在该内核的输出分配对象上使用.copyTo(). .这会“强制”任何尚未运行的排队的RS作业(该层的输出分配依赖于该作业)在此时执行.当然,这可能会引入数据传输开销,并且您的时序不会完全准确 – 事实上,如果以这种方式计时,整个网络的执行时间肯定会低于各个层的总和.但据我所知,这是对链中各个内核计时的唯一可靠方法,它会为您提供一些反馈,以找出瓶颈所在,并更好地指导您的优化,如果这就是您所追求的.