3

行列乗算用の Python アプリケーション Mincemeat map/reduce を試してみたいと思います。Python 2.7 を使用しています。Java で Hadoop を使用して行列乗算を行う方法を説明している Web ページをいくつか見つけました。単純なので、このhttp://importantfish.com/one-step-matrix-multiplication-with-hadoop/を参照しています。また、表示される疑似コードはすでに Python コードに非常に近いためです。

同じく含まれている Java コードで、Context 型の追加の引数を介して、行列の次元が map 関数と reduce 関数に提供されていることに気付きました。Mincemeat はそのようなものを提供しませんが、これらの値をマップに提供し、クロージャーを使用して関数を減らすことができるという提案を受けました。私が書いた map 関数と reduce 関数は次のようになります。

def make_map_fn(num_rows_result, num_cols_result):
    m = num_rows_result
    p = num_cols_result

    def map_fn(key, value):
        # value is ('A', i, j, a_ij) or ('B', j, k, b_jk)
        if value[0] == 'A':
            i = value[1]
            j = value[2]
            a_ij = value[3]

            for k in xrange(1, p):
                yield ((i, k), ('A', j, a_ij))
        else:
            j = value[1]
            k = value[2]
            b_jk = value[3]

            for i in xrange(1, m):
                yield ((i, k), ('B', j, b_jk))
    return map_fn


def make_reduce_fn(inner_dim):
    n = inner_dim

    def reduce_fn(key, values):
        # key is (i, k)
        # values is a list of ('A', j, a_ij) and ('B', j, b_jk)
        hash_A = {j: a_ij for (x, j, a_ij) in values if x == 'A'}
        hash_B = {j: b_jk for (x, j, b_jk) in values if x == 'B'}
        result = 0

        for j in xrange(1, n):
            result += hash_A[j] * hash_B[j]

        return (key, result)
    return reduce_fn

次に、次のように Mincemeat に割り当てます。

s = mincemeat.Server()
s.mapfn = make_map_fn(num_rows_A, num_cols_B)
s.reducefn = make_reduce_fn(num_cols_A)

これを Mincemeat で実行すると、次のエラー メッセージが表示されます。

error: uncaptured python exception, closing channel <__main__.Client connected at 0x2ada4d0>
(<type 'exceptions.TypeError'>:arg 5 (closure) must be tuple
 [/usr/lib/python2.7/asyncore.py|read|83]
 [/usr/lib/python2.7/asyncore.py|handle_read_event|444]
 [/usr/lib/python2.7/asynchat.py|handle_read|140]
 [/usr/local/lib/python2.7/dist-packages/mincemeat.py|found_terminator|96]
 [/usr/local/lib/python2.7/dist-packages/mincemeat.py|process_command|194]
 [/usr/local/lib/python2.7/dist-packages/mincemeat.py|set_mapfn|159])

|python Closure must be tuple| のような検索語でネット上を検索しました。私が見つけたものは、誰かがラムダまたは function() を使用して関数を構築しようとしていて、それらをクロージャーとして定義するときに特定のものを省略していないことを確認する必要がある場合を扱っているようです。私の場合、make_map_fn と make_reduce_fn によって返される map_fn と reduce_fn の値は有効な関数オブジェクトのように見えます。それらの func_closure の値は、指定したい配列次元を含むセルのタプルですが、まだ何かが欠けています。Mincemeat で使用できるようにするには、これらの関数をどのような形式で渡す必要がありますか?

4

1 に答える 1

0

私は悪い知らせを伝えるのは嫌いですが、これはあなたのコードの 1 つずつずれているいくつかのエラーと、リンクしたサイトから提供された入力ファイルの 2 つのエラーの結果です。誤解を招くエラーメッセージにもかかわらず、クロージャーの使用法とは関係ありません。

オフバイワンエラー

疑似コードの最も内側のループが次のようになっていることに注意してください。

for k = 1 to p:
for i = 1 to m:
for j = 1 to n:

疑似コードでは、これは通常、エンドポイントが含まれていることを示します。つまりfor k = 1 to pk = 1, 2, ..., p-1, p. 一方、コード内の対応するループは次のようになります。

for k in xrange(1, p):
for i in xrange(1, m):
for j in xrange(1, n):

そしてもちろん、xrange(1, p)1、2、...、p-2、p-1 が得られます。行列を 0 からインデックス付けしたと仮定すると (リンクしたサイトで行ったように)、すべての xrange は 0 から開始する必要があります (例: xrange(0, p)) for (int k = 0; k < p; k++)。これにより、問題の 1 つが修正されます。

入力ファイルエラー

これを見逃した場合は、サイトが提供する A と B の入力ファイルが正しくありません。両方の行列の (0,0) エントリが忘れられています。特に、フォームの先頭に行を追加し、フォームA,0,0,0.0の 9 ~ 10 の間に行を追加する必要がありB,0,0,0.0ます。(正確にどこに置くかは問題ではないと思いますが、一貫性を保つために、自然に収まる場所に置くこともできます。)


これら 2 つのエラーを修正すると、mincemeat は期待どおりの結果 (フォーマット済み) を返します。

{(0, 1): ((0, 1), 100.0), 
 (1, 2): ((1, 2), 310.0), 
 (0, 0): ((0, 0),  90.0), 
 (0, 2): ((0, 2), 110.0), 
 (1, 0): ((1, 0), 240.0), 
 (1, 1): ((1, 1), 275.0)}

エラーメッセージで何が起こっているのか正確にはわかりませんが、マップ関数のループインデックスが正しくないためにガベージデータがリデュースノードに渡されるという事実に要約されると思います。これがエラーの理由ですreduce 関数について言及しています。

基本的に、reduce 関数ではhash_Ahash_Bが同じキーを持たないことがあるため、 を乗算しようとするとhash_A[j] * hash_B[j]、 がどちらか一方のキーではないKeyErrorためj、これが上流のどこかに引っ掛かり、代わりに再スローされTypeErrorます。

于 2014-06-14T04:32:47.853 に答える