template<>void caffe_cpu_gemm<float>(const CBLAS_TRANSPOSE TransA, const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, const float alpha, const float* A, const float* B, const floatbeta, float* C) { int lda = (TransA == CblasNoTrans) ? K : M; int ldb = (TransB == CblasNoTrans) ? N : K; cblas_sgemm(CblasRowMajor, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, N);} 功能: C=alpha*A*B+beta*C A,B,C 是输入矩阵(一维数组格式) CblasRowMajor :数据是行主序的(二维数据也是用一维数组储存的) TransA, TransB:是否要对A和B做转置操作(CblasTrans CblasNoTrans) M: A、C 的行数 N: B、C 的列数 K: A 的列数, B 的行数 lda : A的列数(不做转置)行数(做转置) ldb: B的列数(不做转置)行数(做转置) |
- template <typename Dtype>
- void BaseConvolutionLayer<Dtype>::forward_cpu_gemm(const Dtype* input,
- const Dtype* weights, Dtype* output, bool skip_im2col) {
- const Dtype* col_buff = input;
- if (!is_1x1_) {
- if (!skip_im2col) {
- // 如果没有1x1卷积,也没有skip_im2col
- // 则使用conv_im2col_cpu对使用卷积核滑动过程中的每一个kernel大小的图像块
- // 变成一个列向量,形成一个height=kernel_dim_的
- // width = 卷积后图像heght*卷积后图像width
- conv_im2col_cpu(input, col_buffer_.mutable_cpu_data());
- }
- col_buff = col_buffer_.cpu_data();
- }
- // 使用caffe的cpu_gemm来进行计算
- for (int g = 0; g < group_; ++g) {
- // conv_out_channels_ / group_是每个卷积组的输出的channel
- // kernel_dim_ = input channels per-group x kernel height x kernel width
- // 计算的是output[output_offset_ * g] =
- // weights[weight_offset_ * g] X col_buff[col_offset_ * g]
- // weights的维度为(conv_out_channels_ /group_) x kernel_dim_
- // weights的形状是 [conv_out_channel x kernel_dim_]
- // col_buff相当于数据,它的形状是[kernel_dim_ x (卷积后图像高度乘以卷积后图像宽度)]=
- // kernel_dim_ x conv_out_spatial_dim_
- // 所以output的形状自然就是conv_out_channel X (卷积后图像高度乘以卷积后图像宽度)=
- // (conv_out_channels_ /group_) x conv_out_spatial_dim_
- caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, conv_out_channels_ /
- group_, conv_out_spatial_dim_, kernel_dim_,
- (Dtype)1., weights + weight_offset_ * g, col_buff + col_offset_ * g,
- (Dtype)0., output + output_offset_ * g);
- }
- }//只是对一张图像进行前向传播!与全连接层类比,conv_out_channels_ / group_相当与全连接层的输出神经元个数;conv_out_spatial_dim_相当于全连接层中的样本个数;kernel_dim_相当与全连接层中每个样本特征向量的维数。
template <typename Dtype>
void BaseConvolutionLayer<Dtype>::backward_cpu_gemm(const Dtype* output,
const Dtype* weights, Dtype* input) {
Dtype* col_buff = col_buffer_.mutable_cpu_data();
if (is_1x1_) {
col_buff = input;
}
for (int g = 0; g < group_; ++g) {
caffe_cpu_gemm<Dtype>(CblasTrans, CblasNoTrans, kernel_dim_,
conv_out_spatial_dim_, conv_out_channels_ / group_,
(Dtype)1., weights + weight_offset_ * g, output + output_offset_ * g,
(Dtype)0., col_buff + col_offset_ * g);
}
if (!is_1x1_) {
conv_col2im_cpu(col_buff, input);
}
}