使用C#加载(预训练)CNTK模型

时间:2017-10-19 12:21:20

标签: c# cntk

我正在使用CNTK.GPU v2.2.0并使用以下方法保存模型:

model.Save(modelFilePath);

现在我想再次加载它,例如继续培训或仅评估样品。我可以通过两种方式看到这种可能性。一种方法有效,但是不切实际。第二个不起作用。

  1. 我再次从头开始构建神经网络的整个结构,然后在其上调用以下方法:

    model.Restore(modelFilePath);
    
  2. 确实,这很有效。

    1. 我使用以下静态方法创建模型:

      Function.Load(modelFilePath, DeviceDescriptor.GPUDevice(0));
      
    2. 这不起作用。

      在完成这些操作后,我只需为模型创建一个培训师,创建一个minibatchSource并尝试按照我保存模型之前的方式训练模型。

      但是使用第二种策略,我得到以下例外:

      System.ArgumentOutOfRangeException:'1个必需参数的值'输入('features',[28 x 28 x 1],[,#])',请求的输出'Output('aggregateLoss) ',[],[]),输出('lossFunction',[1],[,#]),输出('aggregateEvalMetric',[],[])'取决于,尚未提供。

      [CALL STACK]
          > CNTK::Internal::  UseSparseGradientAggregationInDataParallelSGD
          - CNTK::Function::  Forward
          - CNTK::  CreateTrainer
          - CNTK::Trainer::  TotalNumberOfSamplesSeen
          - CNTK::Trainer::  TrainMinibatch (x2)
          - CSharp_CNTK_Trainer_TrainMinibatch__SWIG_0
          - 00007FFA34AE8967 (SymFromAddr() error: The specified module could not be found.)
      

      它表示尚未提供输入功能。我在训练时和通过划痕创建模型时使用输入:

      var input = CNTKLib.InputVariable(_imageDimension, DataType.Float, _featureName);
      var scaledInput = CNTKLib.ElementTimes(Constant.Scalar<float>(0.002953125f, _device), input);
      ...
      

      所以我认为我必须用我为训练创建的模型替换已加载模型的输入,并在我创建模型时使用 - 尽管输入没有区别。 但我坚持尝试这个,因为我无法检索模型对象的输入,我需要更换(我认为)。

      model.FindByName(inputLayerName);
      

      只返回null,虽然我可以清楚地看到该名称与调试器中模型的“输入”列表中的图层名称匹配。

      因此我不知道如何正确加载已保存的模型。我希望有人可以帮助我。

1 个答案:

答案 0 :(得分:3)

幸运的是,我自己找到了答案。我会在这里发布,因为可能还有其他CNTK初学者,他们可能会发现这个问题,或者通常想知道如何正确加载模型。

问题是我没有使用相同的输入对象进行训练和模型创建。换句话说,如果我通过提到的静态方法创建我的模型,我仍然必须确保模型中的对象和用于训练的对象是相同的。这应该可以通过以下方式实现:

  1. 使用您自己的输入对象替换已加载模型的输入,并将其用于训练。我没有测试,但它应该工作。
  2. 提取已加载模型的输入并将其用于训练。我只是测试了它,它的工作原理。 我使用的代码是:

    var labels =
        CNTKLib.InputVariable(new int[] {_classesNumber}, DataType.Float, _labelNa
    
    Variable input;
    Function model;
    if (File.Exists(_modelFile))
    {
        model = Function.Load(_modelFile, DeviceDescriptor.GPUDevice(0));
        input = model.Arguments.Single(a => a.Name == _featureName);
    }
    else
    {
        input = CNTKLib.InputVariable(_imageDimension, DataType.Float, _featureName);
        model = BuildNetwork(input);
    }
    
    var trainer = CreateTrainer(model, labels);
    
    IList<StreamConfiguration> streamConfigurations = new StreamConfiguration[]
    {
        new StreamConfiguration(_featureName, _imageSize), 
        new StreamConfiguration(_labelName, _classesNumber)
    };
    
    var minibatchSource = MinibatchSource.TextFormatMinibatchSource(
        Path.Combine(_ressourceFolder, _trainingDataFile),
        streamConfigurations,
        MinibatchSource.InfinitelyRepeat);
    
    TrainModel(minibatchSource, trainer, labels, input);
    
  3. 我在开始时犯的一个错误就是使用

    Variable layer model.FindByName(inputLayerName)
    

    虽然我不得不使用

    Variable layer = model.Arguments.Single(a => a.Name == inputLayerName);