eyecatch
Sun, Mar 25, 2018

機械学習のHello World: MNISTの分類モデルをKerasで作ってみた

機械学習のHello WorldとしてよくやられるMNISTの分類モデルをKeras on TensorFlowで作ってみた話。 (adsbygoogle = window.adsbygoogle || []).push({}); MNISTとは 手書き数字画像のラベル付きデータセット。 6万個の訓練データと1万個のテストデータからなる。 CC BY-SA 3.0で配布されているっぽい。 一つの画像は28×28ピクセルの白黒画像で、0から9のアラビア数字が書かれている。 画像とラベルがそれぞれ独特な形式でアーカイブされていて、画像一つ、ラベル一つ取り出すのも一苦労する。 Kerasとは Pythonのニューラルネットワークライブラリ。 バックエンドとしてTensorFlowかCNTKかTheanoを使う。 今回はTensorFlowを使った。 やったこと KerasのMNISTのAPIとかコードサンプルとかがあけどこれらはスルー。 MNISTのサイトにあるデータセットをダウンロードしてきて、サイトに書いてあるデータ形式の説明を見ながらサンプルを取り出すコードを書いた。 で、KerasでVGGっぽいCNNを書いて、学習させてモデルをダンプして、ダンプしたモデルをロードしてテストデータで評価するコードを書いた。 コードはGitHubに。 ネットワークアーキテクチャ 入力画像のサイズに合わせてVGGを小さくした感じのCNNを作った。 VGGは2014年に発表されたアーキテクチャで、各層に同じフィルタを使い、フィルタ数を線形増加させるシンプルな構造でありながら、性能がよく、今でもよく使われるっぽい。 VGGを図にすると以下の構造。 実際はバッチ正規化とかDropoutもやるのかも。 プーリング層は数えないで16層なので、VGG-16とも呼ばれる。 パラメータ数は1億3800万個くらいで、結構深めなアーキテクチャ。 VGG-16は244×244×3の画像を入力して1000クラスに分類するのに対し、MNISTは28×28×1を入れて10クラスに分類するので、以下のような7層版を作った。 これでパラメータ数は27万個くらい。 訓練データのサンプル数が6万個なので、パラメータ数が大分多い感じではある。 コードは以下。 inputs: Tensor = Input(shape=(IMAGE_NUM_ROWS, IMAGE_NUM_COLS, 1)) x: Tensor = Conv2D(filters=8, kernel_size=(2, 2), padding='same', activation='relu')(inputs) x = Conv2D(filters=8, kernel_size=(2, 2), padding='same', activation='relu')(x) x = MaxPooling2D(pool_size=(2, 2))(x) x = Conv2D(filters=16, kernel_size=(2, 2), padding='same', activation='relu')(x) x = Conv2D(filters=16, kernel_size=(2, 2), padding='same', activation='relu')(x) x = Conv2D(filters=16, kernel_size=(2, 2), padding='same', activation='relu')(x) x = MaxPooling2D(pool_size=(2, 2))(x) x = Flatten()(x) x = Dense(units=256, activation='relu')(x) x = Dense(units=256, activation='relu')(x) predictions: Tensor = Dense(NUM_CLASSES, activation='softmax')(x) model: Model = Model(inputs=inputs, outputs=predictions) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) 訓練・評価 上記モデルを6万個のサンプルでバッチサイズ512で一周(1エポック)学習させると、Intel Core i5-6300HQプロセッサー、メモリ16GBのノートPCで28秒前後かかる。 とりあえず3エポック学習させてみる。 (ml-mnist) C:\workspace\ml-mnist>python bin\ml_mnist.py train Using TensorFlow backend.
eyecatch
Tue, Feb 27, 2018

CourseraのDeep Learning SpecializationのSequence Modelsコースを修了した

CourseraのDeep Learning SpecializationのConvolutional Neural Networksコースを修了したのに続き、Sequence Modelsコースを修了した。 (adsbygoogle = window.adsbygoogle || []).push({}); このコースは、RNNの原理、代表的なアーキテクチャ、自然言語処理などについて学べる3週間のコース。 生成モデルが色々出てきて面白い。 動画は今のところ全部英語。 2018/2/6に始めて、2/27に完了。 22日間かかった。 修了したらまたCertifacateもらえた。 また、これでDeep Learning Specializationのすべてのコースを修了したので、全部まとめたCertifacateももらえた。 結局2ヶ月ほどかかり、1万円以上課金してしまった… 以下、3週分の内容をメモ程度に書いておく。 1週目 連続データを扱うシーケンス(Sequence)モデルについて学ぶ。 RNN、LSTM、GRU、BRNN。 動画 再帰型ニューラルネットワーク(Recurrent Neural Network) シーケンスモデルにはRNNなどがあって、音声認識(Speech recognition)や自然言語処理(Natural language processing)に使われる。 音楽生成(Music generation)、感情分類(Sentiment classification)、DNA解析(DNA sequence analysis)、動画行動認識(Video Activity Recognition)、固有表現抽出(Named entity recognition)なんてのも。 入力だけが連続データだったり、出力だけが連続データだったり、両方だったり。 自然言語処理では、ボキャブラリ(Vocabulary)を使って単語をone hotベクトルにして扱う。 ボキャブラリは普通5万次元くらいのベクトル。 ボキャブラリにない単語はそれ用(unknown)の次元に割り当てる。 入力や出力の次元がサンプルごとに違うので、普通のNNは使えない。 また、普通のNNだと、文のある個所から学んだ特徴を他の箇所と共有しない。 また、普通のNNだと、入力サイズが大きすぎて、パラメータが多くなりすぎる。 RNNはこうした問題を持たない。 RNNは、最初の単語xを受け取り、層で計算し、最初の出力yとアクティベーションaを出し、そのaと次のxを同じ層で受け取り、次のyとaをだす、ということを繰り返す。 xにかける重みをWax、aにかける重みをWaa、yにかける重みをWyaと呼ぶ。 あとaとyを計算するときに足すバイアスがあって、それぞれba、by。 あるxの計算をするときに、その前のxも使うので、連続データ処理に向いてる。 けど、後のxを考慮しないところが欠点。 この欠点に対処したのがBRNN(Bidirectional RNN)。 RNNのaの活性化関数にはtanhがよく使われる。 ReLUもあり。 yには二値分類だったらシグモイドだし、そうでなければソフトマックスとか。 損失関数は普通に交差エントロピーでいいけど、yがベクトルなので、その各要素について交差エントロピーを計算して、足し合わせたものが損失になる。 ここから逆伝播するんだけど、その際に連続データを過去にさかのぼるので、時をかける逆伝播(BPTT: Backpropagation through time)と呼ばれる。 上で説明したRNNは、入力と出力が同じ長さだけど、そうでない問題のほうが多い。 感情分類なんかは、任意の長さの文を入力して、5段階評価とかするので、最後のxまで入力した後で一つだけyを出すようにする。 音楽生成なんかは入力が一つで出力が多いので、入力がない部分は前の出力を代わりに入力する。 翻訳みたいに入力と出力の長さが違うときは、前半入力だけして、後半出力だけする。 言語モデル(Language model) ある文のあとに、どんな分が続くかを確率で示してくれるモデル。 訓練データは、文をトークンに分解してone-hotベクトルにして、最後にEOSトークンを加えて作る。 モデルは、RNNの出力をボキャブラリと同じサイズのソフトマックスにして、どの単語の確率が高いかを出力させる。 最初に0ベクトルを入力し、その出力を次の入力にして、それを繰り返す。 単語じゃなくて文字単位でやるモデルもあるけど、あんまり使われない。 このモデルを使うと、学習した文章に似た雰囲気の分を生成できる。 このとき、出力したベクトルから、各単語の確率にしたがって単語をサンプリングし、それを次の入力にする。 RNNの勾配消失 英語の文だと、主語が単数だと動詞の形が変わるんだけど、主語と動詞がすごい離れていることがありうる。 最初のほうの単語である主語は浅い層(初期のステップ)で処理されて、一方動詞は深い層(あとのほうのステップ)で処理されることになる。 すると、勾配消失により、深い層の単語が浅い層から受ける影響が小さくなってしまって、動詞の形をいい感じに学習できない。 これがナイーブなRNNの欠点。 勾配爆発も起こり得るけど、Gradient clipping、つまり勾配の値を計算した後に値が閾値を超えていたら修正する手法を使えば比較的簡単に回避できるので、勾配消失が深刻。 GRU(Gated Recurrent Unit) RNNにMemory cell©というアイデアを加えたもの。 cは浅い層の情報を深い層に伝える役目をして、勾配消失問題を緩和する。 cの候補は毎回、前回のcとxの線形変換をtanhに入れたものとして生成され、それを、0か1を返すゲートΓu(シグモイドな感じの関数)で実際にcとして使うかを決めて、cを更新していく。 このゲートを更新ゲート(Update gate)という。 cはソフトマックスに入れてyを出力したり、次のステップのaにする。 実際には、もう一つ関連ゲート(Relevance gate)Γrってのがあって、cの候補を計算するときに前回のcに掛ける。 LSTM(Long short term memory) RNNの勾配消失に対処するまた別のアイデア。 GRUよりパワフル。 けどGRUより古くからあるもので、GRUがそれのシンプル版という関係。 LSTMの論文はかなりむずい。 GRUと比べると、まずΓrはない。 で、GRUはΓuが1だったらcを更新して、0だったら前のを保持するという感じだったけど、LSTMでは忘却ゲート(Forget gate)Γfに前回のcをかけて、捨てるかどうかを決める。 また、出力ゲート(Output gate)Γoが追加されて、単にcを次のaにするんじゃなくて、Γo*cをaにする。 各ゲートは前のaと今回のxの線型結合にバイアスを加えたものをシグモイドして計算する。 ゲートの計算にcもいれることがあって、のぞき穴接続 (Peephole connection)と呼ばれる。 基本的にはLSTM使えばいいけど、GRUのほうが計算コストが少なくて大きなネットワーク作りやすいから、GRUのほうがいいこともある。 BRNN(Bidirectional RNN) 普通にRNNやった後、後ろの入力から順番に逆向きにRNNする。 yは、順向きのaと逆向きのaとバイアスを線形計算して非線形変換したものになる。 Deep RNN 単にyを出力するんじゃなくて、そのyを入力とする別のRNNを積み上げていくとdeepになる。 RNNは時間軸の方向にすでに深いので、出力方向には普通は2、3個だけ積み上げる。 出力方向にRNNを積み上げる代わりに、出力を普通のNNにいれるってのもある。 プログラミング課題 3つもある… ベーシックRNNとLSTMの順伝播をNumPyで実装 恐竜の名前を生成する言語モデルをNumPyで実装 Gradient clippingとサンプリングを実装して、モデルを訓練しながら、恐竜の名前をいい感じに生成できるようになっていく様を観察する。 LSTMの音楽生成モデルをKerasで実装 Jazzの曲の断片を学習させて、それっぽい曲を生成してみる。 2週目 自然言語処理。 動画 単語埋め込み(Word embedding) 1週目でやったように、単語をone-hotベクトルで表すと、単語同士の積が0になって、単語間の関係(距離)が表せられない。 代わりに、単語を特徴のベクトルにして、各次元に特徴量をもたせる、特徴付き表現(Featurized representation)がある。 単語の特徴は数百とかにするけど、可視化するために2Dにすることがある。 このための代表的なアルゴリズムがt-SNE。 t-SNEは複雑で非線形な処理をするので、後述の類推には使えないけど、似たような単語のクラスタを観察できる。 特徴の分布を表すN次元の空間に単語を埋め込むため、単語埋め込みという。 このN次元ベクトルを単語の数だけ結合したものをEで表す。 この表現形式にすると、大量の適当なテキストデータで学習させたり、学習済みのモデルをダウンロードしたりしたあと、特定のタスクのために転移学習させることができる。 また、類推(Analogical reasoning)が可能になる。 単語のペアが二つあって、ペア内の単語ベクトル間の差を計算して、ペア間でその値が近ければ、それらのペアは同じような関係の組み合わせだと言える。 例えば、男 - 女は王 - 女王に近くなる。 類似度の計算にはコサイン類似度(Cosine similarity)がよく使われる。 ユークリッド距離(Euclidean distance)でもいいけど、コサイン類似度のほうが一般的。 単語埋め込みの学習 Eにone-hotベクトルをかけると、そのone-hotベクトルが表す単語の特徴ベクトルが得られる。 数単語の後に続く単語を予測するニューラル言語モデルを考えると、与えられたそれぞれの単語を表すone-hotベクトルを入力して、Eをかける層があって、その結果を全結合層にいれて、その結果をボキャブラリサイズのベクトルを出力するソフトマックス層にいれる。 ソフトマックス層の出力で、一番大きい値の単語が予測する単語になる。 Eをパラメータにしておくと、このモデルを訓練するとEが学習される。 予測精度自体はそんなによくならなくても問題ない。 予測する単語の前だけじゃなくて、前後の単語を使って学習させたりも。 1単語だけで予測しても結構いい結果になる。 上記のモデルはSkip-Gramモデルと呼ばれる。 実際には、文の中からターゲット単語を選び、前後ウィンドウサイズ(5とか)以内のコンテクスト単語を一つ選び、それらをペアにして一つの訓練データを作る。 コンテクスト単語は完全にランダムに選ぶと、aとかtheとかofとかが多くなっちゃうので、ヒューリスティックにバランスよく選ぶ必要がある。 ソフトマックス層は、ボキャブラリサイズのベクトルを出力するため、計算コストがでかい。 その対策として、階層的ソフトマックス(Hierarchical softmax)ってのがあって、これは木構造で分類を表す手法。 もう一つ負例サンプリング(Negative sampling)という手法があって、こっちのほうがシンプルで効果的。 Skip-Gramモデルのほか、CBOW(Continuous Bag Of Words)というモデルもある。 これはターゲット単語とその前後数単語を訓練データにするもの。 これらのモデルをWord2Vecモデルといったり、それを使ってEを学習する手法をWord2Vecアルゴリズムといったりする。 負例サンプリングではまず、コンテクスト単語に対して別の単語を与え、ターゲット単語なら1、違うなら0というラベル付き訓練データを作る。 ターゲット単語とコンテクスト単語の組はSkip-Gramと同様に選んで、0になる単語はランダムに選ぶ。 コンテクスト単語一つに対し、yが1になるデータを一つ、0になるデータをk個(2~20くらい)作る。 kはデータセットが大きいほど少なくする。 で、Skip-Gramモデルのソフトマックス層を、ボキャブラリの数だけの二値分類ノードに変える。 これらのノードは毎回全部計算するんじゃなくて、k+1個だけを計算するので計算コストが小さい。 単語埋め込みの学習アルゴリズムとして、Word2Vecじゃないものだと、GloVe(Global Vectors)アルゴリズムってのがある。 GloVeでは、単語iと単語jが近くに現れることが何回あるかをxijで表す。 xijをボキャブラリのすべての単語の組み合わせで数えて、それらと何かの二乗誤差にヒューリスティックな重み付けをしたコスト関数を作って最適化して単語埋め込みを学習させる。 細かいことはよくわからなかった… 感情分類 Yelpみたいなサービスで、コメントから星の数を推定する。 感情分類は、教師データがあまり得られないことが多いのが課題だけど、よく訓練したEがあれば上手く分類できる。 コメントを単語に分解したら、それぞれのone-hotベクトルをEとかけて単語ベクトルを作って、単語間の平均を計算して、ソフトマックス層に入れて、出力を星の数だけ作る。 というのがシンプルなモデル。 これだと語順を考慮しないので、RNNに単語ごとに入力して、最後の出力をソフトマックスするといい感じになる。 単語埋め込みからのバイアス除去(Debias) 単語埋め込みに性別とか人種のバイアスがかかってると、いいモデルができない。 例えば、プログラマ - 男 + 女 = 主婦みたいになってるとまずい。 こういうバイアスは、学習データのテキストのバイアス、つまりそれを書いた人のバイアスからくる。 単語空間のバイアスの方向を調べるには、例えば性別のバイアスなら、he - sheとかmale - femaleとかの平均をとる。 するとある1次元のベクトルが得られて、これがバイアスの方向になる。 この上にある値を他の次元の射影に変換することでバイアスを削減(Neutralize)できる。 実際には、特異値分解(SVD: Singular Value Decomposition)でもっとシステマチックにバイアスを計算する。 バイアスも数次元のベクトルになりうる。 Neutralizeしたらさらに、バイアスをなくす方向に単語の組の位置をずらす(Equalize pairs)。 例えば、男と女の組を、ベビーシッターからの距離に差がなくなるようにずらす。 Neutralizeすべき単語は、線形分類で決めることができる(?)。 Equalizeすべき単語は手で選ぶ。 プログラミング課題 訓練済みのGloVeの単語埋め込みをロードして、コサイン類似度計算を実装して、類推を実行。 NeutralizationとEqualizationを実装。 感情分類(文に自動で絵文字を付ける)の、シンプルな実装と2層LSTMでの実装。 3週目 連続データを入力して連続データを出力するRNNアーキテクチャを学ぶ。 動画 Sequence to sequence(Seq2Seq)モデル 翻訳などに使うモデル。 エンコーダ(encoder)ネットワークで元の単語を読み込み、デコーダ(decoder)ネットワークが翻訳を吐き出す。 画像を読んでその説明文(caption)を吐くのにもつかわれる。 この場合、CNNで画像を読んで、最後の全結合層の出力をRNNに入れる。 小説を生成するような言語モデルと異なるのは、ランダムに生成してほしいのではなくて、ベストな結果を生成してほしいところ。 デコーダネットワークの部分は言語モデルと一緒。 入力がエンコーダネットワークの出力か0ベクトルかの違いだけ。 このようなのを条件付き言語モデル(Conditional language model)と呼ぶ。 言語モデルだと、次に出力する単語をランダムで選んでたけど、翻訳ではそうはいかない。 貪欲法(Greedy algorithm)みたいに、毎回一番確率が高いものを選んでもうまくいかない。 最終的に出力する全単語の確率の掛け合わせが最大になるやつを選びたい。 ビームサーチ(Beam search)を代わりに使う。 ビーム幅(Beamwidth)Bを決めて、最初にBの数だけ単語の候補を確率の高い順に選ぶ。 で、それらを次の入力にしてB個の出力ベクトルを得たら、最初の単語の確立をそれらのベクトルの各要素にかけて、大きい順にまたB個単語を選ぶ。 あとはこれの繰り返し。 ビームサーチをもう少し改良できる。 その一つが長さ正規化(Length normalization)。 条件付確率を計算するときに、単語が増えてくると1未満の数を何回もかけることになり、アンダーフローや丸め誤差が発生してしまう。 ので、各単語の確率をかけ合わせる代わりに、各確率のlogを足し合わせる。 これだとまだ、確率が1未満なのでlogは常に負の値になり、単語の数が少ない程総和は大きくなるので、翻訳結果に短い文が選ばれがちになっちゃう。 ので単語数で割る。 または単語数をα(0~1)乗したもので割る。 この式(目的関数)をNormalized log probability objectiveとかNormalized log likelihood objectiveとか呼ぶ。 Bはどう選ぶか。 Bが小さいと計算コストが低く、最適解を見つける可能性が低い。 Bが大きいとその逆。 プロダクション環境では、10~100くらいが一般的。 研究では数千とかも。 試行錯誤していい値を見つけるしかない。 深さ優先探索(DFS: Depth First Search)、幅優先探索(BFS: Breadth First Search)に比べて、ビームサーチは最適解を見つけられないかもしれないけど、リーズナブル。 ビームサーチはヒューリスティックなアルゴリズムなので、いつもいい結果を出すとは限らない。 だめだったときはエラー分析をする。 ダメな翻訳が出力されたとき、RNNの訓練が足らないのか、ビームサーチのBが小さすぎるのかを切り分けたい。 まずは、翻訳中のある単語について、期待する出力とモデルの出力の確率をそれぞれ見てみる。 前者が大きければ、モデルは正しい出力してるけど、ビームサーチが間違ったものを選択している。 逆ならモデルに問題がある。 (長さ正規化してたらその目的関数を比べる。) これを色んなサンプルで試して、より多くのサンプルでダメだったほうの改善に努めるべし。 いい感じの訳が複数あったらどうする?
eyecatch
Tue, Feb 6, 2018

CourseraのDeep Learning SpecializationのConvolutional Neural Networksコースを修了した

CourseraのDeep Learning SpecializationのStructuring Machine Learning Projectsコースを修了したのに続き、Convolutional Neural Networksコースを修了した。 (adsbygoogle = window.adsbygoogle || []).push({}); このコースは、CNNの原理、代表的なアーキテクチャ、応用などについて学べる4週間のコース。 動画は今のところ全部英語。 プログラミング課題は初のKeras。 このコースは結構難しくて、特に3週目と4週目は理解に苦しんだ。 というか理解しきれなかったような。 けどNST面白かった。 2018/1/16に始めて、2/6に完了。 22日間かかった。 修了したらまたCertifacateもらえた。 以下、4週分の内容をメモ程度に書いておく。 1週目 畳み込みニューラルネットワーク(CNN: Convolutional neural network)の基本。 動画 畳み込み計算 画像認識でよく使われるNNのアーキテクチャ。 低層ではエッジを検出し、層が進むにつれて複雑な特徴を学習する。 画像を特定の行列(普通は奇数の正方行列。3×3が多い。)で畳み込むことで、特定の方向のエッジを検出できる。 この行列をフィルタ(filter)という。カーネルと呼ばれることもある。 例えば縦なら以下。 [[1, 0, -1], [1, 0, -1], [1, 0, -1]] 縦でもいろいろフィルタはあって、以下はSobelフィルタというもの。 [[1, 0, -1], [2, 0, -2], [1, 0, -1]] 以下はScharrフィルタ。 [[ 3, 0, -3], [10, 0, -10], [ 3, 0, -3]] 縦のフィルタを90度回転すると横のフィルタになる。 深層学習では、フィルタもパラメータとして学習させる。 パディング(Padding) n×nの行列をf×fのフィルタで畳み込むとn-f+1×n-f+1の行列になる。 つまり畳み込めば畳み込むほど画像が小さくなってしまう。 また、画像の端のほうはフィルタにかかる割合が小さいので、情報量が小さくなってしまう。 これらを解決するテクニックがパディング(Padding)。 行列の周囲を0でパディングして、サイズを大きくしてから畳み込む。 パディングがないのをValidな畳み込み、出力が入力と同じサイズになるようにパディングするのをSameな畳み込みという。 Strided畳み込み 畳み込むときにフィルタをずらす幅を1より大きくする。 パディングサイズがpでストライドがsのとき、n×nの行列をf×fのフィルタで畳み込むと(n+2p-f)/s+1×(n+2p-f)/s+1の行列になる。 3次元(カラー画像)の畳み込み カラー画像は3次元の行列、つまりn×n×cの行列で、それを畳み込むのはf×f×cのフィルタで、出力はn-f+1×n-f+1の行列になる。 チャネルごとにフィルタを設定して、色ごとにエッジ検出できる。 フィルタごとの出力は全部スタックして、最終的な出力は3次元になる。 畳み込み層はフィルタの要素数がパラメータ数になる。 入力画像の大きさに依存しないので、パラメータ数が少なくて済み、過学習しにくい。 入力を複数の畳み込み層に通したら、最終的に3次元の出力をなべてベクトルにして、後ろの層に渡す。 プーリング層(Pooling layer) 計算量を減らすため、また特徴の抽出のために、畳み込み層のあとに使われる層。 基本Max poolingが使われるけど、Average poolingというのもある。 Max pooling: フィルタをかけた部分を畳み込む代わりに、最大値を出力とする。大きな値が特徴が大きく出ているところだから、特徴を凝縮するイメージだけど、経験的にこれで上手くいくことが分かっているだけで、なぜ上手くいくかは判明していない。この層はパラメータを持たない。 Average pooling: フィルタをかけた部分を畳み込む代わりに、平均を出力とする。 プーリング層のフィルタは大抵、サイズが2×2でパディングが0でストライドは2。 普通、畳み込み層とプーリング層とセットで1層と数える。 全結合層(Fully connected layer) 全ノードがメッシュ状につながった普通の層。 畳み込み層とプーリング層のセットがいくつかあって、その出力をベクトルになべて、全結合層につなぐ。 一般的なCNN 畳み込み層は、普通nhとnwを縮め、ncを増やす。 また、全体として、層が浅くなるほど出力が減るのが多い。 CNNはハイパーパラメータが多すぎるので、アーキテクチャは自分で考えるんではなく、論文呼んで自分の問題に合いそうなのを探すべし。 畳み込み層は全結合層に比べてパラメータ数がかなり少なくて済むのがいいところ。 これはパラメーター共有(Parameter sharing)という、画像のある個所で上手く動いたフィルタ(e.g.
eyecatch
Tue, Jan 16, 2018

CourseraのDeep Learning SpecializationのStructuring Machine Learning Projectsコースを修了した

CourseraのDeep Learning SpecializationのImproving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimizationコースを修了したのに続き、Structuring Machine Learning Projectsコースを修了した。 (adsbygoogle = window.adsbygoogle || []).push({}); このコースは、深層学習プロジェクトの進め方のコツや問題への対処方法などについて学べる2週間のコース。 今回はプログラミング課題がない。 動画は今のところ全部英語。 ちょっと動画編集ミスが多かった。 同じことを二回言ったり、無音無絵の時間があったり、マイクテストしてたり。 2018/1/13に始めて、1/15に完了。 3日間かかった。 修了したらまたCertifacateもらえた。 以下、2週分の内容をメモ程度に書いておく。 1週目 モデルの改善をするのに、データを増やしたりハイパーパラメータを変えたり色々な手法がある。 一つを試すのに下手すると数か月とかかかるので、効率よく手法の取捨選択し、モデルを改善していくための戦略について学ぶ。 動画 直交化(Orthogonalization) 一つの要素で複数の制御をしようとすると難しいので、一つの制御だけするようにする。 具体的には、以下のことを別々に扱う。 訓練データに目標の精度までフィットさせる。 devデータに目標の精度までフィットさせる。 テストデータに目標の精度までフィットさせる。 現実のデータでうまく動くようにする。 それぞれの目的について、チューニングすべき要素は別々になる。 早期終了は直行化の原則に反しているので、ほかの方法があるならそっちをやったほうがいい。 指標(Goal)の設定 モデルの改善はイテレーティブなプロセスなので、サイクルを速く回したい。 そのため、モデルを評価する単一の数値があるといい。 F1スコアとか。平均とか 単一の指標にまとめるのがむずいときもある。 精度と速さとか。 そんなときは一つ以外の指標を足切りだけに使う。 ある閾値以上の速さが出てるもののなかで精度をくらべるなど。 データの分け方 devデータとテストデータの分布(と評価指標)は同じ感じにしないといけない。 そのために、いったん全データをシャッフルしてから分割する。 訓練データの分布は異なってても問題ない。 訓練:テスト = 70:30とか、訓練:dev:テスト = 60:20:20とかいう比率は、1万くらいのデータなら適当。 けど100万くらいなら、98:1:1くらいが妥当。 テストデータはモデルの最終評価をするためのものなので、どれだけ評価したいかによってサイズを変える。 0もありがちだけど、非推奨。 猫の画像のなかにエロ画像が混じっちゃうようなモデルはだめ。 猫判定率が多少下がっても、エロ画像が含まれないほうがまし。 こういう場合は評価指標を変える必要がある。 エロ画像を猫と判定した場合にペナルティを大きくするなど。 直行化の観点で言うと、指標を決めるのと、その指標に従って最適化するのは、別のタスクとして扱うべき。 人並性能(Human-level performance)との比較 人並性能とは、人が手動で達成できる精度。そのエラー率、つまり人並誤差(Human-level error)はベイズ誤差(Bayes