【问题标题】:Deeplearning4j Splitting datasets for test and trainDeeplearning4j 拆分数据集进行测试和训练
【发布时间】:2016-02-27 10:32:57
【问题描述】:

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 因生成测试和样本数据集这样简单的事情而被破坏,那么它是否应该被信任?还是我最好使用不同的库?

【问题讨论】:

标签: java machine-learning deep-learning


【解决方案1】:

据我所知,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;
    }
}

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

【讨论】:

  • 请参阅我对此的回复。你的“信心”来自于不理解图书馆的假设。我在下面更正了这一点。您的实现最多适用于所有在内存中的玩具问题。这在 gpus 或大型数据集上效率不高。
【解决方案2】:

由于这个问题已经过时,对于可能会发现这个问题的人,您可以查看一些示例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示例

【讨论】:

    【解决方案3】:

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

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

    这意味着我们依赖于数据集,或者使用 datavec 预先拆分数据集来解析数据集(提示:不要编写自己的迭代器:使用我们的迭代器并使用 datavec 进行自定义解析)或允许使用 datasetiterator 拆分器:@ 987654321@ 用于火车测试拆分。

    数据集拆分训练测试类仅在数据集已全部在内存中时才有效,但对于大多数半现实问题(例如:超越 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

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

    【讨论】:

    • 我从你的帖子中了解到,对于生产编码,从最不喜欢到最喜欢的方式的顺序是:1. dataSet.splitTestAndTrain(...) 2. DataSetIteratorSplitter 3. ExistingMiniBatchDataSetIterator
    猜你喜欢
    • 2019-03-15
    • 1970-01-01
    • 2017-11-01
    • 1970-01-01
    • 2018-06-04
    • 1970-01-01
    • 1970-01-01
    • 2017-02-20
    • 2019-05-01
    相关资源
    最近更新 更多