C++实现LeNet-5卷积神经网络

本文记录了作者使用C++实现LeNet-5卷积神经网络的过程,耗时10天,编写了1000多行代码,期间经历了公式推导、网络设计和大量调试。由于C++仅支持基本运算,要求对模型理解极其深入,作者在实现过程中遇到诸多挑战,但最终成功完成。这是第二版实现,第一版因模型错误被废弃。作者鼓励有兴趣者直接私信交流问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

搞了好久好久,公式推导+网络设计就推了20多页草稿纸
花了近10天
程序进1k行,各种debug要人命,只能不断的单元测试+梯度检验
因为C++只有加减乘除,所以对这个网络模型不能有一丝丝的模糊,每一步都要理解的很透彻
挺考验能力的,很庆幸我做出来了,这个是第二版,第一版也写了1k行,写完才发现,模型错了,只能全删掉重新写
算是一次修行
网络的设计,编代码时的各种考虑,debug记录,我不想整理了,有问题的直接私信我吧

#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdlib>
#include <random>
#include <ctime>
using namespace std;

//自然数
const double E = 2.718281828459;
//极小值
const double EPS = 3e-3;
//MNIST
const int MNIST_HEIGHT = 28;
const int MNIST_WIDTH = 28;
//INPUT
const int INPUT_HEIGHT = 32;
const int INPUT_WIDTH = 32;
//padding
const int OFFSET = 2;
//标签的字节数
const int LABEL_BYTE = 1;
//输出的大小
const int OUT_SIZE = 10;
const int NUM_TRAIN = 20;
const int NUM_TEST = 20;

/*------------矩阵类-----------------------*/
typedef vector<vector<double>> Matrix;
inline bool reshapeMatrix(Matrix &mat, size_t row, size_t col)
{
   
    if (row <= 0 || col <= 0)
        throw "reshapeMatrix: row <= 0 || col <= 0";
    mat.resize(row);
    for (int i = 0; i < row; i++)
        mat[i].resize(col);
    return true;
}
inline bool reshapeMatrix(Matrix &mat, size_t row, size_t col, double val)
{
   
    if (row <= 0 || col <= 0)
        throw "reshapeMatrix: row <= 0 || col <= 0";
    mat.resize(row);
    for (int i = 0; i < row; i++)
    {
   
        //先清空,再重塑
        mat[i].clear();
        mat[i].resize(col, val);
    }

    return true;
}
//矩阵二维卷积
inline void convMatrix(const Matrix &a, const Matrix &b, Matrix &res)
{
   
    if (b.size() > a.size() || b[0].size() > a[0].size())
        throw "convMatrix: b is larger than a";
    reshapeMatrix(res, a.size() - b.size() + 1, a[0].size() - b[0].size() + 1, 0);
    for (int i = 0; i < res.size(); i++)
        for (int j = 0; j < res[0].size(); j++)
        {
   
            //遍历卷积矩阵
            for (int _i = 0; _i < b.size(); _i++)
                for (int _j = 0; _j < b[0].size(); _j++)
                    res[i][j] += a[_i + i][_j + j] * b[_i][_j];
        }
    return;
}
//矩阵加法
inline void plusMatrix(Matrix &a, const Matrix &b)
{
   
    if (a.size() != b.size() || a[0].size() != b[0].size())
        throw "plusMatrix: shape don't match";
    for (int i = 0; i < a.size(); i++)
        for (int j = 0; j < a[0].size(); j++)
            a[i][j] += b[i][j];
    return;
}
inline void plusMatrix(Matrix &a, double val)
{
   
    for (int i = 0; i < a.size(); i++)
        for (int j = 0; j < a[0].size(); j++)
            a[i][j] += val;
    return;
}
inline void plusMatrix(const Matrix &a, const Matrix &b, Matrix &res)
{
   
    if (a.size() != b.size() || a[0].size() != b[0].size())
        throw "plusMatrix: shape don't match";
    reshapeMatrix(res, a.size(), a[0].size());
    for (int i = 0; i < res.size(); i++)
        for (int j = 0; j < res[0].size(); j++)
            res[i][j] = a[i][j] + b[i][j];
    return;
}
//矩阵减法
inline void minusMatrix(const Matrix &a, const Matrix &b, Matrix &res)
{
   
    if (a.size() != b.size() || a[0].size() != b[0].size())
        throw "plusMatrix: shape don't match";
    reshapeMatrix(res, a.size(), a[0].size());
    for (int i = 0; i < res.size(); i++)
        for (int j = 0; j < res[0].size(); j++)
            res[i][j] = a[i][j] - b[i][j];
    return;
}
//矩阵乘法
inline void multiplyMatrix(const Matrix &a, const Matrix &b, Matrix &res)
{
   
    if (a[0].size() != b.size())
        throw "multiplyMatrix: a.col != b.row";
    reshapeMatrix(res, a.size(), b[0].size(), 0);
    for (int i = 0; i < res.size(); i++)
        for (int j = 0; j < res[0].size(); j++)
            for (int k = 0; k < a[0].size(); k++)
                res[i][j] += a[i][k] * b[k][j];
    return;
}
//矩阵与标量相乘
inline void multiplyMatrix(Matrix &mat, double val)
{
   
    for (int i = 0; i < mat.size(); i++)
        for (int j = 0; j < mat[0].size(); j++)
            mat[i][j] *= val;
    return;
}
inline void multiplyMatrix(double val, const Matrix &mat, Matrix &res)
{
   
    reshapeMatrix(res, mat.size(), mat[0].size());
    for (int i = 0; i < res.size(); i++)
        for (int j = 0; j < res[0].size(); j++)
            res[i][j] = mat[i][j] * val;
    return;
}
//矩阵点乘
void matmulMatrix(const Matrix &a, const Matrix &b, Matrix &res)
{
   
    if (a.size() != b.size() || a[0].size() != b[0].size())
        throw "matmulMatrix: shape don't match";
    reshapeMatrix(res, a.size(), a[0].size());
    for (int i = 0; i < res.size(); i++)
        for (int j = 0; j < res[0].size(); j++)
            res[i][j] = a[i][j] * b[i][j];
    return;
}
//矩阵池化,步长=大小
inline void downSampleMatrix(const Matrix &mat, size_t height, size_t width, Matrix &res)
{
   
    if (mat.size() % height != 0 || mat[0].size() % width != 0)
        throw "downSampleMatrix: height/width don't match matrix";
    reshapeMatrix(res, mat.size() / height, mat[0].size() / width);
    for (int i = 0; i < res.size(); i++)
        for (int j = 0; j < res[0].size(); j++)
        {
   
            //求和
            int row_b = i * height;
            int row_e = (i + 1) * height;
            int col_b 
LeNet-5神经网络 C源代码,这个写的比较好,可以用gcc编译去跑,结合理论可以对深度学习有更深刻的了解 介绍 根据YANN LECUN的论文《Gradient-based Learning Applied To Document Recognition》设计的LeNet-5神经网络,C语言写成,不依赖任何第三方库。 MNIST手写字符集初代训练识别率97%,多代训练识别率98%。 DEMO main.c文件为MNIST数据集的识别DEMO,直接编译即可运行,训练集60000张,测试集10000张。 项目环境 该项目为VISUAL STUDIO 2015项目,用VISUAL STUDIO 2015 UPDATE1及以上直接打开即可编译。采用ANSI C编写,因此源码无须修改即可在其它平台上编译。 如果因缺少openmp无法编译,请将lenet.c中的#include和#pragma omp parallel for删除掉即可。 API #####批量训练 lenet: LeNet5的权值的指针,LeNet5神经网络的核心 inputs: 要训练的多个图片对应unsigned char二维数组的数组,指向的二维数组的batchSize倍大小内存空间指针。在MNIST测试DEMO中二维数组为28x28,每个二维数组数值分别为对应位置图像像素灰度值 resMat:结果向量矩阵 labels:要训练的多个图片分别对应的标签数组。大小为batchSize batchSize:批量训练输入图像(二维数组)的数量 void TrainBatch(LeNet5 *lenet, image *inputs, const char(*resMat)[OUTPUT],uint8 *labels, int batchSize); #####单个训练 lenet: LeNet5的权值的指针,LeNet5神经网络的核心 input: 要训练的图片对应二维数组 resMat:结果向量矩阵 label: 要训练的图片对应的标签 void Train(LeNet5 *lenet, image input, const char(*resMat)[OUTPUT],uint8 label); #####预测 lenet: LeNet5的权值的指针,LeNet5神经网络的核心 input: 输入的图像的数据 labels: 结果向量矩阵指针 count: 结果向量个数 return 返回值为预测的结果 int Predict(LeNet5 *lenet, image input, const char(*labels)[LAYER6], int count); #####初始化 lenet: LeNet5的权值的指针,LeNet5神经网络的核心
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值