{"id":22243812,"url":"https://github.com/guyi2000/mlp_in_cpp","last_synced_at":"2026-04-30T00:34:53.230Z","repository":{"id":242307190,"uuid":"809213942","full_name":"guyi2000/MLP_in_CPP","owner":"guyi2000","description":"从零实现的 C++ MLP","archived":false,"fork":false,"pushed_at":"2024-06-02T04:57:11.000Z","size":211,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-30T10:13:04.507Z","etag":null,"topics":["ai","cpp","mlp"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/guyi2000.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-02T03:23:24.000Z","updated_at":"2024-06-02T05:02:48.000Z","dependencies_parsed_at":"2024-06-02T05:24:49.016Z","dependency_job_id":null,"html_url":"https://github.com/guyi2000/MLP_in_CPP","commit_stats":null,"previous_names":["guyi2000/mlp_in_cpp"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guyi2000%2FMLP_in_CPP","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guyi2000%2FMLP_in_CPP/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guyi2000%2FMLP_in_CPP/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guyi2000%2FMLP_in_CPP/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/guyi2000","download_url":"https://codeload.github.com/guyi2000/MLP_in_CPP/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245449531,"owners_count":20617187,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","cpp","mlp"],"created_at":"2024-12-03T04:29:22.678Z","updated_at":"2026-04-30T00:34:53.162Z","avatar_url":"https://github.com/guyi2000.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 从零实现的 C++ MLP\n\n## 概述\n\n本项目主要实现了 `MLPclassifier.h` 的编写，但由于编写此头文件使用了大量的矩阵运算，因而本项目也实现了一个较为好用的矩阵类，并且编写了 demo 演示。\n\n## `Matrix\u003cT\u003e` 使用手册\n\n使用时，需要指定模板类型，当然也可以嵌套使用，例如 `Matrix\u003cMatrix\u003cdouble\u003e\u003e`，下面举例说明其使用方法：（包含头文件 `utils.h`）\n\n首先，定义一个Matrix，例如：\n\n```cpp\nMatrix\u003cdouble\u003e A(10, 10);\n```\n\n这样就创建了一个行列均为 `10` 的矩阵 `A`，下面可以通过 `A[1][2]` 访问 `A` 中的元素。注意，本项目中的 `Matrix\u003cT\u003e` **并不会检测下标越界**，因此请保证下标不会越界！（检测后程序运行速度明显减慢）\n\n已经实现的函数包括，矩阵元素的加法，乘法，减法，矩阵的点乘，下面给出详细的使用方法：\n\n定义 `numcpp`：\n\n```cpp\nnumcpp\u003cdouble\u003e nc;\nauto D = A + B; // assert(A.__x == B.__x \u0026\u0026 A.__y == B.__y)\nA += B;  // assert(A.__x == B.__x \u0026\u0026 A.__y == B.__y)\nauto C = nc.dot(A, B); // assert(A.__y == B.__x)\n```\n\n`C` 即为 `A`，`B` 点乘后的结果，当然需要注意的是，使用结束后，需要使用 `delete C;` 删除分配给 `C` 的空间。其余函数使用同理，能够使用的函数列表如下：\n\n|               **函数**               |                   **作用**                   |\n| :----------------------------------: | :------------------------------------------: |\n| `=`，`-=`，`+=`，`*=`，`-`，`+`，`*` |                 基本算术运算                 |\n|             `A.Trans()`              |              `A`的转置，新矩阵               |\n|            `nc.dot(A, B)`            |             `A`、`B`点乘，新矩阵             |\n|             `nc.exp(A)`              |          `A`每个元素求`exp`，新矩阵          |\n|           `nc.ones(x, y)`            |            生成`x*y`的全为`1`矩阵            |\n|            `nc.sigmod(A)`            |        `A`每个元素求`sigmod`，新矩阵         |\n|           `nc.dsigmod(A)`            |      `A`每个元素求`sigmod`导数，新矩阵       |\n|             `nc.exp_(A)`             |              `A`每个元素求`exp`              |\n|            `nc.ones_(A)`             |             `A`每个元素赋值为`1`             |\n|           `nc.sigmod_(A)`            |            `A`每个元素求`sigmod`             |\n|           `nc.dsigmod_(A)`           |          `A`每个元素求`sigmod`导数           |\n|           `nc.random_(A)`            |              `A`每个元素随机化               |\n|            `nc.sum(A, 0)`            |     `A`按行求和，第二个参数为`1`表示按列     |\n|             `nc.sum(A)`              |            `A`求和，返回类型为`T`            |\n|            `nc.max(A, 0)`            |   `A`按行求最大值，第二个参数为`1`表示按列   |\n|          `nc.argmax(A, 0)`           | `A`按行求最大值下标，第二个参数为`1`表示按列 |\n\n## `MLPclassifier` 使用手册\n\n使用时，需要先实例化，然后即可使用。（包含头文件 `cppMLP.h`）\n\n具体而言：\n\n```cpp\nMLPclassifier Solve(I1, I2, I3, learning_rate, iterations, isPredict);\n```\n\n这样就实例化了一个第一层维数为 `I1`，第二层维数为 `I2`，第三层维数为 `I3` 的模型，并且学习率为 `learning_rate`，迭代次数为 `iterations`。`isPredict` 用于决定模型是否在训练时输出预测信息。\n\n在实例化后，就可以使用对应函数完成相应任务：例如使用\n\n```cpp\nSolve.init();\n```\n\n完成对模型内存分配，权重值初始化的工作。\n\n使用\n\n```cpp\nSolve.train(trainingData, trainingLabel);\n```\n\n完成模型对数据的训练，其中必须满足的是：训练集中 `trainingData` 的列数必须等于第一层维数，`trainingLabel` 的可选取值必须为`0~第三层维数减一`，并且其列数必须为`1`。行数要求 `trainingData` 与 `trainingLabel` 相同。\n\n使用\n\n```cpp\nauto predictLabel = Solve.predict(testData);\n```\n\n即可使用模型进行预测，预测后的数据标签保存到 `predictLabel` 中，注意后续必须使用 `delete predictLabel;` 否则会内存泄漏！`testData` 的行数无要求，但列数需要与第一层维数相同。\n\n使用\n\n```cpp\nint similarity = Solve.accurancy(predictLabel, testLabel);\n```\n\n即可输出 `predictLabel` 与 `testLabel` 的相同元素的个数，也就可以得到 `predict` 的准确率。\n\n使用\n\n```cpp\nSolve.save([path])\n```\n\n`path`可选，可以将模型参数写入到 `path` 文件中，方便以后读取使用。默认 `path` 为本目录的 `param.data`\n\n使用\n\n```cpp\nSolve.load([path])\n```\n\n`path` 可选，可以将 `path` 文件中的参数读入到 `model` 中，方便后续调用。默认 `path` 为本目录的 `param.data`\n\n上述即为 `MLPclassifier` 的使用，由于使用了 `class` 包装，其调用显得尤为方便。\n\n \n\n写给开发者：\n\n对于目前的 classifier，尚有不完善之处，如果需要补充新的 classifier，那么请直接继承 `classifier` 类，然后重载所有纯虚函数，即可。具体来说，如果要编写 `SVMclassifier`，那么请：\n\n```cpp\nclass SVMclassifier : public classifier {…}\n```\n\n其中需要实现的函数参见设计手册，实现完成后，也可以类似上述进行调用：\n\n```cpp\nSVMclassifier Solve(init params);\nSolve.init(); Solve.train(trainingData, trainingLabel)……\n```\n\n这样，也可以看出其使用抽象类的泛用性。\n\n## Demo 使用手册\n\n为了更好地表现 `cppMLP.h` 的实现性能，因此编写了本 demo，下面就其进行说明。\n\n本 demo 是一个命令行工具，在 workingDir 下打开命令提示符，输入：\n\n```bash\nCPlusPlusDeepLearning.exe -tps\n```\n\n即可以默认参数运行本程序，观察其训练，预测，保存过程。\n\n此后你可以使用：\n\n```bash\nCPlusPlusDeepLearning.exe -lp\n```\n\n查看其读取，预测的过程。\n\n当然，你随时可以使用：\n\n```bash\nCPlusPlusDeepLearning.exe -h\n```\n\n或者使用 `--help` 或 `-?` 来获取简略的软件帮助。\n\n软件输出的帮助如下：\n\n```bash\nUsage: ./CPlusPlusDeepLearning.exe [-tpsl?hV] [-i \u003cnum\u003e] ...\nOptions\n -h -?                      Print this help message.\n -V                         Print the verison.\n -t                         train the model.\n -p                         predict with the model.\n -s                         save the model.\n -l                         load the model.\n -i \u003cnum\u003e                   define the iterations.\n -r \u003cnum\u003e                   define the learning_rate.\n --help                     Print this help message.\n --version                  Print the verison.\n --train                    train the model.\n --predict                  predict with the model.\n --save                     save the model.\n --load                     load the model.\n --iterations \u003cnum\u003e         define the iterations.\n --learning_rate \u003cnum\u003e      define the learning_rate.\n --save_file \u003cfile\u003e         define save path.\n --load_file \u003cfile\u003e         define load path.\n --train_file \u003cfile\u003e        define train path.\n --predict_file \u003cfile\u003e      define predict path.\n --train_dimensions \u003cnum\u003e   define train dimensions.\n --hidden_layers \u003cnum\u003e      define hidden layers\n --output_dimensions \u003cnum\u003e  define output dimensions.\n --train_rows \u003cnum\u003e         define train rows.\n --predict_rows \u003cnum\u003e       define predict rows.\n```\n\nExamples:\n\n```bash\nCPlusPlusDeepLearning.exe -t --hidden_layers 100 -s\nCPlusPlusDeepLearning.exe -l -p\n```\n\n下面，解释如何使用参数控制该 demo：\n\n使用 `-h`、`-?`、`--help` 查看软件帮助。\n\n使用 `-V`、`--version` 查看软件版本号。\n\n基本 Tasks 共有4项，Load，Train，Predict，Save，分别由短命令 `-l`、`-t`、`-p`、`-s` 表示。也可使用长命令 `--load`、`--train`、`--predict`、`--save` 控制。\n\n当有这些参数时，表示程序需要做这些操作。\n\n此后是一些文件读取的参数：`--save_file \u003cfile\u003e`、`--load_file \u003cfile\u003e`、`--train_file \u003cfile\u003e`、`--predict_file \u003cfile\u003e` 这些选项后必须接参数，分别表示保存路径，读取路径，训练集路径，预测集路径。\n\n此后有一些训练的参数控制：例如两个常用的学习率和迭代次数可以使用 `-r \u003cnum\u003e`、`-i \u003cnum\u003e` 或长命令 `--learning_rate \u003cnum\u003e`、`--iterations \u003cnum\u003e` 控制。\n\n对于一些其他参数，下面给出一些解释：`--train_dimensions \u003cnum\u003e`、`--hidden_layers \u003cnum\u003e`、`--output_dimensions \u003cnum\u003e` 分别表示神经网络第一、二、三层神经元个数，`--train_rows \u003cnum\u003e` 表示训练集读取行数，`--predict_rows \u003cnum\u003e` 表示预测集读取行数。\n\n由于这些参数是可定义的，因此本 demo 不仅适用于手写数字识别，也可用于其他数据集。只要满足 `cppMLP.h` 的需求即可。\n\n## 类图\n\n![image-20240602125043321](assets/image-20240602125043321.png)\n\n## 代码统计\n\n|   文件    |   行数   |\n| :-------: | :------: |\n| main.cpp  |   282    |\n|  cppDL.h  |    25    |\n| cppMLP.h  |   202    |\n|  macro.h  |    25    |\n|  utils.h  |   561    |\n| **TOTAL** | **1195** |\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguyi2000%2Fmlp_in_cpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguyi2000%2Fmlp_in_cpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguyi2000%2Fmlp_in_cpp/lists"}