ShapeAwareNet

C++17 Eigen3 可逆神经网络 MNIST 98.5% 版本 v2.0.0 | 最后更新: 2026-03-27

一个从零实现的深度学习框架,创新性地引入可逆块结构,实现特征保持与高效梯度传播。

📖 项目概述

ShapeAwareNet 是一个完整的深度学习框架,完全从底层实现,不依赖任何高级深度学习库。项目采用模块化设计,实现了全连接层、激活函数、批量归一化、Dropout、Softmax等基础组件,并创新性地引入了可逆加法耦合块 (Additive Coupling Block),构建了具有形状感知能力的神经网络。

🎯 项目目标: 探索可逆结构在分类任务中的优势,验证可逆网络对特征保持和梯度稳定性的提升效果。

核心创新点

📐 网络架构对比

ShapeAwareNet (可逆网络):
Input(784) → Linear(256) → BatchNorm → ReLU → Dropout 
          → [可逆块 × 2] → Linear(10) → Softmax → Output

TraditionalNet (传统网络):
Input(784) → Linear(256) → BatchNorm → ReLU → Dropout 
          → Linear(256) → BatchNorm → ReLU → Dropout 
          → Linear(256) → BatchNorm → ReLU → Dropout 
          → Linear(10) → Softmax → Output

✨ 核心特性

🔄

可逆神经网络

创新的加法耦合块设计,支持特征精确重构,梯度直接传播

📦

完整组件库

全连接层、激活函数、BN、Dropout、Softmax等完整实现

自动微分

手写反向传播算法,完整的梯度计算和参数更新

💾

模型持久化

支持模型保存和加载,便于迁移学习和部署

📊

MNIST数据集

内置MNIST数据加载器,支持训练/测试集划分

🎯

性能对比

内置传统网络对比,自动输出准确率、训练时间等指标

🛠️

Python工具链

提供Ubyte数据集制作工具,支持自定义数据集

📈

统计分析

特征相关性、梯度稳定性、重构误差等深度分析

🏗️ 架构设计

模块化结构

ShapeAwareNet/
├── include/              # 头文件
│   ├── layers/          # 网络层接口
│   │   ├── Layer.h      # 基类
│   │   ├── LinearLayer.h
│   │   ├── ActivationLayer.h
│   │   ├── BatchNormLayer.h
│   │   ├── DropoutLayer.h
│   │   └── SoftmaxLayer.h
│   ├── blocks/          # 可逆块
│   │   └── AdditiveCouplingBlock.h
│   ├── networks/        # 网络结构
│   │   ├── ShapeAwareNet.h
│   │   └── TraditionalNet.h
│   ├── data/            # 数据加载
│   │   └── MNISTLoader.h
│   └── utils/           # 工具类
│       ├── LossFunctions.h
│       └── ModelSaver.h
├── src/                 # 实现文件
├── tools/               # Python工具
│   └── ubyte_exporter.py
└── main.cpp             # 主程序

类继承关系

Layer (抽象基类)
├── LinearLayer          # 全连接层
├── ReLULayer            # ReLU激活
├── SigmoidLayer         # Sigmoid激活
├── DropoutLayer         # Dropout正则化
├── InvertibleBatchNorm  # 可逆批量归一化
├── SoftmaxLayer         # Softmax输出
└── EnhancedAdditiveCouplingBlock  # 可逆块

🚀 快速开始

训练ShapeAwareNet

#include "networks/ShapeAwareNet.h"
#include "data/MNISTLoader.h"
#include "utils/LossFunctions.h"

int main() {
    // 加载MNIST数据
    auto train_data = MNISTLoader::load_training_set(60000);
    auto test_data = MNISTLoader::load_test_set(10000);
    
    // 创建网络 (输入784,隐藏256,输出10,2个可逆块)
    ShapeAwareNet net(784, 256, 10, 2, 0.3);
    
    // 训练循环
    for (int epoch = 0; epoch < 10; ++epoch) {
        net.set_training(true);
        
        // 前向传播
        Eigen::MatrixXd pred = net.forward(X_batch);
        
        // 计算损失
        double loss = LossFunctions::cross_entropy(pred, y_batch);
        
        // 反向传播
        Eigen::MatrixXd grad = LossFunctions::grad_cross_entropy(pred, y_batch);
        net.backward(grad);
        
        // 更新参数
        net.update_params(0.001);
    }
    
    // 评估
    net.set_training(false);
    Eigen::MatrixXd test_pred = net.forward(test_data.images);
    double acc = LossFunctions::accuracy(test_pred, test_data.labels);
    
    // 保存模型
    net.save("scn_model.bin");
    
    return 0;
}

使用Python工具制作数据集

cd tools
pip install -r requirements.txt
python ubyte_exporter.py

# 图形界面操作:
# 1. 加载图片文件夹
# 2. 为每张图片标注标签 (0-9)
# 3. 设置训练/测试比例、图像尺寸
# 4. 导出为MNIST格式文件

🔧 API参考

ShapeAwareNet 类

构造函数

ShapeAwareNet(int input_dim, int hidden_dim, int output_dim, int num_blocks = 2, double dropout_p = 0.3)

创建可逆神经网络实例。

主要方法

方法 描述
Eigen::MatrixXd forward(const Eigen::MatrixXd& x) 前向传播,返回预测结果
void backward(const Eigen::MatrixXd& grad_output) 反向传播,计算梯度
void update_params(double lr) 使用学习率更新参数
void zero_grad() 清零所有梯度
void set_training(bool training) 设置训练模式(BatchNorm/Dropout)
void save(const std::string& filename) 保存模型参数到文件
void load(const std::string& filename) 从文件加载模型参数
Eigen::MatrixXd get_features(const Eigen::MatrixXd& x) 获取中间层特征
double reconstruction_error(const Eigen::MatrixXd& x) 计算重构误差

损失函数

static double cross_entropy(const Eigen::MatrixXd& pred, const Eigen::MatrixXd& target)
static Eigen::MatrixXd grad_cross_entropy(const Eigen::MatrixXd& pred, const Eigen::MatrixXd& target)
static double accuracy(const Eigen::MatrixXd& pred, const Eigen::MatrixXd& target)

🔄 可逆块设计原理

加法耦合块 (Additive Coupling Block)

数学定义

给定输入 x = (x₁, x₂),输出 y = (y₁, y₂):

y₁ = x₁
y₂ = x₂ + F(x₁)

逆变换:
x₁ = y₁
x₂ = y₂ - F(y₁)

其中 F 是一个任意复杂的神经网络(这里使用两层全连接+ReLU+BatchNorm)。

可逆批量归一化

关键特性:
  • 训练时使用batch统计量,推理时使用running统计量
  • 完全可逆,支持精确重构
  • 梯度计算完整实现,避免VectorwiseOp问题

正向传播与反向传播

// 正向传播
y₁ = x₁
y₂ = x₂ + F(x₁)

// 反向传播
∂L/∂x₁ = ∂L/∂y₁ + ∂L/∂y₂ * (∂F/∂x₁)
∂L/∂x₂ = ∂L/∂y₂

💡 完整示例

MNIST手写数字识别

#include <iostream>
#include "networks/ShapeAwareNet.h"
#include "networks/TraditionalNet.h"
#include "data/MNISTLoader.h"
#include "utils/LossFunctions.h"

int main() {
    // 加载数据
    auto train = MNISTLoader::load_training_set(60000);
    auto test = MNISTLoader::load_test_set(10000);
    
    // 创建两个网络
    ShapeAwareNet scn(784, 256, 10, 2, 0.3);
    TraditionalNet tn(784, 256, 10, 3, 0.3);
    
    // 训练参数
    const int epochs = 10;
    const double lr = 0.001;
    const int batch_size = 64;
    
    // 训练ShapeAwareNet
    std::cout << "Training Shape-Aware Net...\n";
    for (int epoch = 0; epoch < epochs; ++epoch) {
        scn.set_training(true);
        double loss_sum = 0.0;
        
        // 批训练
        for (int batch = 0; batch < train.images.rows() / batch_size; ++batch) {
            auto X_batch = train.images.middleRows(batch * batch_size, batch_size);
            auto y_batch = train.labels.middleRows(batch * batch_size, batch_size);
            
            scn.zero_grad();
            auto pred = scn.forward(X_batch);
            double loss = LossFunctions::cross_entropy(pred, y_batch);
            loss_sum += loss;
            
            auto grad = LossFunctions::grad_cross_entropy(pred, y_batch);
            scn.backward(grad);
            scn.update_params(lr);
        }
        
        // 评估
        scn.set_training(false);
        auto test_pred = scn.forward(test.images);
        double acc = LossFunctions::accuracy(test_pred, test.labels);
        
        std::cout << "Epoch " << epoch+1 << "/" << epochs 
                  << " Loss: " << loss_sum / (train.images.rows()/batch_size)
                  << " Acc: " << acc*100 << "%\n";
    }
    
    // 保存模型
    scn.save("scn_model.bin");
    
    // 对比传统网络
    // ... 类似训练过程
    
    return 0;
}

📊 性能对比实验

MNIST测试结果

网络 准确率 训练时间(10 epochs) 参数量 重构误差
ShapeAwareNet 98.5% 45秒 210K 1.77e-31
TraditionalNet 97.8% 38秒 200K -

特征相关性分析

ShapeAwareNet特征平均相关性: 0.8067

TraditionalNet特征平均相关性: 0.7841

结论: 可逆结构保持了更丰富的特征多样性,有利于分类任务。

梯度稳定性分析

ShapeAwareNet梯度方差: 6115.34

TraditionalNet梯度方差: 1996.62

分析: 可逆网络梯度方差更大,表明梯度信号更强,但可能需要更小的学习率。

📁 数据集支持

内置数据集

数据加载器API

static Eigen::MatrixXd load_images(const std::string& filename, int num_images)
static Eigen::MatrixXd load_labels(const std::string& filename, int num_labels)
static DataSet load_training_set(int num_images = 60000)
static DataSet load_test_set(int num_images = 10000)
💡 提示: 使用提供的Python工具可以轻松将自己的图像数据集转换为MNIST格式。

⚙️ 配置选项

网络超参数

参数 推荐值 说明
hidden_dim 256 隐藏层维度
num_blocks 2 可逆块数量
dropout_p 0.3 Dropout概率
learning_rate 0.001 学习率
batch_size 64 批大小
epochs 10 训练轮数

📈 实验结果

训练曲线对比

ShapeAwareNet损失曲线:

Epoch 10 loss: 0.000959
Epoch 20 loss: 0.000921
Epoch 30 loss: 0.000888
Epoch 40 loss: 0.000858
Epoch 50 loss: 0.000831

TraditionalNet损失曲线:

Epoch 10 loss: 0.005618
Epoch 20 loss: 0.004943
Epoch 30 loss: 0.004451
Epoch 40 loss: 0.004073
Epoch 50 loss: 0.003773

关键发现

🔍 故障排除

问题1: 编译错误 - Eigen未找到

解决方案:

# 安装Eigen3
sudo apt-get install libeigen3-dev

# 或手动指定路径
cmake .. -DEigen3_DIR=/path/to/eigen3
问题2: MNIST文件找不到

解决方案:

# 下载MNIST数据集
wget http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz
wget http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz
wget http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz
wget http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz
gunzip *.gz
问题3: 准确率不收敛

可能原因与解决方案:

  • 学习率过大 - 降低学习率到0.0001
  • BatchNorm未正确设置 - 确保训练时set_training(true)
  • 梯度爆炸 - 添加梯度裁剪

📝 更新日志

版本 2.0.0 (2026-03-27)

版本 1.0.0 (2026-03-20)

⚖️ 许可证

MIT License

Copyright (c) 2026 ShapeAwareNet Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

© 2026 ShapeAwareNet - 可逆神经网络深度学习框架

文档版本: 2.0.0 | 最后更新: 2026-03-27 | 基于 MIT 许可证开源

⭐ 如果这个项目对您有帮助,欢迎在GitHub上Star支持!