Нейронная сеть Deeplearning4j предсказывает только 1 класс - PullRequest
0 голосов
/ 12 ноября 2018

В течение прошлой недели или около того я пытался заставить нейронную сеть функционировать с использованием изображений RGB, но, независимо от того, что я делаю, кажется, что прогнозируется только один класс. Я прочитал все ссылки, которые я мог найти с людьми, сталкивающимися с этой проблемой, и экспериментировал со многими разными вещами, но это всегда заканчивалось предсказанием только одного из двух выходных классов. Я проверил партии, поступающие в модель, увеличил размер набора данных, увеличил исходный размер пикселя (28 * 28) до 56 * 56, увеличил эпохи, выполнил много настроек модели, и я даже попробовал простую не сверточную нейронную сеть, а также заглушил мою собственную модель CNN, но это ничего не меняет.

Я также проверил структуру передачи данных для обучающего набора (в частности, imageRecordReader), но эта структура ввода (с точки зрения структуры папок и способа передачи данных в обучающий набор) прекрасно работает, когда заданные полутоновые изображения (как они изначально были созданы с точностью 99% в наборе данных MNIST).

Некоторый контекст: я использую следующие имена папок в качестве меток, т.е. папка (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);
}

Выход от запуска модели:

Нечетные итерационные оценки

Метрики оценки

Любое понимание будет высоко ценится.

Ответы [ 3 ]

0 голосов
/ 12 ноября 2018

Идентичность на CNN почти никогда не имеет смысла в 99% случаев. Придерживайтесь RELU, если можете. Вместо этого я бы переместил ваши усилия в направлении нормализации градиента или разбрасывания выпадающих слоев. Почти каждый раз, когда CNN не учится, это обычно происходит из-за отсутствия регулярности.

Также: Никогда не используйте квадратичные потери с softmax. Это никогда не работает. Придерживайтесь отрицательной логарифмической вероятности.

Я никогда не видел квадрата потерь, используемых с softmax на практике.

Вы можете попробовать регуляризацию l2 и l1 (или обе: это называется упругой регуляризацией)

0 голосов
/ 30 декабря 2018

Похоже, что использование оптимизатора ADAM дало некоторые многообещающие результаты, а также увеличило размер пакета (у меня сейчас тысячи изображений), иначе для начала обучения сети требуется абсурдное количество эпох (не менее 50+).

Спасибо за все ответы независимо.

0 голосов
/ 12 ноября 2018

Я бы предложил изменить функции активации на уровне 1 и 2 на нелинейную функцию. Вы можете попробовать использовать функции Relu и Tanh. Вы можете обратиться к этому Документация для получения списка доступных функций активации.

...