DL4J迁移学习API
DL4J迁移学习API使用户能够:
- 修改现有模型的结构
- 调优现有模型的学习配置。
- 在训练期间保持指定层参数为常量(恒定不变),也称为“冻结”。
将某些层冻结在网络上,并且训练实际上与对输入的转换版本的训练相同,转换版本是冻结层边界处的中间输出。这是从输入数据中“特征提取”的过程,在本文档中称为“特征化”。
迁移学习帮手
在大型的、预训练的网络上,对输入数据进行“特征化”的前向传递可能很耗时。DL4J还提供了一个具有以下功能的TransferLearningHelper类。
- 对输入数据集进行特征化保存以备将来使用
- 用特征化数据集拟合冻结层模型
- 给定一个特征化输入,从冻结层的模型输出。
当运行多个epoch时,用户将节省计算时间,因为对冻结层/顶点的昂贵传递将只需进行一次。
给我看代码
本例将使用VGG16对属于五种花卉的图像进行分类。数据集将自动从http://download.tensorflow.org/example_images/flower_photos.tgz下载
I. 导入动物园模型
在0.9.0(0.8-1快照)下,DL4J有一个新的本地模型动物园。阅读有关deeplearning4j-zoo 模块的更多信息来了解如何使用预训练模型。这里,我们加载用ImageNet上训练的权重初始化的预训练VGG-16模型:
ZooModel zooModel = new VGG16();
ComputationGraph pretrainedNet = (ComputationGraph) zooModel.initPretrained(PretrainedType.IMAGENET);
II. 设置一个调优配置
FineTuneConfiguration fineTuneConf = new FineTuneConfiguration.Builder()
.optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
.updater(new Nesterovs(5e-5))
.seed(seed)
.build();
III. 基于VGG16构建新模型
A.只修改最后一层,保持其他冻结
VGG16的最后一层对ImageNet.中的1000个类进行软最大回归。我们修改最后一层,给出五个类的预测,保持其他层的冻结。
ComputationGraph vgg16Transfer = new TransferLearning.GraphBuilder(pretrainedNet)
.fineTuneConfiguration(fineTuneConf)
.setFeatureExtractor("fc2")
.removeVertexKeepConnections("predictions")
.addLayer("predictions",
new OutputLayer.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD)
.nIn(4096).nOut(numClasses)
.weightInit(WeightInit.XAVIER)
.activation(Activation.SOFTMAX).build(), "fc2")
.build();
在仅仅30次迭代(在这种情况下是曝光450幅图像)之后,该模型在测试数据集上达到了>75%的准确率。考虑到从头训练图像分类器的复杂性,这相当显著。
B.连接新层到瓶颈(block5_pool)
在这里,我们保持除了最后三个密连层之外的所有密连层冻结,并将新的密连层附加到其上。请注意,本文的主要目的是演示API的使用,其次可能提供更好结果。
ComputationGraph vgg16Transfer = new TransferLearning.GraphBuilder(pretrainedNet)
.fineTuneConfiguration(fineTuneConf)
.setFeatureExtractor("block5_pool")
.nOutReplace("fc2",1024, WeightInit.XAVIER)
.removeVertexAndConnections("predictions")
.addLayer("fc3",new DenseLayer.Builder()
.activation(Activation.RELU)
.nIn(1024).nOut(256).build(),"fc2")
.addLayer("newpredictions",new OutputLayer
.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD)
.activation(Activation.SOFTMAX)
.nIn(256).nOut(numClasses).build(),"fc3")
.setOutputs("newpredictions")
.build();
C. 从先前保存的模型中调优图层
假设我们已经从(B)中保存了模型,现在想要允许“block_5”层进行训练。
ComputationGraph vgg16FineTune = new TransferLearning.GraphBuilder(vgg16Transfer)
.fineTuneConfiguration(fineTuneConf)
.setFeatureExtractor(“block4_pool”)
.build();
IV. 保存“特征化”数据集并与之进行训练。
我们使用迁移学习助手API。注意,这冻结了传入的模型的层。
以下是如何在指定层“fc2”获得数据集的特征版本。
TransferLearningHelper transferLearningHelper =
new TransferLearningHelper(pretrainedNet, "fc2");
while(trainIter.hasNext()) {
DataSet currentFeaturized = transferLearningHelper.featurize(trainIter.next());
saveToDisk(currentFeaturized,trainDataSaved,true);
trainDataSaved++;
}
下面是如何与特征数据集拟合的方法。vgg16Transfer 是第三部分(a)中设置的一种模型。
TransferLearningHelper transferLearningHelper =
new TransferLearningHelper(vgg16Transfer);
while (trainIter.hasNext()) {
transferLearningHelper.fitFeaturized(trainIter.next());
}
注意
- 迁移学习构建器返回一个DL4J模型的新实例。
请记住,这是第二个模型,使原件保持原状。对于大型的预训练网络,要考虑内存需求,并相应地调整JVM堆空间。
- 受过训练的模型助手从Keras导入模型而不强制执行训练配置。
因此,最后一层(如打印摘要时所见)是密连层,而不是具有损失函数的输出层。因此,为了修改输出层的nOut,我们删除了层顶点,保持了它的连接,并添加回具有相同名称、不同nOut、合适的损失函数等的新输出层。
- 在层/顶点处更改nOut将修改它的层/顶点的nIn。
当改变nOut时,用户可以指定层的权重初始化方案或分布,以及它的层的单独的权重初始化方案或分布。
- 当将模型写入磁盘时,不保存冻结层配置。
换句话说,在序列化和读回时具有冻结层的模型将不具有任何冻结层。为了持续训练以保持特定层常量,用户需要通过迁移学习助手或迁移学习API。在DL4J模型中有两种方法来“冻结”层。
- On a copy: With the transfer learning API which will return a new model with the relevant frozen layers
- In place: With the transfer learning helper API which will apply the frozen layers to the given model.
- 调优配置将有选择地更新学习参数。
例如,如果指定了学习速率,则该学习速率将应用于模型中的所有未冻结/可训练层。然而,新添加的层可以通过在层构建器中指定它们自己的学习速率来覆盖此学习速率。
实用类
FineTuneConfiguration
微调配置。注意,这里设置的值将覆盖所有非冻结层的值。
FineTuneConfiguration
public FineTuneConfiguration build()
激活函数/神经元非线性
TransferLearning
迁移学习API可用于修改现有多层网络或计算图的结构或学习参数。它允许
- 更改现有层的nOut
- 删除和添加现有的层/顶点
- 调优学习配置(学习率,更新器等)
- 将指定层的参数保持为常数
fineTuneConfiguration
public Builder fineTuneConfiguration(FineTuneConfiguration finetuneConfiguration)
用于微调迁移学习的多层网络
- 参数 origModel
setFeatureExtractor
public Builder setFeatureExtractor(int layerNum)
指定要设置为“特征提取器”的层,指定层及其前面的层将被“冻结”,参数保持常量
- 参数 layerNum 层号
- 返回构建器
nOutReplace
public Builder nOutReplace(int layerNum, int nOut, WeightInit scheme)
通过更改nOut来修改层的结构。注意,这也将影响指定层,除非它是输出层
- 参数 layerNum 改变nOut的层索引
- 参数 nOut 要改变到的nOut值
- 参数 scheme 用于第layernum与第layernum+1层中参数的权重初始化方案
- 返回构建器
nOutReplace
public Builder nOutReplace(int layerNum, int nOut, Distribution dist)
通过更改nOut来修改层的结构。注意,这也将影响指定层,除非它是输出层
- 参数 layerNum 改变nOut的层索引
- 参数 nOut 要改变到的nOut值
- 参数 dist 用于第layernum与第layernum+1层中参数的与权重init分布结合使用的分布
- 返回构建器
- 查看 org.deeplearning4j.nn.weights.WeightInit DISTRIBUTION
nOutReplace
public Builder nOutReplace(int layerNum, int nOut, WeightInit scheme, WeightInit schemeNext)
通过改变nOut来修改层的结构。注意,这也将影响指定层,除非它是输出层。可以为指定层及其后的层指定不同的权重初始化方案。
- 参数 layerNum 改变nOut的层索引
- 参数 nOut 要改变到的nOut值
- 参数 scheme 用于第layerNum层中参数的权重初始化方案
- 参数 schemeNext 用于第 layerNum+1层中的权重初始化方案
- 返回构建器
nOutReplace
public Builder nOutReplace(int layerNum, int nOut, Distribution dist, Distribution distNext)
通过改变nOut来修改层的结构。注意,这也将影响指定层,除非它是输出层。可以为指定层及其后的层指定不同的权重初始化方案。
- 参数 layerNum 改变nOut的层索引
- 参数 nOut 要改变到的nOut值
- 参数 dist 第layerNum层中参数使用分布
- 参数 distNext 第layerNum+1中参数使用分布
- 返回构建器
- 查看org.deeplearning4j.nn.weights.WeightInit分布
nOutReplace
public Builder nOutReplace(int layerNum, int nOut, WeightInit scheme, Distribution distNext)
通过改变nOut来修改层的结构。注意,这也将影响指定层,除非它是输出层。可以为指定层及其后的层指定不同的权重初始化方案。
- 参数 layerNum 改变nOut的层索引
- 参数 nOut 要改变到的nOut值
- 参数 scheme 用于第layerNum层中参数的权重初始化方案
- 参数 distNext 第layerNum+1中参数使用分布
- 返回构建器
- 查看org.deeplearning4j.nn.weights.WeightInit分布
nOutReplace
public Builder nOutReplace(int layerNum, int nOut, Distribution dist, WeightInit schemeNext)
通过改变nOut来修改层的结构。注意,这也将影响指定层,除非它是输出层。可以为指定层及其后的层指定不同的权重初始化方案。
- 参数 layerNum 改变nOut的层索引
- 参数 nOut 要改变到的nOut值
- 参数 dist 第layerNum层中参数使用分布
- 参数 schemeNext 第layerNum+1层中参数的权重初始化方案
- 返回构建器
- 查看org.deeplearning4j.nn.weights.WeightInit分布
removeOutputLayer
public Builder removeOutputLayer()
用于删除网络输出层的助手方法。用- removeOutputLayer() 或removeLayersFromOutput(layerNum) 两者之一。可以在删除层时被指定,至少应该用.addLayer(…) 增加一个输出层。
- 返回构建器
removeLayersFromOutput
public Builder removeLayersFromOutput(int layerNum)
删除网络的最后一个“n”层。至少必须在一个输出层必须被添加
- 参数 layerNum 要移除的层号
- 返回构建器
addLayer
public Builder addLayer(Layer layer)
如果层被移除,需要将层添加到网络中。可以多次调用,并且按照调用的顺序添加层。至少必须添加一个outputLayer(输出层应该在最后添加——根据顺序的说明)在此与层一起指定的学习配置(如更新器、学习速率等)将得到认可
- 参数 layer 要添加的层配置 (类似于 NeuralNetConfiguration .list().layer(…)
- 返回构建器
setInputPreProcessor
public Builder setInputPreProcessor(int layer, InputPreProcessor processor)
为无法自动推断的添加层指定预处理器。
- 参数 processor 用于数据
- 返回构建器
build()
MultiLayerNetwork build()
返回具有调优配置和指定结构更改的模型。不需要调用init()。可以直接拟合。
- 返回 MultiLayerNetwork
removeVertexKeepConnections(String outputName)
public GraphBuilder removeVertexKeepConnections(String outputName)
从计算图中移除指定的顶点,但保持其连接。注意,这里期望是然后添加另一个具有相同名称的顶点,否则该图将处于无效状态,可能引用了不再存在的顶点
- 参数 outputName
- 返回GraphBuilder
TransferLearningHelper
此类旨在与迁移学习API一起使用。通常,迁移学习模型具有“冻结”层,其中参数在训练期间保持恒定。为了便于训练和快速周转次数,要训练的数据集可以被特征化并将其保存到磁盘。在这种情况下,特性化指的是在网络上进行前向传递,并从冻结层的输出中保存激活。在训练期间,可以完全跳过冻结层的向前和向后传递,并且“特征化”数据集可以与计算图的较小的未冻结部分拟合,从而允许更快的迭代。该类在内部遍历计算图/MLN,并构建与未冻结子集相等的计算图/MLN的实例。
TransferLearningHelper
public TransferLearningHelper(ComputationGraph orig, String... frozenOutputAt)
Will modify the given comp graph (in place!) to freeze vertices from input to the vertex specified.将修改给定的计算图(就位!)来冻结从输入到指定顶点之间的顶点。
- 参数 orig 计算图
- 参数 frozenOutputAt 顶点冻结(在训练期间保持参数为常量)
TransferLearningHelper(ComputationGraph orig)
public TransferLearningHelper(ComputationGraph orig)
期望一些顶点被冻结的计算图。
- 参数 orig
unfrozenGraph
public ComputationGraph unfrozenGraph()
返回原始计算图的未冻结子集作为计算图,注意到每次调用featurizedFit时,也将参数更新到原始计算图。
unfrozenMLN
public MultiLayerNetwork unfrozenMLN()
返回多层网络中的未冻结层作为多层网络,注意到每次featurizedFit时,也将参数更新到原始多层网络
outputFromFeaturized
public INDArray outputFromFeaturized(INDArray input)
用于从特征化输入中获取输出
- 参数 input 特征化输入
- 返回 output
featurize
public MultiDataSet featurize(MultiDataSet input)
通过计算图运行并保存一个新模型,这个模型仅是原始模型的未冻结部分。这个未冻结模型用于与特征化数据一起训练。
featurize
public DataSet featurize(DataSet input)
在训练期间,冻结的顶点/层可以被视为“特征化”输入。通过这些冻结的层/顶点的前向传播可以提前完成,并且保存到磁盘的数据集在模型的较小的未冻结部分上快速迭代。当前不支持具有特征掩码的数据集。
- 参数 input 输入带有冻结层的计算图的多数据集
- 返回具有输入特征的多数据集,这些输入特征是冻结层顶点和原始标签的输出。
fitFeaturized
public void fitFeaturized(MultiDataSetIterator iter)
从一个特征化的数据集中进行拟合。拟合是在代表原始模型的未冻结部分的内部实例化子集模型上进行的。在每次调用拟合后,原始模型的参数被更新。
- 参数 iter