【问题标题】:bad result when using precomputed chi2 kernel with libsvm (matlab)将预计算的 chi2 内核与 libsvm (matlab) 一起使用时结果不佳
【发布时间】:2011-11-02 21:55:48
【问题描述】:

我正在尝试 libsvm,并按照该示例在软件随附的 heart_scale 数据上训练 svm。我想使用我自己预先计算的 chi2 内核。训练数据的分类率下降到 24%。我确定我正确计算了内核,但我想我一定是做错了什么。代码如下。你能看出有什么错误吗?非常感谢您的帮助。

%read in the data:
[heart_scale_label, heart_scale_inst] = libsvmread('heart_scale');
train_data = heart_scale_inst(1:150,:);
train_label = heart_scale_label(1:150,:);

%read somewhere that the kernel should not be sparse
ttrain = full(train_data)';
ttest = full(test_data)';

precKernel = chi2_custom(ttrain', ttrain');
model_precomputed = svmtrain2(train_label, [(1:150)', precKernel], '-t 4');

这是内核的预计算方式:

function res=chi2_custom(x,y)
a=size(x);
b=size(y);
res = zeros(a(1,1), b(1,1));
for i=1:a(1,1)
    for j=1:b(1,1)
        resHelper = chi2_ireneHelper(x(i,:), y(j,:));
        res(i,j) = resHelper;
    end
end
function resHelper = chi2_ireneHelper(x,y)
a=(x-y).^2;
b=(x+y);
resHelper = sum(a./(b + eps));

使用不同的 svm 实现 (vlfeat),我获得了大约 90% 的训练数据分类率(是的,我在训练数据上进行了测试,只是为了看看发生了什么)。所以我很确定 libsvm 结果是错误的。

【问题讨论】:

    标签: matlab machine-learning svm libsvm


    【解决方案1】:

    使用支持向量机时,将数据集归一化作为预处理步骤非常重要。 Normalization 将属性放在相同的尺度上,并防止具有较大值的属性对结果产生偏差。它还提高了数值稳定性(最大限度地减少了浮点表示引起的上溢和下溢的可能性)。

    确切地说,您对卡方核的计算略有偏差。取而代之的是下面的定义,并为它使用这个更快的实现:

    function D = chi2Kernel(X,Y)
        D = zeros(size(X,1),size(Y,1));
        for i=1:size(Y,1)
            d = bsxfun(@minus, X, Y(i,:));
            s = bsxfun(@plus, X, Y(i,:));
            D(:,i) = sum(d.^2 ./ (s/2+eps), 2);
        end
        D = 1 - D;
    end
    

    现在考虑使用与您相同的数据集的以下示例(代码改编自我的previous answer):

    %# read dataset
    [label,data] = libsvmread('./heart_scale');
    data = full(data);      %# sparse to full
    
    %# normalize data to [0,1] range
    mn = min(data,[],1); mx = max(data,[],1);
    data = bsxfun(@rdivide, bsxfun(@minus, data, mn), mx-mn);
    
    %# split into train/test datasets
    trainData = data(1:150,:);    testData = data(151:270,:);
    trainLabel = label(1:150,:);  testLabel = label(151:270,:);
    numTrain = size(trainData,1); numTest = size(testData,1);
    
    %# compute kernel matrices between every pairs of (train,train) and
    %# (test,train) instances and include sample serial number as first column
    K =  [ (1:numTrain)' , chi2Kernel(trainData,trainData) ];
    KK = [ (1:numTest)'  , chi2Kernel(testData,trainData)  ];
    
    %# view 'train vs. train' kernel matrix
    figure, imagesc(K(:,2:end))
    colormap(pink), colorbar
    
    %# train model
    model = svmtrain(trainLabel, K, '-t 4');
    
    %# test on testing data
    [predTestLabel, acc, decVals] = svmpredict(testLabel, KK, model);
    cmTest = confusionmat(testLabel,predTestLabel)
    
    %# test on training data
    [predTrainLabel, acc, decVals] = svmpredict(trainLabel, K, model);
    cmTrain = confusionmat(trainLabel,predTrainLabel)
    

    测试数据上的结果:

    Accuracy = 84.1667% (101/120) (classification)
    cmTest =
        62     8
        11    39
    

    在训练数据上,我们得到了大约 90% 的准确率,如您所料:

    Accuracy = 92.6667% (139/150) (classification)
    cmTrain =
        77     3
         8    62
    

    【讨论】:

    • 哦,很酷 - 这是一个详细的答案。感谢您花时间考虑我的问题。这肯定有帮助。
    • @Sallos:很高兴我能帮上忙,如果解决了问题,请考虑accepting 一个答案
    【解决方案2】:

    问题出在下面一行:

    resHelper = sum(a./(b + eps));
    

    应该是:

    resHelper = 1-sum(2*a./(b + eps));
    

    【讨论】:

    • 感谢您回答我的问题,我现在才看到您的回复。
    • @Sallos:虽然你的公式有点不对劲,但真正的问题是数据规范化。看看我的回答
    猜你喜欢
    • 2014-04-28
    • 2012-06-14
    • 2011-12-04
    • 2011-01-29
    • 2014-04-11
    • 2013-03-12
    • 2014-06-21
    • 2014-03-16
    • 2012-04-11
    相关资源
    最近更新 更多