Nolearn在运行分类任务时出现索引错误,但在回归任务中不会出现

几天前我遇到了一个问题,现在仍然困扰着我。我正在按照Daniel Nouri的深度学习教程进行学习:http://danielnouri.org/notes/category/deep-learning/,并尝试将他的示例应用到一个分类数据集上。我的问题是,如果我将数据集视为回归问题,它可以正常工作,但如果我尝试进行分类,它就会失败。我尝试编写了两个可复现的示例。

1) 回归(运行良好)

import lasagnefrom sklearn import datasetsimport numpy as npfrom lasagne import layersfrom lasagne.updates import nesterov_momentumfrom nolearn.lasagne import NeuralNetfrom sklearn.preprocessing import StandardScaleriris = datasets.load_iris()X = iris.data[iris.target<2]  # 我们只取前两个特征。Y = iris.target[iris.target<2]stdscaler = StandardScaler(copy=True, with_mean=True, with_std=True)X = stdscaler.fit_transform(X).astype(np.float32)y = np.asmatrix((Y-0.5)*2).T.astype(np.float32)print X.shape, type(X)print y.shape, type(y)net1 = NeuralNet(    layers=[  # 三层:一个隐藏层        ('input', layers.InputLayer),        ('hidden', layers.DenseLayer),        ('output', layers.DenseLayer),        ],    # 层参数:    input_shape=(None, 4),  # 每批次96x96输入像素    hidden_num_units=10,  # 隐藏层单元数    output_nonlinearity=None,  # 输出层使用恒等函数    output_num_units=1,  # 1个目标值    # 优化方法:    update=nesterov_momentum,    update_learning_rate=0.01,    update_momentum=0.9,    regression=True,  # 标志表示我们处理的是回归问题    max_epochs=400,  # 我们希望训练这么多轮    verbose=1,    )net1.fit(X, y)

2) 分类(引发矩阵维度错误;我将错误信息粘贴在下面)

import lasagnefrom sklearn import datasetsimport numpy as npfrom lasagne import layersfrom lasagne.nonlinearities import softmaxfrom lasagne.updates import nesterov_momentumfrom nolearn.lasagne import NeuralNetfrom sklearn.preprocessing import StandardScaleriris = datasets.load_iris()X = iris.data[iris.target<2]  # 我们只取前两个特征。Y = iris.target[iris.target<2]stdscaler = StandardScaler(copy=True, with_mean=True, with_std=True)X = stdscaler.fit_transform(X).astype(np.float32)y = np.asmatrix((Y-0.5)*2).T.astype(np.int32)print X.shape, type(X)print y.shape, type(y)net1 = NeuralNet(    layers=[  # 三层:一个隐藏层        ('input', layers.InputLayer),        ('hidden', layers.DenseLayer),        ('output', layers.DenseLayer),        ],    # 层参数:    input_shape=(None, 4),  # 每批次96x96输入像素    hidden_num_units=10,  # 隐藏层单元数    output_nonlinearity=softmax,  # 输出层使用恒等函数    output_num_units=1,  # 1个目标值    # 优化方法:    update=nesterov_momentum,    update_learning_rate=0.01,    update_momentum=0.9,    regression=False,  # 标志表示我们处理的是分类问题    max_epochs=400,  # 我们希望训练这么多轮    verbose=1,    )net1.fit(X, y)

使用代码2时,我得到的失败输出如下:

(100, 4) <type 'numpy.ndarray'>(100, 1) <type 'numpy.ndarray'>  input                 (None, 4)               produces       4 outputs  hidden                (None, 10)              produces      10 outputs  output                (None, 1)               produces       1 outputs---------------------------------------------------------------------------IndexError                                Traceback (most recent call last)<ipython-input-13-184a45e5abaa> in <module>()     40     )     41 ---> 42 net1.fit(X, y)/Users/ivanvallesperez/anaconda/lib/python2.7/site-packages/nolearn/lasagne/base.pyc in fit(self, X, y)    291     292         try:--> 293             self.train_loop(X, y)    294         except KeyboardInterrupt:    295             pass/Users/ivanvallesperez/anaconda/lib/python2.7/site-packages/nolearn/lasagne/base.pyc in train_loop(self, X, y)    298     def train_loop(self, X, y):    299         X_train, X_valid, y_train, y_valid = self.train_test_split(--> 300             X, y, self.eval_size)    301     302         on_epoch_finished = self.on_epoch_finished/Users/ivanvallesperez/anaconda/lib/python2.7/site-packages/nolearn/lasagne/base.pyc in train_test_split(self, X, y, eval_size)    399                 kf = KFold(y.shape[0], round(1. / eval_size))    400             else:--> 401                 kf = StratifiedKFold(y, round(1. / eval_size))    402     403             train_indices, valid_indices = next(iter(kf))/Users/ivanvallesperez/anaconda/lib/python2.7/site-packages/sklearn/cross_validation.pyc in __init__(self, y, n_folds, shuffle, random_state)    531         for test_fold_idx, per_label_splits in enumerate(zip(*per_label_cvs)):    532             for label, (_, test_split) in zip(unique_labels, per_label_splits):--> 533                 label_test_folds = test_folds[y == label]    534                 # the test split can be too big because we used    535                 # KFold(max(c, self.n_folds), self.n_folds) instead ofIndexError: too many indices for array

这是怎么回事?我做错了什么吗?我觉得我已经尝试了一切,但还是无法弄清楚发生了什么。

请注意,我今天刚刚使用命令更新了我的lasagne和依赖项:pip install -r https://raw.githubusercontent.com/dnouri/kfkd-tutorial/master/requirements.txt

提前感谢

编辑

通过进行以下更改,我成功地使其工作了,但我仍然有一些疑问:

  • 我将Y定义为包含0/1值的一维向量,如下所示:y = Y.astype(np.int32),但我仍然有一些疑问

  • 我不得不将参数output_num_units=1更改为output_num_units=2,我不是很理解这一点,因为我正在处理一个二元分类问题,我认为这个多层感知器应该只有1个输出神经元,而不是2个…我错了么?

我还尝试将成本函数更改为ROC-AUC。我知道有一个名为objective_loss_function的参数,默认定义为objective_loss_function=lasagne.objectives.categorical_crossentropy,但是…我如何使用ROC AUC作为成本函数而不是分类交叉熵呢?

谢谢


回答:

在nolearn中,如果你进行分类任务,output_num_units表示你有多少个类。虽然可以用一个输出单元实现两类分类,但在nolearn中并没有这样特殊处理,这一点可以从[1]中看出:

    if not self.regression:        predict = predict_proba.argmax(axis=1)

请注意,无论你有多少个类,预测总是使用argmax(这意味着两类分类有两个输出,而不是一个)。

所以你的更改是正确的:output_num_units应该始终是你拥有的类数,即使你有两个类,Y应该具有(num_samples)(num_samples, 1)的形状,包含表示类别的整数值,而不是例如具有每个类别一个位的向量,形状为(num_samples, num_categories)

回答你的另一个问题,Lasagne似乎没有ROC-AUC目标函数,所以你需要自己实现。请注意,你不能使用scikit-learn中的实现,因为Lasagne要求目标函数接受theano张量作为参数,而不是列表或ndarray。要了解Lasagne中如何实现目标函数,你可以查看现有的目标函数[2]。其中许多引用了theano内部的函数,你可以在[3]中查看它们的实现(它会自动滚动到binary_crossentropy,这是一个目标函数的好例子)。

[1] https://github.com/dnouri/nolearn/blob/master/nolearn/lasagne/base.py#L414

[2] https://github.com/Lasagne/Lasagne/blob/master/lasagne/objectives.py

[3] https://github.com/Theano/Theano/blob/master/theano/tensor/nnet/nnet.py#L1809

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注