Mmul TB 4_8_8
Top: -
Par: 6 lines
Problem Statement
\(4 \times 8\) 行列 \(A\) と、\(8 \times 8\) 行列 \(B\) に対して、行列積 \(C = A \times B^T\) (shape:\(4 \times 8\)) を計算してください。\(A,B,C\) のレイアウトは以下のとおりです。
A: ((4:1), (4_PE:1, 2_W:1))
B: ((8:1), (4_PE:1, 2_W:1))
C: ((4:1), (4_PE:1, 2_W:1))
なお、\(A, B\) はそれぞれ
[[ 0, 1, 2, 3, 4, 5, 6, 7],
[ 8, 9, 10, 11, 12, 13, 14, 15],
[ 16, 17, 18, 19, 20, 21, 22, 23],
[ 24, 25, 26, 27, 28, 29, 30, 31]]
[[100,101,102,103,104,105,106,107],
[108,109,110,111,112,113,114,115],
[116,117,118,119,120,121,122,123],
[124,125,126,127,128,129,130,131],
[132,133,134,135,136,137,138,139],
[140,141,142,143,144,145,146,147],
[148,149,150,151,152,153,154,155],
[156,157,158,159,160,161,162,163]]
とします。
計算をすると、\(C = A\times B^T\) は以下の通りになります。
import numpy as np
A = np.array([[ 0, 1, 2, 3, 4, 5, 6, 7],
[ 8, 9, 10, 11, 12, 13, 14, 15],
[ 16, 17, 18, 19, 20, 21, 22, 23],
[ 24, 25, 26, 27, 28, 29, 30, 31]])
B = np.array([[100,101,102,103,104,105,106,107],
[108,109,110,111,112,113,114,115],
[116,117,118,119,120,121,122,123],
[124,125,126,127,128,129,130,131],
[132,133,134,135,136,137,138,139],
[140,141,142,143,144,145,146,147],
[148,149,150,151,152,153,154,155],
[156,157,158,159,160,161,162,163]])
A @ B.T
[[ 2940, 3164, 3388, 3612, 3836, 4060, 4284, 4508],
[ 9564,10300,11036,11772,12508,13244,13980,14716],
[16188,17436,18684,19932,21180,22428,23676,24924],
[22812,24572,26332,28092,29852,31612,33372,35132]]
Answer
端的には、以下の 6 行のコードで Accept できます。
gbfn $lm8v $nowrite # B の 上半分を BF 化
gmwrite $aluf $ly0 # それを行列レジスタの上半分に書き込む
gbfn $lm16v $nowrite # B の 下半分を BF 化
gmwrite $aluf $ly4 # それを行列レジスタの下半分に書き込む
gbfn $lm0v $nowrite # A を BF 化
gmmul $ly $aluf $ln0v # 疑似単精度で行列演算して、結果を書き込み
この仕組みを、解説します。
Explanation
この問題セットで使用する行列積問題は、すべて疑似単精度で計算することを想定しています。
疑似単精度とは、fp32 と同じ bit 表現であるが、計算の際に入力の(仮数部の)下 5bit を無視して計算するモードです。MN-Core の行列演算に関しては、詳しくは 行列演算チュートリアル を御覧ください。
MN-Core で疑似単精度の行列演算を行うには、
gbfn で疑似単精度のブロックフロート化 (BF化) を行い、gmwrite で行列レジスタに書き込む
- 疑似単精度の場合、↑を 2 回行わないと行列レジスタが埋まらないので、2 回行う
- もう片方も
gbfn で BF 化を行い、gmmul で行列演算を行う
の手順が必要です。
出力レイアウトの指定が ((4:1), (4_PE:1, 2_W:1)) と、横方向に PE, 縦方向に Cycle (Address) になっているので、行列演算の図まとめの出力と転置の関係になっています。
行列積 \(A\times B = C\) に対して、\(B^T \times A^T = C^T\) が成り立つので、問題の \(A\) を行列レジスタに入れるのではなく、\(B\) の方を行列レジスタに入れることにします。
問題では、\(B\) の方を \(B^T\) と転置せよとの指示でしたが、上記の式変形と、MN-Core の行列演算は実質的に行列側が転置された状態で計算される仕様により、転置操作をせずともこれで計算ができます。
図で表すと、以下のようになります。
mat B A C
( PE0 ) ( PE1 ) ( PE2 ) ( PE3 ) cy0,cy1,cy2,cy3 cy0 cy1 cy2 cy3
cy0 [[100,101,102,103,104,105,106,107], p0[[ 0, 8, 16, 24], p0[[ 2940, 9564, 16188, 22812],
cy1 [108,109,110,111,112,113,114,115], p0 [ 1, 9, 17, 25], p0 [ 3164, 10300, 17436, 24572],
cy2 [116,117,118,119,120,121,122,123], p1 [ 2, 10, 18, 26], p1 [ 3388, 11036, 18684, 26332],
cy3 [124,125,126,127,128,129,130,131], p1 [ 3, 11, 19, 27], p1 [ 3612, 11772, 19932, 28092],
cy4 [132,133,134,135,136,137,138,139], x p2 [ 4, 12, 20, 28], = p2 [ 3836, 12508, 21180, 29852],
cy5 [140,141,142,143,144,145,146,147], p2 [ 5, 13, 21, 29], p2 [ 4060, 13244, 22428, 31612],
cy6 [148,149,150,151,152,153,154,155], p3 [ 6, 14, 22, 30], p3 [ 4284, 13980, 23676, 33372],
cy7 [156,157,158,159,160,161,162,163]] p3 [ 7, 15, 23, 31]] p3 [ 4508, 14716, 24924, 35132]]
疑似単精度の行列演算の図と同様の形になっています。
\(B\) は $lm[8:24] に配置されているので、
gbfn $lm8v $nowrite # B の 上半分を BF 化
gmwrite $aluf $ly0 # ↑ を行列レジスタの上半分に書き込む
gbfn $lm16v $nowrite # B の 下半分を BF 化
gmwrite $aluf $ly4 # ↑ を行列レジスタの下半分に書き込む
のようにして、行列レジスタに書き込めます。
行列レジスタの中身をデバッグ出力するには、d getbf $ly0n0c0b0m0 8 のように書きます。getbf とは BF された Float, $ly は、行列レジスタ B を、8 は 8 行表示せよとの意味です。
実行してみると、以下のような出力を得られ、実際に書き込めていることが分かります。
DEBUG-MRy(n0c0b0m0,0):{(100, 101) (0x42e40000, 0x42e50000), (102, 103) (0x42e60000, 0x42e70000), (104, 105) (0x42e80000, 0x42e90000), (106, 107) (0x42ea0000, 0x42eb0000)} #d getbf $ly0n0c0b0m0 8
DEBUG-MRy(n0c0b0m0,1):{(108, 109) (0x42ec0000, 0x42ed0000), (110, 111) (0x42ee0000, 0x42ef0000), (112, 113) (0x42f00000, 0x42f10000), (114, 115) (0x42f20000, 0x42f30000)} #d getbf $ly0n0c0b0m0 8
DEBUG-MRy(n0c0b0m0,2):{(116, 117) (0x42f40000, 0x42f50000), (118, 119) (0x42f60000, 0x42f70000), (120, 121) (0x42f80000, 0x42f90000), (122, 123) (0x42fa0000, 0x42fb0000)} #d getbf $ly0n0c0b0m0 8
DEBUG-MRy(n0c0b0m0,3):{(124, 125) (0x433e0000, 0x433e8000), (126, 127) (0x433f0000, 0x433f8000), (128, 129) (0x43400000, 0x43408000), (130, 131) (0x43410000, 0x43418000)} #d getbf $ly0n0c0b0m0 8
DEBUG-MRy(n0c0b0m0,4):{(132, 133) (0x43420000, 0x43428000), (134, 135) (0x43430000, 0x43438000), (136, 137) (0x43440000, 0x43448000), (138, 139) (0x43450000, 0x43458000)} #d getbf $ly0n0c0b0m0 8
DEBUG-MRy(n0c0b0m0,5):{(140, 141) (0x43460000, 0x43468000), (142, 143) (0x43470000, 0x43478000), (144, 145) (0x43480000, 0x43488000), (146, 147) (0x43490000, 0x43498000)} #d getbf $ly0n0c0b0m0 8
DEBUG-MRy(n0c0b0m0,6):{(148, 149) (0x434a0000, 0x434a8000), (150, 151) (0x434b0000, 0x434b8000), (152, 153) (0x434c0000, 0x434c8000), (154, 155) (0x434d0000, 0x434d8000)} #d getbf $ly0n0c0b0m0 8
DEBUG-MRy(n0c0b0m0,7):{(156, 157) (0x434e0000, 0x434e8000), (158, 159) (0x434f0000, 0x434f8000), (160, 161) (0x43500000, 0x43508000), (162, 163) (0x43510000, 0x43518000)} #d getbf $ly0n0c0b0m0 8
行列レジスタへの書き込みができたら、これに続けて、
gbfn $lm0v $nowrite # A を BF 化
gmmul $ly $aluf $ln0v # 行列演算して、結果を書き込み
を行い、Accept です。
Tips として、どの要素単位を行列レジスタに入れる・行列演算の対象にするかは、積和される組をデバッグ出力して確かめると良いです。
例えば、C[0][0] の \(2940\) とは、\((100\times0 )+( 101\times1 )+( 102\times2 )+( 103\times3 )+( 104\times4 )+( 105\times5 )+( 106\times6 )+( 107\times7)\) のような、長さ \(8\) の内積演算です。
行列演算と言っても、中身は単純には内積演算なので、行列レジスタに入れる要素と、行列演算をする要素を出力して確かめて、内積したい組になっているかを確認すると良いでしょう。
gbfn $lm8v $ls0v # B の 上半分を BF 化
d getbf $ls0n0c0b0m0 1 # BF 化した値をデバッグ出力
gbfn $lm0v $lr0v # A を BF 化
d getbf $lr0n0c0b0m0 1 # BF 化した値をデバッグ出力
出力
DEBUG-GREG1(n0c0b0m0p0,0):(100, 101) (0x42e40000, 0x42e50000) #d getbf $ls0n0c0b0m0 1
DEBUG-GREG1(n0c0b0m0p1,0):(102, 103) (0x42e60000, 0x42e70000) #d getbf $ls0n0c0b0m0 1
DEBUG-GREG1(n0c0b0m0p2,0):(104, 105) (0x42e80000, 0x42e90000) #d getbf $ls0n0c0b0m0 1
DEBUG-GREG1(n0c0b0m0p3,0):(106, 107) (0x42ea0000, 0x42eb0000) #d getbf $ls0n0c0b0m0 1
DEBUG-GREG0(n0c0b0m0p0,0):(0, 1) (0x40800000, 0x40900000) #d getbf $lr0n0c0b0m0 1
DEBUG-GREG0(n0c0b0m0p1,0):(2, 3) (0x40a00000, 0x40b00000) #d getbf $lr0n0c0b0m0 1
DEBUG-GREG0(n0c0b0m0p2,0):(4, 5) (0x40c00000, 0x40d00000) #d getbf $lr0n0c0b0m0 1
DEBUG-GREG0(n0c0b0m0p3,0):(6, 7) (0x40e00000, 0x40f00000) #d getbf $lr0n0c0b0m0 1
Inputs
Outputs
-
\(C\):
Float
$ln[0:8], (4,8)/((4:1), (4_PE:1, 2_W:1)) ?
/ \(0.00001\) 以下の絶対誤差が許容されます
Testcases
Submission
ログイン / 新規登録