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++ 实现:
xxxxxxxxxx
class 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 层的关键操作就是对每个通道进行归一化处理,保证每一层的输入具有相同的分布,从而提高模型训练的稳定性和收敛速度。