【问题标题】:Deeplearning4j neural network only predicting 1 classDeeplearning4j 神经网络仅预测 1 类
【发布时间】:2018-11-12 05:39:33
【问题描述】:

在过去一周左右的时间里,我一直在尝试让神经网络使用 RGB 图像发挥作用,但无论我做什么,它似乎都只能预测一个类别。 我已经阅读了所有我能找到的与遇到这个问题的人的链接,并尝试了很多不同的东西,但它总是最终只能预测两个输出类中的一个。我检查了进入模型的批次,我增加了数据集的大小,我将原始像素大小(28*28)增加到 56*56,增加了 epoch,做了很多模型调整,我什至有尝试了一个简单的非卷积神经网络以及简化我自己的 CNN 模型,但它没有任何改变。

我还检查了如何为训练集(特别是 imageRecordReader)传递数据的结构,但是这个输入结构(就文件夹结构和数据如何传递到训练集而言)在以下情况下工作得很好给定灰度图像(因为它最初是在 MNIST 数据集上以 99% 的准确率创建的)。

一些上下文:我使用以下文件夹名称作为我的标签,即用于训练和测试数据的文件夹 (0)、文件夹 (1),因为只有两个输出类。训练集包含 320 个类别 0 的图像和 240 个类别 1 的图像,而测试集分别由 79 个和 80 个图像组成。

代码如下:

private static final Logger log = LoggerFactory.getLogger(MnistClassifier.class);
private static final String basePath = System.getProperty("java.io.tmpdir") + "/ISIC-Images";

public static void main(String[] args) throws Exception {
    int height = 56;
    int width = 56;
    int channels = 3; // RGB Images
    int outputNum = 2; // 2 digit classification
    int batchSize = 1;
    int nEpochs = 1;
    int iterations = 1;
    int seed = 1234;
    Random randNumGen = new Random(seed);

    // vectorization of training data
    File trainData = new File(basePath + "/Training");
    FileSplit trainSplit = new FileSplit(trainData, NativeImageLoader.ALLOWED_FORMATS, randNumGen);
    ParentPathLabelGenerator labelMaker = new ParentPathLabelGenerator(); // parent path as the image label
    ImageRecordReader trainRR = new ImageRecordReader(height, width, channels, labelMaker);
    trainRR.initialize(trainSplit);
    DataSetIterator trainIter = new RecordReaderDataSetIterator(trainRR, batchSize, 1, outputNum);

    // vectorization of testing data
    File testData = new File(basePath + "/Testing");
    FileSplit testSplit = new FileSplit(testData, NativeImageLoader.ALLOWED_FORMATS, randNumGen);
    ImageRecordReader testRR = new ImageRecordReader(height, width, channels, labelMaker);
    testRR.initialize(testSplit);
    DataSetIterator testIter = new RecordReaderDataSetIterator(testRR, batchSize, 1, outputNum);

    log.info("Network configuration and training...");
    Map<Integer, Double> lrSchedule = new HashMap<>();
    lrSchedule.put(0, 0.06); // iteration #, learning rate
    lrSchedule.put(200, 0.05);
    lrSchedule.put(600, 0.028);
    lrSchedule.put(800, 0.0060);
    lrSchedule.put(1000, 0.001);

    MultiLayerConfiguration conf = new NeuralNetConfiguration.Builder()
        .seed(seed)
        .l2(0.0008)
        .updater(new Nesterovs(new MapSchedule(ScheduleType.ITERATION, lrSchedule)))
        .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
        .weightInit(WeightInit.XAVIER)
        .list()
        .layer(0, new ConvolutionLayer.Builder(5, 5)
            .nIn(channels)
            .stride(1, 1)
            .nOut(20)
            .activation(Activation.IDENTITY)
            .build())
        .layer(1, new SubsamplingLayer.Builder(SubsamplingLayer.PoolingType.MAX)
            .kernelSize(2, 2)
            .stride(2, 2)
            .build())
        .layer(2, new ConvolutionLayer.Builder(5, 5)
            .stride(1, 1)
            .nOut(50)
            .activation(Activation.IDENTITY)
            .build())
        .layer(3, new SubsamplingLayer.Builder(SubsamplingLayer.PoolingType.MAX)
            .kernelSize(2, 2)
            .stride(2, 2)
            .build())
        .layer(4, new DenseLayer.Builder().activation(Activation.RELU)
            .nOut(500).build())
        .layer(5, new OutputLayer.Builder(LossFunctions.LossFunction.SQUARED_LOSS)
            .nOut(outputNum)
            .activation(Activation.SOFTMAX)
            .build())
        .setInputType(InputType.convolutionalFlat(56, 56, 3)) // InputType.convolutional for normal image
        .backprop(true).pretrain(false).build();

    MultiLayerNetwork net = new MultiLayerNetwork(conf);
    net.init();
    net.setListeners(new ScoreIterationListener(10));
    log.debug("Total num of params: {}", net.numParams());

    // evaluation while training (the score should go down)
    for (int i = 0; i < nEpochs; i++) {
        net.fit(trainIter);
        log.info("Completed epoch {}", i);
        Evaluation eval = net.evaluate(testIter);
        log.info(eval.stats());
        trainIter.reset();
        testIter.reset();
    }
    ModelSerializer.writeModel(net, new File(basePath + "/Isic.model.zip"), true);
}

运行模型的输出:

Odd iteration scores

Evaluation metrics

任何见解将不胜感激。

【问题讨论】:

    标签: java deep-learning conv-neural-network rgb deeplearning4j


    【解决方案1】:

    我建议将第 1 层和第 2 层中的激活函数更改为非线性函数。您可以尝试使用ReluTanh 函数。 您可以参考Documentaion 获取可用激活功能的列表。

    【讨论】:

    • 我在过去一周做了很多不同的配置实验,恐怕使用 Relu 和 Tanh(除了这些我已经尝试了很多)结果没有改变,因为两者中只有一个输出类由整个测试集预测。
    【解决方案2】:

    在 99% 的情况下,CNN 上的身份几乎没有意义。如果可以,请坚持使用 RELU。 相反,我会将您的努力转向梯度归一化或散布丢弃层。几乎每次 CNN 无法学习时,通常都是由于缺乏正则化。

    另外:永远不要在 softmax 中使用平方损失。它永远不会起作用。坚持负对数似然。

    我从未见过在实践中使用 softmax 的平方损失。

    您可以尝试 l2 和 l1 正则化(或两者都尝试:这称为弹性网络正则化)

    【讨论】:

    • 我开始使用 NegativeLogLikelihood,但它总是给我由 NaN 值组成的迭代分数,结果相同。至于身份激活函数,我已经在好几个之间来回折腾了,看看我是否取得了一些进展。我将更深入地研究正则化和辍学,看看我是否会取得一些进展。谢谢你的回复
    【解决方案3】:

    似乎使用 ADAM 优化器得到了一些有希望的结果,并且增加了批量大小(我现在有数千张图像),否则网络需要大量的 epoch(至少 50+)才能开始学习。

    感谢您的所有回复。

    【讨论】:

      猜你喜欢
      • 2016-10-24
      • 2018-08-29
      • 1970-01-01
      • 1970-01-01
      • 2017-12-02
      • 2021-03-31
      • 2012-05-06
      • 2017-12-28
      • 1970-01-01
      相关资源
      最近更新 更多