0

以下函数计算高斯核,是我编写的核岭回归算法的一部分。我想知道如何正确修改此函数以改善执行时间(即摆脱两个 for 循环)。有任何想法吗?

function [K] = calculate_krr_gaussiankernel(Xi,Xj,S)
    K = zeros(size(Xi,1),size(Xj,1));
    for Ixi = 1:size(Xi,1),
        for Ixj = 1:size(Xj,1),
            K(Ixi,Ixj) = exp((-norm(Xi(Ixi,:) - Xj(Ixj,:)) .^ 2) ./ (2 * (S .^ 2)));
        end
    end
end

编辑:公式: 在此处输入图像描述

4

2 回答 2

3

这是一个最有可能更快的版本。但是,它可能会导致大Xi/的内存问题Xj

function K = calculate_krr_gaussiankernel(Xi, Xj, S)

  %# create an array of difference between Xi(r,:) and Xj(s,:) for all r,s
  delta = bsxfun(@minus, permute(Xi,[1 3 2]), permute(Xj,[3 1 2]));

  %# calculate the squared norm
  ssq = sum(delta.^2, 3);

  %# calculate the kernel
  K = exp(-ssq./(2*S.^2));

这是我在做什么的解释:

  • bsxfun 行:我重塑输入,以便我可以在每个 (i,j) 处获得第三维中的差异向量
  • ssq 线只取平方和。我可以在这里取平方根,从而得到范数,但既然我们会再次平方,无论如何,那没有意义。
  • 最后一行实现了 OP 中的公式,其中ssq是差异的平方范数。
于 2012-08-15T22:58:50.480 回答
2

由于 K 是对称的,因此您当然可以(大约)加倍速度。此外,您可以计算norm差异向量的值,然后进行一次调用,exp()这可能比exp()一遍又一遍地调用更快。把它放在一起:

function [K] = calculate_krr_gaussiankernel(Xi,Xj,S)
    arg = zeros(size(Xi,1),size(Xj,1));
    for Ixi = 1:size(Xi,1),
        % diagonal elements can be done in outer loop:
        arg(Ixi,Ixi) = norm(Xi(Ixi,:) - Xj(Ixi,:));
        for Ixj = Ixi+1:size(Xj,1), % off-diagonals done once and copied
            arg(Ixi,Ixj) = norm(Xi(Ixi,:) - Xj(Ixj,:));
            arg(Ixj,Ixi) = arg(Ixi,Ixj);
        end
    end
end

K = exp(( -arg.^ 2) ./ (2 * (S .^ 2)))
于 2012-08-15T23:13:39.107 回答