我正在尝试用 Python 实现卷积神经网络。最初,我使用 scipy.signal 的 convolve2d 函数来进行卷积,但它有很多开销,而且用 C 实现我自己的算法并从 python 调用它会更快,因为我知道我的输入是什么样的。
我实现了2个功能:
- 将矩阵与不可分离核进行卷积
- 将矩阵与可分离的内核进行卷积(现在我假设 python 在将其传递到 C 之前进行排名检查和分割)
这些函数都没有填充,因为我需要降维。
不可分离的二维卷积
// a - 2D matrix (as a 1D array), w - kernel
double* conv2(double* a, double* w, double* result)
{
register double acc;
register int i;
register int j;
register int k1, k2;
register int l1, l2;
register int t1, t2;
for(i = 0; i < RESULT_DIM; i++)
{
t1 = i * RESULT_DIM; // loop invariants
for(j = 0; j < RESULT_DIM; j++)
{
acc = 0.0;
for(k1 = FILTER_DIM - 1, k2 = 0; k1 >= 0; k1--, k2++)
{
t2 = k1 * FILTER_DIM; // loop invariants
for(l1 = FILTER_DIM - 1, l2 = 0; l1 >= 0; l1--, l2++)
{
acc += w[t2 + l1] * a[(i + k2) * IMG_DIM + (j + l2)];
}
}
result[t1 + j] = acc;
}
}
return result;
}
可分离的二维卷积
// a - 2D matrix, w1, w2 - the separated 1D kernels
double* conv2sep(double* a, double* w1, double* w2, double* result)
{
register double acc;
register int i;
register int j;
register int k1, k2;
register int t;
double* tmp = (double*)malloc(IMG_DIM * RESULT_DIM * sizeof(double));
for(i = 0; i < RESULT_DIM; i++) // convolve with w1
{
t = i * RESULT_DIM;
for(j = 0; j < IMG_DIM; j++)
{
acc = 0.0;
for(k1 = FILTER_DIM - 1, k2 = 0; k1 >= 0; k1--, k2++)
{
acc += w1[k1] * a[k2 * IMG_DIM + t + j];
}
tmp[t + j] = acc;
}
}
for(i = 0; i < RESULT_DIM; i++) // convolve with w2
{
t = i * RESULT_DIM;
for(j = 0; j < RESULT_DIM; j++)
{
acc = 0.0;
for(k1 = FILTER_DIM - 1, k2 = 0; k1 >= 0; k1--, k2++)
{
acc += w2[k1] * tmp[t + (j + k2)];
}
result[t + j] = acc;
}
}
free(tmp);
return result;
}
使用 gcc -O3 标志进行编译并在 2.7GHz Intel i7 上进行测试,使用 4000x4000 矩阵和 5x5 内核,我分别得到(平均值为 5):
271.21900 ms
127.32000 ms
与 scipy.signal 的 convolve2d 相比,这仍然是一个相当大的改进,相同的操作大约需要 2 秒,但我需要更快的速度,因为我将调用这个函数数千次。目前无法将数据类型更改为浮点型,尽管这会带来相当大的加速。
有没有办法进一步优化这些算法?我可以应用任何缓存技巧或例程来加快速度吗?
任何建议,将不胜感激。