iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++实现神经网络框架SimpleNN的详细过程
  • 923
分享到

C++实现神经网络框架SimpleNN的详细过程

2024-04-02 19:04:59 923人浏览 泡泡鱼
摘要

目录Features DependenciesPlatfORMTo DoUsageSimpleNN is a simple neural network framework

SimpleNN is a simple neural network framework written in c++.It can help to learn how neural networks work.
源码地址:https://GitHub.com/Kindn/SimpleNN

Features

  • Construct neural networks.
  • Configure optimizer and loss layer for the network to train models and use models to do prediction.Save models.
  • Network architecture will be saved as a .netJSON file,while weights will be saved as a .weightsbinary file.
  • Load models.Load network from an existing .netfile and load weights from an existing .weights.Load dataset (including data and labels) from a .csvfile.It is neccesary to preprocess the dataset(mnist etc.) into SimpleNN stype 2D matrix and save it into a .csvfile.All data in SimpleNN will be organized into columns and conbined into a 2D matrix.
  • For example,mostly a batch of C C C channels H H Hx W W W images with batch size N N N will be flatten into columns by channel and organized into an ( H ∗ W ) (H*W) (H∗W)x ( C ∗ N ) (C*N) (C∗N) matrix.构建自定义网络
  • 为网络对象配置优化器和损失函数层来训练模型,并用模型作预测。
  • 保存模型。网络结构用json格式描述,扩展名为 .net;权重存为二进制文件,扩展名为.weights
  • 加载模型。从已有的.net文件中加载网络,从已有的.weights文件中加载权重。
  • .csv文件中加载数据集。在此之前需要对原始数据集(如mnist等)进行预处理组织为一个二维矩阵。
  • 在SimpleNN中流动的所有数据都是组织成一列列的并组合成一个二维矩阵。

例如,大多数情况下一批batch size为 N N N 的 C C C 通道 H H Hx W W W 图像会按通道展开成列并组织为一个 ( H ∗ W ) (H*W) (H∗W)x ( C ∗ N ) (C*N) (C∗N)的矩阵。

 Dependencies

The core of SimpleNN is completely written with C++11 STL.So to build SimpleNN it just need a C++ compiler surppoting C++11 stantard.

P.S.:Some examples in examplesfolder needs 3rd-party libraries like OpenCV3.So if you want to build them as well you may install the needed libraries first.

Platform

Any os with C++11 compiler.

To Do

  • 丰富layers和nets。
  • 实现AutoGradient,使之可基于计算图构造网络。
  • 利用并行计算实现矩阵运算等过程的加速优化(多线程、GPU),目前所有矩阵运算都是用for循环硬堆的,毫无性能可言。。。
  • 利用自己造的这个轮子复现更多的神经网络模型。
  • 为什么用二维矩阵来存储数据呢主要是因为一开始只是写了一个二维矩阵运算模板类,然后就想直接用这个类实现神经网络。一般情况下这种数据处理方法应该是够用的,后面看如果有必要的话再实现一个四维的Tensor类。

本来自己想到用C++实现神经网络主要是想强化一下编码能力并入门深度学习,所以我会尽力亲自从头实现以上功能,欢迎各位大佬们批评指点!

Usage

1.Build


git clone 
cd SimpleNN
mkdir build
cd build
cmake ..
make

2.Run examples(linux)

examples都在examples目录下,以例子recognition为例。本例是利用图像分割和LeNet进行数字识别。

若目标数字是黑底白字,则在终端输入(假设终端在SimpleNN根目录下打开)


examples/mnist/recognition <image_path>

效果:

在这里插入图片描述在这里插入图片描述

若目标数字是黑底白字,则输入


examples/mnist/recognition <image_path> --reverse

在mnist目录下已有训练好的LeNet权重参数。若要运行examples/mnist/train,需要先在examples/mnist/dataset目录下运行generate_csv.py来生成数据集的csv文件(这个文件有400多M属于大文件试了好多种都push不上来QAQ)。

注:本例依赖OpenCV3,如果要运行须事先安装,不然不会编译本例。

3.coding

Construct network


int input_img_rows1 = 28;
                int input_img_cols1 = 28;
                int input_img_channels1 = 1;

                int conv_output_img_channels1 = 6;
                int conv_filter_rows1 = 5;
                int conv_filter_cols1 = 5;
                int conv_row_pads1 = 0;
                int conv_col_pads1 = 0;
                int conv_row_strides1 = 1;
                int conv_col_strides1 = 1;

                std::shared_ptr<snn::Convolution> conv_layer1(new snn::Convolution(input_img_rows1, input_img_cols1, 
                                                            input_img_channels1, 
                                                            conv_output_img_channels1, 
                                                            conv_filter_rows1, conv_filter_cols1, 
                                                            conv_row_pads1, conv_col_pads1, 
                                                            conv_row_strides1, conv_col_strides1, 
                                                            0, 0.283, 
                                                            0, 0.01));

                int pool_input_img_rows1 = conv_layer1->output_img_rows;
                int pool_input_img_cols1 = conv_layer1->output_img_cols;
                int pool_filter_rows1 = 2;
                int pool_filter_cols1 = 2;
                int pool_pads1 = 0;
                int pool_strides1 = 2;

                std::shared_ptr<snn::MaxPooling> pool_layer1(new snn::MaxPooling(pool_input_img_rows1, pool_input_img_cols1, 
                                                        pool_filter_rows1, pool_filter_cols1, 
                                                        pool_pads1, pool_pads1, 
                                                        pool_strides1, pool_strides1, 
                                                        conv_output_img_channels1, false));

                int input_img_rows2 = pool_layer1->output_img_rows;
                int input_img_cols2 = pool_layer1->output_img_rows;
                int input_img_channels2 = pool_layer1->image_channels;

                int conv_output_img_channels2 = 16;
                int conv_filter_rows2 = 5;
                int conv_filter_cols2 = 5;
                int conv_row_pads2 = 0;
                int conv_col_pads2 = 0;
                int conv_row_strides2 = 1;
                int conv_col_strides2 = 1;

                std::shared_ptr<snn::Convolution> conv_layer2(new snn::Convolution(input_img_rows2, input_img_cols2, 
                                                            input_img_channels2, 
                                                            conv_output_img_channels2, 
                                                            conv_filter_rows2, conv_filter_cols2, 
                                                            conv_row_pads2, conv_col_pads2, 
                                                            conv_row_strides2, conv_col_strides2, 
                                                            0, 0.115, 
                                                            0, 0.01));

                int pool_input_img_rows2 = conv_layer2->output_img_rows;
                int pool_input_img_cols2 = conv_layer2->output_img_cols;
                int pool_filter_rows2 = 2;
                int pool_filter_cols2 = 2;
                int pool_pads2 = 0;
                int pool_strides2 = 2;

                std::shared_ptr<snn::MaxPooling> pool_layer2(new snn::MaxPooling(pool_input_img_rows2, pool_input_img_cols2, 
                                                        pool_filter_rows2, pool_filter_cols2, 
                                                        pool_pads2, pool_pads2, 
                                                        pool_strides2, pool_strides2, 
                                                        conv_output_img_channels2, true));

                int aff1_input_rows = pool_layer2->output_rows * conv_output_img_channels2; // because flatten-flag is true
                int aff1_input_cols = 1;
                int aff1_output_rows = 120;
                int aff1_output_cols = 1;

                std::shared_ptr<snn::Affine> aff1_layer(new snn::Affine(aff1_input_rows, aff1_input_cols, 
                                                aff1_output_rows, aff1_output_cols, 0, 2.0 / double(aff1_input_rows), 
                                                                                    0, 0.01));

                int aff2_input_rows = 120;
                int aff2_input_cols = 1;
                int aff2_output_rows = 84;
                int aff2_output_cols = 1;

                std::shared_ptr<snn::Affine> aff2_layer(new snn::Affine(aff2_input_rows, aff2_input_cols, 
                                                aff2_output_rows, aff2_output_cols, 0, 2.0 / 120.0, 0, 0.01));

                int aff3_input_rows = 84;
                int aff3_input_cols = 1;
                int aff3_output_rows = 10;
                int aff3_output_cols = 1;

                std::shared_ptr<snn::Affine> aff3_layer(new snn::Affine(aff3_input_rows, aff3_input_cols, 
                                                aff3_output_rows, aff3_output_cols, 0, 2.0 / 84.0, 0, 0.01));

                std::shared_ptr<snn::Relu> relu_layer1(new snn::Relu);
                std::shared_ptr<snn::Relu> relu_layer2(new snn::Relu);
                std::shared_ptr<snn::Relu> relu_layer3(new snn::Relu);
                std::shared_ptr<snn::Relu> relu_layer4(new snn::Relu);
                //std::shared_ptr<Softmax> softmax_layer(new Softmax);
				
				snn::Sequential net;
                net << conv_layer1 << relu_layer1 << pool_layer1
                    << conv_layer2 << relu_layer2 << pool_layer2
                    << aff1_layer << relu_layer3
                    << aff2_layer << relu_layer4
                    <<aff3_layer;

也可以直接封装成一个类,参考models目录下各hpp文件:


#include <../include/SimpleNN.hpp>

namespace snn
{
    // Simplified LeNet-5 model
    class LeNet : public Sequential
    {
        public:
            LeNet():Sequential()
            {
               

                *this << conv_layer1 << relu_layer1 << pool_layer1
                    << conv_layer2 << relu_layer2 << pool_layer2
                    << aff1_layer << relu_layer3
                    << aff2_layer << relu_layer4
                    <<aff3_layer;
            }
    };
}

Train model

配置优化器和loss层:


std::shared_ptr<SoftmaxWithLoss> loss_layer(new SoftmaxWithLoss(true));
net.set_loss_layer(loss_layer);
std::cout << "Loss layer ready!" << std::endl;

std::vector<Matrix_d> init_params = net.get_params();
std::vector<Matrix_d> init_grads = net.get_grads();
 std::shared_ptr<AdaGrad> opt(new AdaGrad(init_params, init_grads, 0.012));
 net.set_optimizer(opt);

加载数据


Dataset train_set(true);
Dataset test_set(true);
    
 if (train_set.load_data(train_data_file_path, train_label_file_path))
     std::cout << "Train set loading finished!" << std::endl;
else
     std::cout << "Failed to load train set data!" << std::endl;

if (test_set.load_data(test_data_file_path, test_label_file_path))
     std::cout << "Test set loading finished!" << std::endl;
else
     std::cout << "Failed to load test set data!" << std::endl;

训练并保存模型


net.fit(train_set, test_set, 256, 2);

if (!net.save_net("../../../examples/mnist/LeNet.net"))
{
     std::cout << "Failed to save net!" << std::endl;
     return 0;
}
if (!net.save_weights("../../../examples/mnist/LeNet.weights"))
{
     std::cout << "Failed to save weights!" << std::endl;
     return 0;
}

Load model


if (!net.load_net(net_path))
{
     std::cerr << "Failed to load net!" << std::endl;
     return -1;
    
}
if (!net.load_weights(weight_path))
{
     std::cerr << "Failed to load weights!" << std::endl;
     return -1;
    
}

或者直接


if (!net.load_model(net_path, weight_path))
{
     std::cerr << "Failed to load model!" << std::endl;
     return -1;
    
}

如果网络结构和权重分开加载,则先加载结构再加载权重。

Predict


y = net.predict(x);

到此这篇关于用C++实现的简易神经网络框架:SimpleNN的文章就介绍到这了,更多相关C++实现神经网络框架SimpleNN内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++实现神经网络框架SimpleNN的详细过程

本文链接: https://www.lsjlt.com/news/133548.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • c语言怎么计算字符串长度
    在C语言中,可以使用内置的strlen()函数来计算字符串的长度。该函数位于string.h头文件中。以下是一个示例代码: #inc...
    99+
    2024-05-14
    c语言
  • c语言怎么判断三个数的大小
    可以通过比较三个数之间的大小关系来判断它们的大小。以下是一个示例代码: #include <stdio.h> int ...
    99+
    2024-05-14
    c语言
  • c++排序函数sort怎么使用
    在C++中,使用sort函数对容器中的元素进行排序,可以按照默认的升序排列,也可以自定义排序规则。 下面是一个简单的例子,对一个ve...
    99+
    2024-05-14
    c++
  • c++中string的compare函数怎么使用
    在C++中,可以使用string的compare函数来比较两个string对象的大小。该函数的原型如下: int compare(c...
    99+
    2024-05-14
    c++
  • c++中string的compare函数有什么用
    c++中string的compare函数用于比较两个字符串的大小关系。该函数返回一个整数值,表示两个字符串的比较结果。 具体来说,如...
    99+
    2024-05-14
    c++
  • c++中print函数的功能有哪些
    在C++中,通常使用std::cout来进行输出操作,而不是使用print函数。std::cout是C++标准库中的一个输出流对象,...
    99+
    2024-05-14
    c++
  • c语言数据结构怎么使用
    在C语言中,数据结构可以通过定义结构体来实现。以下是一些常见的数据结构的使用方法示例: 链表: #include <std...
    99+
    2024-05-14
    c语言
  • c++中print函数的用法是什么
    在C++中没有内置的print函数,但可以使用cout来输出内容到控制台。cout是C++标准库中的一个输出流对象,可以使用<...
    99+
    2024-05-14
    c++
  • c++中concept的用法是什么
    在C++20中,Concept是一种新的语言特性,用于定义类型要求和约束。Concept可以被用来约束函数模板、类模板和普通函数的参...
    99+
    2024-05-14
    c++
  • c++中concept的作用是什么
    在C++中,concept的作用是定义一种通用的约束,用于限制模板参数的类型范围。通过使用concept,可以在编译时对模板参数进行...
    99+
    2024-05-14
    c++
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作