深度学习4j神经网络仅预测1类



在过去的一周左右,我一直在尝试使用RGB图像让神经网络发挥作用,但无论我做什么,它似乎只预测一个类。我已经阅读了我能找到的与遇到这个问题的人的所有链接,并尝试了很多不同的东西,但它最终总是只预测两个输出类中的一个。我检查了进入模型的批次,我增加了数据集的大小,我将原始像素大小(28*28(增加到56*56,增加了历元,进行了大量的模型调整,我甚至尝试了一个简单的非卷积神经网络,并降低了我自己的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);
}

运行模型的输出:

奇数迭代得分

评估指标

任何见解都将不胜感激。

我建议将第1层和第2层中的激活函数更改为非线性函数。您可以尝试使用ReluTanh函数。有关可用激活功能的列表,请参阅本文档。

在99%的时间里,CNNs上的身份几乎没有意义。如果可以的话,坚持RELU。相反,我会把你的努力转向梯度归一化或分散掉层。美国有线电视新闻网几乎每次都不学习,通常是因为缺乏规范。

此外:切勿将平方损失与softmax一起使用。它从来都不起作用。坚持负对数可能性。

在实践中,我从未见过平方损失与softmax一起使用。

你可以尝试l2和l1正则化(或者两者兼有:这被称为弹性网正则化(

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

感谢您的所有回复。

最新更新