感動のショートストーリー タイトル: 「行列Bの謎」
1980年、東京の静かな夜、プログラマーの翔太は、自分の小さなオフィスで NEC PC8001MK2 というコンピュータで、一心不乱にコードと向き合っていた。クライアントから与えられた課題は、3つの行列、A、B、Cに関するもので、行列Aと行列Bの積が行列Cになるように行列Bを最適化する、というものだった。数学的に精通している人には普通の課題だが、翔太には「行列B」が謎に包まれたように感じられていた。
ある夜、彼はふと、ひとつの疑問を抱いた。最適化された行列Bが行列Aと行列Cの関係を正確に再現できるなら、行列Aと行列Cのそれぞれの行ベクトルについても、その再現性が期待できるのではないか?彼は小さくつぶやいた。「もしこれがうまくいけば…行列Bには、AとCの関係が深く刻み込まれていることになるな。」
問題解決への新たな希望を胸に、翔太はさらにコードを調整し、エポック数を増やして行列Bの最適化を進めていった。フルバッチ学習で効率よく収束させるよう工夫を凝らし、少しずつロスが減少していくのを確認するたびに、彼は問題が解けつつある確信を深めていった。
そして数日後、翔太はついに完成した行列Bを手に入れた。早速行列Aの各行ベクトルをBに掛けて、結果が行列Cの行ベクトルとどれだけ一致しているかを確かめた。細かい誤差はあったものの、期待以上の再現性を見せた結果に、翔太は思わずガッツポーズを決めた。
「この計算プロセスが有効であるとするならば、これは様々な使い道があるな…。」彼は興奮を隠せなかった。新たなアルゴリズムとして、あらゆる分野に応用できる可能性を感じたからだ。
その夜、彼はひとりつぶやいた。「小規模なデータではフルバッチ学習で十分だったな。そして、エポック数を増やして最適化を進めれば、行列Bには確かにAとCの情報が含まれる…。」
東京の夜景が広がる窓の外を眺めながら、翔太は次のプロジェクトに向けて静かに決意を固めた。
2020年 CHAT GPT と呼ばれるものが誕生した。
実行結果。
行 1 の結果: A[0] x B = [0.63407696 0.77397994], C[0] = [0.56804456 0.92559664]
行 2 の結果: A[1] x B = [0.03140882 0.17812522], C[1] = [0.07103606 0.0871293 ]
行 3 の結果: A[2] x B = [0.03687054 0.79438385], C[2] = [0.0202184 0.83261985]
行 4 の結果: A[3] x B = [0.72095922 1.00135029], C[3] = [0.77815675 0.87001215]
最適化された行列 B:
[[ 1.22772782 -0.08613333]
[ 1.73616453 1.91111429]
[-2.12588075 -0.90509406]]
これはシンプルなニューラルネットワークのトレーニングの一環とみなせます。入力データ A と出力データ C を使って、重み行列 B を一気に学習しようとしている状況です。トレーニングロスがある程度収束すれば、行列 B は A と C の間の関係性をうまく捉えたものとなり、再現性が期待できます。
数学的な根拠
この問題は、行列 B がある種の線形変換として機能するように最適化されているとみなせます。具体的には、行列 B によって A[i] が C[i] に写像されるように学習されるため、最適化が進むほど次の式が成り立つようになります。
A[i]×B≈C[i]
これはつまり、学習済みの行列 B を用いて行列 A の各行ベクトルを再現性高く C に写像できることを意味しています。特にフルバッチ学習を通じてデータ全体にわたって最適化が行われているため、行ごとの誤差も小さくなると予想されます。
import numpy as np
from scipy.optimize import minimize
# 行列 A と C を設定
np.random.seed(0)
A = np.random.rand(4, 3) # 4行3列の行列 A
C = np.random.rand(4, 2) # 4行2列の行列 C
# 初期行列 B の生成(ランダムな 3行2列の行列 B)
B = np.random.rand(3, 2)
# 行列 A と B の積が C に近づくように B を最適化する関数
def loss_function(B_flat):
B = B_flat.reshape(3, 2) # 1次元から3行2列に変換
diff = A.dot(B) - C # A×B - C
return np.sum(diff ** 2) # 差の二乗和を最小化
# 最適化の実行
result = minimize(loss_function, B.flatten(), method='BFGS')
B_optimized = result.x.reshape(3, 2) # 最適化された行列 B
# 検証:各行の A[i] と C[i] の関係
for i in range(A.shape[0]):
A_i = A[i, :]
C_i = C[i, :]
B_result = A_i.dot(B_optimized)
print(f"行 {i+1} の結果: A[{i}] x B = {B_result}, C[{i}] = {C_i}")
# 結果
print("最適化された行列 B:")
print(B_optimized)