使用 C# 加载(预训练的)CNTK 模型
Load (pretrained) CNTK model using C#
我正在使用 CNTK.GPU v2.2.0 并使用以下方法保存模型:
model.Save(modelFilePath);
现在我想再次加载它,例如继续训练或只是评估样本。我可以通过两种方式看到这是如何可能的。一种方法可行,但不可行。第二个不行。
我再次从头开始构建神经网络的整个结构,然后在其上调用以下方法:
model.Restore(modelFilePath);
的确,这行得通。
我使用以下静态方法创建我的模型:
Function.Load(modelFilePath, DeviceDescriptor.GPUDevice(0));
这不起作用。
在这些操作之后,我只是为模型创建了一个训练器,创建了一个 minibatchSource 并尝试以与保存模型之前相同的方式训练模型。
但是使用第二种策略我得到以下异常:
System.ArgumentOutOfRangeException: 'Values for 1 required arguments 'Input('features', [28 x 28 x 1], [, #])',请求的输出(s) '输出('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);
只是 returns null,尽管我可以清楚地看到该名称与调试器中模型的 "Inputs" 列表中的层名称匹配。
因此我不知道如何正确加载保存的模型。我希望有人能帮助我。
幸运的是我自己找到了答案。我会 post 在这里,因为可能还有其他 CNTK 初学者,他们可能会遇到这个问题,或者通常想知道如何正确加载模型。
问题是我没有使用相同的输入对象进行训练和模型创建。换句话说,如果我让用提到的静态方法创建我的模型,我仍然必须确保模型中的对象和用于训练的对象是相同的。这应该可以通过以下方式实现:
- 用你自己的输入对象替换加载模型的输入,并将这个也用于训练。我没有测试过,但应该可以。
提取加载模型的输入并将其用于训练。我刚刚测试了这个并且它有效。
这是我使用的代码:
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);
我一开始也犯了一个错误,就是使用
Variable layer model.FindByName(inputLayerName)
虽然我不得不使用
Variable layer = model.Arguments.Single(a => a.Name == inputLayerName);
我正在使用 CNTK.GPU v2.2.0 并使用以下方法保存模型:
model.Save(modelFilePath);
现在我想再次加载它,例如继续训练或只是评估样本。我可以通过两种方式看到这是如何可能的。一种方法可行,但不可行。第二个不行。
我再次从头开始构建神经网络的整个结构,然后在其上调用以下方法:
model.Restore(modelFilePath);
的确,这行得通。
我使用以下静态方法创建我的模型:
Function.Load(modelFilePath, DeviceDescriptor.GPUDevice(0));
这不起作用。
在这些操作之后,我只是为模型创建了一个训练器,创建了一个 minibatchSource 并尝试以与保存模型之前相同的方式训练模型。
但是使用第二种策略我得到以下异常:
System.ArgumentOutOfRangeException: 'Values for 1 required arguments 'Input('features', [28 x 28 x 1], [, #])',请求的输出(s) '输出('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);
只是 returns null,尽管我可以清楚地看到该名称与调试器中模型的 "Inputs" 列表中的层名称匹配。
因此我不知道如何正确加载保存的模型。我希望有人能帮助我。
幸运的是我自己找到了答案。我会 post 在这里,因为可能还有其他 CNTK 初学者,他们可能会遇到这个问题,或者通常想知道如何正确加载模型。
问题是我没有使用相同的输入对象进行训练和模型创建。换句话说,如果我让用提到的静态方法创建我的模型,我仍然必须确保模型中的对象和用于训练的对象是相同的。这应该可以通过以下方式实现:
- 用你自己的输入对象替换加载模型的输入,并将这个也用于训练。我没有测试过,但应该可以。
提取加载模型的输入并将其用于训练。我刚刚测试了这个并且它有效。 这是我使用的代码:
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);
我一开始也犯了一个错误,就是使用
Variable layer model.FindByName(inputLayerName)
虽然我不得不使用
Variable layer = model.Arguments.Single(a => a.Name == inputLayerName);