diff --git a/Files/.keep b/Files/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Files/main part--luosirui.c b/Files/main part--luosirui.c new file mode 100644 index 0000000000000000000000000000000000000000..8943dfc49358aadb17edd994997d632fdc910a8f --- /dev/null +++ b/Files/main part--luosirui.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +int main() +{ + char continue_flag = 'Y'; + char input_buffer[1024]; + + while (continue_flag == 'Y' || continue_flag == 'y') + { + printf("please input filenames: "); + fgets(input_buffer, sizeof(input_buffer), stdin); + input_buffer[strcspn(input_buffer, "\n")] = '\0'; // 移除换行符 + + char *filename = strtok(input_buffer, ", "); + int first_file = 1; + + while (filename != NULL) + { + double digit; + pgm_to_matrix(filename, 28, 28, (double[28][28]){0}); // 初始化矩阵 + + // 调用识别函数 + recognize_digit(filename, &digit); + + // 输出结果 + if (first_file) + { + printf("%s: %.0f", filename, digit); + first_file = 0; + } + else + { + printf(", %s: %.0f", filename, digit); + } + + filename = strtok(NULL, ", "); + } + printf("\n"); + + // 检查是否继续 + printf("do you want to continue? please input [Y or N]: "); + scanf(" %c", &continue_flag); + getchar(); // 消耗缓冲区残留字符 + } + + printf("Bye\n"); + return 0; +} \ No newline at end of file diff --git a/Files/part2--Lihaoxuan.c b/Files/part2--Lihaoxuan.c new file mode 100644 index 0000000000000000000000000000000000000000..1e75e216f4dcb6d473bcc44b829be922552e9ccf --- /dev/null +++ b/Files/part2--Lihaoxuan.c @@ -0,0 +1,79 @@ +void pgm_to_matrix(const char *file_path, const int n_rows, const int n_cols, double A[n_rows][n_cols]); +void matrix_to_vector(const int n_rows, const int n_cols, const double matrix[n_rows][n_cols], double vector[1][n_rows * n_cols]); +void vector_to_matrix(const int n_rows, const int n_cols, const double vector[1][n_rows * n_cols], double matrix[n_rows][n_cols]); +void pgm_to_matrix(const char *file_path, const int n_rows, const int n_cols, double A[n_rows][n_cols]) +{ + FILE *fp = fopen(file_path, "rb"); + if (!fp) + { + printf("invalid file.\n"); + return; + } + + char magic_number[3]; + fgets(magic_number, sizeof(magic_number), fp); + + if (strcmp(magic_number, "P5\n") == 0) + { + + char line[256]; + while (fgets(line, sizeof(line), fp) != NULL && line[0] == '#') + { + } + + int width, height, max_value; + fscanf(fp, "%d %d %d", &width, &height, &max_value); + + for (int i = 0; i < n_rows; i++) + { + for (int j = 0; j < n_cols; j++) + { + unsigned char pixel = fgetc(fp); + A[i][j] = (double)pixel / (double)max_value; + } + } + } + else + { + + char line[256]; + fgets(line, sizeof(line), fp); + fgets(line, sizeof(line), fp); + fgets(line, sizeof(line), fp); + fgets(line, sizeof(line), fp); + + for (int i = 0; i < n_rows; i++) + { + for (int j = 0; j < n_cols; j++) + { + unsigned char pixel = fgetc(fp); + A[i][j] = (double)pixel / 255.0; + } + } + } + fclose(fp); +} + + +void matrix_to_vector(const int n_rows, const int n_cols, const double matrix[n_rows][n_cols], double vector[1][n_rows * n_cols]) +{ + for (int i = 0; i < n_rows; i++) + { + for (int j = 0; j < n_cols; j++) + { + vector[0][i * n_cols + j] = matrix[i][j]; + } + } +} + + +void vector_to_matrix(const int n_rows, const int n_cols, const double vector[1][n_rows * n_cols], double matrix[n_rows][n_cols]) +{ + for (int i = 0; i < n_rows; i++) + { + for (int j = 0; j < n_cols; j++) + { + matrix[i][j] = vector[0][i * n_cols + j]; + } + } +} \ No newline at end of file diff --git a/Files/part3--Linjinyi.c b/Files/part3--Linjinyi.c new file mode 100644 index 0000000000000000000000000000000000000000..5ce7bf7d013a853343ef9d54afbe88f8cd7b33ab --- /dev/null +++ b/Files/part3--Linjinyi.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +// subfunction declaration +void read_txt_data(const char *filename, const int n, double array[1][n]); +void add_matrices(const int n_rows, const int n_cols, const double mat1[n_rows][n_cols], const double mat2[n_rows][n_cols], double result[n_rows][n_cols]); +void matrix_mul(const int m, const int n, const int p, const double mat1[m][p], const double mat2[p][n], double result[m][n]); + +// 4.read data in a txt file +void read_txt_data(const char *filename, const int n, double array[1][n]) +{ + FILE *fp = fopen(filename, "r"); + if (!fp) + { + printf("Error reading file %s\n", filename); + return; + } + + for (int i = 0; i < n; i++) + { + fscanf(fp, "%lf", &array[0][i]); + } + fclose(fp); +} + +// 5.add two matrices +void add_matrices(const int n_rows, const int n_cols, const double mat1[n_rows][n_cols], const double mat2[n_rows][n_cols], double result[n_rows][n_cols]) +{ + for (int i = 0; i < n_rows; i++) + { + for (int j = 0; j < n_cols; j++) + { + result[i][j] = mat1[i][j] + mat2[i][j]; + } + } +} + +// 6.multiply two matrices +void matrix_mul(const int m, const int n, const int p, const double mat1[m][p], const double mat2[p][n], double result[m][n]) +{ + for (int i = 0; i < m; i++) + { + for (int j = 0; j < n; j++) + { + result[i][j] = 0.0; + for (int k = 0; k < p; k++) + { + result[i][j] += mat1[i][k] * mat2[k][j]; + } + } + } +} \ No newline at end of file diff --git a/Files/part4--Zhengrenheng.c b/Files/part4--Zhengrenheng.c new file mode 100644 index 0000000000000000000000000000000000000000..798b05f2aceff9429fa13223fa6aafc29c7da2d6 --- /dev/null +++ b/Files/part4--Zhengrenheng.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include + +void active_function(const int SIZE, const double F[1][SIZE], double G[1][SIZE]); +void soft_max(const int rows, const int cols, const double L[rows][cols], double S[rows][cols]); + +// 7. 激活函数(ReLU) +void active_function(const int SIZE, const double F[1][SIZE], double G[1][SIZE]) +{ + for (int i = 0; i < SIZE; i++) + { + G[0][i] = (F[0][i] > 0) ? F[0][i] : 0.0; + } +} + +// 8. SoftMax函数 +void soft_max(const int rows, const int cols, const double L[rows][cols], double S[rows][cols]) +{ + double max_val = L[0][0]; + for (int j = 0; j < cols; j++) + { + if (L[0][j] > max_val) + max_val = L[0][j]; + } + + double sum = 0.0; + for (int j = 0; j < cols; j++) + { + S[0][j] = exp(L[0][j] - max_val); + sum += S[0][j]; + } + + for (int j = 0; j < cols; j++) + { + S[0][j] /= sum; + } +} diff --git a/Files/part5--Linxizhe.c b/Files/part5--Linxizhe.c new file mode 100644 index 0000000000000000000000000000000000000000..64834d5dc174b5cbaf0d5c8d9a4aa2efc0a1d672 --- /dev/null +++ b/Files/part5--Linxizhe.c @@ -0,0 +1,43 @@ +// 从 .pgm 文件识别数字的函数,使用神经网络 +int recognize_digit(const char* filename) { + // 声明前向传播中涉及的所有矩阵 + float A[ROWS_A][COLS_A]; // 28x28 图像矩阵 + float B[1][ROWS_A * COLS_A]; // 展平图像 (1x784) + float C[ROWS_A * COLS_A][COLS_C]; // 第一权重矩阵 W1 (784x128) + float D[1][COLS_C]; // B × C (1x128) + float E[1][COLS_C]; // 偏置 B1 (1x128) + float F[1][COLS_C]; // D + E (1x128) + float G[1][COLS_C]; // ReLU(F) (1x128) + float W2[COLS_C][COLS_W2]; // 第二权重矩阵 W2 (128x10) + float H[1][COLS_W2]; // G × W2 (1x10) + float B2[1][COLS_W2]; // 偏置 B2 (1x10) + float L[1][COLS_W2]; // H + B2 (1x10) + float S[1][COLS_W2]; // SoftMax(L) (1x10) + float W1_flat[ROWS_A * COLS_A * COLS_C]; // 展平 W1 (784*128 = 100352) + float W2_flat[COLS_C * COLS_W2]; // 展平 W2 (128*10 = 1280) +} + +void process_filenames(const char* input) { + char* input_copy = strdup(input); // 复制输入以避免修改原始字符串 + char* token = strtok(input_copy, ","); // 按逗号分割 + while (token != NULL) { + // 去除首尾空格 + while (*token == ' ') token++; + char* end = token + strlen(token) - 1; + while (end > token && *end == ' ') *end-- = '\0'; + + // 检查文件名是否以 .pgm 结尾 + if (strstr(token, ".pgm") == NULL || strstr(token, ".pgm") != token + strlen(token) - 4) { + printf("无效文件\n"); + } else { + int digit = recognize_digit(token); // 识别数字 + if (digit == -1) { + printf("无效文件\n"); // 文件无法打开 + } else { + printf("%s: %d\n", token, digit); // 输出文件名和数字 + } + } + token = strtok(NULL, ","); // 获取下一个文件名 +} +free(input_copy); // 释放复制的字符串 +} diff --git a/Final/main.c b/Final/main.c new file mode 100644 index 0000000000000000000000000000000000000000..80e9b20c3c99974799a00aa7e8c1617a13f8089e --- /dev/null +++ b/Final/main.c @@ -0,0 +1,281 @@ +#include +#include +#include +#include + +// Phase I: 子函数声明 +void pgm_to_matrix(const char *file_path, const int n_rows, const int n_cols, double A[n_rows][n_cols]); +void matrix_to_vector(const int n_rows, const int n_cols, const double matrix[n_rows][n_cols], double vector[1][n_rows * n_cols]); +void vector_to_matrix(const int n_rows, const int n_cols, const double vector[1][n_rows * n_cols], double matrix[n_rows][n_cols]); +void read_txt_data(const char *filename, const int n, double array[1][n]); +void add_matrices(const int n_rows, const int n_cols, const double mat1[n_rows][n_cols], const double mat2[n_rows][n_cols], double result[n_rows][n_cols]); +void matrix_mul(const int m, const int n, const int p, const double mat1[m][p], const double mat2[p][n], double result[m][n]); +void active_function(const int SIZE, const double F[1][SIZE], double G[1][SIZE]); +void soft_max(const int rows, const int cols, const double L[rows][cols], double S[rows][cols]); + +// Phase II: 识别流程函数 +void recognize_digit(const char *file_path, double *result_digit); + +int main() +{ + char continue_flag = 'Y'; + char input_buffer[1024]; + + while (continue_flag == 'Y' || continue_flag == 'y') + { + printf("please input filenames: "); + fgets(input_buffer, sizeof(input_buffer), stdin); + input_buffer[strcspn(input_buffer, "\n")] = '\0'; // 移除换行符 + + // 处理多个文件名(支持逗号或空格分隔) + char *filename = strtok(input_buffer, ", "); + int first_file = 1; + + while (filename != NULL) + { + double digit; + pgm_to_matrix(filename, 28, 28, (double[28][28]){0}); // 初始化矩阵 + + // 调用识别函数 + recognize_digit(filename, &digit); + + // 输出结果 + if (first_file) + { + printf("%s: %.0f", filename, digit); + first_file = 0; + } + else + { + printf(", %s: %.0f", filename, digit); + } + + filename = strtok(NULL, ", "); + } + printf("\n"); + + // 检查是否继续 + printf("do you want to continue? please input [Y or N]: "); + scanf(" %c", &continue_flag); + getchar(); // 消耗缓冲区残留字符 + } + + printf("Bye\n"); + return 0; +} + +// Phase I: 子函数实现 + +// 1. 读取PGM文件并转换为矩阵(支持P2和P5格式) +void pgm_to_matrix(const char *file_path, const int n_rows, const int n_cols, double A[n_rows][n_cols]) +{ + FILE *fp = fopen(file_path, "rb"); + if (!fp) + { + printf("invalid file.\n"); + return; + } + + char magic_number[3]; + fgets(magic_number, sizeof(magic_number), fp); + // 判断是否为P5格式 + if (strcmp(magic_number, "P5\n") == 0) + { + // 跳过注释行 + char line[256]; + while (fgets(line, sizeof(line), fp) != NULL && line[0] == '#') + { + } + // 读取图像宽度、高度和最大像素值 + int width, height, max_value; + fscanf(fp, "%d %d %d", &width, &height, &max_value); + // 读取像素数据并归一化 + for (int i = 0; i < n_rows; i++) + { + for (int j = 0; j < n_cols; j++) + { + unsigned char pixel = fgetc(fp); + A[i][j] = (double)pixel / (double)max_value; + } + } + } + else + { + // 跳过前四行文件头(P2格式处理逻辑) + char line[256]; + fgets(line, sizeof(line), fp); + fgets(line, sizeof(line), fp); + fgets(line, sizeof(line), fp); + fgets(line, sizeof(line), fp); + // 读取像素数据并归一化 + for (int i = 0; i < n_rows; i++) + { + for (int j = 0; j < n_cols; j++) + { + unsigned char pixel = fgetc(fp); + A[i][j] = (double)pixel / 255.0; + } + } + } + fclose(fp); +} + +// 2. 矩阵展平为向量 +void matrix_to_vector(const int n_rows, const int n_cols, const double matrix[n_rows][n_cols], double vector[1][n_rows * n_cols]) +{ + for (int i = 0; i < n_rows; i++) + { + for (int j = 0; j < n_cols; j++) + { + vector[0][i * n_cols + j] = matrix[i][j]; + } + } +} + +// 3. 向量转换为矩阵(反向操作) +void vector_to_matrix(const int n_rows, const int n_cols, const double vector[1][n_rows * n_cols], double matrix[n_rows][n_cols]) +{ + for (int i = 0; i < n_rows; i++) + { + for (int j = 0; j < n_cols; j++) + { + matrix[i][j] = vector[0][i * n_cols + j]; + } + } +} + +// 4. 读取TXT文件数据 +void read_txt_data(const char *filename, const int n, double array[1][n]) +{ + FILE *fp = fopen(filename, "r"); + if (!fp) + { + printf("Error reading file %s\n", filename); + return; + } + + for (int i = 0; i < n; i++) + { + fscanf(fp, "%lf", &array[0][i]); + } + fclose(fp); +} + +// 5. 矩阵加法 +void add_matrices(const int n_rows, const int n_cols, const double mat1[n_rows][n_cols], const double mat2[n_rows][n_cols], double result[n_rows][n_cols]) +{ + for (int i = 0; i < n_rows; i++) + { + for (int j = 0; j < n_cols; j++) + { + result[i][j] = mat1[i][j] + mat2[i][j]; + } + } +} + +// 6. 矩阵乘法 +void matrix_mul(const int m, const int n, const int p, const double mat1[m][p], const double mat2[p][n], double result[m][n]) +{ + for (int i = 0; i < m; i++) + { + for (int j = 0; j < n; j++) + { + result[i][j] = 0.0; + for (int k = 0; k < p; k++) + { + result[i][j] += mat1[i][k] * mat2[k][j]; + } + } + } +} + +// 7. 激活函数(ReLU) +void active_function(const int SIZE, const double F[1][SIZE], double G[1][SIZE]) +{ + for (int i = 0; i < SIZE; i++) + { + G[0][i] = (F[0][i] > 0) ? F[0][i] : 0.0; + } +} + +// 8. SoftMax函数 +void soft_max(const int rows, const int cols, const double L[rows][cols], double S[rows][cols]) +{ + double max_val = L[0][0]; + for (int j = 0; j < cols; j++) + { + if (L[0][j] > max_val) + max_val = L[0][j]; + } + + double sum = 0.0; + for (int j = 0; j < cols; j++) + { + S[0][j] = exp(L[0][j] - max_val); + sum += S[0][j]; + } + + for (int j = 0; j < cols; j++) + { + S[0][j] /= sum; + } +} + +// Phase II: 识别流程实现 +void recognize_digit(const char *file_path, double *result_digit) +{ + double A[28][28] = {0}; + double B[1][784] = {0}; + double C[784][128] = {0}; // W1矩阵 + double D[1][128] = {0}; + double E[1][128] = {0}; // B1偏置 + double F[1][128] = {0}; + double G[1][128] = {0}; + + double W1[1][784 * 128] = {0}; + double W2[1][128 * 10] = {0}; + double B1[1][128] = {0}; + double B2[1][10] = {0}; + + double H[1][10] = {0}; + double L[1][10] = {0}; + double S[1][10] = {0}; + + // 1. 读取PGM文件并展平为向量B + pgm_to_matrix(file_path, 28, 28, A); + matrix_to_vector(28, 28, A, B); + + // 2. 加载第一层权重W1(784x128) + read_txt_data("input_files/W1.txt", 784 * 128, W1); + vector_to_matrix(784, 128, W1, C); + matrix_mul(1, 128, 784, B, C, D); + + // 3. 加载第一层偏置B1并相加 + read_txt_data("input_files/B1.txt", 128, B1); + add_matrices(1, 128, D, B1, F); + + // 4. 激活函数 + active_function(128, F, G); + + // 5. 加载第二层权重W2(128x10) + read_txt_data("input_files/W2.txt", 128 * 10, W2); + double W2_matrix[128][10]; + vector_to_matrix(128, 10, W2, W2_matrix); + matrix_mul(1, 10, 128, G, W2_matrix, H); + + // 6. 加载第二层偏置B2并相加 + read_txt_data("input_files/B2.txt", 10, B2); + add_matrices(1, 10, H, B2, L); + + // 7. SoftMax计算 + soft_max(1, 10, L, S); + + // 8. 找出最大概率的索引 + int max_index = 0; + for (int j = 1; j < 10; j++) + { + if (S[0][j] > S[0][max_index]) + max_index = j; + } + *result_digit = (double)max_index; +} \ No newline at end of file diff --git a/c10_group b/c10_group new file mode 160000 index 0000000000000000000000000000000000000000..96029d27eb0428790892072b8420fd5ff883719b --- /dev/null +++ b/c10_group @@ -0,0 +1 @@ +Subproject commit 96029d27eb0428790892072b8420fd5ff883719b diff --git a/text.txt b/text.txt new file mode 100644 index 0000000000000000000000000000000000000000..273c1a9ffdc201dbca7d19b275bf1cbc88aaa4cb --- /dev/null +++ b/text.txt @@ -0,0 +1 @@ +This is a test. \ No newline at end of file