NumPyで紐解く、機械学習のレシピ帳:eriklindernoren/ML-From-Scratch
eriklindernoren/ML-From-Scratch
五郎さん、今日は神保町で新しいプロジェクトの打ち合わせっすか? いやー、それにしても、五郎さんの目の前にあるそのGitHubリポジトリ、「eriklindernoren/ML-From-Scratch」、なんだか気になりますね。
「ん?なんだか腹が減ってきたな。いや、そうじゃなくて。この『ML-From-Scratch』ってやつ、一体何なんだ?」
ふふ、五郎さん、それはまさに今日の五郎さんの胃袋…じゃなくて、開発者の好奇心を刺激する素晴らしいリポジトリなんですよ!
五郎さんの心の声
「お、こいつは面白いな。まるで、知らない街の小料理屋に入った時のようなワクワク感だ。」
このリポジトリ、例えるなら、「機械学習のレシピを、材料から自分で作ってみる」ようなものなんです。普通、機械学習って、Scikit-learnとかTensorFlowとか、全部できあがった料理を注文する感覚じゃないですか。便利だけど、どうやって作られてるのか、材料は何なのか、よくわからない。
でも、この『ML-From-Scratch』は、それとは全然違う。
「なるほど。つまり、このリポジトリは、機械学習という料理の、一つ一つの材料、つまりNumPyだけで書かれた実装を、見せてくれるってことか。まるで、板前さんが目の前で魚を捌いてくれるように…」
そうです!五郎さん、まさにその通りです。
五郎さんの心の声
「ただ美味いだけの料理はもう飽きた。これからは、美味さの秘密を知りたい…」
このリポジトリは、ただ単にコードを写経するだけじゃない、深い学びがあります。
アルゴリズムの理解が深まる
ブラックボックスになっていた機械学習モデルの内部が、全部NumPyの配列操作として見えてきます。これはもう、料理の隠し味を知るようなもの。例えば、線形回帰の勾配降下法が、どうやって重みを更新しているのか、手で触れるように理解できます。
NumPyの腕前が上がる
NumPyは、データサイエンスの基本中の基本。このリポジトリのコードを読むことで、配列のブロードキャストやスライシングといった、NumPyの高度なテクニックを実戦的に学べます。これは、包丁の使い方を学ぶようなものですね。
既存ライブラリのデバッグ・チューニングに役立つ
「あれ? Scikit-learnのあのモデル、なぜか期待した結果が出ないな…」なんて時、このリポジトリで基礎的な実装を確認することで、問題の切り分けやパラメータ調整のヒントが見つかるかもしれません。
五郎さんの心の声
「さて、腹ごしらえの前に、まずはこの『ML-From-Scratch』という名の定食屋に、どうやって入るかだな…」
導入はめちゃくちゃシンプルです。
リポジトリをクローンする
git clone https://github.com/eriklindernoren/ML-From-Scratch.git
cd ML-From-Scratch
必要なライブラリをインストールする
pip install -r requirements.txt
これだけです! あとは、好きなモデルのディレクトリに入って、コードを読んで、動かしてみるだけ。
五郎さんの心の声
「この店の一番人気、線形回帰…いや、線形回帰定食か。よし、これを注文してみよう。」
supervised_learning/linear_regression.py を見てみましょう。
シンプルな線形回帰の実装なのに、こんなにスッキリしているのかと驚かされます。
# 一部抜粋
class LinearRegression():
def __init__(self, n_iterations=100, learning_rate=0.001):
self.n_iterations = n_iterations
self.learning_rate = learning_rate
def fit(self, X, y):
# 重みとバイアスを初期化
self.W = np.zeros(np.shape(X)[1])
self.w0 = 0
self.X, self.y = X, y
# 勾配降下法
for _ in range(self.n_iterations):
y_pred = self.X.dot(self.W) + self.w0
# 勾配を計算
# ここが一番面白いところ。数式がそのままコードになってる!
grad_W = -(2 / self.m) * (self.X.T.dot(self.y - y_pred))
grad_w0 = -(2 / self.m) * np.sum(self.y - y_pred)
# 重みを更新
self.W -= self.learning_rate * grad_W
self.w0 -= self.learning_rate * grad_w0
def predict(self, X):
return X.dot(self.W) + self.w0
五郎さんの心の声
「ふむ、なるほど。つまり、このgrad_Wってやつが、一番美味しくなるための隠し味、じゃなくて、最適な重みを求めるための道しるべってわけか…。」
そうなんです!このコードは、まさに数学的な概念が、生身のNumPyコードとして目の前に現れているんです。
五郎さん、このリポジトリは、機械学習という大海原を、自分の手漕ぎボートで進むための羅針盤です。
「よし、決めた。今日はこの『ML-From-Scratch』をじっくりと味わってみるか。腹は…まだ減ってるが、それどころじゃなくなってきたな。ふふ、まるで新しい街の路地裏に入り込んだみたいだ。この先には、一体どんな『味』が待っているんだろう…」