I am trying to implement a convolutional neural netwrok and I don't understand why using im2col operation is more efficient. It basically stores the input to be multiplied by filter in separate columns. But why shouldn't loops be used directly to calculate convolution instead of first performing im2col ?
1 Answers
Well, you are thinking in the right way, In Alex Net almost 95% of the GPU time and 89% on CPU time is spent on the Convolutional Layer and Fully Connected Layer.
The Convolutional Layer and Fully Connected Layer are implemented using GEMM that stands for General Matrix to Matrix Multiplication.
So basically in GEMM, we convert the convolution operation to a Matrix Multiplication operation by using a function called
im2col()
which arranges the data in a way that the convolution output can be achieved by Matrix Multiplication.Now, you may have a question instead of directly doing element wise convolution, why are we adding a step in between to arrange the data in a different way and then use GEMM.
The answer to this is, scientific programmers, have spent decades optimizing code to perform large matrix to matrix multiplications, and the benefits from the very regular patterns of memory access outweigh any other losses. We have an optimized CUDA GEMM API in cuBLAS library, Intel MKL has an optimized CPU GEMM while ciBLAS's GEMM API can be used for devices supporting OpenCL.
Element wise convolution performs badly because of the irregular memory accesses involved in it.
In turn,
Im2col()
arranges the data in a way that the memory accesses are regular for Matrix Multiplication.Im2col()
function adds a lot of data redundancy though, but the performance benefit of using Gemm outweigh this data redundancy.This is the reason for using
Im2col()
operation in Neural Nets.This link explains how
Im2col()
arranges the data for GEMM: https://petewarden.com/2015/04/20/why-gemm-is-at-the-heart-of-deep-learning/

- 618
- 7
- 15
-
1Does matrix multiplication having a lower time complexity than you'd get by just manually multiplying the elements naively have a big impact on what makes them be so fast, or is just mostly the super optimized code & hardware? – Hamster Mar 03 '21 at 23:56
-
With GEMM, the matrices are arranged in such a way that accesses become contiguous and hardware features like spatial locality caching and prefetcher helps reduce the overall time, the number of operations with GEMM and naive convolution remain the same, also it is a perfect candidate to parallelize for GPUs as well. With all this said GEMM does bring a lot of data duplication, bloating the size of matrices. – Abhishek Nikam Mar 21 '21 at 22:10
-
Gotcha, thanks for the answer! Just to make sure I got you clearly, you are saying that the fancy algorithms that get the time complexity of matmul down to like O(2.37) are not really being used here, we are still using the naive O(3) one but in a very optimized fashion? – Hamster Mar 23 '21 at 14:17
-
@Hamster Optimized GEMM is a big field of work. Yes, many of them address hardware aware implementation of the naive matrix multiplication algorithm. However, you will find papers that implement algorithms like Strassen's algorithm in an optimized manner, also. For e.g., Tuning Strassen's matrix multiplication for memory efficiency, SC 1998, Communication-avoiding parallel Strassen: Implementation and performance, SC 2012. Deep learning algorithms can benefit from a broad range of ways to improve GEMM. – Hari Apr 11 '21 at 14:45