用于性别分类的SVM:使用线性内核100%正确的结果,但使用RBF的结果更差

ffr*_*end 1 classification image-processing svm scikit-learn

我根据脸部图像制作了一个用于性别分类的小程序.我使用耶鲁面部数据库(男性为175张图像,女性为相同数字),将它们转换为灰度和均衡直方图,因此在预处理后图像看起来像这样:

在此输入图像描述

我运行以下代码来测试结果(它使用SVM和线性内核):

def run_gender_classifier():
    Xm, Ym = mkdataset('gender/male', 1)     # mkdataset just preprocesses images, 
    Xf, Yf = mkdataset('gender/female', 0)   #  flattens them and stacks into a matrix
    X = np.vstack([Xm, Xf])
    Y = np.hstack([Ym, Yf])
    X_train, X_test, Y_train, Y_test = train_test_split(X, Y,
                                                    test_size=0.1,
                                                    random_state=100)
    model = svm.SVC(kernel='linear')
    model.fit(X_train, Y_train)
    print("Results:\n%s\n" % (
        metrics.classification_report(
            Y_test, model.predict(X_test))))
Run Code Online (Sandbox Code Playgroud)

并获得100%的精度!

In [22]: run_gender_classifier()
Results:
             precision    recall  f1-score   support

          0       1.00      1.00      1.00        16
          1       1.00      1.00      1.00        19

avg / total       1.00      1.00      1.00        35
Run Code Online (Sandbox Code Playgroud)

我可以期待不同的结果,但100%正确的图像分类看起来真的很可疑.

此外,当我将内核更改为RBF时,结果变得非常糟糕:

In [24]: run_gender_classifier()
Results:
             precision    recall  f1-score   support

          0       0.46      1.00      0.63        16
          1       0.00      0.00      0.00        19

avg / total       0.21      0.46      0.29        35
Run Code Online (Sandbox Code Playgroud)

这对我来说似乎更奇怪.

所以我的问题是:

  1. 我的方法或代码有什么错误吗?
  2. 如果没有,线性内核的结果怎么会这么好,而RBF的结果如此糟糕?

注意,我通过逻辑回归获得100%正确的结果,并且使用深信念网络得到非常差的结果,因此它不是特定于SVM,而是针对线性和非线性模型.


为了完整起见,这是我的预处理和制作数据集的代码:

import cv2
from sklearn import linear_model, svm, metrics
from sklearn.cross_validation import train_test_split


def preprocess(im):
    im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
    im = cv2.resize(im, (100, 100))
    return cv2.equalizeHist(im)


def mkdataset(path, label):
    images = (cv2.resize(cv2.imread(fname), (100, 100))
              for fname in list_images(path))
    images = (preprocess(im) for im in images)
    X = np.vstack([im.flatten() for im in images])
    Y = np.repeat(label, X.shape[0])
    return X, Y
Run Code Online (Sandbox Code Playgroud)

lej*_*lot 5

所有描述的模型都需要调整参数:

  • 线性SVM:C
  • RBF SVM:C,gamma
  • DBN:图层计数,神经元计数,输出分类器,训练率...

你只是省略了这个元素.因此很自然,具有最少数量的可调参数的模型表现得更好 - 因为简单地说,默认参数实际工作的概率更大.

100%得分总是看起来很可疑,你应该"手动"仔细检查 - 将数据分成火车和测试(放入不同的目录),一部分训练,将模型保存到文件中.然后在单独的代码中 - 加载模型,并在测试文件上测试它,并从模型中显示图像+标签.这样你就可以确保没有implmenentation错误(因为你真的不关心是否有任何处理错误,如果你有一个物理证明你的模型识别那些面,对吧?).这纯粹是"心理学方法",这使得数据分割/共享和进一步评估中没有错误显而易见.

UPDATE

正如评论中所建议的那样,我还检查了您的数据集,并且正如官方网站上所述:

扩展的耶鲁人脸数据库B包含在9个姿势和64个照明条件下的28个人类对象的16128个图像.

所以这肯定是一个问题 - 这不是性别认可的数据集.您的分类器只记忆这28个科目,这些科目很容易分为男/女.它根本不适用于其他主题的任何图像.这个数据集中唯一的"有价值"部分是28个独特个体的面部集合,您可以手动提取,但28个图像似乎至少有一个数量级太小而无法使用.

  • 同样对于火车测试分裂,使测试分裂的面部来自不同的人,而不是来自火车分裂的人.我在耶鲁数据集中最多可以获得每人一张照片.如果人们得到重复的图片,那么分类器可能只需要过度拟合人们的身份而不是仅通过考虑性别特定的属性进行概括. (2认同)