Skip to content

Commit fc90ead

Browse files
committed
add BP conv
1 parent 7e18e93 commit fc90ead

File tree

4 files changed

+391
-110
lines changed

4 files changed

+391
-110
lines changed

conv_backward_test.cpp

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#include <iostream>
2+
#include <cassert>
3+
#include "./matrix/matrix_def.h"
4+
#include "./matrix/matrix_pro.h"
5+
#include "./root/include/edgelayer.h"
6+
7+
// 辅助函数:检查两个浮点数是否近似相等
8+
bool is_close(float a, float b, float rtol = 1e-5, float atol = 1e-8) {
9+
return fabs(a - b) <= (atol + rtol * fabs(b));
10+
}
11+
12+
int main() {
13+
// 创建测试输入 (batch=1, channels=3, height=4, width=4)
14+
Matrix4d input = CreateMatrix4d(1, 3, 4, 4);
15+
16+
// 用固定的测试值填充输入
17+
float test_input[3][4][4] = {
18+
{{1,2,3,4}, {2,3,4,5}, {3,4,5,6}, {4,5,6,7}}, // channel 1
19+
{{2,4,6,8}, {4,6,8,10}, {6,8,10,12}, {8,10,12,14}}, // channel 2
20+
{{3,6,9,12}, {6,9,12,15}, {9,12,15,18}, {12,15,18,21}} // channel 3
21+
};
22+
23+
for(int c = 0; c < 3; c++) {
24+
for(int i = 0; i < 4; i++) {
25+
for(int j = 0; j < 4; j++) {
26+
input.matrix4d[0].matrix3d[c].matrix[i][j] = test_input[c][i][j];
27+
}
28+
}
29+
}
30+
31+
// 创建卷积层并设置固定的卷积核
32+
edge_layer* conv = new conv2d(input, 3, 2, 1, 3, 0, 1);
33+
conv2d* conv_ptr = dynamic_cast<conv2d*>(conv);
34+
35+
// 设置固定的卷积核值
36+
float test_kernel[3][2][3][3] = {
37+
{{{1,0,1}, {0,1,0}, {1,0,1}}, // in_channel 0, out_channel 0
38+
{{0,1,0}, {1,0,1}, {0,1,0}}}, // in_channel 0, out_channel 1
39+
{{{1,1,0}, {1,0,1}, {0,1,1}}, // in_channel 1, out_channel 0
40+
{{0,1,1}, {1,0,1}, {1,1,0}}}, // in_channel 1, out_channel 1
41+
{{{0,0,1}, {0,1,0}, {1,0,0}}, // in_channel 2, out_channel 0
42+
{{1,0,0}, {0,1,0}, {0,0,1}}} // in_channel 2, out_channel 1
43+
};
44+
45+
for(int in_c = 0; in_c < 3; in_c++) {
46+
for(int out_c = 0; out_c < 2; out_c++) {
47+
conv_ptr->set_kernel(&test_kernel[in_c][out_c][0][0], in_c, out_c);
48+
}
49+
}
50+
51+
// 前向传播
52+
Matrix4d output = conv->forward(input);
53+
std::cout << "Forward output shape:" << std::endl;
54+
print_shape(output);
55+
std::cout << "Forward output values:" << std::endl;
56+
cout_mat4d(output);
57+
58+
// 验证前向传播的输出尺寸
59+
assert(output.batch == 1);
60+
assert(output.dep == 2);
61+
// 计算期望的输出尺寸
62+
int expected_size = ((4 + 2*1 - 3) / 1) + 1; // ((4 + 2 - 3) / 1) + 1 = 4
63+
assert(output.wid == expected_size);
64+
assert(output.high == expected_size);
65+
66+
// 创建固定的梯度输出
67+
int output_size = ((4 + 2*1 - 3) / 1) + 1; // 计算正确的输出尺寸
68+
Matrix4d grad_output = CreateMatrix4d(1, 2, output_size, output_size);
69+
float test_grad[2][4][4] = {
70+
{{1,1,1,1}, {1,1,1,1}, {1,1,1,1}, {1,1,1,1}}, // out_channel 0
71+
{{0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}} // out_channel 1
72+
};
73+
74+
for(int c = 0; c < 2; c++) {
75+
for(int i = 0; i < 4; i++) {
76+
for(int j = 0; j < 4; j++) {
77+
grad_output.matrix4d[0].matrix3d[c].matrix[i][j] = test_grad[c][i][j];
78+
}
79+
}
80+
}
81+
82+
// 反向传播
83+
Matrix4d grad_input = conv->backward(grad_output);
84+
std::cout << "Backward gradients shape:" << std::endl;
85+
print_shape(grad_input);
86+
std::cout << "Backward gradients values:" << std::endl;
87+
cout_mat4d(grad_input);
88+
89+
// 验证反向传播的梯度尺寸
90+
assert(grad_input.batch == 1);
91+
assert(grad_input.dep == 3);
92+
assert(grad_input.wid == 4);
93+
assert(grad_input.high == 4);
94+
95+
// 验证一些特定位置的梯度值
96+
// 手动计算的预期梯度值
97+
float expected_grads[3][4][4] = {
98+
// channel 0
99+
{
100+
{2.0f, 1.5f, 1.5f, 1.0f},
101+
{1.5f, 2.0f, 2.0f, 1.5f},
102+
{1.5f, 2.0f, 2.0f, 1.5f},
103+
{1.0f, 1.5f, 1.5f, 1.0f}
104+
},
105+
// channel 1
106+
{
107+
{2.5f, 2.0f, 2.0f, 1.5f},
108+
{2.0f, 3.0f, 3.0f, 2.0f},
109+
{2.0f, 3.0f, 3.0f, 2.0f},
110+
{1.5f, 2.0f, 2.0f, 1.5f}
111+
},
112+
// channel 2
113+
{
114+
{1.5f, 1.0f, 1.0f, 0.5f},
115+
{1.0f, 1.5f, 1.5f, 1.0f},
116+
{1.0f, 1.5f, 1.5f, 1.0f},
117+
{0.5f, 1.0f, 1.0f, 0.5f}
118+
}
119+
};
120+
121+
for(int c = 0; c < 3; c++) {
122+
for(int i = 0; i < 4; i++) {
123+
for(int j = 0; j < 4; j++) {
124+
float actual = grad_input.matrix4d[0].matrix3d[c].matrix[i][j];
125+
float expected = expected_grads[c][i][j];
126+
if (!is_close(actual, expected)) {
127+
std::cout << "Gradient mismatch at position [" << c << "][" << i << "][" << j << "]" << std::endl;
128+
std::cout << "Expected: " << expected << ", Got: " << actual << std::endl;
129+
}
130+
}
131+
}
132+
}
133+
134+
std::cout << "All tests passed!" << std::endl;
135+
136+
delete conv;
137+
return 0;
138+
}

matrix/matrix_pro.h

Lines changed: 53 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -593,112 +593,69 @@ Matrix3d conv_test(Matrix3d mid1, int input_dim = 3, int output_channels = 3, in
593593
}
594594
}
595595
Matrix3d conv_test_with_output(Matrix3d mid1,
596-
int input_dim = 3,
597-
int output_channels = 3,
598-
int stride = 1,
599-
int kernel_size = 2,
600-
int mode = 0,
601-
bool verbose = false)
602-
// padding 暂未实现
603-
{
604-
if (verbose)
605-
{
606-
cout << "Input Matrix3d: " << endl;
607-
cout_mat3d(mid1);
608-
cout << "Parameters: input_dim = " << input_dim
609-
<< ", output_channels = " << output_channels
610-
<< ", stride = " << stride
611-
<< ", kernel_size = " << kernel_size
612-
<< ", mode = " << mode;
613-
}
614-
615-
// Compute padding widths and heights
616-
int padding_wid = stride - (mid1.wid - kernel_size) % stride;
617-
if (padding_wid == stride)
618-
{
619-
padding_wid = 0;
620-
}
621-
int padding_high = stride - (mid1.high - kernel_size) % stride;
622-
if (padding_high == stride)
623-
{
624-
padding_high = 0;
625-
}
626-
if (verbose)
627-
{
628-
cout << "Padding widths: " << padding_wid << ", padding heights: " << padding_high << endl;
629-
}
630-
631-
// Pad each RGB channel in the 3D matrix
632-
Matrix mid_rgb[input_dim];
633-
for (int rgb_idx = 0; rgb_idx < input_dim; rgb_idx++)
634-
{
635-
mid_rgb[rgb_idx] = edge_padding(mid1.matrix3d[rgb_idx],
636-
mid1.matrix3d[rgb_idx].row + padding_high,
637-
mid1.matrix3d[rgb_idx].col + padding_wid);
638-
if (verbose)
639-
{
640-
cout << "RGB[" << rgb_idx << "] channel after padding: " << endl;
641-
cout_mat(mid_rgb[rgb_idx]);
596+
int input_dim = 3,
597+
int output_channels = 3,
598+
int stride = 1,
599+
int kernel_size = 2,
600+
int mode = 0,
601+
int padding = 0,
602+
bool verbose = false)
603+
{
604+
// 如果需要padding,先对输入进行padding
605+
if (padding > 0) {
606+
Matrix3d padded_input = CreateMatrix3d(mid1.dep, mid1.wid + 2*padding, mid1.high + 2*padding);
607+
for (int c = 0; c < mid1.dep; c++) {
608+
padded_input.matrix3d[c] = edge_padding(mid1.matrix3d[c],
609+
mid1.wid + 2*padding,
610+
mid1.high + 2*padding);
642611
}
612+
mid1 = padded_input;
643613
}
644614

645-
// Construct filters
646-
Matrix filters[input_dim][output_channels];
647-
for (int channel_index = 0; channel_index < input_dim; channel_index++)
648-
{
615+
// 计算输出尺寸
616+
int output_height = ((mid1.wid - kernel_size) / stride) + 1;
617+
int output_width = ((mid1.high - kernel_size) / stride) + 1;
649618

650-
for (int filter_index = 0; filter_index < output_channels; filter_index++)
651-
{
652-
Matrix kernel = ones(kernel_size, kernel_size);
653-
filters[channel_index][filter_index] = kernel;
619+
Matrix3d output3d = CreateMatrix3d(output_channels, output_height, output_width);
620+
621+
// 构造卷积核
622+
Matrix** filters = (Matrix**)malloc(input_dim * sizeof(Matrix*));
623+
for(int i = 0; i < input_dim; i++) {
624+
filters[i] = (Matrix*)malloc(output_channels * sizeof(Matrix));
625+
for(int j = 0; j < output_channels; j++) {
626+
filters[i][j] = ones(kernel_size, kernel_size);
654627
}
655628
}
656629

657-
// Compute convolution results for each filter
658-
Matrix kernel = ones(kernel_size, kernel_size);
659-
Matrix feature_maps[output_channels];
660-
for (int filter_idx = 0; filter_idx < output_channels; filter_idx++)
661-
{
662-
Matrix sum_rgb = CreateMatrix(((mid1.wid - kernel_size + 2 * padding_wid) / stride) + 1,
663-
((mid1.high - kernel_size + 2 * padding_high) / stride) + 1);
664-
for (int channel_idx = 0; channel_idx < input_dim; channel_idx++)
665-
{
666-
// Compute convolution result for a single RGB channel and a single filter
667-
Matrix element = conv_element(mid_rgb[channel_idx],
668-
filters[channel_idx][filter_idx],
669-
kernel_size, stride);
670-
if (verbose)
671-
{
672-
cout << "Convolution of RGB[" << channel_idx << "] channel with Filter["
673-
<< filter_idx << "] : " << endl;
674-
cout_mat(mid_rgb[channel_idx]);
675-
cout << " * " << endl;
676-
cout_mat(filters[channel_idx][filter_idx]);
677-
cout << " = " << endl;
678-
cout_mat(element);
679-
cout << endl;
630+
// 执行卷积操作
631+
for(int out_c = 0; out_c < output_channels; out_c++) {
632+
for(int h = 0; h < output_height; h++) {
633+
for(int w = 0; w < output_width; w++) {
634+
float sum = 0;
635+
for(int in_c = 0; in_c < input_dim; in_c++) {
636+
for(int kh = 0; kh < kernel_size; kh++) {
637+
for(int kw = 0; kw < kernel_size; kw++) {
638+
int h_in = h * stride + kh;
639+
int w_in = w * stride + kw;
640+
sum += mid1.matrix3d[in_c].matrix[h_in][w_in] *
641+
filters[in_c][out_c].matrix[kh][kw];
642+
}
643+
}
644+
}
645+
output3d.matrix3d[out_c].matrix[h][w] = sum;
680646
}
681-
// Sum convolution results for each RGB channel
682-
sum_rgb = add(sum_rgb, element, 0);
683-
}
684-
feature_maps[filter_idx] = sum_rgb;
685-
if (verbose)
686-
{
687-
cout << "Feature map [" << filter_idx << "] : " << endl;
688-
cout_mat(feature_maps[filter_idx]);
689647
}
690648
}
691-
// Construct 3D matrix to store different feature maps at different depths
692-
Matrix3d output3d = CreateMatrix3d(output_channels, feature_maps[0].row, feature_maps[0].col);
693-
for (int i = 0; i < output_channels; i++)
694-
{
695-
output3d.matrix3d[i] = feature_maps[i];
696-
}
697-
if (verbose)
698-
{
699-
cout << "Output Matrix3d: " << endl;
700-
cout_mat3d(output3d);
649+
650+
// 释放内存
651+
for(int i = 0; i < input_dim; i++) {
652+
for(int j = 0; j < output_channels; j++) {
653+
free_mat(filters[i][j]);
654+
}
655+
free(filters[i]);
701656
}
657+
free(filters);
658+
702659
return output3d;
703660
}
704661

@@ -729,7 +686,7 @@ Matrix4d batch_conv_test(Matrix4d mid4,
729686
for (int batch_idx = 0; batch_idx < mid4.batch; batch_idx++)
730687
{
731688
Matrix3d mid3 = mid4.matrix4d[batch_idx];
732-
Matrix3d output3d = conv_test_with_output(mid3, input_dim, output_channels, stride, kernel_size, mode, verbose);
689+
Matrix3d output3d = conv_test_with_output(mid3, input_dim, output_channels, stride, kernel_size, mode, 0, verbose);
733690
output3d_arr[batch_idx] = output3d;
734691
}
735692

0 commit comments

Comments
 (0)