「機械学習のエッセンス」を読んだ感想とかメモ
機械学習のエッセンス、読んだ同期からは「誤植ちょっと多すぎるけどそれもある意味学べる」とポジティブな意見もらったので買おうと思う
— ふぁむたろう (@fam_taro) 2019年1月10日
誤植多すぎてすいません
— 加藤公一(はむかず) (@hamukazu) 2019年1月10日
すみません。。。すみません。。。。ちゃんと買って学びきります
— ふぁむたろう (@fam_taro) 2019年1月10日
:;(∩´﹏`∩);:
先日同期から 機械学習のエッセンス -実装しながら学ぶPython, 数学, アルゴリズム- (Machine Learning) | 加藤 公一 | Amazon を推され、神(著者ご本人様)からの啓示圧力もいただきましたので、買って読みました。
以下に各所感や自分が読んだ際のメモを残します。 全実装は終わってないので注意
結論
- この記事読むくらい買うか悩んでるなら買いましょう
まあ 2,800 円(税抜き)なんて人生において許容誤差ですし
- 演習問題もちゃんとやりましょう
- 誤植はある(でも第一刷からに第二刷にかけてかなり減った)ので、数式まで追う人は気をつけましょう
- 地味にページめくる時にうるさいです
- 紙版ですとページめくるたびに表紙やカバーがギチギチ言うので、地味に気になります
- 図書館だと読めないなってくらいです
- どちらにしろ PC 叩くこと多いので図書館では読むことはなさそうですが
- プロフェッショナルシリーズとかはそんなことなかったので、気になってきます
個人的には各回帰(リッジ・ロッソ)や SVM の実装において必要となる式の導出から Python 実装までをカバーされていて非常に勉強になりました(Python 3 で動くということも大変ありがたいです)。
SVM 等は 2014〜2016 年頃(自身が修士の頃)ですと、僕の周辺では サポートベクターマシン入門 | ネロ クリスティアニーニ, ジョン ショー‐テイラー, Nello Cristianini, John Shawe‐Taylor, 大北 剛 | Amazon か パターン認識と機械学習 上 | C.M. ビショップ, 元田 浩, 栗田 多喜夫, 樋口 知之, 松本 裕治, 村田 昇 | Amazon を参考文献にしていたのですが、これらの文献は深いところまで記載されている一方、理論からコードに落とし込もうとすると「???」となって手が全く動かなくなることがあり、この本のように理論から実装につなげてくれる著書は無かった(見つけられなかった)です。当時欲しかったなあ
一方実装までカバーされている分、理論面では足りないところ(例えばカーネル SVM のカーネル部分とか)もあります。ですのでこの本読んでもっと知りたい気持ちを膨らませて上記の本とかにチャレンジするのが良いと思います。
あと演習問題もあってプログラミングに限らず手を動かす場面もあって良かったです。
この本を薦めたい人
- エンジニアやってきて、もう少しちゃんとキカイガクシュウシタイナーって人
- 理系学部1年生等の、線形代数や微積の授業やってて寝ちゃう人
- 使い途わかればもう少しちゃんとやれる人って結構いる気がするので
- 人工知能って単語にワクワクした大学生
- 行列系の数式読んでて「ウッ」となる人
- 数式から Python(numpy) コードに落とし込む際に「ウッ」となる人
この本を薦めない人
- 手を動かしたくない人
- この本に出てくる計算や演習問題・Python コードは自分で書いて動かしてなんぼなので
- 今買えば本文中のコードがそのまま動くのに動かさないのはもったいないです
- 紙版買ったらまず正誤表見て直した方が良いので、手を動かす前提でこの本は買いましょう
- この本に出てくる計算や演習問題・Python コードは自分で書いて動かしてなんぼなので
- サクッと概要だけ押さえたい人
- この本はほどよく深く(浅く)ほどよく広い(狭い)ので、広く浅く概要だけ掴みたい場合には不向きだなと思います
- モデル選択や細かいパラメータチューニングについて知りたい人
- 本書の目的にもある通りココらへんはあまり触れてません
- とりあえず Deep Learning を動かしたい人
- 著者も述べていますが、他に詳細な本がたくさんあります
- とはいえ著者が言う "この本が Deep Learning の理解に役に立つ"というのは同意します
各章の所感とか個人用メモ
前提
- Python の環境構築・基礎あたりはちゃんと読んでません
- 手元に環境あったので
- 自分の環境は Python 3.7 です
- 自分でコード書く時は以下の環境を都度都度(気分で)変えてやってました
- iPython
- jupyter notebook
- jupyter lab
- 自分でコード書く時は以下の環境を都度都度(気分で)変えてやってました
第1章「学習を始めるまえに」
- 本書の目的と本書が含まないものが載ってて良かったです
- 初めに必ず目を通すべき
第2章「Python の基本」
- 例外処理まで触れられてて良いなと思いました
- Python 3.6 からは
"a: {:2d}".format(a)
をf"a : {a:2d}"
で書けたりするので興味がある人はお試しください- "fstring" とか "フォーマット済文字リテラル" とかで調べると出てきます
- オブジェクト指向
- ここは深追いすると二度と帰ってこれなくなるので、これくらいの深度で十分だと思います
クラス=メソッド+データ
程度の理解だけ頭において先に進んだ方が良いです
第3章「機械学習に必要な数学」
- "ブロック化"とかたしかにそんな単語あった気がする…
- 機械学習に必要な線形代数と微積がピックアップされてるのすごくありがたい
- 対称行列(半正定値・正定値)やとかも、単語だけ覚えておいてまたどこかで出てきたらこの本とか他の詳しい本を見れるようにしておきたい
- 多変数関数の極値とヘッセ行列の関係は知らなかった…(一度聞いて忘れたのだと思われ)
- 二次形式の勾配の形はまれによく出るので知っておくと良い
第4章「Python による数値計算」
- 桁落ちとか有効桁数・誤差
- 忘れかけてたので良い戒めになった
- 機械学習続けてると "1e-8 の誤差とか知らんがな" と思う時が結構あったので
- 疎行列の扱い
- めっちゃ参考になりました
- 行とるか列をとるかで
crc_matrix
とcsr_matrix
を使い分ける - それぞれ
getrow()
とgetcol()
の効率が違う
- 逆行列・numpy の solver・LU分解を使った一次連立方程式の解法
- 個人的にすごく楽しかったです
- これまで必死に手計算で方程式を解いてきた人類にとっては、これってものすごく衝撃的だと思うんですよね
- 人によっては解放感とか爽快感があると思います
大学デビューとはかくあるべき
- データの可視化
- 僕自身細かい文法忘れることが多いので、たまにこの本とかに帰ってくる気がしてます
- 数理最適化
- 今後機械学習やるなら絶対押さえなきゃいけないところ
- 線形計画法や2次計画法等の解析的に解ける(≒式変形等で解ける≒手計算で解を出せる)問題から解析的に解けない 問題に対しどのように解を出そうとしているかが載っています
- 解析的 - Wikipedia
- そして現在の機械学習では多くが解析的に解けない問題を扱っています
- 最急降下法とニュートン法について以下の違いは押さえておきましょう
- 更新式
- 収束条件
- "数値微分に関する補足" も地味に大事なお話だなと思いました
- ラグランジュの未定乗数法
- チッ…はいはいラグランジュラグランジュ
- 議論の抽象度的にはここ結構難しかったです…
- きついと思ったら一旦軽く流して先に進んでも良いと思います
- 気になったら他の文献とかまたここに戻ってくれば良いですし
- 統計
- ここも高校までは手計算地獄だった分「数行で書けちゃう俺Tueeeee」できたりして楽しかったりします
- 後半は数式多めだけど大事なので体力ある人は追いましょう
第5章「機械学習アルゴリズム」
この本のメインテーマ(だと思ってます)
- 準備
- 回帰と分類の違いは押さえておきましょう
- インターフェースについては、ここで押さえておくと他のライブラリを使った時なども楽になれます
- 回帰
- なにを最適化(最小化 or 最大化)しようとしているのかは押さえましょう
- 3次元空間でのプロット法が載ってるのすごくありがたいです
- 外部データを自分で持ってきて読み込ませるのは大事な経験なので初めての人は必ずやりましょう
- 評価指標は必ず押さえてください
- リッジ回帰
- 汎化と過学習
- 交差検証(クロスバリデーション)はめっちゃ大事。めっちゃ大事
- ラッソ回帰
- 線形回帰 + 正則化項(L1)
- 線形回帰・リッジ回帰と何が違うのか
- 座標降下法(corordinate descent) を絶対値関数にどう適用するか
- 必要な式変形(うまく j=k の部分のみ抜き出せるか等)
- 上記の実装部分
- ロジスティック回帰
- 回帰と分類がつながる箇所
- ココらへんも式変形が続くので、気を抜いて一行飛ばしたりすると訳分からなくなるので注意
- 式変形が長いと変形ばかり気にして何をしようとしているのか頭から抜けちゃうのも注意
- サポートベクターマシン(要実装)
- k-Means 法
- SVM 超えた方にとってはボーナスステージ
- 主成分分析(PCA)
- どうして固有値が出てくるのか押さえる
- イメージ図がなくてイメージしきれない人も多いので自分で調べてみると良いです
- 僕が読んだ中では scikit-learnとTensorFlowによる実践機械学習 | Aurélien Géron, 下田 倫大, 長尾 高弘 | Amazon は比較的分かりやすかったです
- 適当にググっても良いと思います
- どうして SVD が出てくるのか押さえる
個人用メモ(コード周り)
第4章「Python による数値計算」
1次連立方程式の解法の比較(逆行列・numpy.linalg.solve・scipy.linalg.lu_factor)
この規模の小ささですと numpy.linalg.solve
が最も速かったですが、
行列が大きくなったり b
が複数列になってくると LU 分解(lu_factor) が速くなってくるのだと思います。
In [1]: import numpy as np In [2]: a = np.array([[3, 1, 1], [1, 2, 1], [0, -1, 1]]) ...: b = np.array([1, 2, 3]) In [3]: np.linalg.inv(a) @ b Out[3]: array([-0.57142857, -0.14285714, 2.85714286]) In [4]: np.linalg.solve(a, b) Out[4]: array([-0.57142857, -0.14285714, 2.85714286]) In [5]: from scipy import linalg as slinalg In [6]: lu, p = slinalg.lu_factor(a); slinalg.lu_solve((lu, p), b) Out[6]: array([-0.57142857, -0.14285714, 2.85714286]) In [7]: %timeit np.linalg.inv(a) @ b 13.2 µs ± 968 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) In [8]: %timeit np.linalg.solve(a, b) 8.03 µs ± 79.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) In [9]: %timeit lu, p = slinalg.lu_factor(a); slinalg.lu_solve((lu, p), b) 28.4 µs ± 569 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) In [10]: %timeit slinalg.lu_solve((lu, p), b) 17.5 µs ± 96.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
第5章「機械学習アルゴリズム」
ラッソ回帰
import numpy as np import csv def soft_thresholding(x, y): return np.sign(x) * max(abs(x) - y, 0) class Lasso: def __init__(self, lambda_, convergence_thres=0.0001, max_iter=1000): self.lambda_ = lambda_ self.convergence_thres = convergence_thres self.max_iter = max_iter self.w_ = None def fit(self, X, t): n, d = X.shape self.w_ = np.zeros(d + 1) avg_L1 = 0. for _ in range(self.max_iter): avg_L1_prev = avg_L1 self._update(n, d, X, t) avg_L1 = np.abs(self.w_).sum() / self.w_.shape[0] if abs(avg_L1 - avg_L1_prev) <= self.convergence_thres: break def _update(self, n, d, X, t): self.w_[0] = (t - (X @ self.w_[1:])).sum() / n w0vec = np.ones(n) * self.w_[0] for k in range(d): ww = self.w_[1:] ww[k] = 0 q = (t - w0vec - (X @ ww)) @ X[:, k] r = X[:, k] @ X[:, k] self.w_[k + 1] = soft_thresholding(q / r, self.lambda_) def predict(self, X): if X.ndim == 1: X = X.reshape(X.shape[0], 1) Xtil = np.c_[np.ones(X.shape[0]), X] return Xtil @ self.w_ def main(): # Read data Xy = [] with open("winequality-red.csv") as fp: for row in csv.reader(fp, delimiter=";"): Xy.append(row) Xy = np.array(Xy[1:], dtype=np.float64) # Split train & test data np.random.seed(0) np.random.shuffle(Xy) n_test = 1000 train_X, train_y = Xy[:-n_test, :-1], Xy[:-n_test, -1] test_X, test_y = Xy[-n_test:, :-1], Xy[-n_test:, -1] # Show results reach hyper parameters for lambda_ in [1., 0.1, 0.01]: model = Lasso(lambda_) model.fit(train_X, train_y) y = model.predict(test_X) print(f"--- lambda: {lambda_} ---") print("coefficients:") print(model.w_) mse = ((y - test_y) ** 2).mean() print(f"MSE: {mse:.3f}") if __name__ == '__main__': main()