Deeplearning4j 拆分数据集进行测试和训练

Deeplearning4j Splitting datasets for test and train

Deeplearning4j 具有支持将数据集拆分为测试和训练的功能,以及洗牌数据集的机制,但据我所知,要么它们不起作用,要么我做错了什么。

示例:

    DataSetIterator iter = new IrisDataSetIterator(150, 150);
    DataSet next = iter.next();
    // next.shuffle();
    SplitTestAndTrain testAndTrain = next.splitTestAndTrain(120, new Random(seed));
    DataSet train = testAndTrain.getTrain();
    DataSet test = testAndTrain.getTest();

    for (int i = 0; i < 30; i++) {
        String features = test.getFeatures().getRow(i).toString();
        String actual = test.getLabels().getRow(i).toString().trim();
        log.info("features " + features + " -> " + actual );
    }

返回输入数据集最后30行的结果,splitTestAndTrain的Random(seed)参数似乎被完全忽略了。

如果我没有将随机种子传递给 splitTestAndTrain,而是取消注释 next.shuffle() 行,那么奇怪的是,第 3 和第 4 个特征会被打乱,同时保持第 1 个和第 2 个特征的现有顺序以及测试标签,这比根本不对输入进行排序更糟糕。

所以...问题是,我是不是用错了,还是 Deeplearning4j 本身就坏了?

奖励问题:如果 Deeplearning4j 在生成测试和样本数据集这样简单的事情上被破坏了,它是否应该被信任?或者我最好使用不同的库?

据我所知,deeplearning4j 简直是坏掉了。最终我创建了自己的 splitTestandTrain 实现。

import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.dataset.DataSet;
import java.util.Random;
import org.nd4j.linalg.factory.Nd4j;

public class TestTrain {  
    protected DataSet test;
    protected DataSet train;

    public TestTrain(DataSet input, int splitSize, Random rng) {
        int inTest = 0;
        int inTrain = 0;
        int testSize = input.numExamples() - splitSize;

        INDArray train_features = Nd4j.create(splitSize, input.getFeatures().columns());
        INDArray train_outcomes = Nd4j.create(splitSize, input.numOutcomes());
        INDArray test_features  = Nd4j.create(testSize, input.getFeatures().columns());
        INDArray test_outcomes  = Nd4j.create(testSize, input.numOutcomes());

        for (int i = 0; i < input.numExamples(); i++) {
            DataSet D = input.get(i);
            if (rng.nextDouble() < (splitSize-inTrain)/(double)(input.numExamples()-i)) {
                train_features.putRow(inTrain, D.getFeatures());
                train_outcomes.putRow(inTrain, D.getLabels());
                inTrain += 1;
            } else {
                test_features.putRow(inTest, D.getFeatures());
                test_outcomes.putRow(inTest, D.getLabels());
                inTest += 1;
            }
        }

        train = new DataSet(train_features, train_outcomes);
        test  = new DataSet(test_features, test_outcomes);
    }

    public DataSet getTrain() {
        return train;
    }

    public DataSet getTest() {
        return test;
    }
}

这行得通,但我对图书馆没有信心。如果其他人可以提供更好的答案,我仍然很高兴,但现在必须这样做。

由于这个问题已经过时了,对于可能发现这个问题的人,你可以看一些例子on GitHub,拆分可以用一种简单的方式完成:

DataSetIterator iterator = new RecordReaderDataSetIterator(recordReader,batchSize,labelIndex,numClasses);
DataSet allData = iterator.next();
allData.shuffle();
SplitTestAndTrain testAndTrain = allData.splitTestAndTrain(0.65);  //Use 65% of data for training

DataSet trainingData = testAndTrain.getTrain();
DataSet testData = testAndTrain.getTest();

首先创建迭代器,遍历所有数据,对其进行洗牌以及测试和训练之间的拆分。

这取自this示例

Deeplearning4j 假设数据集是小批量的,例如:它们并不都在内存中。 这与 python 世界相矛盾,后者可能会针对较小的数据集和易用性进行更多优化。

这只适用于玩具问题,不能很好地扩展到实际问题。 取而代之的是,我们针对本地场景优化了 datasetiterator 接口(请注意,对于像 spark 这样的分布式系统,这将有所不同)。

这意味着我们依赖于使用 datavec 预先拆分数据集来解析数据集(提示:不要编写自己的迭代器:使用我们的迭代器并使用 datavec 进行自定义解析)或允许使用 datasetiterator 拆分器: https://deeplearning4j.org/doc/org/deeplearning4j/datasets/iterator/DataSetIteratorSplitter.html 用于火车测试拆分。

数据集拆分训练测试 class 仅当数据集已全部在内存中时才有效,但对于大多数半现实问题(例如:超越 xor 或 mnist)可能没有意义

我建议 运行 您的 ETL 步骤一次而不是每次。将您的数据集预先洗牌到预先切片的批次中。 一种方法是结合使用:https://github.com/deeplearning4j/deeplearning4j/blob/master/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/dataset/BalanceMinibatchesTest.java#L40 和: https://nd4j.org/doc/org/nd4j/linalg/dataset/ExistingMiniBatchDataSetIterator.html

这样做的另一个原因是再现性。如果你想做一些事情,比如每个时期都洗牌你的迭代器,你可以尝试根据上述组合编写一些代码。无论哪种方式,我都会尝试处理您的 ETL 并在您进行培训之前预先创建向量。否则,您将花费大量时间在更大的数据集上加载数据。