ベクトル演算に基づく確率的勾配降下法?


10

N個のサンプルを持つデータセットを使用して、確率的勾配降下回帰アルゴリズムをトレーニングしたいとします。データセットのサイズは固定なので、データをT回再利用します。各反復または「エポック」で、トレーニングセット全体をランダムに並べ替えた後、各トレーニングサンプルを1回だけ使用します。

私の実装はPythonとNumpyに基づいています。したがって、ベクトル演算を使用すると、計算時間を大幅に短縮できます。バッチ勾配降下法のベクトル化された実装を考え出すことは非常に簡単です。ただし、確率的勾配降下法の場合、各エポックですべてのサンプルを反復する外部ループを回避する方法を理解できません。

誰かが確率的勾配降下法のベクトル化された実装を知っていますか?

編集:データセットのサイズが固定されている場合、オンライン勾配降下法を使用する理由を尋ねられました。

[1]から、オンライン勾配降下法は、バッチ勾配降下法よりも経験的コストの最小値まで収束が遅いことがわかります。ただし、一般化のパフォーマンスを測定する予想コストの最小値に速く収束します。これらの理論上の結果が私の特定の問題に及ぼす影響を、相互検証によってテストしたいと思います。ベクトル化された実装がない場合、私のオンライン勾配降下コードはバッチ勾配降下コードよりもはるかに遅くなります。これにより、相互検証プロセスが完了するまでの時間が大幅に増加します。

編集:私は、ffriendからの要求に応じて、オンライン勾配降下法の実装の疑似コードをここに含めます。回帰問題を解決しています。

Method: on-line gradient descent (regression)
Input: X (nxp matrix; each line contains a training sample, represented as a length-p vector), Y (length-n vector; output of the training samples)
Output: A (length-p+1 vector of coefficients)

Initialize coefficients (assign value 0 to all coefficients)
Calculate outputs F
prev_error = inf
error = sum((F-Y)^2)/n
it = 0
while abs(error - prev_error)>ERROR_THRESHOLD and it<=MAX_ITERATIONS:
    Randomly shuffle training samples
    for each training sample i:
        Compute error for training sample i
        Update coefficients based on the error above
    prev_error = error
    Calculate outputs F
    error = sum((F-Y)^2)/n
    it = it + 1

[1]「大規模オンライン学習」、L。ボトム、Y。ル・カン、NIPS 2003。


2
データセットをミニバッチに分割し、モデルを各ミニバッチに順番に合わせます。
ffriend 2014年

@ffriendありがとうございます。ただし、これは純粋なオンライン実装ではありません。
Pablo Suau 2014年

1
データセットが修正されている場合、「純粋なオンライン」実装を使用する理由は何ですか?SGDは、データセット全体を一度に反復する必要はないが、それを任意の数のピース(ミニバッチ)に分割して、1つずつ処理できると述べています。サイズ1のミニバッチは、継続的な、場合によっては無限のデータソース(Twitterフィードなど)があり、新しい観測ごとにモデルを更新する場合にのみ意味があります。ただし、これは非常にまれなケースであり、固定データセットには当てはまりません。
ffriend 2014年

私の非常に遅い応答への謝罪。元の質問に追加したテキストを確認してください。
Pablo Suau 2014年

1
実装を見せていただけますか?誤解はありますが、コードサンプルがないと説明が難しいでしょう。
ffriend 2014年

回答:


10

まず、「サンプル」という単語は通常、母集団のサブセットを表すために使用されるため、「例」と同じものを参照します。

次の行が原因で、SGDの実装が遅くなります。

for each training example i:

ここでは、モデルパラメータの更新ごとに1つの例を明示的に使用します。定義上、ベクトル化は、1つの要素に対する操作を、そのような要素のベクトルに対する操作に変換する手法です。したがって、いいえ、例を1つずつ処理し、ベクトル化を使用することはできません。

することができます、しかし、使用しておおよその真SGD ミニバッチを。ミニバッチは、元のデータセットの小さなサブセットです(たとえば、100の例)。ミニバッチに基づいてエラーとパラメーターの更新を計算しますが、グローバルな最適化を行わずにそれらの多くを繰り返し、プロセスを確率論的にします。したがって、実装をより速くするには、前の行を次のように変更するだけで十分です。

batches = split dataset into mini-batches
for batch in batches: 

単一の例ではなく、バッチからエラーを計算します。

当たり前のことですが、例ごとのレベルでのベクトル化についても触れておきます。つまり、次のようなものではありません。

theta = np.array([...])  # parameter vector
x = np.array([...])      # example
y = 0                    # predicted response
for i in range(len(example)):
    y += x[i] * theta[i]
error = (true_y - y) ** 2  # true_y - true value of response

あなたは間違いなくこのようなことをするべきです:

error = (true_y - sum(np.dot(x, theta))) ** 2

繰り返しになりますが、ミニバッチの一般化は簡単です。

true_y = np.array([...])     # vector of response values
X = np.array([[...], [...]]) # mini-batch
errors = true_y - sum(np.dot(X, theta), 1)
error = sum(e ** 2 for e in errors)

1
これが道だと思います。適切に選択されたサイズのミニバッチは、実際にはバッチバージョンまたはオンラインバージョンよりも速く収束できます(以前は、セット全体で一度だけ重みを更新し、後者はベクトル化できず、さらに頻繁に追加の重み更新ステップがあります)
Neil Slater

あなたがた両方に感謝します。以前は頑固にミニバッチを拒否したことをお詫びしましたが、この方法が収束率に与える影響については確信が持てませんでした。ニール、あなたの肯定はあなた自身の経験から来ていますか、それとも理論的/経験的に発表された結果はありますか?
Pablo Suau 2014年

1
@PabloSuauコース10、週10でAndrew Ngの機械学習クラスを確認できます。彼は、SGDとバッチGDの両方よりも収束が速い理由を説明しています。より正確に言うと、常にSGDと同じくらい高速である必要がありますが、実際にはさらに高速になることがあります。
16

1

scikitのSGD分類器の partial_fitメソッドを確認してください。呼び出すものを制御できます。一度にインスタンスを渡すことで「本当の」オンライン学習を行うことができます。また、すべてのデータが配列で利用可能な場合は、インスタンスをミニバッチにまとめることができます。そうであれば、アレイをスライスしてミニバッチを提供できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.