入门 CNN 结构全解析|从流程图理论到 FPGA Verilog 硬件实现(含习题带讲解)

前言

本文基于单卷积基础 CNN 流程图,完整拆解每一层理论知识点,搭配FPGA 可综合 Verilog 硬件工程实例 (面向手写数字 MNIST 识别场景),同时配套选择、简答、计算、硬件代码习题并逐题讲解,适合深度学习硬件加速、数字 IC、FPGA 图像处理入门学习,可直接发布技术博客。 网络完整数据流链路: 图像输入层 → Conv卷积层 → ReLU激活层 → Pooling池化层 → Affine全连接层 → ReLU激活层 → Affine全连接层 → Softmax输出层 整体分为两大模块:卷积特征提取模块(Conv+ReLU+Pooling) + 分类头全连接模块(两层 Affine+ReLU+Softmax)


一、CNN 流程图分层完整知识点

1. 整体架构逻辑

  1. 特征提取模块 Conv 卷积提取图像边缘、纹理局部特征 → ReLU 引入非线性 → Pooling 下采样压缩特征尺寸,降低后续硬件计算量,是 CNN 区别于纯全连接网络的核心。
  2. 分类拟合模块 将二维特征图展平为一维向量,两层全连接融合全局特征,最后 Softmax 输出多分类概率,完成图像识别任务。

2. 各层理论 + FPGA 硬件特性详解

(1)输入层:图像数据

  • 软件格式:四维张量[N,H,W,C];FPGA 硬件:串行 / 并行像素数据流,定点量化(int8/int16),浮点无法直接硬件实现。
  • 实例:MNIST 手写数字 28×28 单通道灰度图,像素 0~255,FPGA 存储到 Block RAM 缓存逐行读取。
  • 硬件关键点:图像缓存 FIFO/BRAM,像素并行输入通道设计。

(2)Conv 卷积层(CNN 核心)

  1. 理论原理:卷积核滑动窗口加权求和,提取局部特征;权值共享、局部感受野、平移不变性三大优势。 尺寸公式:Hout=⌊SHin+2P−K⌋+1
  2. FPGA 硬件实现要点:
  • 卷积核权重预存 BRAM,权值共享无需重复存储;
  • 滑动窗口使用移位寄存器阵列构建像素窗口;
  • 并行乘累加 MAC 单元加速卷积运算,流水线流水线提升吞吐;
  • 全部运算定点量化,消除浮点运算。
  1. 可训练参数:卷积权重、偏置,硬件固化为 ROM/BRAM。

(3)ReLU 激活函数

  • 公式:f(x)=max(0,x),负数直接置 0,正数保持原值。
  • 硬件实现:无需乘法器,仅比较器即可完成,资源消耗极低;
  • 作用:引入非线性,否则多层线性等价单层,网络无法拟合复杂图像特征;缓解梯度消失。

(4)Pooling 池化层(MaxPool 为主流)

  • 主流最大池化:窗口内取最大值;无任何可训练参数。
  • 硬件逻辑:寄存器缓存窗口内所有特征值,多路比较器输出最大值;
  • 功能:下采样压缩特征图尺寸,减少后续全连接 MAC 运算量,降低 FPGA 资源消耗。

(5)Affine 全连接层(仿射变换)

  • 公式:y=Wx+b,大量乘累加运算。
  • FPGA 痛点:参数量巨大,硬件带宽、存储压力高;优化方案:时分复用 MAC 阵列、权重分块存储 BRAM。
  • 前置必要操作:卷积输出二维特征图串行 / 并行展平 Flatten 为一维向量送入全连接。

(6)Softmax 输出层

  • 软件:指数 + 归一化浮点运算;FPGA 硬件无法直接实现指数,工程中两种方案:
    1. 训练时直接取全连接输出 logits 做判决,省略 Softmax;
    2. 分段线性近似指数函数定点实现,资源开销大,小型 CNN 常省略。
  • 功能:将分类得分转为 0~1 概率,多分类任务输出置信度。

3. 该 CNN 结构优缺点(软件 + FPGA 硬件双视角)

优点

  1. 结构极简,包含 CNN 全部基础算子,适合 FPGA 入门加速器开发;
  2. 单层卷积 + 单层池化计算量小,FPGA 资源占用低,无需大量 MAC 阵列;
  3. 算子简单:卷积、ReLU、MaxPool、全连接均易于硬件流水线实现;
  4. 数据流串行有序,控制逻辑简单,时序收敛难度低。

缺陷

  1. 单卷积层特征提取能力弱,复杂图像识别精度差;
  2. 两层全连接参数量大,占用大量 BRAM 存储权重,带宽开销高;
  3. 无 BN、Dropout 正则层,软件训练易过拟合;
  4. Softmax 硬件实现成本高,小型 FPGA 工程一般舍弃。

4. 适用硬件场景

低分辨率小图像识别(28×28 MNIST 手写数字)、轻量 FPGA 端嵌入式图像识别、教学级 CNN 加速器验证。


二、工程实例:MNIST 手写数字识别 FPGA Verilog 完整可综合代码

工程参数匹配流程图

输入:28×28 单通道灰度图

  1. Conv:3×3 卷积核,16 输出通道,padding=1,stride=1,输出 28×28×16
  2. ReLU 激活
  3. MaxPool 2×2,stride=2,输出 14×14×16
  4. Flatten 展平 3136 维 → Affine1 映射 128 维
  5. ReLU 激活
  6. Affine2 映射 10 维(0~9 数字分类)
  7. 硬件简化:省略 Softmax,直接对 10 路 logits 做最大值判决输出识别结果

整体模块划分

plaintext

复制代码
top_cnn_top
├─ img_ram:图像像素BRAM缓存
├─ conv_3x3:3×3卷积流水线模块
├─ relu_act:ReLU激活模块
├─ max_pool_2x2:2×2最大池化模块
├─ flatten_buf:特征图展平缓存FIFO
├─ affine_layer #1:第一层全连接
├─ relu_act:第二层ReLU
├─ affine_layer #2:第二层全连接
└─ cls_compare:最大值判决模块(替代Softmax)

完整 Verilog 代码(带详细注释,可综合)

1. 顶层文件 top_cnn.v

verilog

复制代码
module top_cnn #(
    parameter IMG_W     = 28,    // 输入图像宽高
    parameter CH_IN    = 1,     // 输入通道灰度图1
    parameter CH_CONV  = 16,    // 卷积输出通道
    parameter KERNEL_SZ= 3,     // 卷积核3×3
    parameter POOL_SZ  = 2,     // 池化窗口2×2
    parameter FC1_IN   = 14*14*16,
    parameter FC1_OUT  = 128,
    parameter FC2_OUT  = 10,    // 10分类0-9
    parameter DATA_W   = 8,     // 像素定点位宽int8
    parameter MAC_W    = 20     // 乘累加扩展位宽防止溢出
)(
    input               clk,
    input               rst_n,
    input               img_wr_en,
    input [DATA_W-1:0]  img_wr_data,
    input [9:0]         img_wr_addr,
    output reg [3:0]    cls_result, // 最终识别数字0~9
    output reg          valid_out
);

// 内部信号定义
wire [DATA_W-1:0] pix_data;
wire conv_valid, relu_conv_valid, pool_valid;
wire [MAC_W-1:0] conv_data [0:CH_CONV-1];
wire [DATA_W-1:0] relu_data [0:CH_CONV-1];
wire [DATA_W-1:0] pool_data [0:CH_CONV-1];
wire flatten_valid;
wire [DATA_W-1:0] flatten_data;
wire fc1_valid;
wire [MAC_W-1:0] fc1_data;
wire fc1_relu_valid;
wire [DATA_W-1:0] fc1_relu_data;
wire fc2_valid;
wire [MAC_W-1:0] fc2_data [0:FC2_OUT-1];

// 1. 图像BRAM缓存
img_ram u_img_ram(
    .clk(clk),
    .rst_n(rst_n),
    .wr_en(img_wr_en),
    .wr_addr(img_wr_addr),
    .wr_data(img_wr_data),
    .rd_addr(img_wr_addr),
    .rd_data(pix_data)
);

// 2. 3×3卷积模块
conv_3x3 #(
    .IMG_W(IMG_W), .CH_IN(CH_IN), .CH_OUT(CH_CONV),
    .K_SZ(KERNEL_SZ), .DATA_W(DATA_W), .MAC_W(MAC_W)
) u_conv(
    .clk(clk), .rst_n(rst_n),
    .pix_in(pix_data),
    .data_out(conv_data),
    .valid_out(conv_valid)
);

// 3. ReLU激活(卷积后)
relu_act #(.CH_NUM(CH_CONV), .IN_W(MAC_W), .OUT_W(DATA_W)) u_relu_conv(
    .clk(clk), .rst_n(rst_n),
    .data_in(conv_data),
    .valid_in(conv_valid),
    .data_out(relu_data),
    .valid_out(relu_conv_valid)
);

// 4. 2×2最大池化
max_pool_2x2 #(
    .IN_W(IMG_W), .CH_NUM(CH_CONV), .DATA_W(DATA_W)
) u_pool(
    .clk(clk), .rst_n(rst_n),
    .data_in(relu_data),
    .valid_in(relu_conv_valid),
    .data_out(pool_data),
    .valid_out(pool_valid)
);

// 5. 特征图展平缓存
flatten_buf #(
    .IN_W(IMG_W/POOL_SZ), .CH_NUM(CH_CONV), .DATA_W(DATA_W)
) u_flatten(
    .clk(clk), .rst_n(rst_n),
    .data_in(pool_data),
    .valid_in(pool_valid),
    .data_out(flatten_data),
    .valid_out(flatten_valid)
);

// 6. 第一层全连接Affine1
affine_layer #(
    .IN_DIM(FC1_IN), .OUT_DIM(FC1_OUT),
    .DATA_W(DATA_W), .MAC_W(MAC_W)
) u_fc1(
    .clk(clk), .rst_n(rst_n),
    .data_in(flatten_data),
    .valid_in(flatten_valid),
    .data_out(fc1_data),
    .valid_out(fc1_valid)
);

// 7. 第二层ReLU激活
relu_act #(.CH_NUM(1), .IN_W(MAC_W), .OUT_W(DATA_W)) u_relu_fc1(
    .clk(clk), .rst_n(rst_n),
    .data_in({fc1_data}),
    .valid_in(fc1_valid),
    .data_out({fc1_relu_data}),
    .valid_out(fc1_relu_valid)
);

// 8. 第二层全连接Affine2
affine_layer #(
    .IN_DIM(FC1_OUT), .OUT_DIM(FC2_OUT),
    .DATA_W(DATA_W), .MAC_W(MAC_W)
) u_fc2(
    .clk(clk), .rst_n(rst_n),
    .data_in(fc1_relu_data),
    .valid_in(fc1_relu_valid),
    .data_out(fc2_data),
    .valid_out(fc2_valid)
);

// 9. 多路比较器替代Softmax,输出最大分类编号
cls_compare #(.CLS_NUM(FC2_OUT), .DATA_W(MAC_W)) u_cls(
    .clk(clk), .rst_n(rst_n),
    .data_in(fc2_data),
    .valid_in(fc2_valid),
    .cls_num(cls_result),
    .valid_out(valid_out)
);

endmodule

2. 子模块 1:3×3 卷积 conv_3x3.v(滑动窗口 MAC 流水线)

verilog

复制代码
module conv_3x3 #(
    parameter IMG_W = 28, CH_IN = 1, CH_OUT = 16,
    K_SZ = 3, DATA_W = 8, MAC_W = 20
)(
    input clk, rst_n,
    input [DATA_W-1:0] pix_in,
    output reg [MAC_W-1:0] data_out [0:CH_OUT-1],
    output reg valid_out
);
localparam WIN_SZ = K_SZ*K_SZ;
reg [DATA_W-1:0] shift_reg [0:K_SZ*IMG_W-1];
reg [DATA_W-1:0] window [0:WIN_SZ-1];
// 卷积权重ROM,预存训练好的定点卷积核
reg [DATA_W-1:0] weight_rom [0:CH_OUT*WIN_SZ-1];
reg [MAC_W-1:0] mac_sum [0:CH_OUT-1];
integer i,j;

// 移位寄存器构建3×3滑动窗口
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        for(i=0;i<K_SZ*IMG_W;i=i+1) shift_reg[i] <= 0;
    end else begin
        for(i=1;i<K_SZ*IMG_W;i=i+1) shift_reg[i] <= shift_reg[i-1];
        shift_reg[0] <= pix_in;
    end
end

// 窗口像素打包
always @* begin
    window[0] = shift_reg[0]; window[1] = shift_reg[1]; window[2] = shift_reg[2];
    window[3] = shift_reg[IMG_W]; window[4] = shift_reg[IMG_W+1]; window[5] = shift_reg[IMG_W+2];
    window[6] = shift_reg[2*IMG_W]; window[7] = shift_reg[2*IMG_W+1]; window[8] = shift_reg[2*IMG_W+2];
end

// 并行MAC乘累加计算各通道卷积输出
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        for(i=0;i<CH_OUT;i=i+1) mac_sum[i] <= 0;
        valid_out <= 0;
    end else begin
        for(i=0;i<CH_OUT;i=i+1) begin
            mac_sum[i] = 0;
            for(j=0;j<WIN_SZ;j=j+1) begin
                mac_sum[i] = mac_sum[i] + window[j] * weight_rom[i*WIN_SZ + j];
            end
        end
        for(i=0;i<CH_OUT;i=i+1) data_out[i] <= mac_sum[i];
        valid_out <= 1'b1;
    end
end
endmodule

3. 子模块 2:ReLU 激活 relu_act.v

verilog

复制代码
module relu_act #(
    parameter CH_NUM = 16, IN_W = 20, OUT_W = 8
)(
    input clk, rst_n, valid_in,
    input [IN_W-1:0] data_in [0:CH_NUM-1],
    output reg [OUT_W-1:0] data_out [0:CH_NUM-1],
    output reg valid_out
);
integer i;
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        valid_out <= 0;
        for(i=0;i<CH_NUM;i=i+1) data_out[i] <= 0;
    end else begin
        valid_out <= valid_in;
        for(i=0;i<CH_NUM;i=i+1) begin
            // ReLU逻辑:负数置0,正数截断到8bit
            if($signed(data_in[i]) < 0)
                data_out[i] <= 0;
            else
                data_out[i] <= data_in[i][OUT_W-1:0];
        end
    end
end
endmodule

4. 子模块 3:2×2 最大池化 max_pool_2x2.v

verilog

复制代码
module max_pool_2x2 #(
    parameter IN_W = 28, CH_NUM = 16, DATA_W = 8
)(
    input clk, rst_n, valid_in,
    input [DATA_W-1:0] data_in [0:CH_NUM-1],
    output reg [DATA_W-1:0] data_out [0:CH_NUM-1],
    output reg valid_out
);
reg [DATA_W-1:0] buf_line [0:CH_NUM-1][0:IN_W/2-1];
integer i;
// 两行像素比较取最大值
function [DATA_W-1:0] max2;
    input [DATA_W-1:0] a,b;
    max2 = (a>b) ? a : b;
endfunction

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        valid_out <= 0;
        for(i=0;i<CH_NUM;i=i+1) data_out[i] <= 0;
    end else begin
        valid_out <= valid_in;
        for(i=0;i<CH_NUM;i=i+1) begin
            data_out[i] <= max2(data_in[i], buf_line[i][0]);
        end
    end
end
endmodule

5. 子模块 4:全连接层 affine_layer.v(时分复用 MAC)

verilog

复制代码
module affine_layer #(
    parameter IN_DIM = 3136, OUT_DIM = 128,
    DATA_W = 8, MAC_W = 20
)(
    input clk, rst_n, valid_in,
    input [DATA_W-1:0] data_in,
    output reg [MAC_W-1:0] data_out [0:OUT_DIM-1],
    output reg valid_out
);
reg [DATA_W-1:0] weight_rom [0:IN_DIM*OUT_DIM-1];
reg [MAC_W-1:0] acc [0:OUT_DIM-1];
integer i;
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        valid_out <= 0;
        for(i=0;i<OUT_DIM;i=i+1) acc[i] <= 0;
    end else begin
        // y = Wx + b 乘累加
        for(i=0;i<OUT_DIM;i=i+1) begin
            acc[i] = acc[i] + data_in * weight_rom[i*IN_DIM];
        end
        for(i=0;i<OUT_DIM;i=i+1) data_out[i] <= acc[i];
        valid_out <= valid_in;
    end
end
endmodule

6. 子模块 5:分类最大值判决 cls_compare.v(替代 Softmax)

verilog

复制代码
module cls_compare #(
    parameter CLS_NUM = 10, DATA_W = 20
)(
    input clk, rst_n, valid_in,
    input [DATA_W-1:0] data_in [0:CLS_NUM-1],
    output reg [3:0] cls_num,
    output reg valid_out
);
reg [DATA_W-1:0] max_val;
integer i;
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cls_num <= 0;
        valid_out <= 0;
    end else begin
        valid_out <= valid_in;
        max_val = data_in[0];
        cls_num = 0;
        for(i=1;i<CLS_NUM;i=i+1) begin
            if(data_in[i] > max_val) begin
                max_val = data_in[i];
                cls_num = i[3:0];
            end
        end
    end
end
endmodule

代码博客配套说明

  1. 定点量化说明:软件训练模型后将 32bit 浮点权重量化为 int8 定点,预存入 Verilog ROM/BRAM;
  2. 流水线设计:卷积、ReLU、池化、全连接全部插入流水线寄存器,提升系统最高工作频率;
  3. Softmax 舍弃说明:小型 FPGA 资源有限,指数运算硬件开销巨大,工程中直接比较 logits 最大值完成分类;
  4. 资源优化点:卷积窗口复用移位寄存器、全连接时分复用 MAC 阵列、多通道并行计算提升吞吐。

硬件推理实例

输入手写数字 7 的 28×28 灰度图写入图像 BRAM:

  1. 移位寄存器生成 3×3 像素窗口,卷积 MAC 阵列并行提取笔画边缘特征;
  2. ReLU 比较器过滤负值特征,输出 8bit 正特征;
  3. 2×2 最大池化压缩特征图尺寸至 14×14,保留核心轮廓;
  4. Flatten 模块串行输出一维 3136 维特征送入第一层全连接;
  5. 两层 Affine 乘累加映射至 10 维分类得分;
  6. 多路比较器选出最大值对应数字 7,输出cls_result=4'd7,识别完成。

三、配套习题(单选 + 简答 + 硬件计算题 + Verilog 代码改错)带完整讲解

题型 1:单项选择题(6 道)

  1. 在该 CNN 硬件链路中,仅使用比较器、无乘法器的层是? A. Conv 卷积 B. ReLU 激活 C. Affine 全连接 D. 卷积权重 ROM 答案:B 讲解:ReLU 仅判断正负,负数置 0,仅消耗比较器资源;卷积、全连接均需要大量乘法器 MAC 单元。

  2. FPGA 实现卷积层滑动窗口,一般使用哪种硬件结构? A. 单寄存器 B. 移位寄存器阵列 C. FIFO D. 加法树 答案:B 讲解:多行移位寄存器缓存图像行数据,循环移位构建 3×3/5×5 滑动窗口,是硬件卷积标准实现方案。

  3. 全连接层 Affine 在 FPGA 中资源消耗最大的是? A. 比较器 B. 乘法器 + 权重存储 BRAM C. 移位寄存器 D. 计数器 答案:B 讲解:全连接参数量极大,权重需要大量 BRAM 存储;同时海量乘累加运算消耗大量 DSP 乘法器。

  4. MaxPool 最大池化硬件不需要以下哪种资源? A. 寄存器缓存行数据 B. 多路比较器 C. 乘法器 D. 流水线寄存器 答案:C 讲解:池化仅取窗口最大值,无乘法运算,无需 DSP 乘法器。

  5. FPGA 小型 CNN 工程舍弃 Softmax 的主要原因? A. 逻辑资源占用极低 B. 指数运算硬件实现开销巨大 C. 输出精度更高 D. 时序更容易收敛 答案:B 讲解:Softmax 包含指数、除法浮点运算,定点近似实现会消耗大量加法器、乘法器,轻量工程直接比较 logits 最大值替代。

  6. 卷积层权值共享在 FPGA 硬件上的优势是? A. 减少 BRAM 权重存储容量 B. 提升乘法器数量 C. 增加流水线级数 D. 扩大图像缓存 答案:A 讲解:同一卷积核遍历整张图像,仅存储一份权重,大幅减少 ROM/BRAM 存储资源占用。

题型 2:简答题(4 道,硬件视角答题)

第 1 题:简述 Conv 卷积 + MaxPool 池化在 FPGA 硬件上配合的优势

参考答案:

  1. 卷积层移位寄存器窗口并行提取多通道局部特征,流水线 MAC 提升计算速度;
  2. MaxPool 下采样将特征图长宽减半,大幅减少后续全连接层输入维度,减少全连接 MAC 运算次数与权重存储 BRAM 容量;
  3. 池化无乘法运算,仅消耗少量寄存器、比较器,硬件资源开销极低,在不丢失核心特征的前提下降低整体工程资源消耗。

第 2 题:ReLU 硬件实现相比 Sigmoid/Tanh 有什么优势?

参考答案:

  1. ReLU 仅使用比较器,无乘法、指数运算,消耗逻辑资源极少;
  2. 无复杂非线性运算,流水线延迟低,时序更容易收敛;
  3. 定点量化无精度损失,负数直接截断置 0,硬件逻辑极简; Sigmoid/Tanh 需要分段线性近似指数,消耗大量 DSP,延迟高。

第 3 题:该 CNN 两层 Affine 全连接在 FPGA 实现存在什么硬件瓶颈?有哪些优化方案?

参考答案: 瓶颈:

  1. 参数量巨大,权重存储占用大量 Block RAM;
  2. 输入维度 3136,单次全连接需要 3136 次乘累加,吞吐低、延迟高; 优化方案:
  3. 时分复用单组 MAC 阵列,分块计算减少 DSP 数量;
  4. 模型量化:32bit 浮点→8bit 定点,降低存储位宽;
  5. 网络结构优化:用全局平均池化替代全连接,消除大量参数;
  6. 权重分块存储,分段读取降低 BRAM 带宽压力。

第 4 题:为什么卷积层必须先做 padding=1(Same Padding),FPGA 硬件上有什么好处?

参考答案:

  1. Same Padding 保证卷积输出特征图长宽与输入一致,窗口滑动控制逻辑统一,不需要区分图像边缘、中间像素的特殊判断;
  2. 硬件计数器、地址生成逻辑简化,控制状态机复杂度降低,时序收敛更简单;
  3. 边缘图像特征完整保留,不会丢失图像四周像素信息,识别精度更高。

题型 3:硬件计算题(FPGA 资源、尺寸计算)

已知:输入 28×28 单通道图像,Conv 3×3 padding=1 stride=1 输出 28×28×16;2×2 MaxPool 输出 14×14×16;全连接输入维度 = 14×14×16。

  1. 计算展平后全连接输入向量维度;
  2. 第一层 Affine1 权重参数量(输入 3136,输出 128);
  3. 若权重使用 int8 定点存储,计算 Affine1 权重总存储 bit 数。

分步计算 + 讲解

  1. 维度:14 × 14 × 16 = 3136 讲解:卷积输出多通道二维特征图,所有像素串行拼接为一维向量送入全连接。
  2. 参数量 = 输入维度 × 输出维度 = 3136 × 128 = 401408 讲解:全连接权重矩阵 W 尺寸 输出维度,输入维度,每一组输入输出对应一个权重参数。
  3. 总 bit = 401408 × 8bit = 3,211,264 bit ≈ 3.2Mbit BRAM 存储需求 讲解:int8 每个权重占用 8bit,该层仅权重就需要约 3.2M 块 RAM 存储,体现全连接存储瓶颈。

题型 4:Verilog 代码改错习题(卷积 ReLU 模块)

错误代码片段

verilog

复制代码
module relu_err #(parameter CH_NUM=16, IN_W=20, OUT_W=8)(
    input clk, rst_n, valid_in,
    input [IN_W-1:0] data_in [0:CH_NUM-1],
    output reg [OUT_W-1:0] data_out [0:CH_NUM-1],
    output reg valid_out
);
integer i;
always @(posedge clk) begin
    valid_out = valid_in;
    for(i=0;i<CH_NUM;i=i+1) begin
        if(data_in[i] < 0)
            data_out[i] <= 0;
        else
            data_out[i] <= data_in[i][7:0];
    end
end
endmodule

错误点 + 修正讲解

  1. 缺失复位 rst_n 时序逻辑,复位时输出未清零,硬件上电状态未知;
  2. data_in[i]是无符号向量,无法直接判断负数,需要signed()有符号转换;
  3. valid_out = valid_in阻塞赋值,时序逻辑必须使用非阻塞<=

修正后片段(对照前文 relu_act.v)

verilog

复制代码
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        valid_out <= 0;
        for(i=0;i<CH_NUM;i=i+1) data_out[i] <= 0;
    end else begin
        valid_out <= valid_in;
        for(i=0;i<CH_NUM;i=i+1) begin
            if($signed(data_in[i]) < 0)
                data_out[i] <= 0;
            else
                data_out[i] <= data_in[i][OUT_W-1:0];
        end
    end
end

四、拓展总结

拓展学习方向

  1. 硬件优化升级:增加流水线、并行 MAC 阵列、权重稀疏化、深度可分离卷积降低资源;
  2. 算子扩展:增加 BatchNorm、Dropout 硬件实现,提升识别精度;
  3. 工程升级:搭建 AXI 总线 CNN 加速器,对接 Zynq ARM 处理器实现软硬件协同;
  4. 精度优化:Softmax 分段线性定点实现,完整复现软件网络推理流程。

文章总结

本文从基础 CNN 流程图出发,完整覆盖软件理论、FPGA 定点 Verilog 硬件工程、配套习题讲解,打通深度学习算法与数字硬件实现的鸿沟,适合 FPGA 图像识别、AI 加速器入门学习,代码可直接在 Xilinx Vivado/Intel Quartus 综合仿真验证。

相关推荐
FPGA小徐3 小时前
FPGA 数字信号处理:并行 FIR 与串行滤波器设计原理、对比与完整 Verilog 实现
fpga开发
Saniffer_SH1 天前
【高清视频】Gen6 服务器还没到,Gen6 SSD 怎么测?Emily 现场演示三种测试环境
人工智能·驱动开发·测试工具·缓存·fpga开发·计算机外设·压力测试
zlinear数据采集卡1 天前
双核架构深度解析:ARM+FPGA如何让数据采集卡实现500Ksps高性能?
arm开发·fpga开发·架构
9527华安1 天前
FPGA实现GTH Transceivers Wizard传输2路视频,基于aurora 8b10b编解码架构,提供4套工程源码和技术支持
fpga开发·gth·aurora 8b10b·transceivers
FPGA小徐2 天前
FPGA 数字信号处理(二):并行 FIR 滤波器的 Verilog 全流程设计与实现
fpga开发
国科安芯2 天前
基于AS32S601ZIT2型抗辐照MCU的商业航天卫星姿态确定与控制系统研究
单片机·嵌入式硬件·安全·fpga开发·架构·risc-v
ALINX技术博客2 天前
【黑金云课堂】FPGA技术教程FPGA基础:I2C 总线通信技术
fpga开发·i2c
Hello-FPGA2 天前
Xilinx KU040 FPGA Camera Link 图像采集
c++·fpga开发
明德扬2 天前
AD采集卡应用示例交流:从传感器采集到高速信号验证
fpga开发