驚!C++竟然還能有這種操作——高性能深度學習庫(DLL)
更多深度文章,請關注雲計算頻道:https://yq.aliyun.com/cloud
作為一個深度學習的老司機,你是不是以為隻有Python才能夠玩轉深度學習?如果是這樣的話,那麼本文作者可能就要教你怎麼“做人”了。畢竟大牛的世界我們不懂!
第一個版本C++的深度學習庫(DLL)1.0發布了!DLL是一個關注速度和易用性的神經網絡庫。大約4年前,作者就開始編寫這個庫。為了獲得博士學位,作者需要一個很好的庫來訓練和使用受限製的玻爾茲曼機器(RBMs),因為當時還沒有很好的庫來完成這項工作。所以我決定自己寫一個庫(大牛就是任性!)。它現在可以支持RBM和卷積RBM(CRBM)模型,也可以使用對比發散預先訓練RBM(或深層信念網絡(DBN))的堆棧,然後通過微型批量梯度下降或共軛梯度進行微調或用作特征提取器。近年來,該庫已經可以處理人造神經網絡(ANN)和卷積神經網絡(CNN)。該網絡還可以訓練常規的自動編碼器,還提供了幾個高級層,如Dropout或批次規範化(BN),以及自適應學習率技術,如Adadelta和Adam。該庫還集成了對幾個數據集的支持:MNIST,CIFAR-10和ImageNet。
該庫是使用C ++接口,它需要一個C ++ 14編譯器。
在這篇文章中,我將介紹一些關於使用該庫的例子,並提供有關庫表現和項目路線圖的一些信息。
我們來看看一個使用這個庫的例子:
#include "dll/neural/dense_layer.hpp"
#include "dll/network.hpp"
#include "dll/datasets.hpp"
int main(int /*argc*/, char* /*argv*/ []) {
// Load the dataset
auto dataset = dll::make_mnist_dataset(dll::batch_size<100>{}, dll::normalize_pre{});
// Build the network
using network_t = dll::dyn_network_desc<
dll::network_layers<
dll::dense_layer<28 * 28, 500>,
dll::dense_layer<500, 250>,
dll::dense_layer<250, 10, dll::softmax>
>
, dll::updater<dll::updater_type::NADAM> // Nesterov Adam (NADAM)
, dll::batch_size<100> // The mini-batch size
, dll::shuffle // Shuffle before each epoch
>::network_t;
auto net = std::make_unique<network_t>();
// Train the network for performance sake
net->fine_tune(dataset.train(), 50);
// Test the network on test set
net->evaluate(dataset.test());
return 0;
}
這是在MNIST數據集上訓練和測試一個簡單的三層全連接神經網絡。
首先,在頭文件中,你需要列出你正在使用的層,這裏隻有密集層;然後,你需要包括network.hpp
這是每個網絡的基本包括;最後一個頭文件是數據集。
在main函數中,首先我們需要完整的加載MNIST數據集並傳遞兩個選項。在這裏,我們要設置批量大小,並指示每個樣本應歸一化為具有零均值和單位方差。
之後是最重要的一部分,網絡的聲明。在DLL中,網絡是一種類(Type)。這個類有兩個部分:網絡層(一個dll::network_layers
)和選項(一個可選的選項列表,在網絡層後)。在上述代碼中,我們有三層,第一層有500個隱藏單元,第二層有250個隱藏單元,最後一層有10個。每層可以采用可選的選項列表。第三層使用softmax激活函數而不是默認的S形函數。我們正在使用Nesterov Adam(NAdam)更新器,批量大小為100(必須與數據集批量大小相同),數據集在每個時期之前被混洗。
最後,我們簡單地創建網絡std::make_unique
,然後在訓練集上訓練50次,最後在測試集上進行測試。
如果你編譯並運行這個程序,你應該看到這樣的:
Network with 3 layers
Dense(dyn): 784 -> SIGMOID -> 500
Dense(dyn): 500 -> SIGMOID -> 250
Dense(dyn): 250 -> SOFTMAX -> 10
Total parameters: 519500
Dataset
Training: In-Memory Data Generator
Size: 60000
Batches: 600
Augmented Size: 60000
Testing: In-Memory Data Generator
Size: 10000
Batches: 100
Augmented Size: 10000
Train the network with "Stochastic Gradient Descent"
Updater: NADAM
Loss: CATEGORICAL_CROSS_ENTROPY
Early Stop: Goal(error)
With parameters:
epochs=50
batch_size=100
learning_rate=0.002
beta1=0.9
beta2=0.999
Epoch 0/50 - Classification error: 0.03248 Loss: 0.11162 Time 3187ms
Epoch 1/50 - Classification error: 0.02737 Loss: 0.08670 Time 3063ms
Epoch 2/50 - Classification error: 0.01517 Loss: 0.04954 Time 3540ms
Epoch 3/50 - Classification error: 0.01022 Loss: 0.03284 Time 2954ms
•••••••••••••••••••
Epoch 48/50 - Classification error: 0.00352 Loss: 0.01002 Time 2665ms
Epoch 49/50 - Classification error: 0.00232 Loss: 0.00668 Time 2747ms
Restore the best (error) weights from epoch 40
Training took 142s
error: 0.02040
loss: 0.08889
首先顯示網絡和數據集信息,如代碼中所設定的,然後用數據訓練網絡,按次數劃分。最後,評估結果。在大約2分半左右的時間裏,我們訓練了一個能夠將MNIST數字分類出錯率為2.04%的神經網絡,這已經不錯的,但仍然可以改進。
幾個關於如何編譯的信息:你可以直接sudo make install_headers
在計算機上安裝dll庫。然後,你可以使用以下方式簡單地編譯文件:
clang ++ -std = c ++ 14 file.cpp
或者,如果將dll複製到本地dll目錄中,這編譯的時候需要指定include文件夾:
clang++ -std=c++14 -Idll/include -Idll/etl/lib/include -dll/Ietl/include/ -Idll/mnist/include/-Idll/cifar-10/include/file.cpp
有幾個編譯選項,以提高性能:
1.-DETL_PARALLEL:允許並行計算。
2.-DETL_VECTORIZE_FULL:啟用算法的全矢量化。
3.-DETL_BLAS_MODE:讓庫知道一個BLAS庫(例如MKL)。然後,你必須為你選擇的BLAS係列添加包含選項和鏈接選項。
4.-DETL_CUBLAS_MODE:讓庫知道NVIDIA cublas在本機上可用。然後必須添加相應的選項(包括目錄和鏈接庫)。
5.-DETL_CUDNN_MODE:讓庫知道NVIDIA cudnn在本機上可用。然後必須添加相應的選項(包括目錄和鏈接庫)。
6.-DETL_EGBLAS_MODE:讓庫知道你在本機上安裝了etl-gpu-blas。然後必須添加相應的選項(包括目錄和鏈接庫)。
如果你想要最佳的CPU性能,你應該使用前三個選項。如果你想要最好的GPU性能,你隻需啟動第三個。理想情況下,你可以啟用所有選項,因此你將獲得最佳性能,因為GPU尚未完全支持。
我們再次進行相同的實驗,但是使用具有兩個卷積層和兩個池層的卷積神經網絡:
#include "dll/neural/conv_layer.hpp"
#include "dll/neural/dense_layer.hpp"
#include "dll/pooling/mp_layer.hpp"
#include "dll/network.hpp"
#include "dll/datasets.hpp"
#include "mnist/mnist_reader.hpp"
#include "mnist/mnist_utils.hpp"
int main(int /*argc*/, char* /*argv*/ []) {
// Load the dataset
auto dataset = dll::make_mnist_dataset(dll::batch_size<100>{}, dll::scale_pre<255>{});
// Build the network
using network_t = dll::dyn_network_desc<
dll::network_layers<
dll::conv_layer<1, 28, 28, 8, 5, 5>,
dll::mp_2d_layer<8, 24, 24, 2, 2>,
dll::conv_layer<8, 12, 12, 8, 5, 5>,
dll::mp_2d_layer<8, 8, 8, 2, 2>,
dll::dense_layer<8 * 4 * 4, 150>,
dll::dense_layer<150, 10, dll::softmax>
>
, dll::updater<dll::updater_type::NADAM> // Momentum
, dll::batch_size<100> // The mini-batch size
, dll::shuffle // Shuffle the dataset before each epoch
>::network_t;
auto net = std::make_unique<network_t>();
// Display the network and dataset
net->display();
dataset.display();
// Train the network
net->fine_tune(dataset.train(), 25);
// Test the network on test set
net->evaluate(dataset.test());
return 0;
}
與上一個例子相比,沒有什麼大的改變。網絡現在以卷積層開始,隨後是一個池層,然後有是卷積層和一個池層,最後是兩個完全連接的層。另一個區別是我們將輸入縮放為255,而不是歸一化它們。最後,我們訓練25次。
一旦編譯並運行,輸出應該是這樣的:
Network with 6 layers
Conv(dyn): 1x28x28 -> (8x5x5) -> SIGMOID -> 8x24x24
MP(2d): 8x24x24 -> (2x2) -> 8x12x12
Conv(dyn): 8x12x12 -> (8x5x5) -> SIGMOID -> 8x8x8
MP(2d): 8x8x8 -> (2x2) -> 8x4x4
Dense(dyn): 128 -> SIGMOID -> 150
Dense(dyn): 150 -> SOFTMAX -> 10
Total parameters: 21100
Dataset
Training: In-Memory Data Generator
Size: 60000
Batches: 600
Augmented Size: 60000
Testing: In-Memory Data Generator
Size: 10000
Batches: 100
Augmented Size: 10000
Train the network with "Stochastic Gradient Descent"
Updater: NADAM
Loss: CATEGORICAL_CROSS_ENTROPY
Early Stop: Goal(error)
With parameters:
epochs=25
batch_size=100
learning_rate=0.002
beta1=0.9
beta2=0.999
Epoch 0/25 - Classification error: 0.09392 Loss: 0.31740 Time 7298ms
Epoch 1/25 - Classification error: 0.07005 Loss: 0.23473 Time 7298ms
••••••
Epoch 24/25 - Classification error: 0.00682 Loss: 0.02327 Time 7335ms
Training took 186s
error: 0.01520
loss: 0.05183
這個網絡性能比以前的網絡好一點,在大約3分鍾內達到1.52%的錯誤率。
如果你有興趣,可以在Github信息庫中找到更多的例子。
我一直在做該庫性能提升方麵的工作。為了看看該庫和其他流行的框架的差別,我決定比較DLL與TensorFlow,Keras,Torch和Caffe的性能。我也嚐試過DeepLearning4J,但是我認為它的表現是相當差的,所以我放棄了。
我做的第一個實驗是在MNIST數據集上訓練一個三層的神經網絡:
在CPU上,DLL是訓練這個網絡最快的框架,比TensorFlow和Keras快35%,比Torch快4倍,比Caffe快5倍。在GPU上,Caffe是最快的框架,其次是Keras和TensorFlow和DLL。
讓我們來看看框架是如何與這些流行框架在一個小的CNN任務:
在CPU上,DLL是最快的框架,並且優勢非常大,比TensorFlow和Keras快四倍,比Torch和Caffe快五倍。在GPU上,它與Keras和TensorFlow相當,比Caffe快3倍。
下一個測試是用較大的CNN在CIFAR-10上完成的:
在這個更大的CNN上,差異不如以前那麼令人印象深刻,但是,DLL仍然是CPU中最快的框架。它比TensorFlow,Keras和Torch還要快兩倍,比Caffe快三倍。在GPU上,DLL比Keras和TensorFlow稍快,比Caffe快2.7倍,比Torch快5倍。
最後一次測試是在Imagenet上完成的,具有12層CNN。這一次,性能體現主要是在必要的時間訓練了128個圖像。
再次,DLL比CPU和GPU上的所有其他框架更快。DLL和TensorFlow和Keras之間的巨大差異主要是由於從Python代碼讀取Imagenet圖像的性能差,而代碼在DLL中進行了優化。
總的來說,在所有測試實驗中,DLL總是CPU上最快的框架。在GPU上,除了一個非常小的全連接網絡,它也是比TensorFlow和Keras快。
如果你有興趣,可以查找這些實驗的代碼。
我不知道下一個版本的DLL將包含什麼,但我知道我將要開發的方向。我想使用DLL來分類文本。第一次打算,我計劃增加對文本嵌入學習的支持,並能夠在嵌入之上使用CNN,希望這不會花太長時間。第二次打算,我希望將支持循環神經網絡(RNNs)納,以及增加對LSTM和GRU單元的支持,這可能會需要一些時間。
雖然該框架性能表現已經相當不錯了,但還有一些事情要改善。現在有些操作在GPU上實現時並不高效,例如Batch Normalization and Dropout。我想保證所有的操作都可以在GPU上進行有效的計算。還有一些在CPU上效率不高的情況,例如,批處理標準化目前很差。一些SGD優化器,如Nadam也很慢。
下載DLL
你可以在Github上下載DLL 。如果你隻對1.0版本感興趣,可以查看 版本頁麵或克隆標簽1.0。有幾個分支:
1.master是前進的發展分支,可能是不穩定的。
2.stable分支總是指向最後一個標簽,這裏沒有開發。
對於文檔,這是關於這個框架迄今為止最好的文檔是可用的示例。你還可以查看使用庫的每個功能的測試源。
如果你對此圖書館有任何意見或任何問題,請隨時給予評論。如果你在使用此庫時遇到問題,或者如果你想對該庫有所貢獻,請及時與我聯係我期待你的到來。
本文由北郵@愛可可-愛生活老師推薦,阿裏雲雲棲社區組織翻譯。
文章原標題:《deep-learning-library-1.0-fast-neural-network-library》
作者:Baptiste Wicht
現年28歲。我是弗裏堡大學應用科學大學計算機科學博士生,主要從事機器學習。目前,主要從事開發C ++高性能應用程序。
Twitter:@wichtounet
LinkedIn:我的LinkedIn個人資料
譯者:袁虎,審校:
文章為簡譯,更為詳細的內容,請查看原文
最後更新:2017-10-08 11:33:20