AI可以不停的输出,但是人的精力是有限的,人要做的是有条件的限制AI的输出,指示AI输出自己想要的内容。本文是多次修改条件,AI生成。AI就是一个只管输出不负责的莽撞汉子。最终还是要看人的调教,至少现在是这个阶段。
我已经完成第一篇,正在学习第二篇。
前言
本教程面向已掌握FPGA基础开发、熟悉AXI总线与DMA架构、希望入门FPGA AI加速的开发者。我们以已跑通的单通道3×3卷积 + 2×2最大池化工程为起点,不追求极致性能优化,先建立「CNN算法原理 ↔ PyTorch软件训练 ↔ FPGA硬件实现」的完整架构认知,逐步补全CNN标准组件,最终打通端到端全链路。
教程全程遵循「最小增量迭代」原则:每一步只修改少量代码,完成后立刻与软件结果对齐验证,确保每一步都可复现、可验证,避免陷入“一改全错”的调试困境。
目录
第一篇 基础认知篇:先建立CNN完整架构
第1章 CNN全景链路与核心概念
1.1 特征提取流水线:CNN的整体工作逻辑
1.2 核心名词速览:卷积、权重、偏置、激活、池化、特征图
1.3 三者对应关系:CNN算法 ↔ PyTorch接口 ↔ FPGA硬件实现
第二篇 基础实践篇:补齐CNN最核心标准单元
第2章 新增ReLU激活层——给网络加入非线性
第3章 Padding填充:控制特征图尺寸,保留边缘信息
第4章 Stride步长:控制计算密度,实现特征降采样
第三篇 核心进阶篇:从单通道到多通道,对应真实CNN结构
第5章 扩展多输出通道:理解多卷积核与多特征图
第6章 池化算子扩展:最大池化与平均池化
第7章 可配置算子设计:通过寄存器切换不同卷积核
第四篇 全链路闭环篇:从单个算子到完整网络
第8章 两级卷积级联:体验多层特征提取
第9章 端到端全流程:PyTorch训练 → 权重导出 → FPGA推理
第10章 全流程总结:从算法到硬件的完整落地路径
第一篇 基础认知篇:先建立CNN完整架构
第1章 CNN全景链路与核心概念
1.1 特征提取流水线:CNN的整体工作逻辑
卷积神经网络(CNN)本质是一套分层特征提取流水线:输入原始图像,经过多层算子堆叠,逐步提取从简单到复杂的特征(边缘→纹理→形状→物体),最终输出分类/检测结果。
一条标准CNN的完整数据流向:
原始输入图像 → 卷积层(Conv) → 批归一化层(BN) → 激活层(ReLU) → 池化层(Pooling)
↓
(重复堆叠N次)
↓
全连接层(FC) → 最终输出结果
我们当前FPGA工程已实现的,是这条链路里的最小核心单元:单通道卷积 + 最大池化。所有大型CNN网络,本质都是这个单元的多次堆叠 + 通道数扩展。
1.2 核心名词速览
| 名词 | 核心功能 | 关键参数 |
|---|---|---|
| 特征图(Feature Map) | 每一层的输入/输出数据,格式为「通道数C × 高度H × 宽度W」 | C、H、W |
| 卷积核(Kernel/Filter) | 也叫权重,在特征图上滑动计算,提取特定特征 | 核大小(如3×3)、权重数值 |
| 偏置(Bias) | 每个输出通道对应一个偏移值,卷积计算完成后叠加 | 单通道单数值 |
| 填充(Padding) | 特征图边缘补0,控制输出尺寸,避免边缘信息丢失 | 补0圈数 |
| 步长(Stride) | 卷积核每次滑动的像素数,步长越大输出越小 | 滑动步长 |
| 激活层(Activation) | 加入非线性变换,让网络可以拟合复杂函数 | ReLU、Sigmoid等 |
| 池化层(Pooling) | 降采样缩小特征图尺寸,减少计算量,保留核心特征 | 最大池化、平均池化 |
| 全连接层(FC) | 二维特征展平为一维,映射到最终分类结果 | 输入维度、输出类别数 |
1.3 三者对应关系:算法↔软件↔硬件
核心逻辑:PyTorch负责训练出权重参数,FPGA负责加载权重、用硬件电路完成推理计算。
| CNN算法概念 | PyTorch对应接口 | FPGA硬件实现 |
|---|---|---|
| 滑动卷积计算 | torch.nn.Conv2d() | 行缓存 + 3×3窗口生成 + 乘加树 |
| 卷积权重 | conv.weight | 权重寄存器组 + DSP乘法器 |
| 卷积偏置 | conv.bias | 偏置寄存器 + 加法器 |
| ReLU激活 | torch.nn.ReLU() | 单路判断逻辑:负数置0,正数直通 |
| 最大池化 | torch.nn.MaxPool2d() | 窗口寄存器 + 数值比较器 |
| 特征图数据 | Tensor张量 | AXI-Stream高速数据流 + 片内缓存 |
补充说明:批归一化(BN)层在推理阶段一般会提前融合进卷积层的权重和偏置中,不需要单独做硬件电路,属于部署优化的常规操作。
第二篇 基础实践篇:补齐CNN最核心标准单元
第2章 新增ReLU激活层
算法原理
ReLU(Rectified Linear Unit)是CNN的标配激活函数,公式为:
y=max(0,x) y = max(0, x) y=max(0,x)
- 正数原样输出,负数直接置0
- 计算成本极低,硬件实现开销极小
- 作用:给线性的卷积计算加入非线性,让多层网络才有意义
硬件实现(单通道版本增量修改)
在卷积输出、池化输入之间,增加一级ReLU处理逻辑,修改量仅几行代码:
// 卷积计算结果先经过ReLU,再进入后续池化
wire signed [15:0] conv_out;
reg signed [15:0] relu_out;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
relu_out <= 16'd0;
end else begin
// ReLU核心逻辑:小于0则输出0,否则直通
relu_out <= (conv_out < $signed(16'd0)) ? $signed(16'd0) : conv_out;
end
end
PyTorch验证对照
import torch
import torch.nn as nn
# 搭建和硬件完全对应的极简网络
model = nn.Sequential(
nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=0),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2)
)
# 写入和FPGA完全相同的恒等算子权重
with torch.no_grad():
model[0].weight.fill_(0)
model[0].weight[0, 0, 1, 1] = 1.0 # 中心位置权重为1
model[0].bias.fill_(0)
# 输入测试数据,得到软件基准结果
input_img = torch.zeros(1, 1, 128, 128) # 全零输入
output_pytorch = model(input_img)
实践步骤
- 在现有卷积模块中增加ReLU逻辑,输出接入池化模块
- 重新打包IP、升级实例、清空综合缓存、生成比特流
- 运行测试程序,对比FPGA输出与PyTorch输出
验收标准
- 全零输入下,输出全为0
- 随机输入下,逐像素与PyTorch结果完全一致
- 连续多帧传输无超时、无错位
第3章 Padding填充:控制特征图尺寸
算法原理
- 问题:3×3卷积在特征图边缘滑动时,边缘像素计算次数少,输出尺寸会缩小(128×128输入→126×126输出)
- 解决:在特征图四周补0(Padding),让边缘像素也能参与完整计算,控制输出尺寸
- 常用padding=1搭配3×3卷积,可实现输出尺寸与输入完全一致
输出尺寸计算公式:
输出尺寸=输入尺寸−核大小+2×PaddingStride+1 输出尺寸 = \frac{输入尺寸 - 核大小 + 2×Padding}{Stride} + 1 输出尺寸=Stride输入尺寸−核大小+2×Padding+1
硬件实现要点
- 输入数据有效时,判断像素坐标,边缘位置补0
- 行缓存读写逻辑配合调整,确保窗口生成正确
验收标准
- 128×128输入 + padding=1 + 3×3卷积,输出尺寸为128×128
- 结果与PyTorch
padding=1配置完全对齐
第4章 Stride步长:控制计算密度
算法原理
- 步长(Stride):卷积核每次滑动的像素数
- stride=1:逐像素滑动,计算最密集,输出尺寸变化小
- stride=2:隔一个像素计算一次,输出尺寸减半,计算量减为1/4
- 作用:降采样,减少后续计算量,扩大感受野
硬件实现要点
- 输出有效信号间隔输出,每stride个输入周期产生一个有效输出
- 行列计数器配合步长做跳变
验收标准
- stride=2时,输出尺寸为输入的一半
- 结果与PyTorch
stride=2配置完全对齐
第三篇 核心进阶篇:从单通道到多通道
第5章 扩展多输出通道
算法原理
- 输出通道(Output Channel):一个卷积层包含多个卷积核,每个卷积核提取一种特征,输出一张特征图
- 比如输出通道=2,就是同时用2个不同的卷积核计算,输出2张特征图
- 这是真实CNN网络的基础结构:通道数逐层增加,尺寸逐层减小
硬件实现要点
- 复制一套乘加计算单元,共用同一套行缓存和窗口生成逻辑
- 两套计算单元分别加载不同的权重和偏置
- 输出按通道顺序拼接,通过AXI-Stream串行输出
- 调整TLAST计数,适配总数据长度(单帧字节数 × 通道数)
验收标准
- 输出数据按通道0、通道1顺序排列
- 两个通道的结果分别与PyTorch对应通道结果完全一致
- 帧长度正确,DMA接收无溢出、无超时
第6章 池化算子扩展:最大池化与平均池化
算法原理
- 最大池化:取窗口内最大值,保留最显著的特征,最常用
- 平均池化:取窗口内平均值,特征更平滑
- 两种池化硬件实现逻辑不同,对应不同的算法场景
硬件实现要点
- 增加1位控制寄存器,通过软件配置选择池化模式
- 平均池化需要增加加法器和移位器(除以4等价于右移2位)
验收标准
- 两种模式下,结果分别与PyTorch的MaxPool2d、AvgPool2d对齐
第7章 可配置算子设计
算法原理
- 卷积的功能完全由权重决定,权重不同,提取的特征就不同
- 常见3×3算子:恒等、Sobel边缘检测、高斯模糊、浮雕、锐化
- 可配置设计:权重通过寄存器写入,不需要修改硬件代码
实践内容
- 依次配置不同的卷积核权重
- 输入测试图像,观察输出效果
- 与OpenCV/PyTorch对应算子的结果做对比
验收标准
- 切换不同权重后,输出效果符合算子预期
- 数值结果与软件计算一致
第四篇 全链路闭环篇:从单个算子到完整网络
第8章 两级卷积级联:体验多层特征提取
算法原理
- CNN的核心思想就是多层堆叠:浅层提取低级特征(边缘),深层提取高级特征(形状、物体)
- 两级卷积+激活+池化级联,就是一个最简的浅层CNN网络
硬件实现要点
- 两套「卷积+ReLU+池化」IP通过AXI-Stream无缝级联
- 前一级的m_axis输出直接连接后一级的s_axis输入
- 两级分别配置各自的权重和偏置
- 流控反压正常:后一级暂停时,前一级自动暂停,数据不丢失
验收标准
- 端到端输出与PyTorch两层网络结果完全一致
- 连续传输无丢数、无错位
第9章 端到端全流程:PyTorch训练 → 权重导出 → FPGA推理
全流程步骤
- 训练阶段:用PyTorch搭建一个小型CNN网络(比如2层卷积+2层池化),在MNIST数据集上训练手写数字分类
- 参数导出:训练完成后,导出每一层的权重、偏置参数,做定点量化(8bit)
- 参数部署:把量化后的权重、偏置,通过AXI-Lite依次写入FPGA对应层的寄存器
- 硬件推理:输入手写数字图片,FPGA完成端到端计算,输出分类结果
- 结果校验:对比FPGA推理结果与PyTorch推理结果的准确率差异
验收标准
- 完整走通「训练→导出→部署→推理」全流程
- 同一输入图片,FPGA推理结果与PyTorch推理结果类别一致
- 理解定点量化对精度的影响
第10章 全流程总结
完成以上所有章节后,你将掌握完整的FPGA AI加速知识架构:
- 算法层:理解CNN各核心算子的作用、参数、相互关系
- 软件层:掌握PyTorch搭建网络、训练、导出参数的基本流程
- 硬件层:掌握各算子的RTL实现、接口设计、模块级联方法
- 系统层:打通「参数配置→DMA数据搬运→硬件计算→结果回传」的软硬件协同全链路
后续可以根据需求,再深入性能优化(更高并行度、脉动阵列、量化优化、带宽优化),此时已有完整架构认知,优化方向会非常清晰。
后记
本教程遵循「先建立整体框架,再逐步填充细节」的学习思路,避免一开始就陷入底层优化的细节中。每一章都有明确的算法原理、硬件修改、验证方法和验收标准,可独立完成,也可按顺序逐步推进。
建议每完成一章,都做一次记录和总结,梳理清楚「这一步解决了什么问题、对应CNN里的什么概念、软硬件是怎么对应的」,逐步构建起完整的知识体系。
1498

被折叠的 条评论
为什么被折叠?



