CNTK从入门到深入研究(2) - 研究CNTK配置文件

前言

根据前一篇文章的介绍,大家已经对CNTK有所了解,并且也已经搭建好了运行环境。在前一篇文章最后的例子中,我们只是简单地运行了CNTK提供的其中一个样例。并且得到了结果。大家可能发现,在命令cntk.exe的后面,需要接一个参数用于指明配置文件。
本文中将详细的描述配置文件的各个部分,笔者会尽量的按照层次结构进行讲解。所以本文可以作为一个交流的文档,也可以当做一个参考资料以备所需。

简单的说明下CNTK配置文件

CNTK配置文件从功能的角度来说就是给大家一个地方去写明操作的逻辑。这里操作的逻辑指的是大家使用CNTK的目的。你希望CNTK去运行什么,设定模型?训练模型?还是评估测试模型?。这些都是命令,CNTK配置文件给出了一种方式去写一个文件来描述这些操作逻辑。由于机器学习中所涉及的参数很多,所以基本无法让用户直接通过命令行的方式输入。所以配置文件基本上是必须的。

其中CNTK的配置文件还有合并和覆盖等特性。cntk.exe可以同时加载多个配置文件,但是如果配置文件中数据块中有一样的项,则后面的配置文件的相应配置信息会覆盖前面的。当然,如果两个配置文件中如果数据快中的项完全不同,则取并集。

CNTK配置文件

基本语法

一切都要从基本语法说起。下面先展示一个简单的配置内容。

block2 = [
    subblock = [string="hi";num=5]
    value = 1e-10
    array = 10:"this is a test":1.25
]

CNTK配置文件中的数据项基本上是由块状结构进行组织的,其中,同一个块中后面的项将合并或覆盖前面相同名称的数据项。在数据块中可以包含其他数据块。如果希望在一行中定义两个数据项,则需要使用“;”进行分割。最后是注释部分,注释以“#”开头

变量定义与引用

配置文件中的变量定义,可以直接写赋值语句。变量的引用则是将之前定义的变量名前后加上“$”来进行引用。下面给出示例:

RootDir = ".."

ConfigDir = "$RootDir$/Config"
DataDir = "$RootDir$/Data"
OutputDir = "$RootDir$/Output"
ModelDir = "$OutputDir$/Models"

注意一点是这样的,在一个块的外面定义的数据,是会被块内引用的。所以,大家发现一些块内本应定义的内容不存在的时候,应该考虑是否他已经在外面有所定义。块与块之间是有数据的继承关系的。

数据类型

数据项的值的数据类型可以为如下几种:

- 简单类型 (12, 1.25, 1e-10,"hi",auto)
- 块(集合)类型 (block1 = [id=1;size=256])
- 数组类型 (array=2:50:2)

简单类型: 其本质就是单独的一个值,可能是整数,浮点,字符串或者特殊的枚举类型。
块(集合)类型:其本质是一系列类型的一个集合,它可将一系列项打包在一起,可以包含其他数据块。
数组类型: 前面几种数据类型不过多的阐述了,唯一有些需要解释的是数组类型
数组类型在定义中可能出现两种符号,分别是“:”和“*”号。
先说“:”,这个符号用于分割数组中的元素,例如array=2:50:2,所对应的是定义一个包含3个元素的数组,分别是2,50,2。
然后是“*”,这个符号并非乘法,而是表示所修饰的类型重复多少遍。例如array=50:150*2:100,这个展开后是array=50:150:150:100。
数组类型经常用于定义网络的结构。定义每层网络的神经元个数。

覆盖与合并

我们在调用cntk.exe的过程中,我们使用configFile参数来指明我们的配置文件的位置。

cntk.exe configFile=yourExp.cntk

这样我们可以加载一个单独的配置文件,但是在一些复杂的工程中,我们可能为了一些特殊的需要,不同的参数写在不同的配置文件中。这时我们可以通过“+”进行拼接使其一次性加载多个配置文件。

cntk.exe configFile=yourExp1.cntk+yourExp2.cntk

当上述的yourExp1.cntk与yourExp2.cntk中有相同的数据项导致配置冲突的情况下,最后加载的yourExp2.cntk将会覆盖前面的数据项内容。

同时cntk.exe也支持在命令行中指定局部的数据项来补充或者覆盖配置文件中的内容。

cntk.exe configFile=yourExp.cntk mnistTrain=[reader=[file=”mynewfile.txt”]]

CNTK配置文件结构

最外层结构

除了自己需要定义的一些变量以外,CNTK的配置文件的最外层我们可以定义如下结构的数据以供cntk.exe使用。

# 定义的一些配置文件内部使用的常用变量
RootDir = ".."

ConfigDir = "$RootDir$/Config"
DataDir = "$RootDir$/Data"
OutputDir = "$RootDir$/Output"
ModelDir = "$OutputDir$/Models"

# 外部引用变量command 用于指明需要执行什么任务
command = Simple_Demo_Train:Simple_Demo_Test

# 外部引用变量deviceId 用于指明所使用的设备
deviceId = -1

# 外部引用变量precision 用于指明计算所使用的精度
precision = "float"

# 外部引用变量traceLevel 输出到Console的内容级别
traceLevel = 1

# 任务1
Simple_Demo_Train = [
    ...
]

# 任务2
Simple_Demo_Test = [
    ...
]

上述就是一个典型的CNTK配置文件的外层结构,这里任务块的内容暂时没有展开说明,相会在后续展开继续讲解。 这里包括的配置的内容除了一些内部使用的变量以外,还有一些外部引用的变量。这些变量将会在cntk.exe中读取并且设置cntk的当前要执行的环境并且之执行相应的任务。

command

command可以理解为是最重要的,也是CNTK配置中不可缺少的,它用于指明当前需要执行什么任务。command的值可以为简单类型,也可以为数组类型。如下所示:

command = Simple_Demo_Train:Simple_Demo_Test

上述配置方式,将指明执行train和test两个任务块的内容。这里所讲的任务块就是下面所示的内容,任务块中的配置将在后面详细说明,这里只简单说明任务块是通过command调用的。

command = Simple_Demo_Train:Simple_Demo_Test

# 任务1
Simple_Demo_Train = [
    ...
]

# 任务2
Simple_Demo_Test = [
    ...
]

deviceId

deviceId参数用于指明操作需要使用的设备,可以设置为auto,或者是一个整数。
当设置为auto时,CNTK会自动选择一个最适合的设备进行计算操作。
当设置为-1或者是cpu时,则只是用CPU进行计算,不使用GPU。
当设置的值为大于等于0时,则使用指定的GPU进行计算。

# 自动识别性能最佳的设备并使用该设备
deviceId = auto

precision

precision用于指明计算过程中所使用的精度,该变量有默认值为float。可以设置的值为float或者是double。

precision = "float"

这个参数的设置会影响训练和测试网络的速度,毕竟精度的提升不仅仅是数据量的提升,还是计算量的提升。具体设置情况可以参考需要权衡训练所需达到的效果与训练或者测试的速度之间的平衡。

traceLevel

traceLevel这个值只是为了控制console中输出内容的量。取值范围是从0-2的整数

traceLevel = 1

其中0代表有限制的输出,也就是只输出有必要的内容。1代表正常的输出。2代表输出所有的内容。该参数可以理解为log的详细程度。

stderr

stderr参数用于设置如果发生错误则log输出文件的位置。这里只是指定错误文件的位置的部分,具体的log文件名称需要和所执行的任务的名称项结合。举例来说,先看下面局部的配置内容。

command = mnistTrain 
stderr="c:\cntk\log\cntk“
mnistTrain = [
...
]

如上所设置,当执行mnistTrain任务时发生错误,错误的log将会输出至“c:\cntk\log\cntk_mnistTrain.log”。

NumCPUThreads

NumCPUThreads = 0

NumCPUThreads参数用于指定所使用的cpu线程数。该参数设定的取值可以是正整数,也可以是负整数,也可以是0。
当NumCPUThreads取值为0时,具体使用的线程数则由MKL、ACML或者是OpenMP自动检测。0也是其默认值。
当NumCPUThreads取值为正整数的时候,最大所使用的线程数为所设定的值与当前并行计算能力两者中相对较小的值。
当NumCPUThreads为负数的时候,则为硬件并行能力的最大值,但至少为1。

任务块的结构

每一个任务块其实就是具体进行的一项操作。例如train,eval,test这都是我们所常用任务。下面列举一个典型的任务快的样例:

mnistTrain = [
    action = "train"

    NDLNetworkBuilder = [
        networkDescription = "$ConfigDir$/01_OneHidden.ndl"
    ]

    SGD = [
        modelPath = "$ModelDir$/01_OneHidden_Model.dnn"
        epochSize = 60000
        minibatchSize = 32
        learningRatesPerMB = 0.1
        maxEpochs = 30
    ]

    reader = [
        readerType = "UCIFastReader"
        file = "$DataDir$/mnist_train.txt"
        features = [
            dim = 784
            start = 1
        ]
        labels = [
            dim = 1
            start = 0
            labelDim = 10
            labelMappingFile = "$DataDir$/mnistlabels.txt"
        ]
    ]
]

一个典型的任务块中,经常出现的有4部分内容。

  • action 用于指明具体的任务行为。
  • Network Builder 网络创建器
  • Learner 学习方法
  • Data Reader 数据读取器

其中action为组成任务块的必要元素,其他3个部分可以根据action的具体内容而设置。

action任务行为

action目前根据官方所给出来的文档中的说法目前可以选择的值为TrainTest以及Eval

action = “train”

同时大家在观察CNTK所给出来的一些Sample中,也会发现action中会出现其他的值,这部分值没有在官方目前所给出来的文档中找到解释,但是笔者会通过笔者自己对代码的解读中尝试性的去解释他的行为。

Train: 当action为Train时,则当前任务块的行为为训练网络。需要在任务块中定义如下内容:

  • (必要)Network Builder 需要为学习行为制定一个网络的构造器以定义具体训练什么类型的网络。后面会详细解释Network Builder的设置。
  • (必要)Reader 需要为学习行为指定一个数据的读取器,以读入训练数据。
  • (必要)Learner(目前是SGD) 需要配置一个SGD(随机梯度下降)块来配置训练相关的训练参数。
  • cvReader 这个根据官方的说明给出的是cross-validation data(交叉验证数据)的读取器的配置块。该参数可选提供。
  • makeMode 这个参数用于指定是当训练行为被打断后在继续开始的时候,是从头开始训练(值为false),还是根据已有的训练结果继续训练(值为true)。该参数的默认值为true。
  • numMBsToShowResult 参数用于指定当多少个minibatches后,中间结果需要被显示出来。

Test/Eval: 当action为Test或者是Eval时,则当前任务块的行为为测试网络或者是使用该网络计算数据。需要在任务块中定义如下内容:

  • (必要)Reader 需要为学习行为指定一个数据的读取器,以读入训练数据。
  • (必要)modelPath 参数用于指明所使用的网络model的位置。该参数由之前train行为训练出来的网络给出。
  • minibatchSize 设定用于从数据集中读取或者处理数据的minibatchSize参数。
  • epochSize 指定数据集大小,可以设定为0,当设定为0时,将会自动判断数据集大小。
  • numMBsToShowResult 参数用于指定当多少个minibatches后,中间结果需要被显示出来。
  • evalNodeNames 该参数用于设定需要执行的一个或多个节点名称的集合。

上述为在实际使用过程中常用的action。还有一些工具类型的action。

convertdbn: 用于将通过微软的dbn.exe生成的网络转换CNTK的网络模型。

  • (必要)dbnModelPath 指定dbn.exe所生成的网络的位置。
  • (必要)modelPath 指定转换后输出的CNTK网络模型的位置。

plot: 用于将已有的网络通过dot绘制到文件。

command = topoplot
topoplot = [
    action = "plot"
    modelPath = "train\lstm.model.0"

    # outputdotFile specifies the dot file to output
    # if the user does not specify this, it will be ${modelPath}.dot
    outputdotFile = "train\lstm.model.dot" 

    # outputFile specifies the rendered image
    outputFile="train\lstm.model.jpg" 

    # if RenderCmd is specified, CNTK will call the plot command after replacing
    # <IN> with ${outputdotFile} and <OUT> with ${outputfile}
    renderCmd="d:\Tools\graphviz\bin\dot.exe -Tjpg <IN> -o<OUT>"
]
  • (必要)modelPath 参数用于指明所使用的网络model的位置。该参数由之前train行为训练出来的网络给出。
  • (必要)outputFile 指定需要输出的图片文件位置。
  • outputdotFile 指定需要输出的dot文件位置。
  • renderCmd 用于指定具体使用的render的执行命令。在调用前,会使用${outputdotFile}去替换宏<IN>,使用${outputfile}去替换宏<OUT>

上述为官方在一些文档中已经说明的action的可选项。还有一些可选项官方未给出说明,但是在Sample中或者是代码中有出现。下面笔者将会根据自己的理解进行解读。

  • trainRNN 等价于 train
  • adapt (等研究完代码后补充)
  • edit 编辑网络
  • cv 执行cross-validation交叉验证
  • write (等研究完代码后补充)
  • devtest(等研究完代码后补充)
  • dumpnode 导出节点信息
  • createLabelMap(等研究完代码后补充)
  • writeWordAndClass 预处理自然语言文本的输入数据
  • SVD 矩阵奇异值分解

Network Builder网络创建器

目前支持两种Network Builder(也许存在第三种), 分别是:

  • SimpleNetworkBuilder
  • NDLNetworkBuilder
  • BrianScript(这个是在代码中发现的第三种,但是没有详细记录如何使用)

    SimpleNetworkBuilder 使用方式比较简单,只需要设定网络的各种参数即可。

 SimpleNetworkBuilder = [
    # 2 inputs, 2 hidden layers with 50 element nodes each, 2 outputs
    layerSizes = 2:50*2:2
    trainingCriterion = "CrossEntropyWithSoftmax"
    evalCriterion = "ErrorPrediction"
    layerTypes = "Sigmoid"
    applyMeanVarNorm = true
]

NDLNetworkBuilder 则是设定一个networkDescription的参数,在参数中引用一个ndl文件。ndl文件有自己的特殊语法。NDL(Network Description Language)是为了CNTK所实现的一种不是编程语言的网络描述语言。

NDLNetworkBuilder = [
    networkDescription = "$ConfigDir$/yourNetwork.ndl"
]

BrianScript 这个是在代码中发现的,未来可能会进行支持。也是定义网络的一种方式。

笔者未来将会针对SimpleNetworkBuilder以及NDLNetworkBuilder这两种网络创建器写一篇详细的文章进行讲解。这里先预留占位。后期将文章的链接补上。

Learner 学习方法

目前CNTK的Learner所支持的学习方法根据笔者自身的研究好像只有SGD(Stochastic gradient descent随机梯度下降)。SGD块的配置虽然参数比较多,但是大多数参数已经有默认值,如果实际情况允许或者符合情况,直接使用默认值即可。否则的话,则需要按需要进行指定。

SGD = [
    modelPath = "$ModelDir$/myModel.dnn"
    epochSize = 60000
    minibatchSize = 32
    learningRatesPerMB = 0.1
    maxEpochs = 30
]

CNTK中提供针对SGD的配置有很多,未来也会针对SGD的配置单独写一篇文章进行详细的描述。

Data Reader 数据读取器

CNTK中提供了很多Data Reader,并且也提供了接口供开发者或者使用者实现针对自身数据专门的Reader。Data Reader主要的功能就是为了读取原始数据。目前CNTK中已有文档描述的Reader如下:

  • UCI Fast Reader 基于UCI数据格式的读取器(可以理解为文本格式)
  • HTKMLF Reader 其中HTK指的是HMM Toolkit 隐马尔科夫链工具箱,这个是一种读取基于HTK的MLF文件的读取器。
  • LM sequence reader 基于LM(语言模型 language modeling)序列的字符串读取器,一般适用于分析语言模型。
  • LU sequence reader 通LM sequence reader有些类似,只是用于语言的理解(language understanding)上。

每种Reader由于其实现不同,所以配置参数不尽相同,笔者将会分为多个部分讲解这四种读取器,并会在未来的文章中,解读代码以及讲解开发的过程中,详细的讲解如何自定义符合特殊数据的读取器。

总结及下一步的计划

在本篇文章中,随同大家一同研究了CNTK配置的一些基本原理和基本的语法。并且也了解了一个基本的CNTK配置中所需要配置的内容及如何进行配置顶层参数以及任务块中的内容。

本文虽然已经描述了CNTK配置文件的一些详细内容,但是在Network Builder网络创建器、Learner学习方法以及Data Reader数据读取器这三个关键的任务块部分只是简单的介绍了一下,并没有给出详细的解释和使用方法。笔者计划针对于这三部分详细的说明,其源于两个原因,一个是在实际使用过程中这三部分十分重要,另外的原因是这三部分中需要讲解的内容过于繁重,无法再一篇文章中详细阐述。笔者将会在未来的文章中视情况拓展。

本节完,其他章节将会持续更新……

你可能感兴趣的:(人工智能,配置文件,DNN,深度学习,CNTK)