Language: 简体中文 English

目录 (Table of Contents)


系统架构概览

分层架构

Mini-Inference Engine 采用清晰的分层架构设计:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
┌─────────────────────────────────────────────────────────────────────────┐
│                           Application Layer                              │
│  ┌────────────┐  ┌────────────┐  ┌────────────┐  ┌────────────┐         │
│  │ Benchmark  │  │ MNIST Demo │  │   Tests    │  │  User App  │         │
│  └────────────┘  └────────────┘  └────────────┘  └────────────┘         │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                           Engine Layer                                   │
│  ┌───────────────────────────────────────────────────────────────────┐  │
│  │                      InferenceEngine                               │  │
│  │  - 权重加载    - 前向传播    - 层管理                              │  │
│  └───────────────────────────────────────────────────────────────────┘  │
│  ┌────────────┐  ┌────────────┐  ┌────────────┐  ┌────────────┐         │
│  │   Tensor   │  │ AutoTuner  │  │  Profiler  │  │   Config   │         │
│  └────────────┘  └────────────┘  └────────────┘  └────────────┘         │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                           Kernel Layer                                   │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐       │
│  │   Naive  │ │   Tiled  │ │Coalesced │ │  Double  │ │Optimized │       │
│  │ MatMul   │ │   GEMM   │ │   GEMM   │ │  Buffer  │ │   GEMM   │       │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘       │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐                     │
│  │   Fused  │ │Vectorized│ │   Half   │ │ Batched  │                     │
│  │   GEMM   │ │   GEMM   │ │   GEMM   │ │   GEMM   │                     │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘                     │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                         Infrastructure Layer                             │
│  ┌────────────┐  ┌────────────┐  ┌────────────┐  ┌────────────┐         │
│  │ MemoryPool │  │StreamMgr   │  │   Logger   │  │Quantization│         │
│  └────────────┘  └────────────┘  └────────────┘  └────────────┘         │
│  ┌────────────┐  ┌────────────┐                                          │
│  │DeviceMemory│  │  GpuTimer  │                                          │
│  └────────────┘  └────────────┘                                          │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                            CUDA Runtime                                  │
│  ┌────────────┐  ┌────────────┐  ┌────────────┐                         │
│  │   cudart   │  │   cuBLAS   │  │   Streams  │                         │
│  └────────────┘  └────────────┘  └────────────┘                         │
└─────────────────────────────────────────────────────────────────────────┘

各层职责

层级 核心职责 关键组件
Application 用户交互、性能测试、示例程序 Benchmark, MNIST Demo, Tests
Engine 推理执行、张量管理、性能优化 InferenceEngine, Tensor, AutoTuner
Kernel 核心计算、GEMM 优化实现 各类 GEMM Kernel
Infrastructure 资源管理、工具支持 MemoryPool, Logger, Config
CUDA Runtime GPU 底层接口 CUDA Driver, cuBLAS

核心组件

1. InferenceEngine(推理引擎)

推理引擎是系统的核心类,负责管理神经网络的前向传播。

类设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class InferenceEngine {
public:
    // 生命周期管理
    void init(int device_id = 0);
    void cleanup();
    
    // 权重管理
    bool load_weights(const std::string& path);
    bool save_weights(const std::string& path) const;
    void add_layer(int in_features, int out_features, bool has_bias,
                   const float* weights_data, const float* bias_data = nullptr);
    
    // 推理执行
    void forward(const float* input, float* output, int batch_size);
    void forward_with_timing(const float* input, float* output, int batch_size,
                             std::vector<float>& layer_times_ms);
    
    // 查询接口
    size_t num_layers() const { return layers_.size(); }
    int input_dim() const;
    int output_dim() const;
    bool is_initialized() const { return initialized_; }

private:
    std::vector<LayerWeights> layers_;
    cublasHandle_t cublas_handle_;
    cudaStream_t stream_;
    DeviceMemory temp_buffers_[2];  // 双缓冲设计
    bool initialized_ = false;
};

设计决策

决策 理由
RAII 资源管理 避免资源泄漏,确保异常安全
禁用拷贝构造 GPU 资源不应共享
支持移动语义 允许所有权转移
双缓冲设计 避免读写冲突,支持交替计算
融合 kernel 减少内存带宽消耗

权重文件格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
权重文件布局 (Weight File Layout):
═════════════════════════════════════════════════════════════
Offset  Size        Description
═════════════════════════════════════════════════════════════
0       32 bytes    文件头 (Header)
  ├─ 0   4 bytes    魔数 (0x4D494E49 = "MINI")
  ├─ 4   4 bytes    版本号 (1)
  ├─ 8   4 bytes    层数
  └─ 12  20 bytes   保留区域
═════════════════════════════════════════════════════════════
32      Variable    层数据 (Layer Data,重复层数次)
  ├─ 0   4 bytes    层类型 (0 = Linear)
  ├─ 4   4 bytes    输入维度 (in_features)
  ├─ 8   4 bytes    输出维度 (out_features)
  ├─ 12  4 bytes    是否有偏置 (0 或 1)
  ├─ 16  in×out×4   权重数据 (行优先存储)
  └─ ... out×4      偏置数据 (如果有)
═════════════════════════════════════════════════════════════

2. Tensor(张量)

N 维张量类,提供 GPU 存储和基本操作。

类设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Tensor {
public:
    // 构造与生命周期
    Tensor() = default;
    explicit Tensor(const std::vector<int>& shape);
    Tensor(const std::vector<int>& shape, const float* data);
    
    // 禁用拷贝,允许移动
    Tensor(const Tensor&) = delete;
    Tensor& operator=(const Tensor&) = delete;
    Tensor(Tensor&&) noexcept = default;
    Tensor& operator=(Tensor&&) noexcept = default;
    
    // 形状操作
    void reshape(const std::vector<int>& new_shape);
    Tensor clone() const;
    
    // 数据访问
    float* data();
    const float* data() const;
    std::vector<float> to_host() const;
    void copy_from_host(const float* host_data);
    void copy_to_host(float* host_data) const;
    
    // 填充操作
    void fill(float value);
    void zero();
    
    // 形状查询
    const std::vector<int>& shape() const { return shape_; }
    const std::vector<int>& strides() const { return strides_; }
    size_t size() const { return size_; }
    int ndim() const { return static_cast<int>(shape_.size()); }
    int dim(int i) const { return shape_[i]; }
    
    // 视图转换
    MatrixDesc as_matrix() const;

private:
    std::vector<int> shape_;
    std::vector<int> strides_;
    size_t size_ = 0;
    PooledMemory data_;  // 使用内存池
};

内存布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
行优先存储 (Row-Major):
═════════════════════════════════════════════════════════════
Shape: [2, 3, 4]
Strides: [12, 4, 1]

索引计算:
element(i, j, k) = i * 12 + j * 4 + k * 1

内存布局:
┌──────────────────────────────────────────────────────┐
│ [0,0,0] [0,0,1] [0,0,2] [0,0,3]                    │  Block 0,0
│ [0,1,0] [0,1,1] [0,1,2] [0,1,3]                    │  Block 0,1
│ [0,2,0] [0,2,1] [0,2,2] [0,2,3]                    │  Block 0,2
│ [1,0,0] [1,0,1] [1,0,2] [1,0,3]                    │  Block 1,0
│ [1,1,0] [1,1,1] [1,1,2] [1,1,3]                    │  Block 1,1
│ [1,2,0] [1,2,1] [1,2,2] [1,2,3]                    │  Block 1,2
└──────────────────────────────────────────────────────┘
═════════════════════════════════════════════════════════════

设计决策

决策 理由
使用内存池 (PooledMemory) 减少 cudaMalloc 开销
禁用拷贝构造 避免意外的大内存拷贝
行优先存储 与 C/C++ 和 CUDA 兼容
延迟计算 strides 仅在需要时计算

3. MemoryPool(内存池)

GPU 内存池,通过缓存减少 cudaMalloc 调用。

类设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class MemoryPool {
public:
    static MemoryPool& instance();  // 单例模式
    
    // 分配与释放
    void* allocate(size_t size);
    void deallocate(void* ptr);
    
    // 缓存管理
    void clear_cache();    // 释放缓存,保留活跃分配
    void clear_all();      // 清理缓存并重置统计
    void release_all();    // 释放所有内存(仅用于关闭时)
    
    // 状态查询
    bool owns(void* ptr) const;
    bool is_cached(void* ptr) const;
    size_t live_allocated_bytes() const;
    size_t cached_block_count() const;
    size_t active_block_count() const;
    
    // 统计
    struct Stats {
        size_t total_allocated;   // 累计分配字节数
        size_t cached_size;       // 缓存大小
        size_t cache_hits;        // 缓存命中次数
        size_t cache_misses;      // 缓存未命中次数
    };
    Stats get_stats() const;
    void print_stats() const;

private:
    MemoryPool() = default;
    mutable std::mutex mutex_;
    std::map<void*, size_t> allocated_blocks_;
    std::multimap<size_t, void*> free_blocks_;
    static constexpr size_t ALIGNMENT = 256;
};

分配策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
内存分配流程:
═════════════════════════════════════════════════════════════
                    ┌─────────────────┐
                    │ allocate(size)  │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
                    │ 对齐到 256 字节  │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
              ┌────▶│ 检查 free_blocks │
              │     └────────┬────────┘
              │              │
              │     ┌────────▼────────┐
              │     │ 找到合适块?     │
              │     └────────┬────────┘
              │              │
         ┌────┴────┐    ┌────▼────┐
         │   是    │    │   否    │
         └────┬────┘    └────┬────┘
              │              │
    ┌─────────▼────┐  ┌──────▼──────┐
    │ 返回缓存块    │  │ cudaMalloc  │
    │ cache_hits++ │  │ cache_misses++│
    └──────────────┘  └─────────────┘
═════════════════════════════════════════════════════════════

性能优化

优化技术 效果
256 字节对齐 支持向量化加载
Best-fit 策略 减少内存碎片
多 map 存储空闲块 O(log n) 查找
线程安全 (mutex) 多线程安全

4. StreamManager(流管理器)

CUDA 流管理器,支持并发执行。

类设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class StreamManager {
public:
    static StreamManager& instance();
    
    // 初始化
    void init(int num_streams = 4);
    
    // 获取流
    cudaStream_t get_stream();           // 轮询分配
    cudaStream_t get_stream(int index);  // 指定索引
    
    // 同步
    void sync_all();
    void sync(int index);
    
    // 清理
    void cleanup();
    
    int num_streams() const { return static_cast<int>(streams_.size()); }

private:
    std::vector<cudaStream_t> streams_;
    int current_stream_ = 0;
    mutable std::mutex mutex_;
};

并发执行模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
单流执行(串行):
═════════════════════════════════════════════════════════════
Stream 0: ├─GEMM 0─┼─GEMM 1─┼─GEMM 2─┼─GEMM 3─┤
时间:     0        T        2T       3T       4T

多流执行(并行):
═════════════════════════════════════════════════════════════
Stream 0: ├─GEMM 0─┼─────────┼─GEMM 2─┼─────────┤
Stream 1: ├─────────┼─GEMM 1─┼─────────┼─GEMM 3─┤
时间:     0        T        2T       3T       4T

重叠执行:
═════════════════════════════════════════════════════════════
Stream 0: ├─GEMM 0─┼─GEMM 2─┤
Stream 1: ├─GEMM 1─┼─GEMM 3─┤
时间:     0        T        2T

加速比: 2x
═════════════════════════════════════════════════════════════

GEMM Kernel 架构

优化层次架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
                    ┌─────────────────┐
                    │   Vectorized    │ Level 7
                    │   (float4)      │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
                    │     Fused       │ Level 6
                    │ (+ Bias + ReLU) │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
                    │    Register     │ Level 5
                    │    Blocking     │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
                    │ Double Buffer   │ Level 4
                    │   (2x shared)   │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
                    │   Coalesced     │ Level 3
                    │ Memory Access   │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
                    │     Tiled       │ Level 2
                    │ (Shared Memory) │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
                    │     Naive       │ Level 1
                    │  (Global Mem)   │
                    └─────────────────┘

模板参数设计

1
2
3
4
5
6
7
8
9
template<
    int BM,    // Block tile M 维度
    int BN,    // Block tile N 维度
    int BK,    // Block tile K 维度(每次迭代)
    int TM,    // Thread tile M 维度
    int TN     // Thread tile N 维度
>
__global__ void optimized_gemm(const float* A, const float* B, float* C,
                                int M, int N, int K);

参数约束

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
约束验证:
═════════════════════════════════════════════════════════════
1. 线程数约束:
   threads = (BM / TM) × (BN / TN) ≤ 1024
   
2. 共享内存约束:
   shared = (BM × BK + BK × BN) × sizeof(float) ≤ 48KB
   
3. 寄存器约束:
   regs ≈ TM × TN + TM + TN + overhead ≤ 255
═════════════════════════════════════════════════════════════

推荐配置:
═════════════════════════════════════════════════════════════
配置          BM   BN   BK   TM   TN   Threads   Shared
─────────────────────────────────────────────────────────
Small         64   64    8    4    4     256     4KB
Medium       128  128    8    8    8     256     8KB
Large        128  256   16    8    8     512    24KB
═════════════════════════════════════════════════════════════

数据流设计

推理数据流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
推理执行流程:
═════════════════════════════════════════════════════════════

Host                    Device
─────                   ──────
   │
   │  cudaMemcpyH2D
   ├──────────────────────▶  Input Buffer
   │                              │
   │                              ▼
   │                         ┌─────────────┐
   │                         │  Layer 0    │
   │                         │ GEMM+ReLU   │
   │                         └──────┬──────┘
   │                                │
   │                                ▼
   │                         ┌─────────────┐
   │                         │  Layer 1    │
   │                         │ GEMM+ReLU   │
   │                         └──────┬──────┘
   │                                │
   │                                ▼
   │                         ┌─────────────┐
   │                         │  Layer N    │
   │                         │ GEMM        │
   │                         └──────┬──────┘
   │                                │
   │  cudaMemcpyD2H                 ▼
   │◀──────────────────────  Output Buffer
   │
   ▼
Result
═════════════════════════════════════════════════════════════

权重加载流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
权重文件加载:
═════════════════════════════════════════════════════════════
File                    Host                    Device
─────                   ─────                   ──────
   │
   │  fread
   ├──────────────────▶  Header
   │
   │                     │ 验证魔数和版本
   │                     ▼
   │  fread
   ├──────────────────▶  Layer Meta
   │                     │ 验证维度
   │                     ▼
   │  fread              │
   ├──────────────────▶  Weight Data
   │                     │ cudaMemcpyH2D
   │                     ├──────────────────────▶  d_weights
   │                     │
   │  fread (if bias)    │
   ├──────────────────▶  Bias Data
                         │ cudaMemcpyH2D
                         ├──────────────────────▶  d_bias
                         │
                         ▼
                   Ready for Inference
═════════════════════════════════════════════════════════════

内存管理

内存策略对比

策略 实现 适用场景 性能
直接分配 cudaMalloc/cudaFree 简单程序
RAII 包装 DeviceMemory 一般应用
内存池 MemoryPool 高频分配
预分配 预先分配大块内存 固定负载 最高

推荐用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 临时内存:使用 DeviceMemory RAII
{
    DeviceMemory temp(M * N * sizeof(float));
    // 使用 temp...
}  // 自动释放

// 频繁分配:使用 MemoryPool
auto& pool = MemoryPool::instance();
void* ptr = pool.allocate(size);
// 使用 ptr...
pool.deallocate(ptr);  // 返回缓存

// 张量数据:使用 PooledMemory
Tensor t({batch, channels, height, width});  // 内部使用 PooledMemory

错误处理机制

异常层次

1
2
3
4
5
6
7
8
std::exception
    │
    ├── CudaException          // CUDA 运行时错误
    │   └── cudaError_t error_
    │
    ├── std::runtime_error     // cuBLAS 错误等
    │
    └── std::invalid_argument  // 参数验证错误

CUDA 错误检查宏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define CUDA_CHECK(call)                                      \
    do {                                                      \
        cudaError_t err = call;                               \
        if (err != cudaSuccess) {                             \
            throw CudaException(err, __FILE__, __LINE__);     \
        }                                                     \
    } while (0)

#define CUBLAS_CHECK(call)                                    \
    do {                                                      \
        cublasStatus_t status = call;                         \
        if (status != CUBLAS_STATUS_SUCCESS) {                \
            throw std::runtime_error("cuBLAS error");         \
        }                                                     \
    } while (0)

使用示例

1
2
3
4
5
6
7
8
9
10
try {
    CUDA_CHECK(cudaMalloc(&ptr, size));
    launch_kernel<<<grid, block>>>(...);
    CUDA_CHECK(cudaGetLastError());
} catch (const CudaException& e) {
    std::cerr << "CUDA 错误: " << e.what() << std::endl;
    std::cerr << "错误码: " << cudaGetErrorName(e.error()) << std::endl;
} catch (const std::exception& e) {
    std::cerr << "错误: " << e.what() << std::endl;
}

扩展指南

添加新的 GEMM Kernel

  1. 声明 kernelinclude/kernels.cuh):
1
2
void launch_my_gemm(const float* A, const float* B, float* C,
                    int M, int N, int K, cudaStream_t stream = 0);
  1. 实现 kernelsrc/my_gemm.cu):
1
2
3
4
5
6
7
__global__ void my_gemm_kernel(...) { ... }

void launch_my_gemm(...) {
    // 配置 grid/block
    // 启动 kernel
    // 错误检查
}
  1. 添加枚举include/common.h):
1
2
3
4
enum class GemmKernelType {
    // ... existing types ...
    MY_KERNEL
};
  1. 注册到 AutoTunerinclude/autotuner.h):
1
2
3
case GemmKernelType::MY_KERNEL:
    launch_my_gemm(A, B, C, M, N, K, stream);
    break;

添加新的激活函数

  1. 扩展 FusionConfiginclude/common.h):
1
2
3
4
5
6
struct FusionConfig {
    bool add_bias = false;
    bool apply_relu = false;
    bool apply_gelu = false;       // 新增
    bool apply_sigmoid = false;    // 新增
};
  1. 扩展 fused_gemm.cu
1
2
3
4
5
6
7
8
9
10
11
template<..., bool APPLY_GELU, bool APPLY_SIGMOID>
__global__ void fused_gemm_bias_activation(...) {
    // ...
    if constexpr (APPLY_GELU) {
        val = gelu(val);
    }
    if constexpr (APPLY_SIGMOID) {
        val = sigmoid(val);
    }
    // ...
}

相关链接


*最后更新:2025-04-16 文档版本:v1.1.0*

Back to top

MIT License | A learning project for the CUDA community