用 CNTK 搞深度學習 (一) 入門

Computational Network Toolkit (CNTK) 是微軟出品的開源深度學習工具包。本文介紹CNTK的基本內容,如何寫CNTK的網絡定義語言,以及跑通一個簡單的例子。html

 根據微軟開發者的描述,CNTK的性能比Caffe,Theano, TensoFlow等主流工具都要強。它支持CPU和GPU模式,因此沒有GPU,或者神經網絡比較小的實驗,直接用CPU版的CNTK跑就好了。 其開源主頁在 https://github.com/Microsoft/CNTK  它把神經網絡描述成一個有向圖的結構,葉子節點表明輸入或者網絡參數,其餘節點計算步驟。 它支持卷積神經網絡和遞歸神經網絡。 因爲CNTK剛推出不久,大衆教程估計很少,並且bug估計也很多。我學習的時候,主要參考三個資料:node

1 官方入門教程  https://github.com/Microsoft/CNTK/wiki/Tutorial  本文也主要以這裏的教程爲例git

2 官方論壇 https://github.com/Microsoft/CNTK/issuesgithub

3 官方論文 http://research.microsoft.com/pubs/226641/CNTKBook-20160217..pdf  這個有150頁,我是看成字典來用,遇到問題的時候就在裏面搜算法

 

安裝CNTK: https://github.com/Microsoft/CNTK/wiki/CNTK-Binary-Download-and-Configuration  去這個頁面找符合本身系統的版本。 我是Windows用戶,CNTK有編譯好的CPU和GPU版本。因爲本人的顯卡不是英偉達的,因此無奈只能用CPU版湊合用用。已經編譯好的包最方便了,解壓,而後把目錄(相似%...%、CNTK-2016-02-08-Windows-64bit-CPU-Only\cntk\cntk)添加到PATH變量中就好了。  有條件的人也能夠本身編譯源代碼,稍微麻煩一些,各類依賴關係,好處是源碼更新的比較快,CNTK一大特色就是目前各類小bug比較多,好比我如今用的編譯好的包仍是兩個月前發佈的,已經本身填了好多坑了。網絡

安裝好CNTK以後,運行一個程序,就是一個簡單的命令行:  CNTK configFile=your_config_file , 其中,your_config_file 是網絡的定義文件,大概長這樣:app

command=Train:Test
Train=[
]action="train"

        NDLNetworkBuilder = [
        ...
        ]

        SGD = [
        ...
        ]

        reader = [
        ...
    ]

 Test=[ ... ]

運行的入口就是command命令,command後面接須要依次運行的模塊,用冒號分開。 每一個模塊裏面須要定義的事情比較相似,主要是定義輸入的格式,網絡結構,學習算法(目前只有SGD)和參數。 在定義網絡結構的時候,會指明哪些節點是優化目標,哪些是評價指標,以及哪些是輸出的點。框架

衆所周知,把神經網絡的隱藏層去掉以後,輸入直接連到輸出層,這樣就行成了一個logistics regression分類器。因此https://github.com/Microsoft/CNTK/wiki/Tutorial 這個教程就指導你們如何構建一個LR。 我這裏稍微變一下,學習一下如何構建帶有一層隱藏層的neural network,以下圖:dom

定義網絡結構函數

CNTK用網絡描述語言(network description language, NDL)描述一個神經網絡。 簡單的說,咱們要描述輸入的feature,輸入的label,一些參數,參數和輸入之間的計算關係,以及目標節點是什麼。

NDLNetworkBuilder=[
    
    run=ndlLR
    
    ndlLR=[
      # sample and label dimensions
      SDim=$dimension$
      LDim=1
    
      features=Input(SDim, 1)
      labels=Input(LDim, 1)
    
      # parameters to learn
      B0 = Parameter(4) 
      W0 = Parameter(4, SDim)
      
      
      B = Parameter(LDim)
      W = Parameter(LDim, 4)
    
      # operations
      t0 = Times(W0, features)
      z0 = Plus(t0, B0)
      s0 = Sigmoid(z0)   
      
      t = Times(W, s0)
      z = Plus(t, B)
      s = Sigmoid(z)    
    
      LR = Logistic(labels, s)
      EP = SquareError(labels, s)
    
      # root nodes
      FeatureNodes=(features)
      LabelNodes=(labels)
      CriteriaNodes=(LR)
      EvalNodes=(EP)
      OutputNodes=(s,t,z,s0,W0)
    ]   
  ]
features=Input(SDim, 1) labels=Input(LDim, 1) 和 B0 = Parameter(4)  等能夠想象成是在定義變量。 輸入是列向量,CNTK裏面的運算全是矩陣運算,因此就把輸入當作只有一列的矩陣。  t0 = Times(W0, features) 是作矩陣乘法,t0把輸入和權重相乘,z0 是在t0上面加了一個bias,
s0表示通過一個激活函數。 B0,W0,t0,z0,s0構成了隱層的操做,這裏定義的隱層有4個節點。 t,z,s是輸出層的操做,s就是輸出節點的值。 框架定義好以後,還須要指定一些根節點,用來指定特殊的任務,例如 FeatureNodes=(features) 和LabelNodes=(labels)分別規定了輸入和輸出節點,CriteriaNodes 是訓練的
時候優化的目標,EvalNodes 是在作評測的時候輸出的參考值。OutputNodes 指定了須要輸出到文件的節點。

設置訓練算法
SGD = [    
        epochSize=0     #  每輪迭代使用的樣例數,  =0 表示使用整個訓練集
        minibatchSize=25  # 訓練25個樣本就更新一次參數
        learningRatesPerMB=0.1                # learning rates per MB
        maxEpochs=50    #迭代50次
    ]
    

目前只有SGD(以及在SGD上的各類變種),能夠在裏面設置各類參數。

 

設置輸入格式

reader = [
        #customDelimiter = " "
        readerType = "UCIFastReader"
        file = "Train.txt"
        miniBatchMode = "partial"        
        verbosity = 1
        randomize = "none"
        
        features=[
            dim = $dimension$
            start = 0
        ]
    
        labels=[
            start = $dimension$              # skip $dimension$ elements before reading the label (i.e. the first two dimensions so we have "x1 x2 y" basically)
            dim = 1                          # label has 1 dimension
            labelType=regression
            labelMappingFile = "SimpleMapping.txt"
        ]
    ]

這也是CNTK的一個特色(吐槽點), 指定用什麼方式讀取數據文件。 readerType = "UCIFastReader" 指定用普通的扁平化表格的格式(一行一個樣例,同一行內用空格隔開不一樣的數值),還有別的格式類型,例如圖像格式,文本語料格式等。UCIFastReader 是將被棄用的,並且在目前最新的binary包中是有bug的 (因此說,有條件的同窗儘可能本身編譯最新的源碼)。  用官方教程裏的設置直接跑回出bug,以上是我修改過的代碼。 輸入格式主要描述了feature是哪幾列,維度是多少,label是哪幾列, label的類型等等。

 

綜上,Train這個模塊就是定義了這幾件事情:輸入格式,網絡內容,訓練模式。 運行的時候也是這個步驟: 讀取數據-> SGD 訓練. 

其餘

除了Train以外的模塊的流程比較相似,它們不須要再定義網絡結構和訓練模式,可是輸入格式仍是要指定的。 例如Test模塊的流程是:  讀取數據->計算網絡->獲得預測值->評估.    評估針對的是在網絡結構中被定義爲EvalNodes 的節點。 SquareError 只是其中的一種評估指標。若是想用別的偏差函數,能夠去查字典http://research.microsoft.com/pubs/226641/CNTKBook-20160217..pdf 

Test=[
    action="test"
    reader=[
        readerType="UCIFastReader"
        file="Test.txt"
        features=[
            dim=2
            start=0
        ]
        labels=[
            start=$dimension$
            dim=1
            labelDim=2
        ]
    ]
]

 

Output模塊和Test的流程基本同樣,只不過最後一個不是評估,而是把屬於OutputNodes的值給輸出到文件。 Output模塊會指定一個輸出目錄 outputPath = "LR.txt" , 輸出的文件以「LR.txt」爲前綴,再加上變量命做爲文件名。例如"LR.txt.W0"。

 

# output the results
Output=[
    action="write"
    reader=[
        readerType="UCIFastReader"
        file="Test.txt"
        features=[
            dim=$dimension$
            start=0
        ]
        labels=[
            start=2
            dim=1
            labelType=regression
        ]
    ]
    outputPath = "LR.txt"       # dump the output as text
]

 

dumpNodeInfo  用來輸出參數的值。這在調試中頗有用,例如去看看網絡的參數是如何變化的:

dumpNodeInfo=[
        action=dumpnode
        printValues=true
    ]
#################################################################### B
=LearnableParameter [1,1] NeedGradient=true -6.67130613 #################################################################### EP=SquareError ( labels , s ) features=InputValue [ 2 x 1 {1,2} ] labels=InputValue [ 1 x 1 {1,1} ] LR=Logistic ( labels , s ) s=Sigmoid ( z ) t=Times ( W , features ) W=LearnableParameter [1,2] NeedGradient=true 1.23924482 1.59913719 #################################################################### z=Plus ( t , B )

 

所有的代碼以下。 train文件 https://github.com/Microsoft/CNTK/wiki/Tutorial/Train-3Classes.txt  test 文件 https://github.com/Microsoft/CNTK/wiki/Tutorial/Test-3Classes.txt。 數據是2維的:

 

# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.

# logistic regression cntk script -- Network Description Language

# which commands to run
command=Train:Output:dumpNodeInfo:Test

#required...
modelPath="Models/LR_reg.dnn"        # where to write the model to
deviceId=-1                                # CPU
dimension=2                 # input data dimensions

# training config
Train=[
    action="train"
    traceLevel = 1
    NDLNetworkBuilder=[
    
    run=ndlLR
    
    ndlLR=[
      # sample and label dimensions
      SDim=$dimension$
      LDim=1
    
      features=Input(SDim, 1)
      labels=Input(LDim, 1)
    
      # parameters to learn
      B0 = Parameter(4)
      W0 = Parameter(4, SDim)
      
      
      B = Parameter(LDim)
      W = Parameter(LDim, 4)
    
      # operations
      t0 = Times(W0, features)
      z0 = Plus(t0, B0)
      s0 = Sigmoid(z0)   
      
      t = Times(W, s0)
      z = Plus(t, B)
      s = Sigmoid(z)    
    
      LR = Logistic(labels, s)
      EP = SquareError(labels, s)
    
      # root nodes
      FeatureNodes=(features)
      LabelNodes=(labels)
      CriteriaNodes=(LR)
      EvalNodes=(EP)
      OutputNodes=(s,t,z,s0,W0)
    ]   
  ]
    
    SGD = [    
        epochSize=0                              # =0 means size of the training set
        minibatchSize=25
        learningRatesPerMB=0.1                # learning rates per MB
        maxEpochs=50
    ]
    
    # parameter values for the reader
    reader = [
        #customDelimiter = " "
        readerType = "UCIFastReader"
        file = "Train.txt"
        miniBatchMode = "partial"        
        verbosity = 1
        randomize = "none"
        
        features=[
            dim = $dimension$
            start = 0
        ]
    
        labels=[
            start = $dimension$              # skip $dimension$ elements before reading the label (i.e. the first two dimensions so we have "x1 x2 y" basically)
            dim = 1                          # label has 1 dimension
            labelType=regression
            labelMappingFile = "SimpleMapping.txt"
        ]
    ]
]

# test
Test=[
    action="test"    
    reader=[
        readerType="UCIFastReader"
        randomize = "none"
        file="Test.txt"
        features=[
            dim=$dimension$
            start=0
        ]
        labels=[
            start = $dimension$              # skip $dimension$ elements before reading the label (i.e. the first two dimensions so we have "x1 x2 y" basically)
            dim = 1                          # label has 1 dimension
            labelType=regression
            labelMappingFile = "SimpleMapping.txt"
        ]
    ]
]

# output the results
Output=[
    action="write"    
    reader=[
        readerType="UCIFastReader"
        file="Test.txt"        
        randomize = "none"
        features=[
            dim=$dimension$
            start=0
        ]
        
        labels=[
            start = $dimension$              # skip $dimension$ elements before reading the label (i.e. the first two dimensions so we have "x1 x2 y" basically)
            dim = 1                          # label has 1 dimension
            labelType=regression
            labelMappingFile = "SimpleMapping.txt"
        ]
    ]    
    outputPath = "LR.txt"        # dump the output as text
]

dumpNodeInfo=[
  action=dumpnode
  printValues=false
]

 

 後一篇:

用CNTK搞深度學習 (二) 訓練基於RNN的天然語言模型 ( language model )

 http://www.cnblogs.com/sylvanas2012/p/5419477.html

 

原創博客,未經容許,請勿轉載。

相關文章
相關標籤/搜索