其实这一次课还蛮好理解的:
首先将kernel展平:
cpp
for (uint32_t g = 0; g < groups; ++g) {
std::vector<arma::fmat> kernel_matrix_arr(kernel_count_group);
arma::fmat kernel_matrix_c(1, row_len * input_c_group);
for (uint32_t k = 0; k < kernel_count_group; ++k) {
const std::shared_ptr<Tensor<float>> &kernel =
weights.at(k + g * kernel_count_group);
for (uint32_t ic = 0; ic < input_c_group; ++ic) {
memcpy(kernel_matrix_c.memptr() + row_len * ic,
kernel->at(ic).memptr(), row_len * sizeof(float));
}
LOG(INFO) << "kernel展开后: " << "\n" << kernel_matrix_c;
kernel_matrix_arr.at(k) = kernel_matrix_c;
}
将原来的kernel放到kernel_matrix_c里面,之后如果是多个channel,也就是input_c有多个,那就按照rowlen*ic依次存放到里面。
将输入input展平:
cpp
//按照上面的图就是input = 3*9 ,4的这样一个空间
arma::fmat input_matrix(input_c_group * row_len, col_len);
for (uint32_t ic = 0; ic < input_c_group; ++ic) {
const arma::fmat &input_channel = input_->at(ic + g * input_c_group);
int current_col = 0;
//下面是以窗口滑动的顺序选取
for (uint32_t w = 0; w < input_w - kernel_w + 1; w += stride_w) {
for (uint32_t r = 0; r < input_h - kernel_h + 1; r += stride_h) {
float *input_matrix_c_ptr =
input_matrix.colptr(current_col) + ic * row_len;//对准窗口位置,比如对第一个就是对准红色, 黄色, 绿色
current_col += 1;
for (uint32_t kw = 0; kw < kernel_w; ++kw) {
const float *region_ptr = input_channel.colptr(w + kw) + r;
memcpy(input_matrix_c_ptr, region_ptr, kernel_h * sizeof(float));
input_matrix_c_ptr += kernel_h;
}
}
}
}
LOG(INFO) << "input展开后: " << "\n" << input_matrix;
对于:
cpp
for (uint32_t kw = 0; kw < kernel_w; ++kw) {
const float *region_ptr = input_channel.colptr(w + kw) + r;
memcpy(input_matrix_c_ptr, region_ptr, kernel_h * sizeof(float));
input_matrix_c_ptr += kernel_h;
}
w+kw指向的是窗口的列,r指向的是窗口的行
然后对于每个窗口的以kernel的列为标准复制过去。
最后两个矩阵相乘就可以得到结果