代碼分析CNTK和TensorFlow高層次的對比
大?。?/span>0.2 MB 人氣: 2017-10-12 需要積分:1
原標題:當TensorFlow遇見CNTK

CNTK是微軟用于搭建深度神經(jīng)網(wǎng)絡的計算網(wǎng)絡工具包,此項目已在Github上開源。因為我最近寫了關于TensorFlow的文章,所以想比較一下這兩個系統(tǒng)的相似和差異之處。畢竟,CNTK也是許多圖像識別挑戰(zhàn)賽的衛(wèi)冕冠軍。為了內(nèi)容的完整性,我應該也對比一下Theano、Torch和Caffe。后三者也是現(xiàn)在非常流行的框架。但是本文僅限于討論CNTK和TensorFlow,其余的框架將在今后討論。Kenneth Tran對這五個深度學習工具包做過一次高水平(以他個人觀點)的分析。本文并不是一個CNTK或者TensorFlow的使用教程。我的目的在于從程序員的角度對它們做高層次的對比。本文也不屬于性能分析,而是編程模型分析。文中會夾雜著大量的代碼,如果你討厭閱讀代碼,請直接跳到結(jié)論部分。
CNTK有一套極度優(yōu)化的運行系統(tǒng)來訓練和測試神經(jīng)網(wǎng)絡,它是以抽象的計算圖形式構(gòu)建。如此看來,CNTK和TensorFlow長得非常相似。但是,它們有一些本質(zhì)上的區(qū)別。為了演示這些特性和區(qū)別,我會用到兩個標準示例,它們分別包括了兩個系統(tǒng)及調(diào)用各自系統(tǒng)完成的任務。第一個例子是用較淺的卷積神經(jīng)網(wǎng)絡來解決標準的MNIST手寫數(shù)字集的識別任務。我會針對它們兩種遞歸神經(jīng)網(wǎng)絡方法的差異性做一些點評總結(jié)。
TensorFlow和CNTK都屬于腳本驅(qū)動型的。我的意思是說神經(jīng)網(wǎng)絡構(gòu)建的流程圖都是在一個腳本里完成,并調(diào)用一些智能的自動化步驟完成訓練。TensorFlow的腳本是與Python語言捆綁的,Python操作符能夠用來控制計算圖的執(zhí)行過程。CNTK目前還沒有和Python或是C++綁定(盡管已經(jīng)承諾過),所以它目前訓練和測試的流程控制還是需要精心編制設計的。等會我將展示,這個過程并不能算是一種限制。CNTK網(wǎng)絡需要用到兩個腳本:一個控制訓練和測試參數(shù)的配置文件和一個用于構(gòu)建網(wǎng)絡的網(wǎng)絡定義語言(Network Definition Language, NDL)文件。
我會首先描述神經(jīng)網(wǎng)絡的流程圖,因為這是與TensorFlow最相似之處。CNTK支持兩種方式來定義網(wǎng)絡。一種是使用“Simple Network Builder”,只需設置幾個參數(shù)就能生成一個簡單的標準神經(jīng)網(wǎng)絡。另一種是使用網(wǎng)絡定義語言(NDL)。此處例子(直接從Github下載的)使用的是NDL。下面就是Convolution.ndl文件的縮略版本。(為了節(jié)省頁面空間,我把多行文件合并到同一行,并用逗號分隔)
CNTK網(wǎng)絡圖有一些特殊的節(jié)點。它們是描述輸入數(shù)據(jù)和訓練標簽的FeatureNodes和LabelNodes,用來評估訓練結(jié)果的CriterionNodes和EvalNodes,和表示輸出的OutputNodes。當我們在下文中遇到它們的時候我再具體解釋。在文件頂部還有一些用來加載數(shù)據(jù)(特征)和標簽的宏定義。如下所示,我們將MNIST數(shù)據(jù)集的圖像作為特征讀入,經(jīng)過歸一化之后轉(zhuǎn)化為若干浮點數(shù)組。得到的數(shù)組“featScaled”將作為神經(jīng)網(wǎng)絡的輸入值。
load= ndlMnistMacros # the actual NDL that defines the networkrun= DNN ndlMnistMacros= [ imageW = 28, imageH = 28 labelDim = 10 features = ImageInput(imageW, imageH, 1) featScale = Const(0.00390625) featScaled = Scale(featScale, features) labels = Input(labelDim) ] DNN=[ # conv1kW1 = 5, kH1 = 5 cMap1 = 16 hStride1 = 1, vStride1 = 1 conv1_act = ConvReLULayer(featScaled,cMap1,25,kW1,kH1,hStride1,vStride1,10, 1) # pool1pool1W = 2, pool1H = 2 pool1hStride = 2, pool1vStride = 2 pool1 = MaxPooling(conv1_act, pool1W, pool1H, pool1hStride, pool1vStride) # conv2kW2 = 5, kH2 = 5 cMap2 = 32 hStride2 = 1, vStride2 = 1 conv2_act = ConvReLULayer(pool1,cMap2,400,kW2, kH2, hStride2, vStride2,10, 1) # pool2pool2W = 2, pool2H = 2 pool2hStride = 2, pool2vStride = 2 pool2 = MaxPooling(conv2_act, pool2W, pool2H, pool2hStride, pool2vStride) h1Dim = 128 h1 = DNNSigmoidLayer(512, h1Dim, pool2, 1) ol = DNNLayer(h1Dim, labelDim, h1, 1) ce = CrossEntropyWithSoftmax(labels, ol) err = ErrorPrediction(labels, ol) # Special NodesFeatureNodes = (features) LabelNodes = (labels) CriterionNodes = (ce) EvalNodes = (err) OutputNodes = (ol) ]
DNN小節(jié)定義了網(wǎng)絡的結(jié)構(gòu)。此神經(jīng)網(wǎng)絡包括了兩個卷積-最大池化層,接著是有一個128節(jié)點隱藏層的全連接標準網(wǎng)絡。
在卷積層I 我們使用5x5的卷積核函數(shù),并且在參數(shù)空間定義了16個(cMap1)。操作符ConvReLULayer實際上是在宏文件中定義的另一個子網(wǎng)絡的縮寫。
在計算時,我們想把卷積的參數(shù)用矩陣W和向量B來表示,那么如果輸入的是X,網(wǎng)絡的輸出將是f(op(W, X) + B)的形式。在這里操作符op就是卷積運算,f是標準規(guī)則化函數(shù)relu(x)=max(x,0)。
ConvReLULayer的NDL代碼如下圖所示:
ConvReLULayer(inp, outMap, inWCount, kW, kH, hStride, vStride, wScale, bValue) = [ convW = Parameter(outMap, inWCount, init=“uniform”, initValueScale=wScale) convB = Parameter(outMap, 1, init=“fixedValue”, value=bValue) conv = Convolution(convW, inp, kW, kH, outMap, hStride,vStride, zeroPadding=false) convPlusB = Plus(conv, convB); act = RectifiedLinear(convPlusB); ]
矩陣W和向量B是模型的參數(shù),它們會被賦予一個初始值,并在訓練的過程中不斷更新直到生成最終模型。這里,convW是一個16行25列的矩陣,B是長度為16的向量。Convolution是內(nèi)置的卷積函數(shù),默認不使用補零的方法。也就是說對28x28的圖像做卷積運算,實際上只是對24x24的中心區(qū)域操作,得到的結(jié)果是16個24x24的sudo-image。
接著我們用2x2的區(qū)域應用最大池化操作,最后得到的結(jié)果是16個12x12的矩陣。

對于第二個卷積層,我們把卷積濾波器的個數(shù)由16個提升到32個。這一次我們有16通道的輸入數(shù)據(jù),因此W矩陣的尺寸為32行25×16 = 400列,向量B的長度為32。這次的卷積運算針對12x12圖像幀的中心區(qū)域,所以得到的結(jié)果是32個8x8的矩陣。第二次池化操作的結(jié)果是32個4x4的幀,或者32x16=512。
最后兩層,是由512個池化輸出結(jié)果經(jīng)過128個節(jié)點的隱藏層連接到10個輸出節(jié)點,經(jīng)歷了兩次運算操作。
DNNSigmoidLayer(inDim, outDim, x, parmScale) = [ W = Parameter(outDim, inDim, init=“uniform”, initValueScale=parmScale) b = Parameter(outDim, 1, init=“uniform”, initValueScale=parmScale) t = Times(W, x) z = Plus(t, b) y = Sigmoid(z) ] DNNLayer(inDim, outDim, x, parmScale) = [ W = Parameter(outDim, inDim, init=“uniform”, initValueScale=parmScale) b = Parameter(outDim, 1, init=“uniform”, initValueScale=parmScale) t = Times(W, x) z = Plus(t, b) ]
如你所見,這些運算步驟都是標準的線性代數(shù)運算形式W*x+b。
圖定義的最后部分是交叉熵和誤差節(jié)點,以及將它們綁定到特殊的節(jié)點名稱。
我們接著要來定義訓練的過程,但是先把它與用TensorFlow構(gòu)建相似的網(wǎng)絡模型做個比較。我們在之前的文章里討論過這部分內(nèi)容,這里再討論一次。你是否注意到我們使用了與CNTK相同的一組變量,只不過這里我們把它稱作變量,而在CNTK稱作參數(shù)。維度也略有不同。盡管卷積濾波器都是5x5,在CNTK我們前后兩級分別使用了16個和32個濾波器,但是在TensorFlow的例子里我們用的是32個和64個。
defweight_variable(shape, names):initial = tf.truncated_normal(shape, stddev=0.1) returntf.Variable(initial, name=names) defbias_variable(shape, names):initial = tf.constant(0.1, shape=shape) returntf.Variable(initial, name=names) x = tf.placeholder(tf.float32, [None, 784], name=“x”) sess = tf.InteractiveSession() W_conv1 = weight_variable([5, 5, 1, 32], “wconv”) b_conv1 = bias_variable([32], “bconv”) W_conv2 = weight_variable([5, 5, 32, 64], “wconv2”) b_conv2 = bias_variable([64], “bconv2”) W_fc1 = weight_variable([7* 7* 64, 1024], “wfc1”) b_fc1 = bias_variable([1024], “bfcl”) W_fc2 = weight_variable([1024, 10], “wfc2”) b_fc2 = bias_variable([10], “bfc2”)
網(wǎng)絡的構(gòu)建過程也大同小異。
defconv2d(x, W):returntf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding=‘SAME’) defmax_pool_2x2(x):returntf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding=‘SAME’) #first convolutional layerx_image = tf.reshape(x, [-1,28,28,1]) h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1) h_pool1 = max_pool_2x2(h_conv1) #second convolutional layerh_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2) h_pool2 = max_pool_2x2(h_conv2) #final layerh_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64]) h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1) h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob) y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
卷積運算的唯一不同之處是這里定義了補零,因此第一次卷積運算的輸出是28x28,經(jīng)過池化后,降為14x14。第二次卷積運算和池化之后的結(jié)果降為了7x7,所以最后一層的輸入是7x7x64 = 3136維,有1024個隱藏節(jié)點(使用relu而不是sigmoid函數(shù))。(在訓練時,最后一步用到了dropout函數(shù)將模型數(shù)值隨機地置零。如果keep_prob=1則忽略這步操作。)
非常好我支持^.^
(0) 0%
不好我反對
(0) 0%
下載地址
代碼分析CNTK和TensorFlow高層次的對比下載
相關電子資料下載
- 【風火輪YY3568開發(fā)板免費體驗】第六章:在Solus上運行自定義模型并遷移到Y(jié)Y3 411
- 深度學習框架tensorflow介紹 480
- 深度學習框架pytorch介紹 454
- 【米爾MYC-JX8MPQ評測】+ 運行 TensorFlow Lite(CPU和NPU對比) 524
- 手把手帶你玩轉(zhuǎn)—i.MX8MP開發(fā)板移植官方NPU TensorFlow例程 444
- 在樹莓派64位上安裝TensorFlow 505
- TensorFlow Lite for MCUs - 網(wǎng)絡邊緣的人工智能 339
- 2023年使用樹莓派和替代品進行深度學習 1506
- 用TensorFlow2.0框架實現(xiàn)BP網(wǎng)絡 1849
- 那些年在pytorch上踩過的坑 571