直接卷积代码,在网上找了很久,只要是卷积就是im2col+gemm
,想找个direct convolution
的代码找不到,干脆自己写了。
卷积过程
卷积参数
代码
#include <stdio.h>
#include <stdlib.h>
typedef struct {
float *data;
int n;
int c;
int h;
int w;
} tensor;
int get_index(tensor *tensor, int index0, int index1, int index2, int index3) {
return ((index0 * tensor->c + index1) * tensor->h + index2) * tensor->w +
index3;
}
void direct_conv(tensor *input, tensor *kernel, tensor *output, int stride) {
int input_n = input->n;
int input_channel = input->c;
int input_height = input->h;
int input_width = input->w;
int kernel_n = kernel->n;
int kernel_channel = kernel->c;
int kernel_height = kernel->h;
int kernel_width = kernel->w;
int output_n = output->n;
int output_channel = output->c;
int output_height = output->h;
int output_width = output->w;
// input N C H W
// kernel K C R S
// output N K P Q
// 第几张照片
for (int out_n = 0; out_n < output_n; out_n++) {
// 卷积核个数=输出的通道数,比如一个卷积核有三个通道,和输入三个通道对应乘,3个加一起得到输出的一个通道
// 第2个卷积核和同一个输入 得到输出的第2个通道
for (int out_c = 0; out_c < output_channel; out_c++) {
// 这时候就锁定输出的每个点的位置
for (int out_h = 0; out_h < output_height; out_h++) {
for (int out_w = 0; out_w < output_width; out_w++) {
// 根据out位置,定此时in在哪里, 第in_c个通道里的位置
int in_h = out_h * stride;
int in_w = out_w * stride;
// 从起始位置开始跟卷积对应位置点乘
// 这个时候就是3个通道累加
for (int in_c = 0; in_c < input_channel; in_c++) {
for (int k_h = 0; k_h < kernel_height; k_h++) {
for (int k_w = 0; k_w < kernel_width; k_w++) {
// 找位置 nchw排序
int kernel_index = get_index(kernel, out_c, in_c, k_h, k_w);
int data_index =
get_index(input, out_n, in_c, (in_h + k_h), (in_w + k_w));
int output_index =
get_index(output, out_n, out_c, out_h, out_w);
output->data[output_index] +=
kernel->data[kernel_index] * input->data[data_index];
}
}
}
// NOTE: 算完之后可能要加个bias
// int output_index = get_index(output, out_n, out_c, out_h, out_w);
// output->data[output_index] += bias;
}
}
}
}
}
void init_tensor(tensor *input, int n, int c, int h, int w) {
input->n = n;
input->c = c;
input->h = h;
input->w = w;
input->data = (float *)malloc(sizeof(float) * n * c * h * w);
for (int p = 0; p < input->n; p++) {
for (int i = 0; i < input->c; i++) {
for (int j = 0; j < input->h; j++) {
for (int k = 0; k < input->w; k++) {
// int index = (p * input->c * input->h * input->w) +
// (i * (input->h * input->w) + (j * input->w + k));
// int index = ((p * input->c + i) * input->h + j) * input->w + k;
int index = get_index(input, p, i, j, k);
input->data[index] = 0;
}
}
}
}
}
void print_tensor(tensor *input, char *name) {
printf("%s\n", name);
for (int p = 0; p < input->n; p++) {
printf("n: %d\n", p);
for (int i = 0; i < input->c; i++) {
printf("channel: %d\n", i);
for (int j = 0; j < input->h; j++) {
for (int k = 0; k < input->w; k++) {
// int index = (i * (input->h * input->w) + (j * input->w + k));
int index = get_index(input, p, i, j, k);
printf("[%f] ", input->data[index]);
}
}
printf("\n");
}
printf("\n");
}
}
void test_01() {
tensor *input = (tensor *)malloc(sizeof(tensor));
tensor *kernel = (tensor *)malloc(sizeof(tensor));
tensor *output = (tensor *)malloc(sizeof(tensor));
init_tensor(input, 2, 3, 6, 6);
init_tensor(kernel, 2, 3, 3, 3);
int stride = 3;
init_tensor(output, 2, 2, 2, 2);
for (int p = 0; p < input->n; p++) {
for (int i = 0; i < input->c; i++) {
int data = i + 1;
for (int j = 0; j < input->h; j++) {
for (int k = 0; k < input->w; k++) {
// int index = (p * input->c * input->h * input->w) +
// (i * (input->h * input->w) + (j * input->w + k));
// int index = ((p * input->c + i) * input->h + j) * input->w + k;
int index = get_index(input, p, i, j, k);
input->data[index] = index;
}
}
}
}
print_tensor(input, "input");
for (int p = 0; p < kernel->n; p++) {
for (int i = 0; i < kernel->c; i++) {
// 第 i 通道的kernel全是 data
int data = i + 1;
for (int j = 0; j < kernel->h; j++) {
for (int k = 0; k < kernel->w; k++) {
// int index = (p * kernel->c * kernel->h * kernel->w) +
// (i * (kernel->h * kernel->w) + (j * kernel->w + k));
// int index = ((p * kernel->c + i) * kernel->h + j) * kernel->w + k;
int index = get_index(kernel, p, i, j, k);
kernel->data[index] = data;
}
}
}
}
print_tensor(kernel, "kernel");
// 计算
direct_conv(input, kernel, output, stride);
print_tensor(output, "output");
}
int main() {
test_01();
return 0;
}