conv2d 优化算法 img2col

在深度学习中,卷积操作是常用的运算之一。在深层神经网络中,参数数量通常很大,因此需要寻找一些方法来减少运算量。本文介绍卷积操作的优化算法 img2col,可以有效地减少计算量。

卷积操作

在介绍 img2col 算法之前,我们先来回顾一下卷积操作的基本概念。

卷积操作可以看作两个函数的乘积之后对其中一个函数进行平移所得到的新的函数。在深度学习中,这两个函数一般分别为输入数据和卷积核。

假设输入数据为 XXX,卷积核为 WWW,则卷积操作可以表示为:

Yi,j=∑k,lXi+k,j+lWk,l Y_{i,j} = \sum_{k,l} X_{i+k,j+l}W_{k,l} Yi,j=k,lXi+k,j+lWk,l

其中,YYY 表示输出数据,i,ji,ji,j 分别表示输出数据中的行和列,k,lk,lk,l 分别表示卷积核中的行和列。

img2col 算法

在实践中,卷积操作通常会涉及到较大的输入数据和卷积核,因此上述的卷积操作需要计算大量的乘积,并且需要访问很多次同一片区域的数据。这样会导致计算量较大,效率较低。

为了降低卷积操作的计算量,可以引入 img2col 算法。该算法可以将输入数据和卷积核通过形变,转换成矩阵相乘的形式,从而减少计算量和访存次数。

具体地,我们先将输入数据进行重塑,得到一个新的矩阵 X^\hat{X}X^

X^k,:=Xi,j,(i,j)∈Sk \hat{X}_{k,:} = X_{i,j}, (i,j) \in S_k X^k,:=Xi,j,(i,j)Sk

其中,SkS_kSk 表示以 kkk 为中心的子区域,kkk 是原始输入数据的索引。

然后,我们将卷积核也进行重塑,得到矩阵 W^\hat{W}W^

W^:,l=Wk,l \hat{W}_{:,l} = W_{k,l} W^:,l=Wk,l

接着,我们将 X^\hat{X}X^W^\hat{W}W^ 进行矩阵相乘:

Y′=X^⋅W^ Y' = \hat{X} \cdot \hat{W} Y=X^W^

最后,我们将 Y′Y'Y 变形成输出数据 YYY 的形式。

通过以上的形变操作,我们将原来需要做 m×nm \times nm×n 次乘法的卷积操作,转化为了两个 m×km \times km×k 矩阵相乘,其中 kkk 是卷积核大小,通常 kkk 很小,因此计算量大大减少。

img2col 算法实现

下面,我们使用 JavaScript 语言代码来实现 img2col 算法。假设输入数据的 shape 为 (n,cin,hin,win)(n, c_{in}, h_{in}, w_{in})(n,cin,hin,win),卷积核的 shape 为 (cout,cin,kh,kw)(c_{out}, c_{in}, k_h, k_w)(cout,cin,kh,kw),步长为 sss,填充为 ppp。具体实现过程如下:

/**
 * 使用 img2col 算法计算二维卷积
 * @param {Array} x 输入数据
 * @param {Array} w 卷积核
 * @param {number} s 步长
 * @param {number} p 填充
 * @returns {Array} 输出数据
 */
function conv2d(x, w, s = 1, p = 0) {
  const [n, ci, hi, wi] = x.shape;
  const [co, ci2, kh, kw] = w.shape;

  // 计算输出形状
  const ho = Math.floor((hi + 2 * p - kh) / s) + 1;
  const wo = Math.floor((wi + 2 * p - kw) / s) + 1;

  // 重塑输入数据和卷积核
  const xCol = im2col(x, kh, kw, s, p);
  const wCol = w.reshape(co, -1);

  // 矩阵相乘
  const y = wCol.dot(xCol);

  // 变形输出数据
  return y.reshape(n, ho, wo, co).transpose(0, 3, 1, 2);
}

/**
 * img2col 实现
 * @param {Array} x 输入数据
 * @param {number} kh 卷积核高度
 * @param {number} kw 卷积核宽度
 * @param {number} s 步长
 * @param {number} p 填充
 * @returns {Array} 转换后的矩阵
 */
function im2col(x, kh, kw, s, p) {
  const [n, ci, hi, wi] = x.shape;
  const ho = Math.floor((hi + 2 * p - kh) / s) + 1;
  const wo = Math.floor((wi + 2 * p - kw) / s) + 1;

  // 添加填充
  const paddedX = np.pad(x, [[0, 0], [0, 0], [p, p], [p, p]]);

  // 初始化转换后的矩阵
  const col = np.zeros([n, ci * kh * kw, ho * wo]);

  // 遍历输入数据,提取子区域并存储到 col 矩阵中
  for (let y = 0; y < ho; ++y) {
    for (let x = 0; x < wo; ++x) {
      const hStart = y * s;
      const wStart = x * s;
      const hEnd = hStart + kh;
      const wEnd = wStart + kw;
      const slice = paddedX[:, :, hStart:hEnd, wStart:wEnd];
      col[:, :, y * wo + x] = slice.reshape(n, -1);
    }
  }

  return col;
}

总结

img2col 算法通过将输入数据和卷积核转换为矩阵形式,从而减少了计算量和访存次数,可以提高卷积操作的效率。在实现时,需要注意输入数据和卷积核的形状、步长和填充等参数,并且需要对数据进行重塑和变形。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐