运用C语言编写Lenet-5(一)

在运用Vivado HLS生成IP Core的过程中,HLS只能综合C或者C++语言,之前用于编写卷积神经网络的一直都是运用Python语言,虽然学习过C语言但是对它已经很陌生了,这里详细记录以下用C语言实现lenet-5的过程,希望对大家有所帮助。下面的代码是我在github上下载下来进行阅读的。

1、对卷积的定义

#include "lenet.h"
#include <memory.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>

#define GETLENGTH(array) (sizeof(array)/sizeof(*(array)))

#define GETCOUNT(array)  (sizeof(array)/sizeof(double))

#define FOREACH(i,count) for (int i = 0; i < count; ++i)

#define CONVOLUTE_VALID(input,output,weight)                                            
{                                                                                       
    FOREACH(o0,GETLENGTH(output))                                                       
        FOREACH(o1,GETLENGTH(*(output)))                                                
            FOREACH(w0,GETLENGTH(weight))                                               
                FOREACH(w1,GETLENGTH(*(weight)))                                        
(output)[o0][o1] += (input)[o0 + w0][o1 + w1] * (weight)[w0][w1]; 

以上代码中,反复用到了GETLENGTH这个函数,由于对C语言目前比较生疏,我重新翻看相关知识,其中涉及到了指针、sizeof等。

  1. sizeof
    sizeof运算符以字节为单位返回运算对象的大小,运算对象可以是具体的数据对象或类型。

  2. 指针

指针是一个值为内存地址的变量。需要用到间接运算符 * ,如果前面有带 * ,这表示是相应地址的值。
具体的知识可以通过网络或者书籍进行查询。

#define GETLENGTH(array) (sizeof(array)/sizeof(*(array)))

这个语句中,对GETLENGTH函数进行了定义,输入的是一个矩阵,输出的是矩阵中的行数。sizeof计算的是整个矩阵的字节长度,而*(array)表示的是第一行有多少个字节,因为每一行的字节数都相等,所以两者相除求出的就是有多少行。

#define FOREACH(i,count) for (int i = 0; i < count; ++i)

本句代表定义一个FOREACH函数来遍历每个数。

#define CONVOLUTE_VALID(input,output,weight)                                            
{                                                                                       
    FOREACH(o0,GETLENGTH(output))                                                       
        FOREACH(o1,GETLENGTH(*(output)))                                                
            FOREACH(w0,GETLENGTH(weight))                                               
                FOREACH(w1,GETLENGTH(*(weight)))                                        
                    (output)[o0][o1] += (input)[o0 + w0][o1 + w1] * (weight)[w0][w1]; 
   }

本段是进行卷积操作,padding=VALID类型的定义,运用了四个for循环,计算出最终卷积的结果,这里的定义十分巧妙,花时间去理解。

#define CONVOLUTE_FULL(input,output,weight)                                             \
{                                                                                       \
    FOREACH(i0,GETLENGTH(input))                                                        \
        FOREACH(i1,GETLENGTH(*(input)))                                                 \
            FOREACH(w0,GETLENGTH(weight))                                               \
                FOREACH(w1,GETLENGTH(*(weight)))                                        \
                    (output)[i0 + w0][i1 + w1] += (input)[i0][i1] * (weight)[w0][w1]; 
   }

这段代码是对padding=SAME的定义。

#define CONVOLUTION_FORWARD(input,output,weight,bias,action)                    
{                                                                               
    for (int x = 0; x < GETLENGTH(weight); ++x)                                 
        for (int y = 0; y < GETLENGTH(*weight); ++y)                            
            CONVOLUTE_VALID(input[x], output[y], weight[x][y]);                 
    FOREACH(j, GETLENGTH(output))                                               
        FOREACH(i, GETCOUNT(output[j]))                                         
        ((double *)output[j])[i] = action(((double *)output[j])[i] + bias[j]);  
}

本段代码中加了偏置和激活函数,并且对前面定义的卷积运算进行了调用,得到的是前向传播过程中卷积加上偏置还有激活函数处理后所得到的结果。

LeNet-5神经网络 C源代码,这个写的比较好,可以用gcc编译去跑,结合理论可以对深度学习有更深刻的了解 介绍 根据YANN LECUN的论文《Gradient-based Learning Applied To Document Recognition》设计的LeNet-5神经网络,C语言写成,不依赖任何第三方库。 MNIST手写字符集初代训练识别率97%,多代训练识别率98%。 DEMO main.c文件为MNIST数据集的识别DEMO,直接编译即可运行,训练集60000张,测试集10000张。 项目环境 该项目为VISUAL STUDIO 2015项目,用VISUAL STUDIO 2015 UPDATE1及以上直接打开即可编译。采用ANSI C编写,因此源码无须修改即可在其它平台上编译。 如果因缺少openmp无法编译,请将lenet.c中的#include和#pragma omp parallel for删除掉即可。 API #####批量训练 lenet: LeNet5的权值的指针,LeNet5神经网络的核心 inputs: 要训练的多个图片对应unsigned char二维数组的数组,指向的二维数组的batchSize倍大小内存空间指针。在MNIST测试DEMO中二维数组为28x28,每个二维数组数值分别为对应位置图像像素灰度值 resMat:结果向量矩阵 labels:要训练的多个图片分别对应的标签数组。大小为batchSize batchSize:批量训练输入图像(二维数组)的数量 void TrainBatch(LeNet5 *lenet, image *inputs, const char(*resMat)[OUTPUT],uint8 *labels, int batchSize); #####单个训练 lenet: LeNet5的权值的指针,LeNet5神经网络的核心 input: 要训练的图片对应二维数组 resMat:结果向量矩阵 label: 要训练的图片对应的标签 void Train(LeNet5 *lenet, image input, const char(*resMat)[OUTPUT],uint8 label); #####预测 lenet: LeNet5的权值的指针,LeNet5神经网络的核心 input: 输入的图像的数据 labels: 结果向量矩阵指针 count: 结果向量个数 return 返回值为预测的结果 int Predict(LeNet5 *lenet, image input, const char(*labels)[LAYER6], int count); #####初始化 lenet: LeNet5的权值的指针,LeNet5神经网络的核心
### 回答1: LeNet-5是一种经典的卷积神经网络模型,常用于手写数字识别任务。HLS(High-Level Synthesis)是针对FPGA设计的一种高级综合工具,它可以将高级语言如C/C++代码转化为硬件描述语言。 要实现LeNet-5模型的HLS版本,我们可以按照以下步骤进行: 1. 首先,我们需要将LeNet-5的网络结构进行转换,以适应HLS工具的要求。LeNet-5由两个卷积层、两个池化层和三个全连接层组成。我们需要将这些层的相应操作转化为HLS中的硬件描述。例如,卷积操作可以使用HLS中的乘法器和加法器实现,池化操作可以使用选择器进行。 2. 接下来,我们可以使用HLS工具中的数据流和并行指令来优化LeNet-5的实现。通过合理地划分和并行化计算以及使用流水线技术,可以提高模型的效率和速度。 3. 在转换为HLS代码后,我们可以使用HLS工具提供的仿真功能进行测试和验证。通过在测试数据上运行HLS代码,我们可以确保模型在硬件上的实现与预期输出一致。 4. 最后,我们可以将HLS代码综合为目标FPGA设备上的位文件。通过将生成的位文件加载到FPGA上,我们就可以在硬件平台上运行LeNet-5模型进行手写数字识别任务了。 总之,通过使用HLS工具,我们可以将LeNet-5模型从C语言代码转化为硬件实现,并在FPGA上运行,以提高其性能和效率。这种转换过程需要注意HLS工具的特性和限制,并进行适当的优化和测试,以确保模型的正确性和可靠性。 ### 回答2: Lenet-5是一种经典的卷积神经网络(CNN)结构,由Yann LeCun在1998年提出。要在HLS(高层次综合)中实现Lenet-5,主要需要将Lenet-5网络结构转换为可在HLS工具中使用的硬件描述语言(HDL)。 Lenet-5网络结构主要包含七个层级:两个卷积层,两个池化层和三个全连接层。在HLS实现Lenet-5时,每个层级都需要进行适当的转换。 首先是卷积层。在HLS中,可以使用具有适当参数的卷积内核来表示卷积层。通过在HDL描述文件中定义卷积核的大小、步长和填充,可以实现卷积层。 第二是池化层。池化层的操作可以通过在HDL描述文件中定义池化区域的大小和类型来实现。常用的是最大池化和平均池化。 第三是全连接层。全连接层可以通过使用适当的权重矩阵和偏置向量来实现。在HLS中,可以使用乘法和加法操作来实现全连接层。 最后,在HLS工具中,需要将输入数据流和输出数据流与适当的处理单元(如DSP、BRAM等)进行连接,以实现完整的Lenet-5网络结构。 实现完成后,可以对HLS代码进行综合、优化和验证,以生成可在FPGA上运行的硬件实现。在FPGA上运行Lenet-5可以进行图像分类、目标检测等任务。 总而言之,要在HLS中实现Lenet-5,需要将Lenet-5网络结构转化为HDL代码,并对其进行综合、优化和验证,最终生成可在FPGA上运行的硬件实现。这样就能够利用硬件加速的方式快速处理Lenet-5网络的图像识别任务。 ### 回答3: Lenet-5是一个经典的卷积神经网络模型,常用于手写数字识别任务。HLS(High-Level Synthesis)是一种用于FPGA(Field-Programmable Gate Array)的高级综合工具,可以将C/C++代码转化为硬件描述语言(HDL)。 实现Lenet-5模型的HLS过程主要包括以下几个步骤: 1. 定义Lenet-5的网络结构:Lenet-5由两个卷积层、两个池化层和三个全连接层组成。在C代码中,我们需要定义网络的各层结构、参数和激活函数。 2. 数据预处理:在Lenet-5中,输入图像为32x32的灰度图像。我们可以使用C代码读取输入图像,并对其进行预处理,如图像缩放和归一化等操作。 3. 卷积计算:在C代码中,我们可以使用循环嵌套来实现卷积计算。对于每个卷积层,我们需要定义卷积核的大小和数量,并对输入图像进行卷积操作。卷积操作可以通过计算每个卷积核与输入图像的点积得到输出特征图。 4. 池化计算:在C代码中,我们可以使用循环嵌套来实现池化计算。对于每个池化层,我们需要定义池化窗口的大小和步长,并对卷积层的输出特征图进行池化操作。常用的池化操作有最大池化和平均池化,可以根据需求选择适合的池化方法。 5. 全连接计算:在C代码中,我们可以使用矩阵乘法和激活函数来实现全连接计算。对于每个全连接层,我们需要定义权重矩阵和偏置向量,并对前一层的输出进行矩阵乘法运算,然后通过激活函数进行非线性映射。 6. 输出结果:在C代码中,我们可以将最后一个全连接层的输出结果与标签进行比较,计算损失并进行反向传播。 通过以上步骤,我们可以使用C语言编写Lenet-5模型的HLS实现。在完成C代码编写后,可以使用HLS工具将C代码转化为HDL代码,以便在FPGA上进行硬件加速计算。这样可以实现Lenet-5模型的高效部署和运行,提高模型的执行速度和计算效率。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值