0

次の関数はガウス カーネルを計算し、私が書いたカーネル リッジ回帰アルゴリズムの一部です。実行時間を改善するために、この関数を適切に変更するにはどうすればよいでしょうか (つまり、2 つの 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) で、3 次元の差分ベクトルを取得できるように、入力を再形成します。
  • ssq 行は単純に二乗和を取ります。ここで平方根をとってノルムを得ることができますが、それを再び二乗するので、とにかく、それには意味がありません。
  • 最後の行は OP の式を実装します。ここssqで、 は差の二乗ノルムです。
于 2012-08-15T22:58:50.480 に答える
2

K は対称であるため、速度を (ほぼ) 2 倍にすることができます。さらに、差分ベクトルを計算してから、何度も呼び出すよりも高速な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 に答える