在大量类上训练分类器时,SVM 非常慢
Posted
技术标签:
【中文标题】在大量类上训练分类器时,SVM 非常慢【英文标题】:SVM is very slow when training classifier on big number of classes 【发布时间】:2019-06-28 13:14:29 【问题描述】:我正在尝试在大量项目和类上训练一个 SVM 分类器,这变得非常非常慢。
首先,我从我的数据中提取了一个特征集,总体上是特定的 512 个特征,并将其放入 numpy 数组中。此数组中有 13k 项。看起来是这样的:
>>print(type(X_train))
<class 'numpy.ndarray'>
>>print(X_train)
[[ 0.01988654 -0.02607637 0.04691431 ... 0.11521499 0.03433102
0.01791015]
[-0.00058317 0.05720023 0.03854145 ... 0.07057668 0.09192026
0.01479562]
[ 0.01506544 0.05616265 0.01514515 ... 0.04981219 0.05810429
0.00232013]
...
此外,还有大约 4k 个不同的类:
>> print(type(labels))
<class 'list'>
>> print(labels)
[0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, ... ]
这里是分类器:
import pickle
from thundersvmScikit import SVC
FILENAME = 'dataset.pickle'
with open(FILENAME, 'rb') as infile:
(X_train, labels) = pickle.load(infile)
clf = SVC(kernel='linear', probability=True)
clf.fit(X_train, labels)
大约 90 小时过去后(我正在使用 Thundersvm 形式的 sci-learn 套件的 GPU 实现)拟合操作仍在运行。考虑到在我的情况下它是一个非常小的数据集,我肯定需要更高效的东西,但我似乎没有取得任何好的成功。例如,我尝试过这种类型的 Keras 模型:
model = Sequential()
model.add(Dense(input_dim=512, units=100, activation='tanh'))
model.add(Dropout(0.2))
model.add(Dense(units=n_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adadelta', metrics=['accuracy'])
model.fit(X_train, labels, epochs=500, batch_size=64, validation_split=0.1, shuffle=True)
我最终在训练阶段获得了相当不错的准确度:
Epoch 500/500
11988/11988 [==============================] - 1s 111us/step - loss: 2.1398 - acc: 0.8972 - val_loss: 9.5077 - val_acc: 0.0000e+00
但是,在实际测试期间,即使是在训练数据集中存在的数据上,我的准确率也极低,预测的类别基本上是随机的:
Predictions (best probabilities):
0 class710015: 0.008
1 class715573: 0.007
2 class726619: 0.006
3 class726619: 0.010
4 class720439: 0.007
Accuracy: 0.000
请您指出正确的方向吗?我应该以某种方式调整 SVM 方法,还是应该针对此类问题切换到自定义 Keras 模型?如果是,我的模型可能存在什么问题?
非常感谢。
【问题讨论】:
【参考方案1】:如果它依赖于多类 SVC 的 scikit-learn 实现,则不应使用该 SVC 实现。在documentation 中,它声明“多类支持是根据一对一的方案处理的。”这意味着您为每一对类训练一个分类器,即正在训练约 2^4k 个分类器。您可以使用“固有多类”下列出的 here 任何内容
此外,您的 Keras 实现可能还需要另一层。我假设每个类的输出层有 1 个神经元,在这种情况下,您需要使用分类交叉熵和 softmax 激活,以及一个热编码。
我现在假设您的所有示例都只有一个类标签。
【讨论】:
感谢您的回答。顺便说一句,您的假设是正确的,即我的示例只有一个类标签。所以,据我所知,我应该摆脱 SVM (SVC) 的实现。 另外,其实还是推荐使用二元交叉熵损失函数和sigmoid激活函数进行多类分类,所以问题肯定不在这块模型上。 你能给我一个引用 @none32 吗? 当然。我在那里找到了这个信息:github.com/keras-team/keras/issues/2166#issuecomment-204746792 我相信这不是你所说的。在几乎所有的神经网络设置中,你应该 1 对你的类进行热编码。在这种情况下,他们说如果你在做多标签分类,那么二元交叉熵是正确的。您之前说过您的每个示例都有 1 个标签,因此,它不是多标签,因此它应该是 1 个带有分类交叉熵的热编码。【参考方案2】:SVM 最适合二元分类。对于多类,scikit-learn 使用一对一来组合 O(K^2) 二进制分类器 (https://scikit-learn.org/stable/modules/svm.html),其中 K 是类的数量。因此,运行时间与 K^2 成正比,或者在您的情况下为 1600 万。这就是它如此缓慢的原因。
您应该减少类的数量,或者切换到其他模型,例如神经网络或决策树。
P.S:scikit-learn 也有用于 SVM (https://scikit-learn.org/stable/modules/multiclass.html) 的 one-vs-all 方法,即 O(K)。你也可以试试这个。
【讨论】:
感谢您的回答。正如我所说,我已经尝试将 Keras 用于神经网络来解决这个分类问题,尝试了很多不同的模型配置,但仍然没有得到好的结果。请您指出我的问题的模型结构的写作方向吗? 你不能指望这么多类有很好的准确性。通常,大量的类需要大型的深度神经网络和相当大量的训练时间。您可以查看在 CIFAR-100 上运行的一些论文(应该有很多)以了解最新技术。我不能告诉你正确的结构,因为你没有给出任何关于这个问题的说明。以上是关于在大量类上训练分类器时,SVM 非常慢的主要内容,如果未能解决你的问题,请参考以下文章