栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

全连接神经网络用C语言实现

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

全连接神经网络用C语言实现

全连接神经网络用C语言实现
    • 一、分析输入输出
    • 二、分析神经网络层数
    • 三、分析神经元数量
    • 四、分析参数数量
    • 五、分析传递过程连接方式
    • 六、代码框架
    • 七、完整代码实现:

关于参数的获取:已经在上篇博客中提出,请参照相关链接请点击

一、分析输入输出

1、手写体输入为28x28的黑白图片,所以输入为784个x
2、输出为识别0-9的数字的概率,所以有10个输出
3、输入只能是-1~1的小数,主要是防止计算溢出

二、分析神经网络层数

如果只是一层,输入784,输出10,中间能记录的神经元只能是10个,很难达到识别0-9这10个数字,所以2层比较合适

三、分析神经元数量

隐藏层神经元数量没有特定的计算方法,主要是靠经验测试,当然设置过多会导致参数太多训练比较困难,太少会达不到识别效果

1、第一层:第一层的神经元没有绝对,这里给64,主要是方便后面上fpga使用

2、第二层:因为一个神经元只有一个输出,而输出的数量是0-9的数字概率,所以第二层神经元为10

四、分析参数数量

1、第一层:因为输入层28x28图片,所以一个神经元有784个w,1个b,64个神经元对应64x784个w,64个b

2、第二层:第一层的64个神经元对应64个输出,第二层输入则为64,所以第二层一个神经元有64个w,1个b,64个神经元对应64x10个w,10个b

五、分析传递过程连接方式

1、第一层:单神经元计算,每个像素点w0x0+w1x1…w783x783+b经过激活函数输出a1,然后拓展给第一层所有神经元

2、第二层:第一层输出a0,a1…a63,单神经元计算,每个像素点w0a0+w1a1…w63a63+b经过激活函数输出a2,然后拓展给第二层所有神经元

注意:推理一般是为了拿到推理结果,不关心概率,所以为了节省运行时间,我们把最后一层激活函数省略

六、代码框架

代码框架:
输入 图片数组,第一层权重,第一层偏置,第二层权重,第二层偏置
输出 推理结果
实现逻辑:
第一层神经网络计算
第二层神经网络计算
查询最大概率的结果输出
//全连接推理
//传入图片大小img 2828
//第一层的权重参数784
64 偏置参数64个 输出64个
//第二层的权重参数64*10 偏置参数10
//找到最大值结果,并返回0-9

int my_predict(float *img, float *w1, float *b1, float *w2, float *b2)
{
	//第一层64个神经元 x 28x28 w 784*64个 b 64个 输出 64个输出 
	//w1x1+w2x2 ... wnxn+b

	//第二层 10个特征0-9 10个神经元  输入连接第一层的输出 64 w 64x10个 b 10个 输出10个 
	//w1x1+w2x2 ... wnxn+b

	//查询那个特征值的概率最大,返回
}
七、完整代码实现:
#include 
#include 
//导入图片
#include "input_0.h"
#include "input_1.h"
#include "input_2.h"
#include "input_3.h"
#include "input_4.h"
#include "input_5.h"
#include "input_6.h"
#include "input_7.h"
#include "input_8.h"
#include "input_9.h"

#include 
//导入权重w和偏置b
#include "layer1_weight.h"
#include "layer1_bais.h"
#include "layer2_weight.h"
#include "layer2_bais.h"

//输入图片  28*28 
//layer1 神经元 64个  w:784*64   b:64
//layer2 神经元 10    w:64*10    b:10
//计算概率最大的值并返回

int predict(float *img,float *w1,float *b1,float *w2,float *b2)
{
    int i,j;
    float y;
    float a1[64],a2[10];
    int ret;
    //第一层计算
    //多个神经元计算
    for(i=0;i<64;i++)
    {
        //单个神经元计算
        //y=w0*x0+w1*x1+w2*x2+...+w783*x783 + b
        y = 0.0;
        for(j=0;j<784;j++)
        {
            y =  y + w1[j*64+i]*img[j]; 
        }
        //加偏置
        y = y + b1[i];
        //加激活  relu  将线性转化为非线性
        y = y > 0?y:0;

        a1[i] = y;    //将单个神经元的值保存下来
        // y = 0.0;
    }
    //y = 0.0;
    //第二层计算
    //多个神经元计算
    for(i=0;i<10;i++)
    {
        y = 0.0;
        for(j=0;j<64;j++)
        {
            //单点计算  
            //y=w0*x0+w1*x1+w2*x2+...+w63*x63 + b
            y = y + w2[i+10*j]*a1[j];
        }
        //加偏置
        y = y + b2[i];
        a2[i] = y;
    }
    y = 0.0;
    //计算概率最大值
    for(i=0;i<10;i++)
    {
        if(a2[i] > y)
        {
            y = a2[i];
            ret = i;
        }
    }
    return ret;
}

void full_connect_test()
{
    int ret;
    float *imgx[10]={
        input_0,
        input_1,
        input_2,       
        input_3,
        input_4,
        input_5,
        input_6,
        input_7,
        input_8,
        input_9
    };
    
    double run_time;
    LARGE_INTEGER time_start;	//开始时间
	LARGE_INTEGER time_over;	//结束时间
	double dqFreq;		//计时器频率
	LARGE_INTEGER f;	//计时器频率
	QueryPerformanceFrequency(&f);
	dqFreq=(double)f.QuadPart;
    
    for(int i=0;i<10;i++)
    {
        
	    QueryPerformanceCounter(&time_start);	//计时开始
	    ret = predict(imgx[i],layer1_weight,layer1_bais,layer2_weight,layer2_bais);
	    QueryPerformanceCounter(&time_over);	//计时结束
	    run_time=1000000*(time_over.QuadPart-time_start.QuadPart)/dqFreq;
	    //乘以1000000把单位由秒化为微秒,精度为1000 000/(cpu主频)微秒
	    printf("nrun_time:%fusn",run_time);

        //clock_t start = clock();
        //ret = predict(imgx[i],layer1_weight,layer1_bais,layer2_weight,layer2_bais);
        //clock_t end = clock();
        //double runtime = (double)(end - start) / CLOCKS_PER_SEC;
        //printf("runtime:%f s ",runtime);

        printf("input is %d ,predict:%dn",i,ret);
    }
}
int main()
{
    full_connect_test();
    return 0;
}

运行结果如下:

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/384887.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号