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

目录
  • Features
  • Dependencies
  • Platform
  • To Do
  • Usage

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内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++实现神经BP神经网络

    本文实例为大家分享了C++实现神经BP神经网络的具体代码,供大家参考,具体内容如下 BP.h #pragma once #include<vector> #include<stdlib.h> #include<time.h> #include<cmath> #include<iostream> using std::vector; using std::exp; using std::cout; using std::endl; class BP

  • C++实现简单BP神经网络

    本文实例为大家分享了C++实现简单BP神经网络的具体代码,供大家参考,具体内容如下 实现了一个简单的BP神经网络 使用EasyX图形化显示训练过程和训练结果 使用了25个样本,一共训练了1万次. 该神经网络有两个输入,一个输出端 下图是训练效果,data是训练的输入数据,temp代表所在层的输出,target是训练目标,右边的大图是BP神经网络的测试结果. 以下是详细的代码实现,主要还是基本的矩阵运算. #include <stdio.h> #include <stdlib.h>

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

    目录 Features Dependencies Platform To Do Usage 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 a

  • Java中批处理框架spring batch详细介绍

    spring batch简介 spring batch是spring提供的一个数据处理框架.企业域中的许多应用程序需要批量处理才能在关键任务环境中执行业务操作. 这些业务运营包括: 无需用户交互即可最有效地处理大量信息的自动化,复杂处理. 这些操作通常包括基于时间的事件(例如月末计算,通知或通信). 在非常大的数据集中重复处理复杂业务规则的定期应用(例如,保险利益确定或费率调整). 集成从内部和外部系统接收的信息,这些信息通常需要以事务方式格式化,验证和处理到记录系统中. 批处理用于每天为企业处

  • 使用JAVA+Maven+TestNG框架实现超详细Appium测试安卓真机教程

    前言:前段时间做了selenium的学习和实践,有点意犹未尽,所以自己就又学了下Appium的使用,因为这一套东西在16年已经停止维护了,不管实现还是设计上都不是很容易,也踩了很多坑,现在在此记录下大概过程.后续有时间再完善手册. 一.准备 安装SDK,配置环境变量 链接: https://pan.baidu.com/s/1g2QaWjdfg6Txa0gZf9kk3A 提取码: 8aaz windows配置环境SDK变量 我的电脑右键->属性 点击高级系统设置 点击环境变量 点击新建按钮,变量名

  • C++小游戏tankwar之界面绘制的详细过程

    一.前言 闲来无趣,写个C++小游戏 二.新建项目 2.1创建MFC项目 2.2 新建路径 2.3 基于对话框 三.窗口界面绘制 3.1 设置框架 进入资源视图 双击打开IDD_TANKWAR_DIALOG 出现下列界面后删除多余控件 修改Caption为Tankwar 增加缩小最大化按钮 3.2 初始化GDI 进入"TankWar.h",加入以下代码 进入"TankWar.cpp",加入以下代码 GDI初始化完成 3.3 绘制背景 进入TankWarDlg.cpp

  • Springboot入门案例及部署项目的详细过程

    今天闲来无事就来学习一下SpringBoot框架,顺手搭了一个入门小案例. Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者. 这篇入门案例使用的是Springboot1.5.9,可能最新的已经更简单了,创建的

  • springboot+thymeleaf+mybatis实现甘特图的详细过程

    首先我们要明白:这个甘特图需要哪些动态数据. (1)需要:ID,tName,number,计划开始时间,开始时间,计划结束时间,结束时间,项目负责人,参与人,知情人ID,计划时长(可以计算得出的,不必在数据库中):前置任务:项目进度,该任务属于哪个任务 (2)然后利用easycode插件生成实体类,映射类,服务类,ontCroller等 (3)利用bootstrap框架做出甘特图的样式,写好JS. <!DOCTYPE html> <html xmlns:th="http://w

  • 亲手教你Docker Compose安装DOClever的详细过程

    目录 一.Docker Compose是什么以及Docker Compose安装和使用 二.DOClever是什么 三.使用Docker Compose安装DOClever步骤 一.Docker Compose是什么以及Docker Compose安装和使用 点击查看我的另外一篇:<Docker Compose的安装和使用> 二.DOClever是什么 DOClever是一个可视化免费开源的接口管理工具 ,可以分析接口结构,校验接口正确性, 围绕接口定义文档,通过一系列自动化工具提升我们的协作

  • 基于Jupyter notebook搭建Spark集群开发环境的详细过程

    一.概念介绍: 1.Sparkmagic:它是一个在Jupyter Notebook中的通过Livy服务器 Spark REST与远程Spark群集交互工作工具.Sparkmagic项目包括一组以多种语言交互运行Spark代码的框架和一些内核,可以使用这些内核将Jupyter Notebook中的代码转换在Spark环境运行. 2.Livy:它是一个基于Spark的开源REST服务,它能够通过REST的方式将代码片段或是序列化的二进制代码提交到Spark集群中去执行.它提供了以下这些基本功能:提

  • java开发分布式服务框架Dubbo暴露服务过程详解

    目录 Dubbo服务暴露机制 前言 服务暴露流程 源码解析 本地暴露 远程暴露 Dubbo服务暴露机制 前言 在进行服务暴露机制的分析之前,必须谈谈什么是URL,在Dubbo服务暴露过程中URL是无处不在的,贯穿了整个过程. 一般情况下,URL指的是统一资源定位符,标准格式如下: protocol://host:port/path?key1=value1&key2=value2 Dubbo就是用这种URL的方式来作为约定的参数类型,服务之间也是用URL来进行交互. Dubbo用URL作为配置总线

  • SpringBoot中Mybatis + Druid 数据访问的详细过程

    目录 1.简介 2.JDBC 3.CRUD操作 4.自定义数据源 DruidDataSource 1.配置 Druid 数据源监控 2.配置 Druid web 监控 filter 5.SpringBoot 整合mybatis 1. 导入mybatis所需要的依赖 2.配置数据库连接信息 3,创建实体类 4.配置Mapper接口类 6.SpringBoot 整合 1.简介 ​ 对于数据访问层,无论是SQL(关系型数据库) 还是NOSQL(非关系型数据库),SpringBoot 底层都是采用 Sp

随机推荐