一起学习用Verilog在FPGA上实现CNN----(七)全连接层设计
1 全连接层设计
1.1 Layer
进行线性计算的单元layer,原理图如图所示:

1.2 processingElement
Layer中的线性计算单元processingElement,原理图如图所示:

processingElement模块展开原理图,如图所示,包含一个乘法器和一个加法器,对输入进行累乘和累加

1.3 weightMemory
全连接层的权重存储于weightMemory单元,原理图如图所示:

2 代码实现
2.1 weightMemory
2.1.1 设计输入
创建weightMemory文件,操作如图:

双击打开,输入代码:
module weightMemory(clk,address,weights);parameter DATA_WIDTH = 32;
parameter INPUT_NODES = 100;
parameter OUTPUT_NODES = 32;
parameter file = "E:/FPGA_Learn/FPGA/Day1211/Weight/weightsdense_1_IEEE.txt";localparam TOTAL_WEIGHT_SIZE = INPUT_NODES * OUTPUT_NODES;input clk;
input [7:0] address;
output reg [DATA_WIDTH*OUTPUT_NODES-1:0] weights;reg [DATA_WIDTH-1:0] memory [0:TOTAL_WEIGHT_SIZE-1];integer i;always @ (posedge clk) begin if (address > INPUT_NODES-1 || address < 0) beginweights = 0;end else beginfor (i = 0; i < OUTPUT_NODES; i = i + 1) beginweights[(OUTPUT_NODES-1-i)*DATA_WIDTH+:DATA_WIDTH] = memory[(address*OUTPUT_NODES)+i];endend
endinitial begin$readmemh(file,memory);
endendmodule
如图所示:

2.1.2 分析与综合
将weightMemory设置为顶层:

关闭上次分析文件:

对设计进行分析,操作如图:

分析后的设计,Vivado自动生成原理图,如图:

原理图如图:

对设计进行综合,操作如图:

综合完成,关闭即可
2.1.3 功能仿真
创建仿真激励文件,操作如图:

双击打开,输入激励代码:
module tb_weightMemroy();reg clk;
reg [6:0] address;
wire [32*32-1:0] weights;localparam PERIOD = 100;always#(PERIOD/2) clk = ~clk;initial begin#0clk = 1'b0;address = 0;#PERIODaddress = 1;#PERIOD address = 2;#PERIODaddress = 32;#PERIOD$stop;
endweightMemory UUT
(.clk(clk),.address(address),.weights(weights)
);endmodule
如图所示:

将tb_weightMemory设置为顶层:

开始进行仿真,操作如下:

仿真波形,如图:

仿真结束,关闭仿真:

2.2 processingElement
2.2.1 设计输入
创建processingElement文件,操作如图:

双击打开,输入代码:
module processingElement(clk,reset,floatA,floatB,result);parameter DATA_WIDTH = 32;input clk, reset;
input [DATA_WIDTH-1:0] floatA, floatB;
output reg [DATA_WIDTH-1:0] result;wire [DATA_WIDTH-1:0] multResult;
wire [DATA_WIDTH-1:0] addResult;floatMult FM (floatA,floatB,multResult);
floatAdd FADD (multResult,result,addResult);always @ (posedge clk or posedge reset) beginif (reset == 1'b1) beginresult = 0;end else beginresult = addResult;end
endendmodule
如图所示:

2.2.2 分析与综合
将processingElement设置为顶层:

对设计进行分析,操作如图:

分析后的设计,Vivado自动生成原理图,如图:

对设计进行综合,操作如图:

综合完成,关闭即可:

2.2.3 功能仿真
创建仿真激励文件,操作如图:

双击打开,输入激励代码:
module tb_processingElement();reg clk,reset;
reg [31:0] floatA, floatB;
wire [31:0] result;localparam PERIOD = 100;always#(PERIOD/2) clk = ~clk;initial begin#0clk = 1'b0;reset = 1;// A = 2 , B = 3floatA = 32'b01000000000000000000000000000000;floatB = 32'b01000000010000000000000000000000;#(PERIOD/4)reset = 0;// A = 1 , B = 5#(3*PERIOD/4)floatA = 32'b00111111100000000000000000000000;floatB = 32'b01000000101000000000000000000000;#(3*PERIOD/2)reset = 1;#(PERIOD)$stop;
endprocessingElement PE
(.clk(clk),.reset(reset),.floatA(floatA),.floatB(floatB),.result(result)
);endmodule
如图所示:

将tb_processingElement设置为顶层:

开始进行仿真,操作如下:

仿真波形,如图:

仿真结束,关闭仿真:

2.3 Layer
2.3.1 设计输入
创建Layer文件,操作如图:

输入文件名:

确定创建:

双击打开,输入代码:
module layer(clk,reset,input_fc,weights,output_fc);parameter DATA_WIDTH = 32;
parameter INPUT_NODES = 100;
parameter OUTPUT_NODES = 32;input clk, reset;
input [DATA_WIDTH*INPUT_NODES-1:0] input_fc;
input [DATA_WIDTH*OUTPUT_NODES-1:0] weights;
output [DATA_WIDTH*OUTPUT_NODES-1:0] output_fc;reg [DATA_WIDTH-1:0] selectedInput;
integer j;genvar i;generatefor (i = 0; i < OUTPUT_NODES; i = i + 1) beginprocessingElement PE (.clk(clk),.reset(reset),.floatA(selectedInput),.floatB(weights[DATA_WIDTH*i+:DATA_WIDTH]),.result(output_fc[DATA_WIDTH*i+:DATA_WIDTH]));end
endgeneratealways @ (posedge clk or posedge reset) beginif (reset == 1'b1) beginselectedInput = 0;j = INPUT_NODES - 1;end else if (j < 0) beginselectedInput = 0;end else beginselectedInput = input_fc[DATA_WIDTH*j+:DATA_WIDTH];j = j - 1;end
endendmodule
如图所示:

2.3.2 分析与综合
将Layer设置为顶层:

关闭上次的分析文件:

对设计进行分析,操作如图:

分析后的设计,Vivado自动生成原理图,如图:

原理图如图:

对设计进行综合,操作如图:

综合完成,关闭即可:

2.3.3 功能仿真
创建仿真激励文件,操作如图:

双击打开,输入激励代码:
module tb_layer();
reg clk, reset;
reg [32*100-1:0] input_fc;
wire [32*32-1:0] weights;
wire [32*32-1:0] output_fc;reg [7:0] address;localparam PERIOD = 100;always#(PERIOD/2) clk = ~clk;always @ (posedge clk or posedge reset) beginif (reset == 1'b1) beginaddress = 0;end else beginaddress = address + 1;end
endweightMemory WM
(.clk(clk),.address(address),.weights(weights)
);initial begin#0clk = 1'b0;reset = 1'b1;input_fc = 3200'b00111110110101101010010110110100001111110011010001110101011100000011111100101101101110010110001000111110101011101000010101010100001111110110000001111111101110100011111011000011010010010111101000111111011111001000101111111100001111110111001000101111111000000011111101011010001000111010111000111111011101000000011111101110001111100010111111011001011101100011111100000010101100110000001000111110101010010111100101011010001111101100110010000101101000000011111101111011101001111111110000111110011010111101000111101110001111110110011010000011110100100011111101101111110100011101110000111110101011011010100101100100001111100001000110100001000100100011111100010001101100110010100000111111001011100010000101100100001111110111100011001101111010100011111010100100100001010011110000111111010011010100111110011100001111110010101001000011010101100011111101111100000000000000000000111110101010001011100101010110001111110100110001101111100111000011111000001100010010010011010000111111000110110111111100111000001111011001010011100001001010100011111100001100000001110001010000111111000000111101100100000010001111110110111100001011111000000011111100111000110101110110101000111111001011110010100101011110001111110110111101110111111000100011111101101001101000011100101000111111010110110100010110111110001111110011000111010101010111100011111101001000000100011001000000111110110001001110100110000000001111101111011010111101111101000011111011110100011110011111011000111101110110011001000110111100001111101110000100001101101111100011110110101010011000010101101000111111010100001000110110100000001111101011010011101101011100000011111101100000101000011011111000111110101110111001010110000000001111110100010100110011100011100011111010010001011000010001110000111101010111101000000110110000001111110101100010001101101100000011111100001101101010010010001000111111000000111001100100001010001111110110010011011011110011100011111101101111001100111101101000111111010111111011100110111110001111110001000111101011001000000011111010110001110010010111000000111111001100001010001101100010001111101010011010010001010000100011111101011110000100111100001000111101101000101100000101000110001111110110000011111011110010100011111101010010101000111010110000111111000001010101101100000010001111110010101100000101010100100011111100000001111101010000011000111111001000010011100101000010001111101100011100001101100001000011110110111001100100010111100000111110111101111001110111110100001110110111000000000001110110100011111010000110000011010000001000111111010010010011011110001110001111110000111010110101000111000011111101111101111010111111101000111111000110011001101100101100001111011000101110000001000101000011111001010010100010011001100000111110110100011001010110101010001111110011100101111011011101000011111000110011010110010111100000111111000110111101100100110100001111110000011101111011000001100011111101011111000000111100000000111111001110111111111101111010001111101100001101100101100010000011111100000100011111010000101000111100001100111000000100110110001111110110110010100011110101100011111001011000011110011100010000111110000100101010000100110000001111110101100001110101101101000011110111101101011100011111001000111101011101111110000111101110;#PERIODreset = 1'b0;#(102*PERIOD)$stop;
endlayer UUT
(.clk(clk),.reset(reset),.input_fc(input_fc),.weights(weights),.output_fc(output_fc)
);
endmodule
如图所示:

将tb_layer设置为顶层:

开始进行仿真,操作如下:

仿真波形,如图:

仿真结束,关闭仿真:

2.4 integrationFC
2.4.1 设计输入
打开integrationFC文件,输入代码:
module integrationFC(clk,reset,iFCinput,CNNoutput);parameter DATA_WIDTH = 32;
parameter IntIn = 120;
parameter FC_1_out = 84;
parameter FC_2_out = 10;input clk, reset;
input [IntIn*DATA_WIDTH-1:0] iFCinput;
output [FC_2_out*DATA_WIDTH-1:0] CNNoutput;wire [FC_1_out*DATA_WIDTH-1:0] fc1Out;
wire [FC_1_out*DATA_WIDTH-1:0] fc1OutTanh;wire [FC_2_out*DATA_WIDTH-1:0] fc2Out;
wire [FC_2_out*DATA_WIDTH-1:0] fc2OutSMax;wire [DATA_WIDTH*FC_1_out-1:0] wFC1;
wire [DATA_WIDTH*FC_2_out-1:0] wFC2;reg FC1reset;
reg FC2reset;
reg SMaxEnable;
wire DoneFlag;reg [7:0] address1;weightMemory
#(.INPUT_NODES(IntIn),.OUTPUT_NODES(FC_1_out),.file("E:/FPGA_Learn/FPGA/Day1211/Weight/weightsdense_1_IEEE.txt"))W1(.clk(clk),.address(address1),.weights(wFC1));layer
#(.INPUT_NODES(IntIn),.OUTPUT_NODES(FC_1_out))FC1(.clk(clk),.reset(FC1reset),.input_fc(iFCinput),.weights(wFC1),.output_fc(fc1Out));
layer
#(.INPUT_NODES(FC_1_out),.OUTPUT_NODES(FC_2_out))FC2(.clk(clk),.reset(FC2reset),.input_fc(fc1OutTanh),.weights(wFC2),.output_fc(fc2Out));
softmax SMax(.inputs(fc2Out),.clk(clk),.enable(SMaxEnable),.outputs(CNNoutput),.ackSoft(DoneFlag));endmodule
如图所示:

2.4.2 分析与综合
将integrationFC设置为顶层:

关闭上次的分析文件:

对设计进行分析,操作如图:

分析后的设计,Vivado自动生成原理图,如图:

希望本文对大家有帮助,上文若有不妥之处,欢迎指正
分享决定高度,学习拉开差距
相关文章:
一起学习用Verilog在FPGA上实现CNN----(七)全连接层设计
1 全连接层设计 1.1 Layer 进行线性计算的单元layer,原理图如图所示: 1.2 processingElement Layer中的线性计算单元processingElement,原理图如图所示: processingElement模块展开原理图,如图所示,包含…...
tomcat打debug断点调试
windows debug调试 jdk版本:1.8.0_181 tomcat版本:apache-tomcat-9.0.68.0 idea版本:2020.1 方法一 修改catalina.bat 在%CATALINA_HOME%\bin\catalina.bat中找到 set “JAVA_OPTS%JAVA_OPTS% -Djava.protocol.handler.pkgsorg.apache…...
如果持有互斥锁的线程没有解锁退出了,该如何处理?
文章目录如果持有互斥锁的线程没有解锁退出了,该如何处理?问题引入PTHREAD_MUTEX_ROBUST 和 pthread_mutex_consistent登场了结论:如果持有互斥锁的线程没有解锁退出了,该如何处理? 问题引入 看下面一段代码…...
信息论绪论
本专栏针包含信息论与编码的核心知识,按知识点组织,可作为教学或学习的参考。markdown版本已归档至【Github仓库:information-theory】,需要的朋友们自取。或者关注公众号【AIShareLab】,回复 信息论 也可获取。 文章目…...
Buffer Status Reporting(BSR)
欢迎关注同名微信公众号“modem协议笔记”。 以一个实网中的异常场景开始,大概流程是有UL data要发送,UE触发BSR->no UL grant->SR->no UL grant->trigger RACH->RACH fail->RLF->RRC reestablishment:简单描述就是UE触…...
代码随想录LeetCode | 单调栈问题
前沿:撰写博客的目的是为了再刷时回顾和进一步完善,其次才是以教为学,所以如果有些博客写的较简陋,是为了保持进度不得已而为之,还请大家多多见谅。 预:看到题目后的思路和实现的代码。 见:参考…...
C++之可调用对象、bind绑定器和function包装器
可调用对象在C中,可以像函数一样调用的有:普通函数、类的静态成员函数、仿函数、lambda函数、类的非静态成员函数、可被转换为函数的类的对象,统称可调用对象或函数对象。可调用对象有类型,可以用指针存储它们的地址,可…...
MongoDB--》文档查询的详细具体操作
目录 统计查询 分页列表查询 排序查询 正则的复杂条件查询 比较查询 包含查询 条件连接查询 统计查询 统计查询使用count()方法,其语法格式如下: db.collection.count(query,options) ParameterTypeDescriptionquerydocument查询选择条件optio…...
网络协议(六):网络层
网络协议系列文章 网络协议(一):基本概念、计算机之间的连接方式 网络协议(二):MAC地址、IP地址、子网掩码、子网和超网 网络协议(三):路由器原理及数据包传输过程 网络协议(四):网络分类、ISP、上网方式、公网私网、NAT 网络…...
热启动预示生态起航的Smart Finance,与深度赋能的SMART通证
2023年初加密市场的回暖,意味着各个赛道都将在新的一年里走向新的叙事。最近,我们看到GameFi赛道也在市场回暖的背景下,逐渐走出阴霾。从融资数据上看,1月获得融资的GameFi项目共12个,融资突破8000万美元,1…...
提分必练,中创教育PMP全真模拟题分享
湖南中创教育每日五题分享来啦,“日日行,不怕千万里;常常做,不怕千万事。”,每日五题我们练起来! 1、在系统测试期间,按已识别原因的类型或类别记录了失败测试的数量。项目经理首先需要从最大故…...
PID控制算法基础介绍
PID控制的概念 生活中的一些小电器,比如恒温热水器、平衡车,无人机的飞行姿态和飞行速度控制,自动驾驶等等,都有应用到 PID——PID 控制在自动控制原理中是一套比较经典的算法。 为什么需要 PID 控制器呢? 你一定用…...
Ajax 学习笔记
一、Ajax1.1 什么是AjaxAJAX Asynchronous JavaScript and XML(异步的JavaScript和XML)。Ajax是一种在无需加载整个网页的情况下,能够更新部分网页的技术,它不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术…...
力扣解法汇总1234. 替换子串得到平衡字符串
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣 描述: 有一个只含有 Q, W, E, R 四种字符,且长度为 n 的字符串。 假如在该…...
C++关键字之const、inline、static
C 关键字总结 1.const const是 constant 的缩写,本意是不变的、不易改变的意思。在C中用来修饰内置类型变量,自定义对象,成员函数,返回值,函数参数使用如下: //修饰普通类型变量 const int a 7; int ba;…...
【成为架构师课程系列】怎样进行概念架构(Conceptual Architecture)?
目录 前言 什么是概念架构 概念架构阶段的3个步骤 初步设计 高层分割 分层式概念服务架构 Layer:逻辑层 Tier: 物理层 按通用性分层 技术堆叠 考虑非功能需求 【禅与计算机程序设计艺术:更多阅读】 前言 胜兵先胜而后求战,败兵先站而后求胜。…...
PostgreSQL的下载安装教程(macOS、Windows)
postgresql是GIS服务端几乎不可避免要打交道的数据库。因为mysql的空间扩展真是不尽人意。所以想要学会GIS服务端知识,postgresql(下文简称pg)你是必须要会的。 首先要知道,pg是一个空间数据库,和普通数据库不同的是pg支持空间数据的存储与操作。这里所谓的空间数据一般指…...
98年的确实卷,公司新来的卷王,我们这帮老油条真干不过.....
都说00后躺平了,但是有一说一,该卷的还是卷。这不,前段时间我们公司来了个00后,工作没两年,跳槽到我们公司起薪18K,都快接近我了。后来才知道人家是个卷王,从早干到晚就差搬张床到工位睡觉了。 …...
软件架构知识2-系统复杂度
架构设计的真正目的:是为了解决软件系统复杂度带来的问题,一个解决方案。 系统复杂度,如何入手: 1、通过熟悉和理解需求,识别系统复杂性所在的地方,然后针对这些复杂点进行架构设计。 2、架构设计并不是要…...
JavaSE学习day4_02 数组(超级重点)
3.数组 3.1什么是数组 数组就是存储数据长度固定的容器,存储多个数据的数据类型要一致。 3.2数组定义格式 3.2.1第一种(常用) 数据类型[] 数组名 示例: int[] arr; double[] arr; char[] arr; 3.2.2第二种(在…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
Qt的学习(一)
1.什么是Qt Qt特指用来进行桌面应用开发(电脑上写的程序)涉及到的一套技术Qt无法开发网页前端,也不能开发移动应用。 客户端开发的重要任务:编写和用户交互的界面。一般来说和用户交互的界面,有两种典型风格&…...
【PX4飞控】mavros gps相关话题分析,经纬度海拔获取方法,卫星数锁定状态获取方法
使用 ROS1-Noetic 和 mavros v1.20.1, 携带经纬度海拔的话题主要有三个: /mavros/global_position/raw/fix/mavros/gpsstatus/gps1/raw/mavros/global_position/global 查看 mavros 源码,来分析他们的发布过程。发现前两个话题都对应了同一…...
RabbitMQ 各类交换机
为什么要用交换机? 交换机用来路由消息。如果直发队列,这个消息就被处理消失了,那别的队列也需要这个消息怎么办?那就要用到交换机 交换机类型 1,fanout:广播 特点 广播所有消息:将消息…...
