5

現在、MATLAB でロジスティック損失関数を含む機械学習アルゴリズムを実装しようとしています。残念ながら、数値のオーバーフローが原因で問題が発生しています。

一般に、特定の入力に対してs、ロジスティック関数の値は次のようになります。

 log(1 + exp(s))

ロジスティック損失関数の傾きは次のとおりです。

 exp(s)./(1 + exp(s)) = 1./(1 + exp(-s))

私のアルゴリズムでは、 の値はs = X*beta. これは、データ ポイントとデータ ポイントごとの特徴 (つまり) を含むX行列で、は各特徴の係数のベクトルであり、となります。NPsize(X)=[N,P]betaPsize(beta)=[P 1]

の与えられた値に対するロジスティック関数の平均値と勾配を計算することに特に興味がありbetaます。

の値に対するロジスティック関数の平均値betaは次のとおりです。

 L = 1/N * sum(log(1+exp(X*beta)),1)

の値に対するロジスティック関数の勾配の平均値bは次のとおりです。

 dL = 1/N * sum((exp(X*beta)./(1+exp(X*beta))' X, 1)'

ご了承くださいsize(dL) = [P 1].

私の問題は、これらの式が数値オーバーフローを生成し続けることです。問題は事実上、exp(s)=Infいつs>1000exp(s)=0いつ、という事実から生じます。s<-1000.

s浮動小数点演算で任意の値を取ることができるソリューションを探しています。理想的には、ベクトル化された/効率的な方法で値と勾配を評価できるソリューションも本当にありがたいです。

4

2 に答える 2

9

次の近似はどうでしょうか。

– を計算Lする場合、sが大きい場合、 はexp(s)1 よりもはるかに大きくなります。

1 + exp(s) ≅ exp(s)

そしてその結果

log(1 + exp(s)) ≅ log(exp(s)) = s.

sが小さい場合、exp()のテイラー級数を使用して

exp(s) ≅ 1 + s

log() のテイラー級数を使用する

log(1 + exp(s)) ≅ log(2 + s) ≅ log(2) + s / 2.

– コンピューティングdL用、大規模用s

exp(s) ./ (1 + exp(s)) ≅ 1

そして小さなもののためにs

exp(s) ./ (1 + exp(s)) ≅ 1/2 + s / 4.

– 計算するコードはL、たとえば次のようになります。

s = X*beta;
l = log(1+exp(s));
ind = isinf(l);
l(ind) = s(ind);
ind = (l == 0);
l(ind) = log(2) + s(ind) / 2;
L = 1/N * sum(l,1)
于 2013-11-20T02:04:33.113 に答える
5

この問題に関する良い記事を見つけました。

多くの言葉を切り抜けて、議論を単純化して、元の表現は

log(1 + exp(s)) 

として書き換えることができます

log(exp(s)*(exp(-s) + 1))
= log(exp(s)) + log(exp(-s) + 1)
= s + log(exp(-s) + 1)

これにより、オーバーフローの発生が停止します。アンダーフローは防止されませんが、発生するまでに、答えが得られます (つまり、s)。それでも問題が発生するため、オリジナルの代わりにこれを使用することはできません。ただし、正確でオーバー/アンダーフローを生成しない関数を作成するための基礎ができました。

function LL = logistic(s)
if s<0
  LL = log(1 + exp(s));
else
  LL = s + logistic(-s);

これはかなり良い精度を維持していると思います。

あなたの質問の要点を編集してください - これをベクトル化し、勾配の計算も可能にします。これらを 1 つずつ取り上げてみましょう。

function LL = logisticVec(s)
  LL = zeros(size(s));
  LL(s<0) = log(1 + exp(s(s<0)));
  LL(s>=0) = s(s>=0) + log(1 + exp(-s(s>=0)));

必要な平均を取得するには:

L = logisticVec(X*beta) / N;

スロープは少しトリッキーです。式にタイプミスがある可能性があることに注意してください(乗算記号がありません)。

dL/dbeta = sum(X * exp(X*beta) ./ (1 + exp(X*beta))) / N;

上と下を で割るexp(X*beta)

dL = sum(X ./ (exp(-X*beta) + 1)) / N;

ここでも、オーバーフローはなくなり、アンダーフローが残りますが、アンダーフローした値が1追加されているため、これによって生じるエラーは重要ではありません。

于 2013-11-20T02:27:15.837 に答える