你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

在 BrainScript 中如何实现训练模型

层明智训练

若要执行按层训练,只需在配置文件中使用多个“命令”,其中每个命令的类型为 action=train。

command = TrainLayer1:TrainLayer2:TrainLayer3:EndToEndTrain:Test:Output

TrainLayer1= [ 
   action = train
   ...
]

TrainLayer2= [ 
   action = train
   ...
]
...

使用多任务目标进行训练

只需将组合条件定义为 BrainScript 表达式,可以通过指定这些 evaluationNodes条件来监视所有单个任务损失。

task1loss = CrossEntropyWithSoftMax(prediction,label)
task2loss = SquareError(reconstruction,input)
mtloss = task1loss + Constant(0.3) .* task2loss 
criterionNodes = (mtloss)
evaluationNodes = (task1loss:task2loss)

在图像上训练回归模型

下面介绍如何使用 CNTK 预测输入图像的一个或多个浮点值。 示例用例是预测给定图像中对象的边界框,例如 (x、y、w、h) 。 你也可以想到,仅仅通过查看汽车 (的图像来预测汽车的价格实际上会很有趣) 。 在这里,我们使用一个非常简单的示例来训练网络来预测图像的平均 RGB 值, (规范化为 [0, 1]) 。 但是,相同的步骤适用于其他用例。 这些步骤包括:

  1. 将图像和地面真相回归标签定义为网络输入
  2. 定义一个网络,用于预测与回归标签匹配的值数 w.r.t。
  3. 定义一个损失函数,该函数将预测值与基本事实进行比较
  4. 调整 .cntk 配置文件中的读取器部分以读取图像和回归标签

下面介绍了如何执行此操作。 示例 /图像/回归/RegrSimple_CIFAR10.cntk 的“示例”文件夹中包含完整的配置文件。 该文件夹还包含用于下载图像数据的脚本,并生成用于训练和测试的回归地面真相。

1-3) 定义输入、网络和丢失函数:

    BrainScriptNetworkBuilder = [
        imageShape = 32:32:3
        featScale = Constant(1/256)
        labelDim = 3

        model (features) = {
            featNorm = Scale(features, featScale)
            h1 = LinearLayer {100,      init="gaussian", initValueScale=1.5} (featNorm)
            ol = LinearLayer {labelDim, init="gaussian", initValueScale=1.5} (h1)
        }.ol

        # inputs
        features = Input {imageShape}
        regrLabels = Input {labelDim}
        
        # apply model to features
        ol = model (features)

        # define regression loss
        # rmse = sqrt(SquareError(regrLabels, ol) / labelDim)
        sqerr = SquareError (regrLabels, ol)
        rmse = Sqrt (Constant(1/labelDim).* sqerr)

        featureNodes    = (features)
        labelNodes      = (regrLabels)
        criterionNodes  = (rmse)
        evaluationNodes = (rmse)
        OutputNodes     = (ol)
    ]
  1. 使用 ImageReader 和 CNTKTextFormatReader 定义复合读取器:
    reader = {
        verbosity = 0 ; randomize = true
        deserializers = ({
            type = "ImageDeserializer" ; module = "ImageReader"
            file = "$dataDir$/cifar-10-batches-py/train_map.txt"
            input = {
                features = { transforms = (
                    { type = "Scale" ; width = 32 ; height = 32 ; channels = 3 ; interpolations = "linear" } :
                    { type = "Transpose" }
                )}
                ignored = { labelDim = 10 }
            }
        } : {
            type = "CNTKTextFormatDeserializer" ; module = "CNTKTextFormatReader"
            file = "$dataDir$/cifar-10-batches-py/train_regrLabels.txt"
            input = {
                regrLabels = { dim = 3 ; format = "dense" }
            }
        })
    }

读取器是一个复合读取器,它使用 ImageReader 读取图像和 CNTKTextFormatReader 读取回归地面真实标签。 它通过使用) 定义一组反序列化程序 ({...} : {...} ,并分配上述网络中定义的输入, (cf. 特征和重新生成) 来执行此操作。

有关完整配置文件和该文件夹中对应的自述文件,请参阅 示例/图像/杂项/CIFAR-10/06_RegressionSimple.cntk

训练多标签分类器

对于多标签分类,应避免使用 CrossEntropy,因为它只能处理总和为 1 的输入向量。 明智的替代方法是使用逻辑损失函数的总和,每个输出一个

...
probabilities = DenseLayer {outputSize, activation=Sigmoid} (hidden)
logisticLoss = Logistic (multiLabels, probabilities)
trainingCriterion = (logisticLoss)
...

除了损失本身之外,你可能还希望监视其他指标,例如错误预测的数量。 此表达式没有内置表达式,但可以表示为

...
hammingLoss (y, p) = ReduceSum (y != (p > 0.5))
hl = hammingLoss(multiLabels,probabilities)
evaluationNodes = (hl)
...

这计算 y[i] 与 p[i]>0.5 意见不一的次数。

按顺序开始对建模进行排序

动手实验室 介绍开始序列处理的主要成分,如 CNTK 文本格式,以及如何将读取器配置为使用各种输入序列的短别名。 grapheme 到 phoneme (G2P) 示例演示了实际的序列到序列任务。

序列到序列建模的一个重要问题是如何使用束搜索解码测试数据。 可以在配置中完成此操作,其中顶级操作为“write”。 解码需要搜索最可能的输出序列。 CNTK 有 一个梁搜索 解码器,而你可以像这样调用

BrainScriptNetworkBuilder = (BS.Seq2Seq.BeamSearchSequenceDecoderFrom (
                                        BS.Network.Load (decodeModelPath), beamSize))

并将使用指定的梁大小执行梁搜索。 对于 1 的梁大小,有专门的贪婪解码器

BrainScriptNetworkBuilder = (BS.Seq2Seq.GreedySequenceDecoderFrom (
                                        BS.Network.Load (decodeModelPath)))

这两个解码器对网络都有特定要求,如 G2P 示例所示

训练 DSSM (或卷积 DSSM) 模型

DSSM (或深度语义相似性模型) 是在源目标文本对上训练的 DNN 模型,用于学习相关源文本和目标文本对更近的地方的短文本嵌入空间。 模型的文本输入由其预先计算的三元报哈希表示, (见, 黄等 人) 。 对于 C-DSSM,三元语法哈希按单词计算,然后按照文本中单词发生的顺序进行串联。 这两个模型的输入大小固定。 如果考虑 50K 三元语法,则对应于源和目标文本的 DSSM 输入将为长度为 50K 的矢量。 对于 C-DSSM,矢量的长度为 50K x n,其中第一个 n-1 字向量是串联的,第 n 个向量包含对应于文本中所有剩余单词的向量之和。 如果文本中的单词少于 n 个,则向量其余部分将填充为零。 若要使用图像绘制类比,可以将 C-DSSM 的文本输入视为采用格式存储 [C x H x W] 尺寸 10x1 和 50K 通道的图像。

此示例演示如何使用 CNTKTextFormatReader 训练 DSSM /C-DSSM 模型。 数据应包含 2 个功能 (源文本和目标文本) 和 1 个标签 (始终设置为定型数据中的值 1,因为它仅包含正样本 - 在训练期间,负目标示例由随机采样) 生成。 下面是读取器配置,

reader = {
    verbosity   = 0
    randomize   = true

    deserializers = ({
        type    = "CNTKTextFormatDeserializer"
        module  = "CNTKTextFormatReader"
        file    = "data.txt"

        input = {
            Q   = { dim = 500000; format = "sparse" }
            D   = { dim = 500000; format = "sparse" }
            L   = { dim = 1;      format = "dense" }
        }
    })
}

输入数据的示例,

|L 1 |Q 482:1 761:1 1832:1 2117:1 12370:1 17131:1 17854:1 24976:1 27676:1 28055:1 28177:1 29507:1|D 482:1 761:1 1832:1 2117:1 12370:1 17131:1 17854:1 24976:1 27676:1 28055:1 28177:1 29507:1
|L 1 |Q 149:1 153:1 595:1 671:1 675:1 1110:1 1517:1 2077:1 2114:1 5533:1 5662:1 6886:1 6901:1 7294:1 12846:1 13033:1 16614:1 19425:1 22015:1 24839:1 24994:1 26196:1 26358:1 27565:1|D 149:1 153:1 595:1 671:1 675:1 1110:1 1517:1 2077:1 2114:1 5533:1 5662:1 6886:1 6901:1 7294:1 12846:1 13033:1 16614:1 19425:1 22015:1 24839:1 24994:1 26196:1 26358:1 27565:1
|L 1 |Q 187:1 2294:1 2800:1 6920:1|D 187:1 2294:1 2800:1 6920:1

最后是网络定义,

BrainScriptNetworkBuilder = {
    # Constants scalars
    isConvolutional     = true
    numWords            = (if isConvolutional then 10 else 1)
    numTrigramsPerWord  = 50000
    numHiddenNodes      = 300
    wordWindowSize      = 3
    numWindows          = numWords - wordWindowSize + 1
    numNeg              = 50

    # Constant tensors
    CONST_GAMMA     = Constant(10)
    CONST_SHIFT     = Constant(1)
    CONST_NEG       = Constant(numNeg)
    CONST_PAD_NEG   = Constant(0, rows=numNeg, cols=1)
    CONST_PAD_POS   = Constant(1, rows=1, cols=1)
    CONST_PAD       = Splice(CONST_PAD_POS : CONST_PAD_NEG, axis=1)

    # Inputs
    Q   = Input(500000)
    D   = Input(500000)
    L   = Input(1)

    qr      = if isConvolutional
                then TransposeDimensions(ReshapeDimension(Q, 1, numTrigramsPerWord:1:numWords), 1, 3)
                else Slice(0, numTrigramsPerWord, Q, axis=1)
    dr      = if isConvolutional
                then TransposeDimensions(ReshapeDimension(D, 1, numTrigramsPerWord:1:numWords), 1, 3)
                else Slice(0, numTrigramsPerWord, D, axis=1)

    qdssm   = Sequential (
                DenseLayer {numHiddenNodes, activation=Tanh} :
                DenseLayer {numHiddenNodes, activation=Tanh} :
                DenseLayer {numHiddenNodes, activation=Tanh})
    qcdssm  = Sequential (
                ConvolutionalLayer {numHiddenNodes, (wordWindowSize:1), pad=false, activation=Tanh} :
                MaxPoolingLayer {(numWindows:1), stride=(1:1)} :
                DenseLayer {numHiddenNodes, activation=Tanh} :
                DenseLayer {numHiddenNodes, activation=Tanh})
    ddssm   = Sequential (
                DenseLayer {numHiddenNodes, activation=Tanh} :
                DenseLayer {numHiddenNodes, activation=Tanh} :
                DenseLayer {numHiddenNodes, activation=Tanh})
    dcdssm  = Sequential (
                ConvolutionalLayer {numHiddenNodes, (wordWindowSize:1), pad=false, activation=Tanh} :
                MaxPoolingLayer {(numWindows:1), stride=(1:1)} :
                DenseLayer {numHiddenNodes, activation=Tanh} :
                DenseLayer {numHiddenNodes, activation=Tanh})
    qembed  = if isConvolutional
                then qcdssm
                else qdssm
    dembed  = if isConvolutional
                then dcdssm
                else ddssm

    qf  = qembed(qr)
    df  = dembed(dr)
    lf  = Times(CONST_PAD, L)
    c   = CosDistanceWithNegativeSamples(qf, df, CONST_SHIFT, CONST_NEG)
    s   = Slice(0, 1, c, axis=1, tag="output")
    ce  = CrossEntropyWithSoftmax(lf, Scale(CONST_GAMMA, c), tag="criterion")
}

注意:

  • 虽然 C-DSSM 的性能一直优于 DSSM,但它也会训练速度较慢 (有时速度高达 5-10 倍) 。 因此,在某些情况下,通过对更多数据 (或更多纪元) 进行训练,可能会从 DSSM 在同一训练时间获得更好的性能。
  • 原始 DSSM/C-DSSM 在查询和文档标题对上进行了训练。 但是,可以通过训练其他类型的数据(例如 会话查询对查询前缀后缀对)来了解短文本之间的其他关系。

使用反卷积和取消池训练图像自动编码器

此处有说明。

使用快速 R CNN 训练对象检测

此处有说明。