author:张一极
date:2025年02月28日22:29:00
在深度学习模型中,卷积神经网络(CNN)使用了许多不同的层(Layer),如卷积层(Convolutional Layer)、全连接层(Fully Connected Layer)、Batch Normalization 层等,以提取数据的特征和加速训练。在这篇博客中将详细分析 C++ 中 focus 和 bn 两个层的实现方式。
1. Focus 层的实现
在很多现代神经网络架构中,focus 层是卷积网络中的一个重要组件。它通过对输入数据进行多通道的卷积运算,通常用于对图像进行局部的特征提取。
以下是 focus 层的 C++ 实现:
class focus : public edge_layer{public: int in_channel = 32; int out_channel = 64; focus(int in_channel, int out_channel); Matrix3d forward(Matrix3d mid1) { // 创建一个中间矩阵作为卷积输入 Matrix4d template_mid1 = CreateMatrix4d(in_channel, mid1.dep, mid1.wid, mid1.high); // 定义卷积层 edge_layer *conv2d_1 = new conv2d(template_mid1, 3, 12, 1, 9, 0, 5); // 输出矩阵 Matrix3d output_focus; return output_focus; }};• focus 类继承自 edge_layer,是一个深度学习中的计算层(Layer)基类。
• in_channel 和 out_channel 分别代表输入通道数和输出通道数。
• forward 方法中,首先创建了一个 Matrix4d 类型的矩阵 template_mid1,它包含了输入数据的多通道数据。CreateMatrix4d 是一个函数,用来初始化这个矩阵,它的作用是给定输入通道、深度、宽度和高度,创建一个合适的矩阵。
• 然后,conv2d_1 是一个 conv2d 对象,用来执行卷积运算。传入的参数包括输入数据、卷积核的通道数、输出通道数、步长、卷积核大小等。
• 最后,forward 方法的返回值是一个 Matrix3d,即卷积层处理后的数据。
这里进一步实现 conv2d 层的具体细节,通常这个卷积层会利用卷积核对输入数据进行多通道运算,提取空间特征。
xclass conv2d : public edge_layer{public: conv2d(Matrix4d mid_4, int in_channel, int out_channle, int _stride, int ksize, int _mode, int _padding); int arg1; Matrix4d mid4; int input_dim; int output_channels; int stride; int kernel_size; int mode; int padding;
Matrix4d forward(Matrix4d mid4) { std::cout << "in_channel = " << input_dim << std::endl; std::cout << "out_channle = " << output_channels << std::endl; std::cout << "_stride = " << stride << std::endl; std::cout << "ksize = " << kernel_size << std::endl; std::cout << "_mode = " << mode << std::endl; std::cout << "_padding = " << padding << std::endl; Matrix3d *output3d_arr = (Matrix3d *)malloc(mid4.batch * sizeof(Matrix3d)); for (int batch_idx = 0; batch_idx < mid4.batch; batch_idx++) { Matrix3d mid3 = mid4.matrix4d[batch_idx]; Matrix3d output3d = conv_test_with_output(mid3, input_dim, output_channels, stride, kernel_size, mode, false); output3d_arr[batch_idx] = output3d; }
Matrix4d output4d = CreateMatrix4d(mid4.batch, output_channels, output3d_arr[0].wid, output3d_arr[0].high); for (int batch_idx = 0; batch_idx < mid4.batch; batch_idx++) { output4d.matrix4d[batch_idx] = output3d_arr[batch_idx]; } return output4d; } int parameter_counter() { int num_params = input_dim * output_channels * kernel_size * kernel_size;
// if (bias) // { // num_params += out_channels; // }
return num_params; }};
conv2d::conv2d(Matrix4d mid_1, int in_channel, int out_channle, int _stride, int ksize, int _mode, int _padding){ mid4 = mid_1; input_dim = in_channel; output_channels = out_channle; stride = _stride; kernel_size = ksize; mode = _mode; padding = _padding;}2. Batch Normalization(BN)层的实现
Batch Normalization 是一种常用的技术,目的是使得每层的输入分布稳定,避免因训练过程中参数变化过大导致梯度消失或爆炸。通过对每层的输入进行标准化处理,BN 层加速了训练收敛速度,并有助于防止过拟合。
以下是 BN 层的 C++ 实现:
xxxxxxxxxxclass bn : public edge_layer{public: double beta = 0.1; double gamma = 0.1; bn(double beta, double gamma); Matrix3d forward(Matrix3d mid1) { Matrix3d output_bn = CreateMatrix3d(mid1.dep, mid1.wid, mid1.high); // 对每个通道执行批量归一化 for (int i = 0; i < mid1.dep; i++) { double mean_bn = matrix_mean(mid1.matrix3d[i]); double var_bn = matrix_var(mid1.matrix3d[i]); // 标准化处理 output_bn.matrix3d[i] = subtract_ele(mid1.matrix3d[i], mean_bn); output_bn.matrix3d[i] = matrix_division(output_bn.matrix3d[i], sqrt(var_bn)); // 缩放和偏移 output_bn.matrix3d[i] = times_mat(beta, output_bn.matrix3d[i]); output_bn.matrix3d[i] = add_ele(output_bn.matrix3d[i], gamma); } return output_bn; }};
bn::bn(double beta_bn, double gamma_bn){ beta = beta_bn; gamma = gamma_bn;}代码解读:
• bn 类继承自 edge_layer,表示批量归一化层。
• beta 和 gamma 是可学习的参数,分别是平移(偏移)和缩放系数。它们会在训练过程中根据数据自动调整。
• 在 forward 方法中,首先通过 matrix_mean 和 matrix_var 函数计算当前通道的均值和方差。
• 接着,使用 subtract_ele 和 matrix_division 对输入数据进行标准化操作(减去均值并除以标准差)。
• 然后,通过 times_mat 和 add_ele 函数进行缩放和平移操作,这两个操作对应着 gamma 和 beta。
• 最后,返回处理后的输出 output_bn。
BN 层的关键操作就是对每个通道进行归一化处理,保证每一层的输入具有相同的分布,从而提高模型训练的稳定性和收敛速度。