めるぱんブログ

とある医大生の勉強の記録です

PCが壊れました

ディープラーニング用ではない普通のPCで無理に学習させていたりしたのが祟ったのか全く起動することができなくなってしまいました。

幸い今までの研究データはUSBに入れてあるので大丈夫ですがプログラミング等のデータは復旧できなさそうです…

これを機に10万円配布されるみたいですししっかりとしたPCに変えようかと思います。


プログラミングやディープラーニングの勉強は一時中断してしばらくは医学の勉強に専念します。

PythonとKerasによるディープラーニング 第5章②

先ほどはMNISTを用いましたが、次はKaggleで提供されているDogs vs. Catsというデータセットを用いて学習をしていきます。

 

この最初の画像データをディレクトリにコピーする部分がどうしてもできずに毎回 invalid argumentのエラーが出てしまいました。いろいろと調べて治そうと努力したのですが結局改善できず、手動でディレクトリにコピペしてしまいました。

まあここは本質的な部分ではないので良しとします。(どなたかわかる方がいれば教えてください)

 

CNNモデルは前回MNSITに使用したものを少し変えたものを使用し、コンパイルではbinary_crossentropyを損失関数として使用し、ほかはいつもと同じです。

 

データの前処理ではImageDataGeneratorというものを使って画像の読み込みからRGBピクセルにデコード、浮動小数点型のテンソルに変換、1/255にし[0, 1]に収めるということができます。

このジェネレータはデータを無限に生成するため、モデルにfitさせるときに今までと違いfit_generatorというものを使用します。これを用いことで、次のエポックに進むタイミングを決めることができます。

例えばトータルのサンプル数が合計2000の場合、最初のジェネレータのバッチを20に設定したときにはこのfit_generatorのsteps_per_epochを100で設定することで20×100で2000となる、といった感じです。

また、検証用のデータも無限に生成されるため、指定しておく必要があります。

 

このモデルで学習した結果、図のようになりました。

f:id:melpan:20200415150819p:plain

訓練データと検証データでの正解率

f:id:melpan:20200415150851p:plain

訓練データと検証データでの損失値

結果は正解率は70%くらいで頭打ちとなり、過学習になってしまいました。

今回は元のデータが2000しかなかったので、データの拡張を行います。これは、同じくImageDataGeneratorを用いることで、元の画像を回転させたり平行移動させたりすることで少しずつ違う画像を生成するという作業です。

ただし、検証データは水増しすることは禁忌なので注意が必要です。

これによりバッチを少し大きくし、モデルにフィットさせます。

また、モデルの方にもドロップアウトを入れることで過学習を抑制します。

その結果、図のようになりました。

f:id:melpan:20200415151722p:plain

訓練データと検証データでの正解率改

f:id:melpan:20200415151747p:plain

訓練データと検証データでの損失値改

80%以上の正解率になりました。損失値はあらぶっていますがなかなかの結果です。

また、今回のモデルはmodel.save()を用いて保存しておきます。

 

実際にCNNを試してみましたが、データの水増しの部分は非常に重要で今後絶対必要になると思いました。

あと実際に学習しているときなのですが、パソコンがめちゃくちゃ熱くなって少し危険な気がしています…時間も1時間くらいかかってしまうのでいいデスクトップのPCがほしくなりますね。

PythonとKerasによるディープラーニング 第5章①

第5章では実際に畳み込みニューラルネットワーク(CNN)を使っていく章です。

最初はMNISTを用いてCNNを試していきます。

CNNを用いることで今まで画像を平坦なベクトルにしてから処理していたのを丸々画像として読み込めるようになります。

 

CNNで特徴的なのはConv2D層とMaxPooling2D層を用いる点です。

これまでのDense層では1次元のベクトルを用いてたのに対し、この二つは(height, width, channels)の3次元テンソルを用います。

これにより空間的な連続性を認識できるようになります。

Conv2D層では、Conv2D(output_depth, (window_height, window_width))となっています。例えばConv2D(32, (3, 3))であれば、3×3のウインドウを画像全体をスライドさせ、(32, )の1次元ベクトルで出力するということです。この際にパディングやストライドを行うこともできます。

MaxPooling2D層では、2×2のウインドウの中の最大値のみをピックアップすることでサンプルを小さくします。

そして最後にFlattenを用いてベクトルに変換し、Dense層に出力します。

 

このあたりの層についての説明は割と省いてあるので、ゼロから作るDeepLearningの方がわかりやすいかなと思いました。

PythonとKerasによるディープラーニング 第4章

第4章では機械学習についての基礎的な内容が主に書かれていました。

 

機械学習モデルの評価

まずモデルを訓練データで訓練し、検証データでモデルの評価、テストデータで実際にテストするという流れが基本です。

検証データというのはモデルの層などのハイパーパラメータを調整するために必要です。しかし、この調整を繰り返すことは検証データに合わせて調整をするということで過学習に陥ることがあり、これを情報のもれといいます。

また、テストデータは訓練データとは互いに素である必要があります。

 

もとのデータを訓練データと検証データに分ける方法でいくつかあります。

まず一つ目はホールドアウト法です、これはデータの一部を検証データとする方法です。これは二値分類の問題をやるときに使いました。

二つ目はk分割交差検証です。これも回帰の問題を解くときに使いました。サンプルの数が少なく、データを分割する前にランダムなシャッフルを行い、モデルごとに大きな差があるような場合に使います。

まあた、シャッフルに基づく反復的なk分割交差検証というのもあります。

 

データを分ける際にはまず最初にランダムにシャッフルすることが大事です。というのも数字が昇順にきれいに並んでいる場合などがあるからです。

 

データの前処理

まずデータのベクトル化です。多ラベル分類を行うときなどで使ったものです。

 

続いて値の正規化です。これも回帰の問題で使ったものですが、平均値を引いて標準偏差で割るやつです。

 

欠損値の処理というのもありますが、これは0を代わりに入れることでニューラルネットワークが底を欠損値として学習してくれます。

 

特徴的エンジニアリング

これは入力のデータをさらに簡単な特徴量に変換するという工程です。これを行うことで処理が楽になるものなのですが、ニューラルネットワークでは勝手に特徴量を見つけ出してくれます。

 

過学習

過学習を抑制することを正則化といい、その方法にはいくつかあります。

最もいい方法は訓練データを増やすことです。

それ以外の方法では以下の方法があります。

 

・ネットワークのサイズを小さくする

 層の数やユニットの数を減らすことで過学習に陥りにくくなります。しかし、最も適したサイズをいきなり出すことはできないので、増やしたり減らしたりの試行錯誤を繰り返す必要があります。

そういえば前に一度2層のモデルを3層に変えたときに微妙な結果になったのはこういうことだったんですね。

 

・重みを正則化する

 大きな重みにコストを追加することで小さい重みのみ設定されるようになります。

L1正則化とL2正則化の2種類があります。regularizerをimportし、kernel_regularizer=regularizers.l2(0.001) のように追加することができます。

 

ドロップアウトの追加

 これは訓練する際に一定の割合で出力されるベクトルを減らすというものです。

実際にテストする際はドロップアウト率に基づき出力をスケールダウンします。

 

これらに基づいて機械学習を行っていきます。

 

今回は本当に全体の流れやイメージをつかむ用の章でしたね。

多くは今までやったことの復習だったので理解しやすかったです。特に過学習の抑制をするための部分は重要なのでしっかり押さえておきたいです。

 

次からパート2でディープラーニングの実践が始まります。いよいよですね。

PythonとKerasによるディープラーニング 第3章③

最後は回帰の問題をやっていきます。

回帰は今までの分類問題とは異なり、連続値を予想する問題です。

 

今回はBoston Housingデータセットを使用します。これは1970年代のボストン近郊に関する犯罪発生率や平均部屋数など住宅価格の予想に使う13種類の様々なデータが入っています。

データのサンプル数は訓練サンプル404、テストサンプル102の合計506と少なめです。この少なさを解消するために後でいろいろ頑張ります。

また、入力データの特徴量の尺度もそれぞれ異なり、犯罪発生率であれば%、部屋の数であれば何部屋…と単位が異なっています。ここも後で頑張る必要が出てきます。

 

では、実際にデータセットを読み込んだらいつものようにデータの下準備をします。

今回は先ほど言ったようにデータの特徴量の尺度が異なります。

そのため、データごとにデータの正規化を行います。具体的には

((特徴量) - (平均値)) / (標準偏差

という計算を行ことで特徴量の中心が0になり、標準偏差が1になります。

 

ニューラルネットワークの構築では隠れ層が2層のニューラルネットワークを作ります。サンプル数が少ない場合は過学習が起きやすいので、その対策として小さいニューラルネットワークを使うのがよいみたいです。

今回は回帰であるため、最後に活性化関数を適用しないで1つのユニットに出力します。ここでシグモイドやソフトマックス関数を使ってしまうと出力が0から1に収まってしまうためです。

またコンパイルするときに損失関数は平均二乗誤差(MSE)、監視には平均絶対誤差(MAE)を用います。これは回帰問題のときに広く使われるそうなので覚えておきたいです。

 

前回まではサンプルを検証データと訓練データに分けて学習させていましたが、今回はサンプル数が少ないため、分けるとさらに少ない数となってしまい、過学習が起きてしまいます。

そのため今回はk分割交差検証という方法を使います。

これはデータをk個のフォールドに分け、そのうちの一つを検証データとし、残りのk - 1個のデータを訓練します。これをk回行い、それぞれの検証結果を平均することで最終的な結果とする方法です。

正直自分も最初は何を言っているのか全く分かりませんでしたが、実際に手を動かしてみると納得できると思います。

 

これを実際にやってみたわけなのですが、めちゃくちゃ処理に時間かかりました。

エポック数を最初は100で、二回目は500でやってみようと書いてあるのですが、500にしたときに20分くらい処理にかかってしまいました。

また、結果をプロットしてみたのですが、本のようにうまくいかず、何か別の方法を勉強しないといけないと感じました。

 

この回帰の問題が第3章の中では一番難しく、大変でした。

まず本自体にいくつか誤植があり、そしてしっかりその部分を直してもエラーが出ることがあったりして結局かなり調べながらやることになりました。

またk分割交差検証もなかなか理解するのが大変で時間がかかってしまいました。

 

この問題を通して大切だった点は

・特徴量に複数の尺度がある場合は正規化を行う

・回帰では出力は1ユニットで活性化関数は不要

・回帰のコンパイルには損失関数はMSE、監視はMAEを用いる

・サンプル数が少ない場合はk分割交差検証が有効

だと思います。

 

次の章では機械学習に入るみたいです。また頑張ろうと思います。

PythonとKerasによるディープラーニング 第3章②

続いて行うのは多クラス分類の問題です。

 

今回はReutersデータセットというニュース記事とそのトピックを集めたデータセットを使用します。トピックの種類は全部で46種類です。

 

前回と同様にnum_words=10000とすることで単語の数を制限します。

 

データの下準備をまた今回も行います。データのベクトル化は前回と同じコードで行うことができます。ラベルのベクトル化は前回と異なり46種類あるので、前回より複雑になります。しかし、ここで第2章で用いたto_categoricalを使うことで一発でいけます。

 

続いてモデルの構築を行います。

今回は46種類のクラスを学習しないといけないので、ユニットの数を46以上にしておかないといけないです。狭い次元を通すことにより必要なデータが失われてしまう可能性があるからです。

また出力層はもちろん46次元でソフトマックス関数を用います。

46種類に確率で分類するので当然ですね。

 

今回用いる損失関数はcategorical_crossentropyです。これは前回の二値分類ではシグモイドとbainary_crossentropyを用いたように、ソフトマックスにはcategorical_crossentropyという対応なようです。ここが多分今回一番重要なところですね。

 

検証データを今回は1000サンプルで行います。

そして512サンプルのミニバッチで20エポック訓練します。

f:id:melpan:20200412141501p:plain

訓練データと検証データの損失値

f:id:melpan:20200412141545p:plain

訓練データと検証データでの正解率

今回は8エポック目で過学習になっていますね。

ということで8エポックで学習しなおした結果正解率は78%くらいになりました。

 

この多クラス分類は正直前回の二値分類とほぼ同じで難しい要素はありませんでした。

ただ、一部異なる点として、

・ラベルのベクトル化

・ユニット数を分類する数より多くする

・出力層でソフトマックス関数、損失関数ではcategorical_crossentropyを用いる

という点があげられます。

前回苦戦したデータの前処理ですが、今回はそのままほとんど流用できたためかなり楽にできました。

ひとつひとつしっかり積み上げていくことが大切ですね。

PythonとKerasによるディープラーニング 第3章①

第3章では二値分類、多クラス分類、スカラー回帰の3つを実際に試してみる章です。

今回はとりあえず二値分類をやってみます。 まず最初にIMDbというデータセットを使用するみたいです。 これは50000件の映画の肯定的な、または否定的なレビューで構成されています。また、訓練データ25000件、テストデータ25000件に分かれており、それぞれ肯定的と否定的が50%ずつ含まれています。

出現頻度の高い10000個の単語のみを残すことによりデータを扱いやすいサイズにします。 train_dataとtest_dataは各レビューの単語のシーケンスをエンコードしたものからなるリストで、整数のリストです。([1, 20 ,145, 500, ...]のようなリスト) 一方train_labelとtest_labelは0と1のリストで、0は否定的、1は肯定的を意味します。

続いてこれらのデータをニューラルネットワークに入れるための準備をします。 整数のリストをそのまま入力はできないようなので今回はone-hotエンコーディングで0と1のベクトルに変換します。

ベクトルに変換する際、今回は10000の単語を選んでいるため、まず10000次元をすべて0で埋め、次に実際に先ほどの例の[1, 20 ,145, 500, ...]のようなリストを考えるとインデックスの1,20,145,500...が1になるという感じです。 これでデータの下準備は完了です。 ここでは手動で行うと書いてあったのでもしかしたらもっと楽に自動化できる方法がこの後出てくるのかもしれません。正直個々の部分が一番つらかったので自動でできるようになってほしい…

今回ニューラルネットワークでは活性化関数としてReLUを用い、16のユニットを持つ中間層を2つ、最後の出力層ではシグモイド関数を使用しています。二値分類ではシグモイド関数を用いるのがベストらしいです。

最後に損失関数とオプティマイザの選択をします。 今回はオプティマイザはrmspropを使用しました。これはどんな問題でもとりあえず使えるという便利なものらしいので覚えときたいです。 また損失関数はbinary_crossentropyを使いました。これは二値分類でシグモイド関数を使うときに用いる最適なものだそうです。 そして今回は正解率で監視をします。

全く新しいデータでモデルを訓練するときの正解率を監視するには、元のデータセットから取り分けた10000個のサンプルで検証データセットを作成する必要があるそうです。

次に512サンプルのミニバッチで20エポック訓練を行います。 この際に取り分けた10000サンプルで正解率を監視します。この検証データはvalidation_dataに指定します。

訓練データと検証データでの損失値と正解率をmatplotlibでプロットします。

ドットは訓練データ、実線は検証データを表します。

f:id:melpan:20200412065923p:plain
訓練データと検証データでの正解率

これをみると訓練データではどちらもうまく学習されているように見えます。 しかし、検証データでは損失関数では5エポック目以降逆に上昇しているように見え、正解率も横ばいになっています。 これがいわゆる過学習の状況です。 そのため今回は4エポックで訓練すること正解率87.5%になりました。

今回は中間層を2層でやってみましたが、3層にしてやってみた結果も載せてみます。

f:id:melpan:20200412071736p:plain
3層損失値
f:id:melpan:20200412071822p:plain
3層正解率
正直そんなに変わったようには見えないですね... むしろ2層の時のほうが訓練データでの上がり方も滑らかなように見えます。 層を増やせばいいっていうものではないということなのでしょうか?

実際にやっていると感じますがモデルの構築はそこまで難しい要素はなく、むしろ入力するデータの処理が毎回大変なような感じがします。今回もベクトルに変換するなどなかなか難しい処理が多かったので勉強が必要だなあと感じます。 今回自分として一番大事だと思ったのは二値分類では出力はシグモイド関数で損失関数はbinary_crossentropyを使うということですね。