/* 不考虑输出的padding input的维度:[batch, h, w, channel] kernel的维度:[kerner_cnt, kh, kw, channel] */ int output_h = (h - kh) / sh + 1; int output_w = (w - kw) / sw + 1;
for (int b = 0; b < batch; b ++) for (int i = 0; i < output_h; i ++) for (int j = 0; j < output_w; j ++) for (int d = 0; d < kernel_cnt; d ++) for (int c = 0; c < channel; c ++) for (int ph = 0; ph < kh; ph ++) for (int pw = 0; pw < kw; pw ++) res[b][i][j][d] += kernel[d][ph][pw][c] * input[b][i * sh + ph][j * sw + pw][c];
for (int d = 0; d < kernel_cnt; d ++) for (int i = 0; i < output_h; i ++) for (int j = 0; j < output_w; j ++) for (int c = 0; c < channel; c ++) for (int ph = 0; ph < kh; ph ++) for (int pw = 0; pw < kw; pw ++) res[i][j][d] += kernel[d][ph][pw][c] * input[i + ph][j + pw][c];
for (int b = 0; b < batch; b ++) for (int i = 0; i < output_h; i ++) for (int j = 0; j < output_w; j ++) for (int d = 0; d < kernel_cnt; d ++) for (int c = 0; c < channel; c ++) for (int ph = 0; ph < kh; ph ++) for (int pw = 0; pw < kw; pw ++) res[b][i][j][d] += kernel[d][ph][pw][c] * input[b][i + ph][j + pw][c];
for (int b = 0; b < batch; b ++) for (int i = 0; i < output_h; i ++) for (int j = 0; j < output_w; j ++) for (int d = 0; d < kernel_cnt; d ++) for (int c = 0; c < channel; c ++) for (int ph = 0; ph < kh; ph ++) for (int pw = 0; pw < kw; pw ++) res[b][i][j][d] += kernel[d][ph][pw][c] * input[b][i * sh + ph][j * sw + pw][c];
for (int b = 0; b < B; b ++) { int row = 0; for (int h = 0; h < out_h; h ++) for (int w = 0; w < out_w; w ++) { int idx = 0; for (int i = 0; i < kh; i ++) for (int j = 0; j < kw; j ++) for (int c = 0; c < C; c ++) output[b][row][idx ++] = v[b][sh * h + i][sw * w + j][c]; row ++; } } return output; }
// [D, kh, kw, C] -> [kh * kw * C, D] vec2d im2col_rhs_new(vec4d v){ int Dout = v.size(); int Hout = v[0].size(); int Wout = v[0][0].size(); int Cout = v[0][0][0].size(); vec2d res(Hout * Wout * Cout, vec1d(Dout));
for (int d = 0; d < Dout; d ++) for (int i = 0; i < Hout; i ++) for (int j = 0; j < Wout; j ++) for (int k = 0; k < Cout; k ++) res[i * Wout * Cout + j * Cout + k][d] = v[d][i][j][k]; return res; }
// [out_h * out_w, kh * kw * C] dot [kh * kw * C, D]->[out_h * out_w, D] vec2d gemm(vec2d a, vec2d b){ int n = a.size(), m = a[0].size(), l = b[0].size(); vec2d c(n, vec1d(l)); for (int i = 0; i < n; i ++) for (int k = 0; k < m; k ++) for (int j = 0; j < l; j ++) c[i][j] += a[i][k] * b[k][j]; return c; }
// [B, out_h, out_w, d] vec4d conv2d(vec4d input, vec4d weight, int sh, int sw){
int H = input[0].size(); int W = input[0][0].size(); int D = weight.size(); int kh = weight[0].size(); int kw = weight[0][0].size(); int out_h = (H - kh) / sh + 1; int out_w = (W - kw) / sw + 1;
for (int i = 0; i < M; i++) { for (int j = 0; j < N; j++) { result[i][j] =0; for (int k = 0; k < K; k++) { result[i][j] += matrix1[i][k] * matrix2[k][j]; } } }
n = j /(Oh*Ow) //N维度坐标 c = k / (R*S) //C维度坐标 h = oh * STRIDE + r //H维度坐标 w = ow * STRIDE + s //W维度坐标
接下来我们重新改写GEMM实现的卷积算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
//Implicit GEMM Convolution
for (int i = 0; i < K; i++) { for (int j = 0; j < N*Oh*Ow; j++) { int on = j/(Oh*Ow); //N维度坐标 int oh = (j%(Oh*Ow))/Ow; //Oh维度坐标 int ow = (j%(Oh*Ow))%Ow; //Ow维度坐标 output[on][i][oh][ow] =0; for (int k = 0; k < C*R*S; k++) { int ic = k/(R*S); //C维度坐标 int ir = k%(R*S)/S; //R维度坐标 int is = k%(R*S)%S; //S维度坐标 int ih = oh*STRIDE + ir; //H维度坐标 int iw = ow*STRIDE + is; //W维度坐标 output[on][i][oh][ow] += filter[i][ic][ir][is] * input[on][ic][ih][iw]; } } }