一位同事最近询问了我推荐的方法的更多详细信息,但她没有看到任何文档。我意识到这是我从与 Google 的模型构建者交谈中学到的东西,而且我不确定是否有任何记录,所以本着为后面的任何人留下面包屑的精神,我想我应该把它变成了一个快速的博客文章。总结是,如果您在网络中的卷积层之后有 MaxPool 或 AveragePool,并且您的目标是像微控制器这样的资源受限系统,您应该尝试完全删除它们,并用卷积中的步幅替换它们。这有两个主要好处,但为了解释,最容易绘制前后网络图。在左侧显示的典型设置中,卷积层后跟池化操作。这至少从 AlexNet 开始就很常见,并且仍然存在于许多现代网络中。我经常发现有用的设置显示在右侧。我在此图表中使用了 224 宽 x 224 高的示例输入大小,但该讨论适用于任何维度。首先要注意的是,在标准配置中,在卷积层之后有一个 224x224x8 的激活缓冲区写入内存。到目前为止,这是图中这一部分所需的最大内存块,即使使用 8 位值,也占用超过 400 KB。我所知道的所有 ML 框架都需要在调用下一个操作之前实例化并填充此缓冲区。从理论上讲,可能可以按照图像处理框架常见的方式进行平铺执行,但到目前为止,增加的复杂性并未使其成为优先事项。如果您在嵌入式系统上运行,400KB 是很多 RAM,特别是因为它仅用于临时值。这使它成为大小优化的诱人目标。我的第二个观察是我们只使用了这些值的 25%,假设 MaxPool 正在执行典型的 2x 缩减,在 2×2 窗口中取 4 中的最大值。根据经验,这些值通常非常相似,因此虽然进行池化确实有助于整体准确性,但随机取这四个值中的任何一个也不会差多少。本质上,这就是去除池化和增加卷积步长所做的。当卷积滤波器在输入上滑动时,Stride 是一个控制步长的参数。默认情况下,许多网络的窗口彼此水平偏移一个像素,垂直偏移一个像素。这意味着(忽略填充,这是一个完全不同的讨论)输出与输入的大小相同,但通常有更多的通道(上图中的八个)。您可以将步幅设置为 2,2,而不是将步幅设置为水平 1、垂直 1 的默认值。这意味着每个窗口与其邻居垂直和水平偏移两个像素。这导致输出数组的宽度和高度是输入的一半,因此元素数量是四分之一。从本质上讲,我们正在选择池操作会选择的四个值之一,但没有在标准配置中使用的比较或平均。这意味着卷积层的输出使用更少的内存,导致 TFL Micro 的竞技场更小,但也减少了 75% 的计算,因为只计算了四分之一的卷积窗口。它确实会导致一些精度损失,您可以在训练期间进行验证,但由于它如此显着地减少了资源使用,您甚至可以增加一些其他参数,例如输入大小或通道数,并获得一些回报。如果您确实发现自己在为竞技场大小而苦苦挣扎,我强烈建议您尝试这种方法,它对我们的许多模型都非常有帮助。如果您不确定您的模型是否具有卷积/池化模式,或者想更好地了解激活缓冲区的大小以及它们如何影响您需要的领域,我推荐 Netron 可视化工具,它可以采用 TensorFlow Lite 模型文件。