- 投稿日:2020-06-04T20:23:31+09:00
MacでCUDAが使えなくなることを誰も不満に思ってないの?
https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html#title-new-features
家で機械学習やる人は自作してUbuntu使うのかな。
業務で機械学習やる人はGoogleやAmazonに金を積むのかな
研究室では大学のスパコンや研究室のサーバー使うのかな。
50万ぐらい払ってもいいからMacで機械学習したい人っていると思うんだけどなぁ。
- 投稿日:2020-06-04T19:34:23+09:00
実装で学ぶ深層学習~異常検知編(教師なし学習)~
はじめに
この記事はAuto Encoderを実装、チューニング、考察する記事である。
Target となる読者
1.異常検知を教師なしでするモデルを作りたい人
2.基礎的なニューラルネットワークを自身で読んで改良できる。上記に当てはまる人に対しておすすめのモデルを提案する。
異常検知の流れの説明
問題設定
まず教師なしの異常検知とはなにかについて例を用いて説明する。
製品をつくるとどうしても不良品というものができてしまう。
その不良品の画像をとるとシワが目視できるような場合それを人が分離するのは非常に大変なのでニューラルネットワークで自動で検知してしまおうというものである。
しかしシワのついた画像が異常か正常かを2値分類するには足りない時に正常な画像のみを訓練に使って画像の異常値をもとめることができないかというものである。ベーシックなアプローチ
正常画像を入力として正常画像を返す関数:$f(x)=x$となる$f$をニューラルネットワークで学ぶ($x$は正常画像)。
異常値を$|x-f(x)|$によって定義すると$x$が正常画像なら0になるように訓練されているので小さくなるが、$x$が異常画像の場合ニューラルネットワークにとって初見のものなので$|x-f(x)|$は大きくなり,成立するというものだ。
このようなモデルをAuto Encoderと呼び,モデルの内部構造としては畳み込み層で小さくしてUp Sampling で画像を大きくして返すようなものが多い。(砂時計型)
ここでU-netなどの賢いモデルを使うと異常画像などに対しても予測がうまくいってしまいやすいので異常値をうまく取れないことに注意する。デノイズを行うアプローチ
上に書いたモデルだとある程度アホなモデルにして正常だとうまく予想するけど異常だと失敗するようなモデルを作る必要がある。
そこでモデルは最大限賢くして入力にノイズを加えたものを元に戻す(デノイズ),つまり$x=f(x+z)$($z$はノイズ)を学習するというものがそれなりによく動くようである。筆者のおすすめ
画像の予測を難しくする上でデノイズではなく超解像を用いるとうまく動くのではないかと当たりをつけて行ったところシワや傷を検知する問題においてかなり良いパフォーマンスになった。
ここまでに紹介した3つのアプローチを比較してどの程度差が出るかを示す。具体的実装
問題設定
実際の製品の画像を使って結果を考察するのは権利の関係から行うことができないので問題がかなり簡単になってしまうが,mnistの手書き数字のうち1を正常画像、1以外の数字を異常画像として上記3つのアプローチを比較する。
データの整理
コードの部分を全てコピーすれば動く形で紹介する。
kerasで実装を行う。
まずもろもろimportしてデータダウンロードする。import numpy as np import seaborn as sns import matplotlib.pyplot as plt from tensorflow.keras.datasets import mnist from keras import layers from keras import models from keras import optimizers (train_images, train_labels), (test_images, test_labels) = mnist.load_data()データを扱いやすい形式に変換する
train_true = train_images[train_labels==1].reshape(6742,28,28,1)/255#訓練画像(1)は6742枚 test_true = test_images[test_labels==1].reshape(1135,28,28,1)/255#検証の正常画像(1)は1135枚 test_false = test_images[test_labels!=1].reshape(8865,28,28,1)/255#検証の異常画像(1以外)は1032枚mnistのデータセットは0~9まで枚数が均一だと思っていたがバラバラのようだ。
画像は[0,1]の範囲に正規化した。モデルの定義
model1をただのエンコーダデコーダmodel1を定義
ffc = 8#first filter count model1 = models.Sequential() model1.add(layers.Conv2D(ffc,(3,3),padding="same",activation="relu",input_shape = (28,28,1))) model1.add(layers.BatchNormalization()) model1.add(layers.MaxPooling2D((2,2))) model1.add(layers.Conv2D(ffc,(3,3),padding="same",activation="relu")) model1.add(layers.BatchNormalization()) model1.add(layers.MaxPooling2D((2,2))) model1.add(layers.Conv2D(ffc,(3,3),padding="same",activation="relu")) model1.add(layers.BatchNormalization()) model1.add(layers.UpSampling2D()) model1.add(layers.Conv2D(ffc,(3,3),padding="same",activation="relu")) model1.add(layers.BatchNormalization()) model1.add(layers.UpSampling2D()) model1.add(layers.Conv2D(ffc,(3,3),padding="same",activation="relu")) model1.add(layers.BatchNormalization()) model1.add(layers.Conv2D(1,(3,3),padding="same",activation="sigmoid")) model1.compile(loss = "mae",optimizer="adam") model1.summary()ここで畳み込みと畳み込みの間にバッチ正則化をほどこした。
出力層の活性化はsigmoidである。([0,1]に写像するため)
損失関数はMAEで二乗誤差でなく絶対値を使った方が画像生成ではボケづらいなどの利点がある。
同様にmodel2を定義していった。ffc = 8#first filter count model2 = models.Sequential() model2.add(layers.MaxPooling2D((4,4),input_shape = (28,28,1))) model2.add(layers.UpSampling2D()) model2.add(layers.Conv2D(ffc,(3,3),padding="same",activation="relu")) model2.add(layers.BatchNormalization()) model2.add(layers.Conv2D(ffc,(3,3),padding="same",activation="relu")) model2.add(layers.BatchNormalization()) model2.add(layers.UpSampling2D()) model2.add(layers.Conv2D(ffc,(3,3),padding="same",activation="relu")) model2.add(layers.BatchNormalization()) model2.add(layers.Conv2D(ffc,(3,3),padding="same",activation="relu")) model2.add(layers.BatchNormalization()) model2.add(layers.Conv2D(1,(3,3),padding="same",activation="sigmoid")) model2.compile(loss = "mae",optimizer="adam") model2.summary()maxpooling のみを行ってエンコードすることでデコードに計算材料をさいている。
訓練と結果
それでは実際に訓練してみよう。
通常のエンコーダデコーダ
t_acc = np.zeros(50) f_acc = np.zeros(50) for i in range(50): hist = model1.fit(train_true,train_true,steps_per_epoch=10,epochs = 1,verbose=0) true_d = ((test_true - model1.predict(test_true))**2).reshape(1135,28*28).mean(axis=-1) false_d = ((test_false- model1.predict(test_false))**2).reshape(8865,28*28).mean(axis=-1) t_acc[i] = (true_d<=true_d.mean()+3*true_d.std()).sum()/len(true_d) f_acc[i] = (false_d>true_d.mean()+3*true_d.std()).sum()/len(false_d) print("{}週目の学習正常画像の正答率は{:.2f}%で、異常画像の正答率は{:.2f}%です".format(i+1,t_acc[i]*100,f_acc[i]*100)) plt.plot(t_acc) plt.plot(f_acc) plt.show()異常値の導出は損失関数と違い二乗誤差をもちいた。
これを行うとmodel1つまり普通のエンコーダデコーダが訓練する中で正常画像と異常画像をそれぞれどの程度正しく判断できたかの確率の推移を表したグラフが出力される。
閾値を正常画像の$\mu(平均)+3\sigma(標準偏差)$とおいた。以下出力例
青は正常画像を正常と判断する確率の推移でオレンジが異常画像を異常画像と判断するの確率の推移である。
正常画像の平均から上に標準偏差3つ分のところに常に閾値があるので正常画像を正常画像と判断する確率は常に98%程度である。
50epoch程度で十分学習できたようだ。
(最終値は正常画像の正答率が98.68%で、異常画像の正答率は97.13)ノイズ付きエンコーダデコーダ
モデルはmodel1を用いて入力に0中心でscale0.1で学習するサイズと同じサイズのノイズを加えて学習を行う。具体的なコードは以下の通りである。
t_acc = np.zeros(50) f_acc = np.zeros(50) for i in range(50): hist = model1.fit(train_true,train_true+0.1*np.random.normal(size=train_true.shape),steps_per_epoch=10,epochs = 1,verbose=0) true_d = ((test_true - model1.predict(test_true))**2).reshape(1135,28*28).mean(axis=-1) false_d = ((test_false- model1.predict(test_false))**2).reshape(8865,28*28).mean(axis=-1) t_acc[i] = (true_d<=true_d.mean()+3*true_d.std()).sum()/len(true_d) f_acc[i] = (false_d>true_d.mean()+3*true_d.std()).sum()/len(false_d) print("{}週目の学習正常画像の正答率は{:.2f}%で、異常画像の正答率は{:.2f}%です".format(i+1,t_acc[i]*100,f_acc[i]*100)) plt.plot(t_acc) plt.plot(f_acc) plt.show()これを実行すると以下のようなグラフが得られる。
収束がある程度早くなったようだ。
最終値は正常画像の正答率が98.68%で、異常画像の正答率は97.59%であった。超解像的アプローチ
それではmodel2を訓練して結果を見てみよう。
t_acc = np.zeros(50) f_acc = np.zeros(50) for i in range(50): hist = model2.fit(train_true,train_true,steps_per_epoch=10,epochs = 1,verbose=0) true_d = ((test_true - model2.predict(test_true))**2).reshape(1135,28*28).mean(axis=-1) false_d = ((test_false- model2.predict(test_false))**2).reshape(8865,28*28).mean(axis=-1) t_acc[i] = (true_d<=true_d.mean()+3*true_d.std()).sum()/len(true_d) f_acc[i] = (false_d>true_d.mean()+3*true_d.std()).sum()/len(false_d) print("{}週目の学習正常画像の正答率は{:.2f}%で、異常画像の正答率は{:.2f}%です".format(i+1,t_acc[i]*100,f_acc[i]*100)) plt.plot(t_acc) plt.plot(f_acc) plt.show()結果グラフ
想像以上にだめなモデルであった。
最終値も収束していなさそうだが正常正答率が98.59%で、異常画像の正答率は84.85%であった。結論
手書き文字の1を見て1とそれ以外を区別していったがこの問題の場合ノイズを加えるのが効果的であることがわかった。それはこのノイズを加えるという操作で1は7に見えたり9に見えたりするのでそれを1に戻すのに慣れたモデルが精度向上をするのはかなり目に見えている。
つまり異常の種類がわかっていればその種類の異常を付け足すような変換をしてそれを戻すという訓練を入れるとAuto Encoder の性能は非常に高くなると考えられる。今回のデータセットでおすすめした超解像的アプローチがあまり効果を得なかったが、実際の工業製品のシワや傷を検知する場合解像度を落としてシワや傷を一度見えなくしてから復元するというアプローチが効果的なケースもあるので、対象となる問題を見ながら使うモデルを変えていくといいだろう。
- 投稿日:2020-06-04T13:45:50+09:00
tensorflowのインポートエラー
エラー内容
Using TensorFlow backend. Traceback (most recent call last): File "C:\Python37\lib\site-packages\tensorflow\python\pywrap_tensorflow.py", line 58, in <module> from tensorflow.python.pywrap_tensorflow_internal import * File "C:\Python37\lib\site-packages\tensorflow\python\pywrap_tensorflow_internal.py", line 28, in <module> _pywrap_tensorflow_internal = swig_import_helper() File "C:\Python37\lib\site-packages\tensorflow\python\pywrap_tensorflow_internal.py", line 24, in swig_import_helper _mod = imp.load_module('_pywrap_tensorflow_internal', fp, pathname, description) File "C:\Python37\lib\imp.py", line 242, in load_module return load_dynamic(name, filename, file) File "C:\Python37\lib\imp.py", line 342, in load_dynamic return _load(spec) ImportError: DLL load failed: 指定されたモジュールが見つかりません。解決方法
tensorflowをダウングレードすればOK。pip install tensorflow==2.0.0こちらを参考にしました:https://github.com/tensorflow/tensorflow/issues/22512
英語のエラーメッセージだと、
ImportError: DLL load failed: The specified module could not be found.
になるみたいです。
- 投稿日:2020-06-04T08:57:47+09:00
kerasの環境設定とtensorflow1.xのバージョンの問題について(2020.6現在)
環境:macOS catalina, pipenv, pyenv, vs code
Kerasの昔のサンプルコードを試そうと思って、詰まったのでメモ。
https://github.com/keras-team/keras/blob/master/examples/mnist_mlp.py
最近、kerasを始めた方だと、環境構築の情報やkerasのサンプルコードが以前のままになっているケースがあるので要注意です。以前のKeras(TensolFlow1.x)
kerasは、2019年10月以前、Tensorflow1.xをバックグラウンドにして動いており、少し前のkerasのimportのコードは下記のような記述になっています。
pythonimport kerasこの記述でimportするためには、KerasとTensolflow1.x(最終盤は1.15)の両方をインストールする必要がありました。
consolepip install tensorflow==1.15 pip install keras # pipenvを使っている方は、pip->pipenvに。とする必要があり。
しかも、python 3.8
だとtensorflow 1.x
がうまく動かないことがあり、python3.6
にダウングレードする必要がありました。そうするとpyenv
でpython3.6
をインストールした上で、pipenv
で別な仮想環境を作る必要があり、かなり面倒くさいです。簡単な解決方法
googleのcolaboratoryを使うと、すでにkerasのセットアップがされていいます。下記のコードを前にインサートするだけでOK。
colaboratory%tensorflow_version 1.x現在のKeras(tensorFlow 2.0以降)
Kerasは、現在、Tensorflow2.xの中に統合されたため、tensorflowの最新版2.xをインストールするだけで良いようです。
TensorFlow 2.0.0 リリースノート
http://tensorflow.classcat.com/2019/10/01/tensorflow-2-0-0-release-note/Keras インストールについて
https://keras.io/ja/#_2consolesudo pip install keras
だけでOK。その場合、
consoleimport keras
↓
consoleimport tensolflow.keras
と表記を変える必要があります。
layer関係の表記も、下記のように少し整理されているようです。
モジュールのimportも同様に、pythonfrom keras.models import Sequential, Model, load_model from keras.layers.convolutional import Conv2D, MaxPooling2D from keras.layers.core import Dense, Dropout, Activation, Flatten from keras.layers.pooling import GlobalAveragePooling2D from keras.callbacks import EarlyStopping, ReduceLROnPlateau from keras.preprocessing.image import ImageDataGenerator↓
pythonfrom tensorflow.keras.models import Sequential, Model, load_model from tensorflow.keras.layers import Conv2D, MaxPooling2D from tensorflow.keras.layers import Dense, Dropout, Flatten from tensorflow.keras.layers import GlobalAveragePooling2D from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau from tensorflow.keras.preprocessing.image import ImageDataGeneratorこれで、すっきり。
- 投稿日:2020-06-04T08:57:47+09:00
kerasの環境設定とtensorflow1.xのバージョンの問題について
環境:macOS catalina, pipenv, pyenv, vs code
Kerasの昔のサンプルコードを試そうと思って、詰まったのでメモ。
https://github.com/keras-team/keras/blob/master/examples/mnist_mlp.py
最近、kerasを始めた方だと、環境構築の情報やkerasの基本概念の說明用のサンプルコードが以前のままになっているケースがあるので要注意です。以前のKeras(TensolFlow1.x)
kerasは、以前、Tensorflow1.xをバックグラウンドにしてい動いており、
少し前のkerasのimportのコードは下記のような記述になっています。pythonimport kerasこの記述でimportするためには、KerasとTensolflow1.x(最終盤は1.15)の両方をインストールする必要がありました。
consolepip install tensorflow==1.15 pip install keras # pipenvを使っている方は、pip->pipenvに。とする必要があり。
しかも、python 3.8
だとtensorflow 1.x
がうまく動かないことがあり、python3.6
にダウングレードする必要がありました。そうするとpyenv
でpython3.6
をインストールした上で、pipenv
で別な仮想環境を作る必要があり、かなり面倒くさいです。簡単な解決方法
googleのcolaboratoryを使うと、すでにkerasのセットアップがされていいます。下記のコードを前にインサートするだけでOK。
colaboratory%tensorflow_version 1.x現在のKeras(tensorFlow 2.0以降)
Kerasは、現在、Tensorflow2.xの中に統合されたため、tensorflowの最新版2.xをインストールするだけで良いようです。
TensorFlow 2.0.0 リリースノート
http://tensorflow.classcat.com/2019/10/01/tensorflow-2-0-0-release-note/Keras インストールについて
https://keras.io/ja/#_2consolesudo pip install keras
だけでOK。その場合、
consoleimport keras
↓
consoleimport tensolflow.keras
と表記を変える必要があります。
モジュールのimportも同様に、pythonfrom keras.models import Sequential from keras.layers import Dense, Dropout, Flatten from keras.layers import Conv2D, MaxPooling2D↓
pythonfrom tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Dropout, Flatten from tensorflow.keras.layers import Conv2D, MaxPooling2Dこれで、すっきり。