Deepity
Ultra-fast, SIMD-accelerated Predictive Coding
Loading...
Searching...
No Matches
Im2Col.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstddef>
4#include <cstring>
5#include <immintrin.h>
6
46
47namespace Deep
48{
57 inline int ConvOutDim(int inDim, int kernel, int stride, int pad) noexcept
58 {
59 return (inDim + 2 * pad - kernel) / stride + 1;
60 }
61
88 inline void Im2Col(const float *input,
89 int channels, int height, int width,
90 int kH, int kW,
91 int strideH, int strideW,
92 int padH, int padW,
93 float *columns) noexcept
94 {
95 const int outH = ConvOutDim(height, kH, strideH, padH);
96 const int outW = ConvOutDim(width, kW, strideW, padW);
97 const int colWidth = outH * outW;
98
99 for (int c = 0; c < channels; ++c)
100 {
101 for (int kh = 0; kh < kH; ++kh)
102 {
103 for (int kw = 0; kw < kW; ++kw)
104 {
105 const int rowIdx = (c * kH + kh) * kW + kw;
106 float *destRow = columns + (size_t)rowIdx * colWidth;
107
108 for (int oh = 0; oh < outH; ++oh)
109 {
110 const int inRow = oh * strideH - padH + kh;
111 float *dst = destRow + (size_t)oh * outW;
112
113 if (inRow < 0 || inRow >= height)
114 {
115 std::memset(dst, 0, (size_t)outW * sizeof(float));
116 continue;
117 }
118
119 const float *src =
120 input + ((size_t)c * height + inRow) * width;
121
122 if (strideW == 1)
123 {
124 const int first = padW > kw ? padW - kw : 0;
125 const int last = width + padW - kw < outW
126 ? width + padW - kw
127 : outW;
128
129 int ow = 0;
130
131 for (; ow < first; ++ow)
132 dst[ow] = 0.0f;
133
134 const float *s = src + first - padW + kw;
135 float *d = dst + first;
136 const int count = last - first;
137 int i = 0;
138
139#if defined(__AVX512F__)
140 for (; i + 16 <= count; i += 16)
141 _mm512_storeu_ps(
142 d + i,
143 _mm512_loadu_ps(s + i));
144#elif defined(__AVX2__) || defined(__AVX__)
145 for (; i + 8 <= count; i += 8)
146 _mm256_storeu_ps(
147 d + i,
148 _mm256_loadu_ps(s + i));
149#elif defined(__SSE__)
150 for (; i + 4 <= count; i += 4)
151 _mm_storeu_ps(
152 d + i,
153 _mm_loadu_ps(s + i));
154#endif
155
156 for (; i < count; ++i)
157 d[i] = s[i];
158
159 for (ow = last; ow < outW; ++ow)
160 dst[ow] = 0.0f;
161 }
162 else
163 {
164 for (int ow = 0; ow < outW; ++ow)
165 {
166 const int inCol =
167 ow * strideW - padW + kw;
168
169 dst[ow] =
170 (inCol < 0 || inCol >= width)
171 ? 0.0f
172 : src[inCol];
173 }
174 }
175 }
176 }
177 }
178 }
179 }
180
213 inline void Col2Im(const float *columns,
214 int channels, int height, int width,
215 int kH, int kW,
216 int strideH, int strideW,
217 int padH, int padW,
218 float *outputImage) noexcept
219 {
220 const int outH = ConvOutDim(height, kH, strideH, padH);
221 const int outW = ConvOutDim(width, kW, strideW, padW);
222 const int colWidth = outH * outW;
223
224 for (int c = 0; c < channels; ++c)
225 {
226 for (int kh = 0; kh < kH; ++kh)
227 {
228 for (int kw = 0; kw < kW; ++kw)
229 {
230 const int rowIdx = (c * kH + kh) * kW + kw;
231 const float *srcRow =
232 columns + (size_t)rowIdx * colWidth;
233
234 for (int oh = 0; oh < outH; ++oh)
235 {
236 const int inRow = oh * strideH - padH + kh;
237
238 if (inRow < 0 || inRow >= height)
239 continue;
240
241 float *dst =
242 outputImage +
243 ((size_t)c * height + inRow) * width;
244
245 const float *src =
246 srcRow + (size_t)oh * outW;
247
248 if (strideW == 1)
249 {
250 const int first = padW > kw ? padW - kw : 0;
251 const int last = width + padW - kw < outW
252 ? width + padW - kw
253 : outW;
254
255 const float *s = src + first;
256 float *d = dst + first - padW + kw;
257 const int count = last - first;
258 int i = 0;
259
260#if defined(__AVX512F__)
261 for (; i + 16 <= count; i += 16)
262 {
263 const __m512 a = _mm512_loadu_ps(s + i);
264 const __m512 b = _mm512_loadu_ps(d + i);
265 _mm512_storeu_ps(
266 d + i,
267 _mm512_add_ps(a, b));
268 }
269#elif defined(__AVX2__) || defined(__AVX__)
270 for (; i + 8 <= count; i += 8)
271 {
272 const __m256 a = _mm256_loadu_ps(s + i);
273 const __m256 b = _mm256_loadu_ps(d + i);
274 _mm256_storeu_ps(
275 d + i,
276 _mm256_add_ps(a, b));
277 }
278#elif defined(__SSE__)
279 for (; i + 4 <= count; i += 4)
280 {
281 const __m128 a = _mm_loadu_ps(s + i);
282 const __m128 b = _mm_loadu_ps(d + i);
283 _mm_storeu_ps(
284 d + i,
285 _mm_add_ps(a, b));
286 }
287#endif
288
289 for (; i < count; ++i)
290 d[i] += s[i];
291 }
292 else
293 {
294 for (int ow = 0; ow < outW; ++ow)
295 {
296 const int inCol =
297 ow * strideW - padW + kw;
298
299 if (inCol >= 0 && inCol < width)
300 dst[inCol] += src[ow];
301 }
302 }
303 }
304 }
305 }
306 }
307 }
308}
This file exists to provide both Tensor.h and IComputeBackend.h with device types without introducing...
Definition Backend.cpp:10
void Im2Col(const float *input, int channels, int height, int width, int kH, int kW, int strideH, int strideW, int padH, int padW, float *columns) noexcept
Rearranges a single (channels, height, width) input image into a (channels*kH*kW, outH*outW) column m...
Definition Im2Col.h:88
void Col2Im(const float *columns, int channels, int height, int width, int kH, int kW, int strideH, int strideW, int padH, int padW, float *outputImage) noexcept
The adjoint of Im2Col(): scatters a (channels*kH*kW, outH*outW) column-gradient buffer back into a (c...
Definition Im2Col.h:213
int ConvOutDim(int inDim, int kernel, int stride, int pad) noexcept
Computes a single convolution output dimension (height or width) from its corresponding input dimensi...
Definition Im2Col.h:57