基于C#的機(jī)器學(xué)習(xí)--c# .NET中直觀的深度學(xué)習(xí)
在本章中,將會(huì)學(xué)到:
l 如何使用Kelp.Net來(lái)執(zhí)行自己的測(cè)試
l 如何編寫測(cè)試
l 如何對(duì)函數(shù)進(jìn)行基準(zhǔn)測(cè)試
Kelp.Net是一個(gè)用c#編寫的深度學(xué)習(xí)庫(kù)。由于能夠?qū)⒑瘮?shù)鏈到函數(shù)堆棧中,它在一個(gè)非常靈活和直觀的平臺(tái)中提供了驚人的功能。它還充分利用OpenCL語(yǔ)言平臺(tái),在支持cpu和gpu的設(shè)備上實(shí)現(xiàn)無(wú)縫操作。深度學(xué)習(xí)是一個(gè)非常強(qiáng)大的工具,對(duì)Caffe和Chainer模型加載的本機(jī)支持使這個(gè)平臺(tái)更加強(qiáng)大。您將看到,只需幾行代碼就可以創(chuàng)建一個(gè)100萬(wàn)個(gè)隱藏層的深度學(xué)習(xí)網(wǎng)絡(luò)。
Kelp.Net還使得從磁盤存儲(chǔ)中保存和加載模型變得非常容易。這是一個(gè)非常強(qiáng)大的特性,允許您執(zhí)行訓(xùn)練、保存模型,然后根據(jù)需要加載和測(cè)試。它還使代碼的產(chǎn)品化變得更加容易,并且真正地將訓(xùn)練和測(cè)試階段分離開(kāi)來(lái)。
其中,Kelp.Net是一個(gè)非常強(qiáng)大的工具,可以幫助你更好地學(xué)習(xí)和理解各種類型的函數(shù)、它們的交互和性能。例如,你可以使用不同的優(yōu)化器在相同的網(wǎng)絡(luò)上運(yùn)行測(cè)試,并通過(guò)更改一行代碼來(lái)查看結(jié)果。此外,可以輕松地設(shè)計(jì)你的測(cè)試,以查看使用不同批處理大小、隱藏層數(shù)、紀(jì)元、和更多內(nèi)容。
什么是深度學(xué)習(xí)?
深度學(xué)習(xí)是機(jī)器學(xué)習(xí)和人工智能的一個(gè)分支,它使用許多層次的神經(jīng)網(wǎng)絡(luò)層(如果你愿意,可以稱之為層次結(jié)構(gòu))來(lái)完成它的工作。在很多情況下,這些網(wǎng)絡(luò)的建立是為了反映我們對(duì)人類大腦的認(rèn)知,神經(jīng)元像錯(cuò)綜復(fù)雜的網(wǎng)狀結(jié)構(gòu)一樣將不同的層連接在一起。這允許以非線性的方式進(jìn)行數(shù)據(jù)處理。每一層都處理來(lái)自上一層的數(shù)據(jù)(當(dāng)然,第一層除外),并將其信息傳遞到下一層。幸運(yùn)的話,每一層都改進(jìn)了模型,最終,我們實(shí)現(xiàn)了目標(biāo)并解決了問(wèn)題。
OpenCL
Kelp.Net 大量使用了開(kāi)源計(jì)算語(yǔ)言(OpenCL).
OpenCL認(rèn)為計(jì)算系統(tǒng)是由許多計(jì)算設(shè)備組成的,這些計(jì)算設(shè)備可以是中央處理器(CPU),也可以是附加在主機(jī)處理器(CPU)上的圖形處理單元(GPU)等加速器。在OpenCL設(shè)備上執(zhí)行的函數(shù)稱為內(nèi)核。單個(gè)計(jì)算設(shè)備通常由幾個(gè)計(jì)算單元組成,這些計(jì)算單元又由多個(gè)處理元素(PS)組成。一個(gè)內(nèi)核執(zhí)行可以在所有或多個(gè)PEs上并行運(yùn)行。
在OpenCL中,任務(wù)是在命令隊(duì)列中調(diào)度的。每個(gè)設(shè)備至少有一個(gè)命令隊(duì)列。OpenCL運(yùn)行時(shí)將調(diào)度數(shù)據(jù)的并行任務(wù)分成幾部分,并將這些任務(wù)發(fā)送給設(shè)備處理元素。
OpenCL定義了一個(gè)內(nèi)存層次結(jié)構(gòu):
Global:由所有處理元素共享,并且具有高延遲。
Read-only:更小,更低的延遲,可由主機(jī)CPU寫入,但不包括計(jì)算設(shè)備。
Local:由流程元素組共享。
Per-elemen:私有內(nèi)存。
OpenCL還提供了一個(gè)更接近數(shù)學(xué)的API。這可以在固定長(zhǎng)度向量類型的公開(kāi)中看到,比如float4(單精度浮點(diǎn)數(shù)的四個(gè)向量),它的長(zhǎng)度為2、3、4、8和16。如果你接觸了更多的Kelp.Net并開(kāi)始創(chuàng)建自己的函數(shù),你將會(huì)遇到OpenCL編程。現(xiàn)在,只要知道它的存在就足夠了,而且它正在被廣泛地使用。
OpenCL 層次結(jié)構(gòu)
在Kelp.Net各種OpenCL資源的層次結(jié)構(gòu)如下圖所示:

讓我們更詳細(xì)地描述這些。
Compute kernel
內(nèi)核對(duì)象封裝在程序中聲明的特定內(nèi)核函數(shù),以及執(zhí)行此內(nèi)核函數(shù)時(shí)使用的參數(shù)值。
Compute program
由一組內(nèi)核組成的OpenCL程序。程序還可以包含內(nèi)核函數(shù)和常量數(shù)據(jù)調(diào)用的輔助函數(shù)。
Compute sampler
描述如何在內(nèi)核中讀取圖像時(shí)對(duì)圖像進(jìn)行采樣的對(duì)象。圖像讀取函數(shù)以采樣器作為參數(shù)。采樣器指定圖像尋址模式(表示如何處理范圍外的坐標(biāo))、過(guò)濾模式以及輸入圖像坐標(biāo)是規(guī)范化還是非規(guī)范化值。
Compute device
計(jì)算設(shè)備是計(jì)算單元的集合。命令隊(duì)列用于將命令排隊(duì)到設(shè)備。命令示例包括執(zhí)行內(nèi)核或讀寫內(nèi)存對(duì)象。OpenCL設(shè)備通常對(duì)應(yīng)于GPU、多核CPU和其他處理器,如數(shù)字信號(hào)處理器(DSP)和cell/B.E.處理器。
Compute resource
可以由應(yīng)用程序創(chuàng)建和刪除的OpenCL資源。
Compute object
在OpenCL環(huán)境中由句柄標(biāo)識(shí)的對(duì)象。
Compute context
計(jì)算上下文是內(nèi)核執(zhí)行的實(shí)際環(huán)境和定義同步和內(nèi)存管理的域。
Compute command queue
命令隊(duì)列是一個(gè)對(duì)象,它包含將在特定設(shè)備上執(zhí)行的命令。命令隊(duì)列是在上下文中的特定設(shè)備上創(chuàng)建的。對(duì)隊(duì)列的命令按順序排隊(duì),但可以按順序執(zhí)行,也可以不按順序執(zhí)行。
Compute buffer
存儲(chǔ)線性字節(jié)集合的內(nèi)存對(duì)象。可以使用在設(shè)備上執(zhí)行的內(nèi)核中的指針來(lái)訪問(wèn)緩沖區(qū)對(duì)象。
Compute event
事件封裝了操作(如命令)的狀態(tài)。它可用于同步上下文中的操作。
Compute image
存儲(chǔ)2D或3D結(jié)構(gòu)數(shù)組的內(nèi)存對(duì)象。圖像數(shù)據(jù)只能通過(guò)讀寫函數(shù)訪問(wèn)。讀取函數(shù)使用采樣器。
Compute platform
主機(jī)加上OpenCL框架管理的設(shè)備集合,允許應(yīng)用程序共享資源并在平臺(tái)上的設(shè)備上執(zhí)行內(nèi)核。
Compute user event
這表示用戶創(chuàng)建的事件。
Kelp.Net Framework
函數(shù)
函數(shù)是Kelp.Net神經(jīng)網(wǎng)絡(luò)的基本組成部分。單個(gè)函數(shù)在函數(shù)堆棧中鏈接在一起,以創(chuàng)建功能強(qiáng)大且可能復(fù)雜的網(wǎng)絡(luò)鏈。
我們需要了解四種主要的函數(shù)類型:
Single-input functions 單輸入函數(shù)
Dual-input
functions 雙輸入函數(shù)
Multi-input
functions 多輸入函數(shù)
Multi-output
functions 多輸出函數(shù)
當(dāng)從磁盤加載網(wǎng)絡(luò)時(shí),函數(shù)也被鏈接在一起。
每個(gè)函數(shù)都有一個(gè)向前和向后的方法。
public abstract NdArray[] Forward(params NdArray[] xs); public virtual void Backward([CanBeNull] params NdArray[] ys){}
函數(shù)棧
函數(shù)堆棧是在向前、向后或更新傳遞中同時(shí)執(zhí)行的函數(shù)層。當(dāng)我們創(chuàng)建一個(gè)測(cè)試或從磁盤加載一個(gè)模型時(shí),將創(chuàng)建函數(shù)堆棧。下面是一些函數(shù)堆棧的例子。
它們可以小而簡(jiǎn)單:
FunctionStack nn = new FunctionStack( new Linear(2, 2, name: "l1 Linear"), new Sigmoid(name: "l1 Sigmoid"), new Linear(2, 2, name: "l2 Linear"));
它們也可以在大一點(diǎn):
FunctionStack nn = new FunctionStack( // Do not forget the GPU flag if necessary new Convolution2D(1, 2, 3, name: "conv1", gpuEnable: true), new ReLU(), new MaxPooling(2, 2), new Convolution2D(2, 2, 2, name: "conv2", gpuEnable: true), new ReLU(), new MaxPooling(2, 2), new Linear(8, 2, name: "fl3"), new ReLU(), new Linear(2, 2, name: "fl4") );
它們也可以非常大:
FunctionStack nn = new FunctionStack( new Linear(neuronCount * neuronCount, N, name: "l1 Linear"),//L1 new BatchNormalization(N, name: "l1 BatchNorm"), new LeakyReLU(slope: 0.000001, name: "l1 LeakyReLU"), new Linear(N, N, name: "l2 Linear"), // L2 new BatchNormalization(N, name: "l2 BatchNorm"), new LeakyReLU(slope: 0.000001, name: "l2 LeakyReLU"), new Linear(N, N, name: "l3 Linear"), // L3 new BatchNormalization(N, name: "l3 BatchNorm"), new LeakyReLU(slope: 0.000001, name: "l3 LeakyReLU"), new Linear(N, N, name: "l4 Linear"), // L4 new BatchNormalization(N, name: "l4 BatchNorm"), new LeakyReLU(slope: 0.000001, name: "l4 LeakyReLU"), new Linear(N, N, name: "l5 Linear"), // L5 new BatchNormalization(N, name: "l5 BatchNorm"), new LeakyReLU(slope: 0.000001, name: "l5 LeakyReLU"), new Linear(N, N, name: "l6 Linear"), // L6 new BatchNormalization(N, name: "l6 BatchNorm"), new LeakyReLU(slope: 0.000001, name: "l6 LeakyReLU"), new Linear(N, N, name: "l7 Linear"), // L7 new BatchNormalization(N, name: "l7 BatchNorm"), new LeakyReLU(slope: 0.000001, name: "l7 ReLU"), new Linear(N, N, name: "l8 Linear"), // L8 new BatchNormalization(N, name: "l8 BatchNorm"), new LeakyReLU(slope: 0.000001, name: "l8 LeakyReLU"), new Linear(N, N, name: "l9 Linear"), // L9 new BatchNormalization(N, name: "l9 BatchNorm"), new PolynomialApproximantSteep(slope: 0.000001, name: "l9 PolynomialApproximantSteep"), new Linear(N, N, name: "l10 Linear"), // L10 new BatchNormalization(N, name: "l10 BatchNorm"), new PolynomialApproximantSteep(slope: 0.000001, name: "l10 PolynomialApproximantSteep"), new Linear(N, N, name: "l11 Linear"), // L11 new BatchNormalization(N, name: "l11 BatchNorm"), new PolynomialApproximantSteep(slope: 0.000001, name: "l11 PolynomialApproximantSteep"), new Linear(N, N, name: "l12 Linear"), // L12 new BatchNormalization(N, name: "l12 BatchNorm"), new PolynomialApproximantSteep(slope: 0.000001, name: "l12 PolynomialApproximantSteep"), new Linear(N, N, name: "l13 Linear"), // L13 new BatchNormalization(N, name: "l13 BatchNorm"), new PolynomialApproximantSteep(slope: 0.000001, name: "l13 PolynomialApproximantSteep"), new Linear(N, N, name: "l14 Linear"), // L14 new BatchNormalization(N, name: "l14 BatchNorm"), new PolynomialApproximantSteep(slope: 0.000001, name: "l14 PolynomialApproximantSteep"), new Linear(N, 10, name: "l15 Linear") // L15 );
函數(shù)字典
函數(shù)字典是一個(gè)可序列化的函數(shù)字典(如前所述)。當(dāng)從磁盤加載網(wǎng)絡(luò)模型時(shí),將返回一個(gè)函數(shù)字典,并且可以像在代碼中創(chuàng)建函數(shù)堆棧一樣對(duì)其進(jìn)行操作。函數(shù)字典主要用于Caffe數(shù)據(jù)模型加載器。
Caffe1
Kelp.Net是圍繞Caffe風(fēng)格開(kāi)發(fā)的,它支持許多特性。
Caffe為多媒體科學(xué)家和實(shí)踐者提供了一個(gè)簡(jiǎn)潔和可修改的框架,用于最先進(jìn)的深度學(xué)習(xí)算法和一組參考模型。該框架是一個(gè)bsd許可的c++庫(kù),帶有Python和MATLAB綁定,用于在普通架構(gòu)上高效地培訓(xùn)和部署通用卷積神經(jīng)網(wǎng)絡(luò)和其他深度模型。Caffe通過(guò)CUDA GPU計(jì)算滿足了行業(yè)和互聯(lián)網(wǎng)規(guī)模的媒體需求,在一個(gè)K40或Titan GPU上每天處理超過(guò)4000萬(wàn)張圖像(大約每張圖像2毫秒)。通過(guò)分離模型表示和實(shí)際實(shí)現(xiàn),Caffe允許在平臺(tái)之間進(jìn)行試驗(yàn)和無(wú)縫切換,以簡(jiǎn)化開(kāi)發(fā)和部署,從原型機(jī)到云環(huán)境。
鏈
“Chainer是一個(gè)靈活的神經(jīng)網(wǎng)絡(luò)框架。一個(gè)主要的目標(biāo)是靈活性,因此它必須使我們能夠簡(jiǎn)單而直觀地編寫復(fù)雜的體系結(jié)構(gòu)。”
Chainer采用了按運(yùn)行定義的方案,即通過(guò)實(shí)際的正向計(jì)算動(dòng)態(tài)地定義網(wǎng)絡(luò)。更準(zhǔn)確地說(shuō),Chainer存儲(chǔ)的是計(jì)算歷史,而不是編程邏輯。例如,Chainer不需要任何東西就可以將條件和循環(huán)引入到網(wǎng)絡(luò)定義中。按運(yùn)行定義方案是Chainer的核心概念。這種策略也使得編寫多gpu并行化變得容易,因?yàn)檫壿嫺咏诰W(wǎng)絡(luò)操作。
Kelp.Net可以直接從磁盤加載Chainer模型。
Loss
Kelp.Net由一個(gè)抽象的LossFunction類組成,設(shè)計(jì)用于確定如何評(píng)估損失的特定實(shí)例。
在機(jī)器學(xué)習(xí)中,損失函數(shù)或成本函數(shù)是將一個(gè)事件或一個(gè)或多個(gè)變量的值直觀地映射到一個(gè)實(shí)數(shù)上的函數(shù),表示與該事件相關(guān)的一些成本。Kelp.Net提供了兩個(gè)開(kāi)箱即用的損失函數(shù):均方誤差和軟最大交叉熵。我們可以很容易地?cái)U(kuò)展它們以滿足我們的需求。
模型保存和加載
Kelp.Net使得通過(guò)調(diào)用一個(gè)簡(jiǎn)單的類來(lái)保存和加載模型變得非常容易。ModelIO類同時(shí)提供了保存和加載方法,以便輕松地保存和加載到磁盤。下面是一個(gè)非常簡(jiǎn)單的例子,在訓(xùn)練、重新加載并對(duì)模型執(zhí)行測(cè)試之后保存模型:

優(yōu)化程序
優(yōu)化算法根據(jù)模型的參數(shù)最小化或最大化誤差函數(shù)。參數(shù)的例子有權(quán)重和偏差。它們通過(guò)最小化損失來(lái)幫助計(jì)算輸出值并將模型更新到最優(yōu)解的位置。擴(kuò)展Kelp.Net以添加我們自己的優(yōu)化算法是一個(gè)簡(jiǎn)單的過(guò)程,盡管添加OpenCL和資源方面的東西是一個(gè)協(xié)調(diào)的工作。
Kelp.Net提供了許多預(yù)定義的優(yōu)化器,比如:
AdaDelta
AdaGrad
Adam
GradientClipping
MomentumSGD
RMSprop
SGD
這些都是基于抽象的優(yōu)化器類。
數(shù)據(jù)集
Kelp.Net本身支持以下數(shù)據(jù)集:
CIFAR
MNIST
CIFAR
CIFAR數(shù)據(jù)集有兩種形式,CIFAR-10和CIFAR 100,它們之間的區(qū)別是類的數(shù)量。讓我們簡(jiǎn)要地討論一下兩者。
CIFAR-10
CIFAR-10數(shù)據(jù)集包含10個(gè)類中的60000張32×32張彩色圖像,每個(gè)類包含6000張圖像。有50,000張訓(xùn)練圖像和10,000張測(cè)試圖像。數(shù)據(jù)集分為五個(gè)訓(xùn)練批次和一個(gè)測(cè)試批次,每個(gè)測(cè)試批次有10,000張圖像。測(cè)試批次包含從每個(gè)類中隨機(jī)選擇的1000個(gè)圖像。訓(xùn)練批次包含隨機(jī)順序的剩余圖像,但是一些訓(xùn)練批次可能包含一個(gè)類的圖像多于另一個(gè)類的圖像。在他們之間,每批訓(xùn)練包含了5000張圖片。
CIFAR-100
CIFAR-100數(shù)據(jù)集與CIFAR-10一樣,只是它有100個(gè)類,每個(gè)類包含600個(gè)圖像。每班有500張訓(xùn)練圖片和100張測(cè)試圖片。CIFAR-100中的100個(gè)類被分為20個(gè)超類。每個(gè)圖像都有一個(gè)細(xì)標(biāo)簽(它所屬的類)和一個(gè)粗標(biāo)簽(它所屬的超類)。以下是CIFAR-100的類型列表:
|
Superclass |
Classes |
|
水生哺乳動(dòng)物 |
海貍、海豚、水獺、海豹和鯨魚 |
|
魚 |
水族魚,比目魚,鰩魚,鯊魚和魚 |
|
花 |
蘭花、罌粟、玫瑰、向日葵和郁金香 |
|
食品容器 |
瓶子、碗、罐子、杯子和盤子 |
|
水果和蔬菜 |
蘋果、蘑菇、桔子、梨和甜椒 |
|
家用電器設(shè)備 |
時(shí)鐘、電腦鍵盤、燈、電話和電視 |
|
家用家具 |
床、椅子、沙發(fā)、桌子和衣柜 |
|
昆蟲(chóng) |
蜜蜂、甲蟲(chóng)、蝴蝶、毛蟲(chóng)和蟑螂 |
|
大型食肉動(dòng)物 |
熊、豹、獅子、老虎和狼 |
|
大型人造戶外用品 |
橋、城堡、房子、道路和摩天大樓 |
|
大型自然戶外景觀 |
云、林、山、平原、海 |
|
大型雜食動(dòng)物和食草動(dòng)物 |
駱駝、牛、黑猩猩、大象和袋鼠 |
|
中等大小的哺乳動(dòng)物 |
狐貍,豪豬,負(fù)鼠,浣熊和臭鼬 |
|
無(wú)脊椎動(dòng)物 |
螃蟹、龍蝦、蝸牛、蜘蛛和蠕蟲(chóng) |
|
人 |
寶貝,男孩,女孩,男人,女人 |
|
爬行動(dòng)物 |
鱷魚、恐龍、蜥蜴、蛇和烏龜 |
|
小型哺乳動(dòng)物 |
倉(cāng)鼠,老鼠,兔子,鼩鼱和松鼠 |
|
樹(shù) |
楓樹(shù)、橡樹(shù)、棕櫚樹(shù)、松樹(shù)和柳樹(shù) |
|
車輛1 |
自行車、公共汽車、摩托車、小貨車和火車 |
|
車輛2 |
割草機(jī)、火箭、有軌電車、坦克和拖拉機(jī) |
MNIST
MNIST數(shù)據(jù)庫(kù)是一個(gè)手寫數(shù)字的大型數(shù)據(jù)庫(kù),通常用于訓(xùn)練各種圖像處理系統(tǒng)。該數(shù)據(jù)庫(kù)還廣泛用于機(jī)器學(xué)習(xí)領(lǐng)域的培訓(xùn)和測(cè)試。它有一個(gè)包含6萬(wàn)個(gè)例子的訓(xùn)練集和一個(gè)包含1萬(wàn)個(gè)例子的測(cè)試集。數(shù)字的大小已經(jīng)標(biāo)準(zhǔn)化,并集中在一個(gè)固定大小的圖像中,這使它成為人們想要嘗試各種學(xué)習(xí)技術(shù)而不需要進(jìn)行預(yù)處理和格式化的標(biāo)準(zhǔn)選擇:

測(cè)試
測(cè)試是實(shí)際的執(zhí)行事件,也可以說(shuō)是小程序。由于OpenCL的使用,這些程序是在運(yùn)行時(shí)編譯的。要?jiǎng)?chuàng)建一個(gè)測(cè)試,您只需要提供一個(gè)封裝代碼的靜態(tài)運(yùn)行函數(shù)。Kelp.Net提供了一個(gè)預(yù)配置的測(cè)試器,這使得添加我們自己的測(cè)試變得非常簡(jiǎn)單。
現(xiàn)在,這里有一個(gè)簡(jiǎn)單的XOR測(cè)試程序的例子:
public static void Run() { const int learningCount = 10000; Real[][] trainData = { new Real[] { 0, 0 }, new Real[] { 1, 0 }, new Real[] { 0, 1 }, new Real[] { 1, 1 } }; Real[][] trainLabel = { new Real[] { 0 }, new Real[] { 1 }, new Real[] { 1 }, new Real[] { 0 } }; FunctionStack nn = new FunctionStack( new Linear(2, 2, name: "l1 Linear"), new ReLU(name: "l1 ReLU"), new Linear(2, 1, name: "l2 Linear")); nn.SetOptimizer(new AdaGrad()); RILogManager.Default?.SendDebug("Training..."); for (int i = 0; i < learningCount; i++) { //use MeanSquaredError for loss function Trainer.Train(nn,trainData[0],trainLabel[0],newMeanSquaredError(), false); Trainer.Train(nn, trainData[1], trainLabel[1], new MeanSquaredError(), false); Trainer.Train(nn, trainData[2], trainLabel[2], new MeanSquaredError(), false); Trainer.Train(nn, trainData[3], trainLabel[3], new MeanSquaredError(), false); //If you do not update every time after training, you can update it as a mini batch nn.Update(); } RILogManager.Default?.SendDebug("Test Start..."); foreach (Real[] val in trainData) { NdArray result = nn.Predict(val)[0]; RILogManager.Default?.SendDebug($"{val[0]} xor {val[1]} = {(result.Data[0] > 0.5 ? 1 : 0)} {result}"); } }
Weaver
Weaver是Kelp.Net的重要組成部分。是運(yùn)行測(cè)試時(shí)要執(zhí)行的第一個(gè)對(duì)象調(diào)用。這個(gè)對(duì)象包含各種OpenCL對(duì)象,比如:
l 計(jì)算上下文
l 一組計(jì)算設(shè)備
l 計(jì)算命令隊(duì)列
l 一個(gè)布爾標(biāo)志,表明GPU是否為啟用狀態(tài)
l 可核心計(jì)算資源的字典
Weaver是用來(lái)告訴我們的程序我們將使用CPU還是GPU,以及我們將使用哪個(gè)設(shè)備(如果我們的系統(tǒng)能夠支持多個(gè)設(shè)備)的地方。我們只需要在我們的程序開(kāi)始時(shí)對(duì)Weaver做一個(gè)簡(jiǎn)單的調(diào)用,就像在這里看到的:
Weaver.Initialize(ComputeDeviceTypes.Gpu);
我們還可以避免使用weaver的初始化調(diào)用,并允許它確定需要自動(dòng)發(fā)生什么。
以下是Weaver的基本內(nèi)容。它的目的是構(gòu)建(在運(yùn)行時(shí)動(dòng)態(tài)編譯)將執(zhí)行的程序:
///<summary>上下文</summary> internal static ComputeContext Context; ///<summary>設(shè)備</summary> private static ComputeDevice[] Devices; ///<summary>命令隊(duì)列</summary> internal static ComputeCommandQueue CommandQueue; ///<summary>設(shè)備的從零開(kāi)始索引</summary> private static int DeviceIndex; ///<summary>True啟用,false禁用</summary> internal static bool Enable; ///<summary>平臺(tái)</summary> private static ComputePlatform Platform; ///<summary>核心資源</summary> private static readonly Dictionary<string, string> KernelSources = new Dictionary<string, string>();
編寫測(cè)試
為Kelp.Net創(chuàng)建測(cè)試非常簡(jiǎn)單。我們編寫的每個(gè)測(cè)試只需要公開(kāi)一個(gè)運(yùn)行函數(shù)。剩下的就是我們希望網(wǎng)絡(luò)如何運(yùn)作的邏輯了。
運(yùn)行函數(shù)的一般準(zhǔn)則是:
- 負(fù)載數(shù)據(jù)(真實(shí)或模擬):
Real[][] trainData = new Real[N][]; Real[][] trainLabel = new Real[N][]; for (int i = 0; i < N; i++) { //Prepare Sin wave for one cycle Real radian = -Math.PI + Math.PI * 2.0 * i / (N - 1); trainData[i] = new[] { radian }; trainLabel[i] = new Real[] { Math.Sin(radian) };
2.創(chuàng)建函數(shù)堆棧:
FunctionStack nn = new FunctionStack( new Linear(1, 4, name: "l1 Linear"), new Tanh(name: "l1 Tanh"), new Linear(4, 1, name: "l2 Linear") );
3.選擇優(yōu)化器:
nn.SetOptimizer(new SGD());
4.訓(xùn)練數(shù)據(jù):
for (int i = 0; i < EPOCH; i++) { Real loss = 0; for (int j = 0; j < N; j++) { //When training is executed in the network, an error is returned to the return value loss += Trainer.Train(nn, trainData[j], trainLabel[j], new MeanSquaredError()); } if (i % (EPOCH / 10) == 0) { RILogManager.Default?.SendDebug("loss:" + loss / N); RILogManager.Default?.SendDebug(""); } }
5.測(cè)試數(shù)據(jù):
RILogManager.Default?.SendDebug("Test Start..."); foreach (Real[] val in trainData) { RILogManager.Default?.SendDebug(val[0]+":"+nn.Predict(val)[0].Data[0]); }
總結(jié)
在這一章中,我們進(jìn)入了深度學(xué)習(xí)的世界。我們學(xué)習(xí)了如何使用Kelp.Net作為我們的研究平臺(tái),它幾乎可以測(cè)試任何假設(shè)。我們還看到了Kelp.Net的強(qiáng)大功能和靈活性。
下一章開(kāi)始,我們進(jìn)入實(shí)際應(yīng)用階段。

浙公網(wǎng)安備 33010602011771號(hào)