使用C++從0到1實現人工智能神經網絡及實戰案例

引言

既然是要用C++來實現,那么我們自然而然的想到設計一個神經網絡類來表示神經網絡,這里我稱之為Net類。由于這個類名太過普遍,很有可能跟其他人寫的程序沖突,所以我的所有程序都包含在namespace liu中,由此不難想到我姓劉。在之前的博客反向傳播算法資源整理中,我列舉了幾個比較不錯的資源。對于理論不熟悉而且學習精神的同學可以出門左轉去看看這篇文章的資源。這里假設讀者對于神經網絡的基本理論有一定的了解。

一、Net類的設計與神經網絡初始化

神經網絡的要素

在真正開始coding之前還是有必要交代一下神經網絡基礎,其實也就是設計類和寫程序的思路。簡而言之,神經網絡的包含幾大要素:

  • 神經元節點

  • 層(layer)

  • 權值(weights)

  • 偏置項(bias)

神經網絡的兩大計算過程分別是前向傳播和反向傳播過程。每層的前向傳播分別包含加權求和(卷積?)的線性運算和激活函數的非線性運算。反向傳播主要是用BP算法更新權值。 雖然里面還有很多細節,但是對于作為第一篇的本文來說,以上內容足夠了。

Net類的設計

Net類——基于Mat

神經網絡中的計算幾乎都可以用矩陣計算的形式表示,這也是我用OpenCV的Mat類的原因之一,它提供了非常完善的、充分優化過的各種矩陣運算方法;另一個原因是我最熟悉的庫就是OpenCV......有很多比較好的庫和框架在實現神經網絡的時候會用很多類來表示不同的部分。比如Blob類表示數據,Layer類表示各種層,Optimizer類來表示各種優化算法。但是這里沒那么復雜,主要還是能力有限,只用一個Net類表示神經網絡。

還是直接讓程序說話,Net類包含在Net.h中,大致如下。

#ifndef NET_H
#define NET_H
#endif // NET_H
#pragma once
#include <iostream>
#include<opencv2\core\core.hpp>
#include<opencv2\highgui\highgui.hpp>
//#include<iomanip>
#include"Function.h"
namespace liu
{class Net{public:std::vector<int> layer_neuron_num;std::vector<cv::Mat> layer;std::vector<cv::Mat> weights;std::vector<cv::Mat> bias;public:Net() {};~Net() {};//Initialize net:genetate weights matrices、layer matrices and bias matrices// bias default all zerovoid initNet(std::vector<int> layer_neuron_num_);//Initialise the weights matrices.void initWeights(int type = 0, double a = 0., double b = 0.1);//Initialise the bias matrices.void initBias(cv::Scalar& bias);//Forwardvoid forward();//Forwardvoid backward();protected://initialise the weight matrix.if type =0,Gaussian.else uniform.void initWeight(cv::Mat &dst, int type, double a, double b);//Activation functioncv::Mat activationFunction(cv::Mat &x, std::string func_type);//Compute delta errorvoid deltaError();//Update weightsvoid updateWeights();};
}

說明

以上不是Net類的完整形態,只是對應于本文內容的一個簡化版,簡化之后看起來會更加清晰明了。

成員變量與成員函數

現在Net類只有四個成員變量,分別是:

  • 每一層神經元數目(layer_neuron_num)

  • 層(layer)

  • 權值矩陣(weights)

  • 偏置項(bias)

權值用矩陣表示就不用說了,需要說明的是,為了計算方便,這里每一層和偏置項也用Mat表示,每一層和偏置都用一個單列矩陣來表示。

Net類的成員函數除了默認的構造函數和析構函數,還有:

  • initNet():用來初始化神經網絡

  • initWeights():初始化權值矩陣,調用initWeight()函數

  • initBias():初始化偏置項

  • forward():執行前向運算,包括線性運算和非線性激活,同時計算誤差

  • backward():執行反向傳播,調用updateWeights()函數更新權值。

這些函數已經是神經網絡程序核心中的核心。剩下的內容就是慢慢實現了,實現的時候需要什么添加什么,逢山開路,遇河架橋。

神經網絡初始化

initNet()函數

先說一下initNet()函數,這個函數只接受一個參數——每一層神經元數目,然后借此初始化神經網絡。這里所謂初始化神經網絡的含義是:生成每一層的矩陣、每一個權值矩陣和每一個偏置矩陣。聽起來很簡單,其實也很簡單。

實現代碼在Net.cpp中。

這里生成各種矩陣沒啥難點,唯一需要留心的是權值矩陣的行數和列數的確定。值得一提的是這里把權值默認全設為0。

    //Initialize netvoid Net::initNet(std::vector<int> layer_neuron_num_){layer_neuron_num = layer_neuron_num_;//Generate every layer.layer.resize(layer_neuron_num.size());for (int i = 0; i < layer.size(); i++){layer[i].create(layer_neuron_num[i], 1, CV_32FC1);}std::cout << "Generate layers, successfully!" << std::endl;//Generate every weights matrix and biasweights.resize(layer.size() - 1);bias.resize(layer.size() - 1);for (int i = 0; i < (layer.size() - 1); ++i){weights[i].create(layer[i + 1].rows, layer[i].rows, CV_32FC1);//bias[i].create(layer[i + 1].rows, 1, CV_32FC1);bias[i] = cv::Mat::zeros(layer[i + 1].rows, 1, CV_32FC1);}std::cout << "Generate weights matrices and bias, successfully!" << std::endl;std::cout << "Initialise Net, done!" << std::endl;}

權值初始化

initWeight()函數

權值初始化函數initWeights()調用initWeight()函數,其實就是初始化一個和多個的區別。

偏置初始化是給所有的偏置賦相同的值。這里用Scalar對象來給矩陣賦值。

    //initialise the weights matrix.if type =0,Gaussian.else uniform.void Net::initWeight(cv::Mat &dst, int type, double a, double b){if (type == 0){randn(dst, a, b);}else{randu(dst, a, b);}}//initialise the weights matrix.void Net::initWeights(int type, double a, double b){//Initialise weights cv::Matrices and biasfor (int i = 0; i < weights.size(); ++i){initWeight(weights[i], 0, 0., 0.1);}}

偏置初始化是給所有的偏置賦相同的值。這里用Scalar對象來給矩陣賦值。

    //Initialise the bias matrices.void Net::initBias(cv::Scalar& bias_){for (int i = 0; i < bias.size(); i++){bias[i] = bias_;}}

至此,神經網絡需要初始化的部分已經全部初始化完成了。

初始化測試

我們可以用下面的代碼來初始化一個神經網絡,雖然沒有什么功能,但是至少可以測試下現在的代碼是否有BUG:

#include"../include/Net.h"
//<opencv2\opencv.hpp>
using namespace std;
using namespace cv;
using namespace liu;
int main(int argc, char *argv[])
{//Set neuron number of every layervector<int> layer_neuron_num = { 784,100,10 };// Initialise Net and weightsNet net;net.initNet(layer_neuron_num);net.initWeights(0, 0., 0.01);net.initBias(Scalar(0.05));getchar();return 0;
}

二、前向傳播與反向傳播

在Net類的設計和神經網絡的初始化中,大部分還是比較簡單的。因為最重要事情就是生成各種矩陣并初始化。神經網絡中的重點和核心就是本文的內容——前向和反向傳播兩大計算過程。每層的前向傳播分別包含加權求和(卷積?)的線性運算和激活函數的非線性運算。反向傳播主要是用BP算法更新權值。

前向過程

如前所述,前向過程分為線性運算和非線性運算兩部分。相對來說比較簡單。

線型運算可以用Y=WX+b 來表示,其中X是輸入樣本,這里即是第N層的單列矩陣,W是權值矩陣,Y是加權求和之后的結果矩陣,大小與N+1層的單列矩陣相同。b是偏置,默認初始化全部為0。不難推知鬼知道我推了多久!,W的大小是 (N+1).rows * N.rows。正前面中生成weights矩陣的代碼實現一樣:

weights[i].create(layer[i + 1].rows, layer[i].rows, CV_32FC1); 

非線性運算可以用O

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/164990.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/164990.shtml
英文地址,請注明出處:http://en.pswp.cn/news/164990.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CTF-PWN-QEMU-前置知識

文章目錄 QEMU 內存管理(QEMU 如何管理某個特定 VM 的內存)MemoryRegion gpa->hpaFlatView&#xff1a;表示MR 樹對應的地址空間FlatRange&#xff1a;存儲不同MR對應的地址信息AddressSpace&#xff1a;不同類型的 MemoryRegion樹RAMBlock總體簡化圖 QEMU 設備模擬 &#x…

【Java進階開發實戰】用Java中的Base64數據加密與解密處理

簡介 ? Base64編碼,是我們程序開發中經常使用到的編碼方法。它是一種基于用64個可打印字符來表示二進制數據的表示方法。它通常用作存儲、傳輸一些二進制數據編碼方法, 也是MIME(多用途互聯網郵件擴展,主要用作電子郵件標準)中一種可打印字符表示二進制數據的常見編碼方法…

Proteus下仿真AT89C51報“串行口通信失敗,請檢查電平適配是否正確。”解決辦法

在Proteus下進行AT89C51串行口仿真時&#xff0c;如果遇到“串行口通信失敗&#xff0c;請檢查電平適配是否正確”的錯誤提示&#xff0c;以下是一些解決辦法&#xff1a; 1. 了解AT89C51和外部設備的電平要求&#xff1a; 首先&#xff0c;了解AT89C51和外部設備之間的電平…

【華為OD機試python】分班【2023 B卷|100分】

【華為OD機試】-真題 !!點這里!! 【華為OD機試】真題考點分類 !!點這里 !! 題目描述 幼兒園兩個班的小朋友在排隊時混在了一起,每位小朋友都知道自己是否與前面一位小朋友是否同班,請你幫忙把同班的小朋友找出來。 小朋友的編號為整數,與前一位小朋友同班用Y表示,不同班…

C語言——文件操作

歸納編程學習的感悟&#xff0c; 記錄奮斗路上的點滴&#xff0c; 希望能幫到一樣刻苦的你&#xff01; 如有不足歡迎指正&#xff01; 共同學習交流&#xff01; &#x1f30e;歡迎各位→點贊 &#x1f44d; 收藏? 留言?&#x1f4dd; 我輩皆凡人&#xff0c;用一生鋪就的…

C++的new / delete 與 C語言的malloc/realloc/calloc / free 的講解

在C語言中我們通常會使用malloc/realloc/calloc來動態開辟的空間&#xff0c;malloc是只會開辟你提供的空間大小&#xff0c;并不會初始化內容&#xff1b;calloc不但會開辟空間&#xff0c;還會初始化&#xff1b;realloc是專門來擴容的&#xff0c;當你第一次開辟的空間不夠用…

目標檢測YOLO實戰應用案例100講-基于YOLO的小目標檢測改進算法(續)

目錄 3.3基于混合注意力的多尺度特征融合改進方法 3.3.1整體網絡架構 3.3.2特征金字塔的構建

Vue 2.0源碼分析-實例掛載的實現

Vue 中我們是通過 $mount 實例方法去掛載 vm 的&#xff0c;$mount 方法在多個文件中都有定義&#xff0c;如 src/platform/web/entry-runtime-with-compiler.js、src/platform/web/runtime/index.js、src/platform/weex/runtime/index.js。因為 $mount 這個方法的實現是和平臺…

Python 使用tkinter復刻Windows記事本UI和菜單功能(三)

上一篇&#xff1a;Python 使用tkinter復刻Windows記事本UI和菜單功能&#xff08;二&#xff09;-CSDN博客 下一篇&#xff1a;敬請耐心等待&#xff0c;如發現BUG以及建議&#xff0c;請在評論區發表&#xff0c;謝謝&#xff01; 本文章完成了記事本的新建、保存、另存、打…

【技巧】前端開發技巧 增加前端的請求緩存 提高開發效率

定義變量 /*** 開發緩存 開關* 說明* 方便開發使用 提升開發效率* true 打開緩存* false 關閉緩存 這里上線的時候必須改為* type {boolean}*/ const cacheFlag true/*** 排除某個url 方便開發時的數據實時生效* 這里根據開發到哪個功能 實時變更&#xff0c; 比如開…

京東數據分析(京東大數據):2023年10月京東手機行業品牌銷售排行榜

鯨參謀監測的京東平臺10月份手機市場銷售數據已出爐&#xff01; 根據鯨參謀平臺的數據顯示&#xff0c;今年10月份&#xff0c;京東平臺手機行業的銷量約340萬&#xff0c;環比增長約11%&#xff0c;同比則下滑約2%&#xff1b;銷售額為108億&#xff0c;環比增長約17%&#x…

請你說一下Vue中v-if和v-for的優先級誰更高

v-if 與 v-for簡介 v-ifv-forv-if & v-for使用 v-if 與 v-for優先級比較 vue2 中&#xff0c;v-for的優先級高于v-if 例子進行分析 vue3 v-if 具有比 v-for 更高的優先級 例子進行分析 總結 在vue2中&#xff0c;v-for的優先級高于v-if在vue3中&#xff0c;v-if的優先級高…

RubyMine 2023:提升Rails/Ruby開發效率的強大利器

在Rails/Ruby開發領域&#xff0c;JetBrains RubyMine一直以其強大的功能和優秀的性能而備受開發者的青睞。現如今&#xff0c;我們迎來了全新的RubyMine 2023版本&#xff0c;它將為開發者們帶來更高效的開發體驗和無可比擬的工具支持。 首先&#xff0c;RubyMine 2023提供了…

Java-使用poi-tl根據word模板動態生成word

作者wangsz&#xff0c;想寫一些關于word的工具&#xff0c;所以就寫了這篇文章 1.首先&#xff0c;先導入所需要的依賴&#xff08;poi相關依賴即可&#xff09; <!-- POI --><dependency><groupId>org.apache.poi</groupId><artifactId>poi&l…

【libGDX】使用Mesh繪制立方體

1 前言 本文主要介紹使用 Mesh 繪制立方體&#xff0c;讀者如果對 Mesh 不太熟悉&#xff0c;請回顧以下內容&#xff1a; 使用Mesh繪制三角形使用Mesh繪制矩形使用Mesh繪制圓形 在繪制立方體的過程中&#xff0c;主要用到了 MVP &#xff08;Model View Projection&#xff0…

目標檢測YOLO系列從入門到精通技術詳解100篇-【目標檢測】計算機視覺(最終篇)

目錄 知識儲備 KITTI數據集 1.KITTI數據集概述 2.數據采集平臺 3.Dataset詳述 算法原理

GIT無效的源路徑/URL

ssh-add /Users/haijunyan/.ssh/id_rsa ssh-add -K /Users/haijunyan/.ssh/id_rsa

windows11上enable WSL

Windows電腦上要配置linux&#xff08;這里指ubuntu&#xff09;開發環境&#xff0c;主要有三種方式&#xff1a; 1&#xff09;在windows上裝個虛擬機&#xff08;比如vmware&#xff09;。缺點是vmware加載ubuntu后系統會變慢很多&#xff0c;而且需要通過samba來實現window…

git clone -mirror 和 git clone 的區別

目錄 前言兩則區別git clone --mirrorgit clone 獲取到的文件有什么不同瘦身倉庫如何選擇結語開源項目 前言 Git是一款強大的版本控制系統&#xff0c;通過Git可以方便地管理代碼的版本和協作開發。在使用Git時&#xff0c;常見的操作之一就是通過git clone命令將遠程倉庫克隆…

【vue2】axios請求與axios攔截器的使用詳解

&#x1f973;博 主&#xff1a;初映CY的前說(前端領域) &#x1f31e;個人信條&#xff1a;想要變成得到&#xff0c;中間還有做到&#xff01; &#x1f918;本文核心&#xff1a;當我們在路由跳轉前與后我們可實現觸發的操作 【前言】ajax是一種在javaScript代碼中發請…