【おてがる開発環境をつくろう】さいきょうのえでぃた VS Code
ルーキー開発者が最強のえでぃたを装備した
おてがる開発環境シリーズの最後は、「VS Code」です
今までの、Docker、Python、Jupyter 全てにおいて、VS Code で便利に使うことができます
【おてがる開発環境をつくろう】
1.まずは Docker Desktop インストール
2.Docker であそぶ Python 入りのコンテナつくる
3.コンテナで Jupyter Lab 環境
4.さいきょうのえでぃた VS Code ←今ココ
5.VS Code はあれもこれもエクステンション!!
VS Code のオススメな理由
・エディタなので、当然ながら Python との相性は抜群
・ターミナルがついてる
・リモートSSH/コンテナがかなり便利
- パスワードでも、鍵認証でも
- ssh先のファイルを VSCodeエディタで開けるだとっっ!!!
- コンテナ内のエクスプローラも楽ちん
・gitを GUI でも CLI でも
・Azure 機能との連携も豊富
VS Code をインストールしよう
ここからダウンロード
azure.microsoft.com
MS製ですが、もちろん MAC版も用意されています
インストールしたら、VS Code 画面配置でよく使うところをみてみましょう
VS Code の設定は初期のままでも結構いける
昔のエディタは、デフォルトのままでは使い物にならなくて、初期設定から結構いじる必要がありましたが
(主に文字サイズとかショートカットとか)
ちなみに固有のセッティングはここから変更できますが、ほとんどさわったことないです
設定やプラグインなど導入した場合に、自宅用のデスクトップとノートPC、Windows と MAC 間で設定を同期することもできます
プラグイン設定も同期できるのは、超便利
Githubアカウント経由で同期される
この辺はさすが MSさん
ワークスペースを作る
ワークスペースはおおざっぱにいうと、作業フォルダのショートカット集をつくるみたいな感じです
VS Code のエクスプローラをより便利に使いこなす為には、まずはじめにワークスペースを作っておくべき
プロジェクトごとや、やりたいこと別にワークスペースごとに作ってくようなイメージです
ターミナルを開く
「Ctrl + @」でターミナルをトグルできます
また、VS Code の超便利な機能(パート2)として、指定のディレクトリでターミナルを開くってのがあります
プログラミングしていて、このファイルを実行したいって時に
ターミナル開いて、ディレクトリ移動して、実行ってメンドウな経験したことないでしょうか
開きたいファイルやディレクトリを右クリックして、「Open in integrated Terminal」
よく使うショートカットコマンド
Ctrl+@:ターミナルをトグル
Ctrl+Shift+p:コマンドパレットを開く
【おてがる開発環境をつくろう】Jupyter Labで Python してみる
機械学習ではド定番というか、大前提?な Jupyter notebook の環境をDocker コンテナ上に Python と一緒に作ってしまいましょう
【おてがる開発環境をつくろう】
1.まずは Docker Desktop インストール
2.Docker であそぶ Python 入りのコンテナつくる
3.コンテナで Jupyter Lab 環境 ←今ココ
4.さいきょうのえでぃた VS Code
Jupyter Lab の使いみち
jupyter.org
AI/MLはド定番というか、必須な代物ですが、それ以外の Python コーディングでも有用だと思います
プログラム全体を実行しないで、セルといわれる任意の行単位ごとに実行して即結果を出力できます
プログラム全体を実行しなくてよいので、Python初心者がコードの出力結果を確認できるのが便利、それでいて変数の結果などを使い回せる
・REST APIや、DBへのデータ出し入れなど
・ちょっとした変更をすぐその場で確認!
・最終的には、.py の実行ファイルを作る
Jupyter Lab 入りのコンテナを作る(Python 3.9.4)
Jupyter Lab は Python モジュールとして提供されていて、pip install jupyterlab でインストールできます
jupyterlabモジュール込みのコンテナを作ってみましょう
# Python 3.9.4-slimをベースに FROM python:3.9.4-slim # おまじない RUN apt update -y RUN pip install -U pip # Jupyterモジュール RUN pip install jupyterlab WORKDIR /home # デフォルトの jupyterlab 実行コマンド CMD ["jupyter", "lab", "--ip=0.0.0.0", "--allow-root", "--LabApp.token=''"]
コンテナイメージ作成とコンテナの起動
- v で指定している ホスト側のマウントポイントは任意に変更しましょう
$ docker build . -t python:3.9.4-jupyter $ docker run --rm -it -p 1234:8888 -v "D:\work\sample\app:/home/app" --name python-jupyter python:3.9.4-jupyter
【おてがる開発環境をつくろう】Docker であそぶ Python 入りのコンテナつくる
【おてがる開発環境をつくろう】
1.まずは Docker Desktop インストール
2.Docker であそぶ Python 入りのコンテナつくる ←今ココ
3.コンテナで Jupyter Lab 環境
4.さいきょうのえでぃた VS Code
あくまで今回の目的は、マイクロサービスを作るとかではなく
「開発環境をつくる!」です
Dockerコンテナがなんなのか、とか、アーキテクチャみたいなことは
他のサイトにおまかせして、あくまで使い方に終始していきます
コンテナをダウンロード
まずは、Dockerhub のアカウントを用意しておいて
https://hub.docker.com/
Docker ログインする
$ docker login
Dockerhub上のコンテナを、Powershell などで docker pull コマンドでダウンロードする
$ docker pull <container名>:<tag>
最近はだいたいアプリは公式が Dockerhub上にコンテナを用意していたりするので、Dockerhub をググるクセをつけておくと何かと便利、「dockerhub “ほしいもの”」でググると良いでしょう
例)docker ubuntu, docker splunkなどなど
自作コンテナを作ろう
dockerfile 作成
用途によってベースのコンテナを決めて、モジュールを加えてカスタマイズしていきます
例えば Python なら Dockerhub に用意されている tag ごとにインストールされているモジュールが違うので、ベースのコンテナを決めて追加の Pythonモジュールやパッケージインストール、設定ファイルなどをコピーしたりしてをコンテナを作っていきます
その設計図が dockerfile です
dockerfile という名前(拡張子なし)のファイルになります
dockerfile のサンプル(Dateコマンドが出力されるだけ)
# From: ベースになるコンテナを指定、tagなしだとlatestが自動的に選択される(ちゃんと指定しよう) FROM python:3.9.4-slim # WORKDIR ディレクトリ作って、そこに移動して以降のコマンド実行 WORKDIR /oreore # RUN:の後にOS上で実行するコマンド RUN apt update -y # CMD: コンテナ起動時に実行されるコマンド CMD ["date"]
コンテナイメージのビルド
dockerfile と同じ場所にて
docker build . -t <container名>
を実行して dockerfile を元にコンテナイメージを作ります
(例)
$ docker build . –t test_container
コンテナイメージの確認
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE test_container latest 80afafe350ea 55 seconds ago 132MB
コンテナの起動
コンテナを起動は
docker run
(場所はどこでもよい)
上で作った test_container を実行してみます
date コマンド出力結果だけが表示されます
$ docker run test_container .... Sat May 22 13:16:33 UTC 2021
よく使うオプション
--rm:コンテナ終了とともにコンテナを消す
-it:コンテナの入出力に接続
-p:外部からアクセスされるポート番号:コンテナ側のポート番号を指定
-v:ディレクトリのマウント設定、ローカルのディレクトリ:マウントポイント
-name :コンテナ名を指定
コンテナの状況を確認
docker ps コマンドで
起動中のコンテナ確認
$ docker ps
起動していないコンテナも含めて確認
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 361bf7a7ffb9 test_container "date" About an hour ago Exited (0) About an hour ago ecstatic_solomon
検証するときや、開発環境用には、 “--rm” オプションをつけよう
作り始めはバンバン修正しながら作っていくのでコンテナ終了してもゴミが残らないように
コンテナ実行
$ docker run --rm <コンテナイメージ名>
コンテナ実行と同時にコンテナに入る(bashがある場合)
画面表示のオプション-it と、実行シェル /bin/bash を指定
$ docker run --rm –it <コンテナイメージ名> /bin/bash
ローカルの Pythonファイルを編集
おてがる開発環境を作る上での目玉の手法です
Docker のホストマウントを使います
Pythonファイルはローカルのエディタで編集しつつ
実行するのは、コンテナの中で実行
こうすることで、開発環境を作っては、FTPやSCPでファイルを送ったりSSHして vi みたいな手間が全部無くなります
コンテナからローカルフォルダをマウント方法
オプション -v "ローカルフォルダ : コンテナ内のマウントポイント"
(例)
$ docker run --rm -it -v “C:\work\sample\app\:/home/app" --name python394 test_container /bin/sh
これで準備完了
あとは、
・ローカルのエディタで python ファイルを編集
・Docker コンテナは好きなバージョンの Python 環境を用意して、実行して確認
開発環境をいつでも潰して、作りなおしたり、持ち運びができます
コンテナイメージの更新
コンテナでは基本的に起動後はコンテナ内のファイルは固定(変更しない)、いつ起動しても同じ環境を再現できるイミュータブル性を確保します
なので、コンテナにパッケージやモジュールを追加したい場合は、dockerfile を修正してコンテナを再作成しよう
おまけ
本番環境でコンテナを作るのときのセキュリティについて
#ベースコンテナのtag(バージョン)はちゃんと指定することFROM python:x.x.x
# 設定ファイルの書き込み権限をなくすRUN chmod a-w /etc
# シェルを実行させないRUN rm –rf /bin/*
# ユーザ指定する(デフォルトは root になる)USER appuser
【おてがる開発環境をつくろう】まずは Docker Desktop インストール
プログラミング言語いれたら、得てしてアレもコレも追加モジュールいれてなんだか PC自体おかしくなって、全部消してやりなおした経験はでしょうか?
開発環境のお作法なんてのは、本職で毎日さわってないと、すぐ忘れる。。。
忘れたってええじゃない、開発環境をつくること自体が目的になってはいけません
新品のPCでもソッコーで以前までと同じ開発環境をつくれるような、「おてがる」な開発環境を作る
きっかけは AI の勉強をしていく上での勉強用に class="st" Python 環境を作って触ってきました
Python 環境もいろいろ実現方法があり
・Windows に Python をそのままインストール
・Windows に Anaconda をインストールして、仮想環境上に Python
・Linux系 OSで Python インストール
・pyenv を使う
・Docker で python 入りコンテナを使う
すでに 5種類。。。。色々試していくうちに、どれが正しいのかわからないまま、ずいぶんぐちゃぐちゃのボロボロになりました
結果、たどり着いた開発環境を自分の備忘録も含めまとめていきます
こんな感じでまとめていこうかと
【おてがる開発環境をつくろう】
1.まずは Docker Desktop インストール←今ココ
2.Docker であそぶ Python 入りのコンテナつくる
3.コンテナで Jupyter Lab 環境
4.さいきょうのえでぃた VS Code
まずは今となっては、開発者の方にとっては常識になってるかと思う Docker から
なんでコンテナ使うのか
壊れてもすぐ作り治せる
別のPCでも共通環境をソッコーで準備
自分のPCを汚さない、開発言語はちょっとしたバージョン変更、ライブラリ依存が大変
WSL 2 をセットアップ
Windows10 で標準に入っている Hyper-Vだけでも、DockerDesktop はインストールできますが、WSL で Ubuntu を用意しておくと何かと便利なので、一緒に準備しておく
https://docs.microsoft.com/ja-jp/windows/wsl/install-win10
※バージョン 1903 以降、ビルド 18362 以上
このバージョンアップに結構時間がかかった
Hyper-Vを有効にする
Powershell で
> dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
> dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
これが実行出来ない場合は、ビルドを確認
> wsl --set-default-version 2
Ubuntu と Windows Terminal を準備
Microsoft Storeでインストール
- Windows Terminal
- Ubuntu
※MSのアカウントが必要
Windows Terminal で WSL の Ubuntu が実行できるようになると、Windows上でも Linuxコマンドが実行できるようになるので何かと便利
Docker Desktop のインストール
ここでようやく Docker Desktop をインストール
ダウンロードして、インストール(5分くらい)
https://www.docker.com/products/docker-desktop
インストール後、一度ログアウトする
まずは dockerhub アカウントを作ろう
dockerhubサイト
https://hub.docker.com/
Windows Terminal を開いて dockerhubアカウントを config 登録しておく
$ docker login
はじめてのコンテナ起動
こんな感じでとりあえず流してみる
$ docker version $ docker pull hello-world # dockerhub からコンテナダウンロード $ docker ps # 起動しているコンテナの状況確認 $ docker ps –a # 起動していないコンテナも確認 $ docker rm <CONTAINER ID> #コンテナ削除
実行例)
$ docker run hello-world Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/
よくつかう Dockerコマンド
・起動中のコンテナを表示
$ docker ps
・コンテナイメージを表示
$ docker images
・コンテナ起動
$ docker run
・起動中のコンテナに入る
$ docker exec
E資格対策 で丸暗記した Pythonコード
とうとうこれを堂々と使うことができます
JDLA E資格 2021#1 取得しました
喜びとともに忘れないうちに試験の振り返り第2段
Pythonコード問題は、基本的に穴埋めなので何がやりたいかを理解していれば時間さえかければ答えにたどり着くことはできるわけですが、試験時間もそんなに余裕があるものではないので公式の丸暗記と一緒で、時間短縮には結構大切かも
python コード
順伝播と誤差逆伝播
基本中の基本、コードを書いてると自然と覚えてるもんですが(デバッグもできるし)、いざ4択になると転置とかいるっけ?とか混乱するかも
アフィン変換 順伝播
y = np.dot(x, w) + b
アフィン変換 誤差逆伝播
dx = np.dot(dout, w.T)
dw = np.dot(x.T, dout)
db = np.sum(dout, axis=0)
活性化関数の勾配
シグモイドの勾配
dout = dout * (1.0 - out) * out
dout = (1.0 - y**2)
ReLUの勾配
順伝播で「0」にした部分を覚えておいて、0にする
dout[relu_mask] = 0
損失関数(コスト関数)の勾配
平均二乗誤差の勾配
d = -2 * (t - y) # t: 正解データ、y: 予測データ
交差エントロピーの勾配
delta = 1e-8
dout = -np.mean(t * np.log(y + delta))
交差エントロピー with ソフトマックス
dout = y - t
最適化関数
SDG
モーメント
ネストロフのモーメント
AdaGrad
RMSprop
Adam
バッチノーマライゼーション
これが結構有用で、標準偏差を求める式も一緒に頭に叩き込めます
mu = np.mean(x, axis=0) #平均 xc = x - mu # 今回のミニバッチの平均との差分 var = np.mean(xc**2, axis=0) # 分散 std = np.sqrt(var + 10e-7) # 今回のミニバッチの標準偏差 xn = xc / std # 正規化
CNN の im2col
これは 畳み込み処理の頻出問題のようなので、覚えておいて損はない
for y in range(filter_h): y_max = y + stride*out_h for x in range(filter_w): x_max = x + stride*out_w col[:, :, y, x, :, :] = img[:,:, y:y_max:stride, x:x_max:stride]
特に重要なのはココ
col[:, :, y, x, :, :] = img[:,:, y:y_max:stride, x:x_max:stride]
必要なのは、shape がどうなっているかを意識しておけば、im2col かかわる応用問題にも対応できるようになります
N:バッチサイズ
Ch:入力チャネル
H, W:入力高さ、 横幅
out_H, out_W:出力高さ、横幅
(N, Ch, H, W) ➔ (N*out_H*out_W, C*H*W)
LSTMの重み計算
LSTM覚えておけば、GRUも簡単に連想できます
特徴は、各ゲート分の重みをいっぺんに計算しておいて、各ゲート用にスライスして取り出すところになります
A = np.dot(h_prev, wh) + np.dot(x, wx) + b # 各ゲート用の[N,4H] まとめて計算 # slice f = sigmoid(A[:, :H]) # 忘却ゲート [N,H] i = sigmoid(A[:, 2*H:3*H]) # 入力ゲート [N,H] g = np.tanh(A[:, H:2*H]) o = sigmoid(A[:, 3*H:]) # 出力ゲート [N,H]
おわりに
これからは実践活用のAI構築をやっていこう
KPS へ導入すっぞ!
E資格受けてみまして
合格ラインとかそんなのよくわかってないままに受けてきました
毎回こういうガチな試験を受ける時は人生で最高に勉強したーとか言ってるようなきがするけど、今回もまさしく人生で一番勉強した気がする
手応えは7-8割くらい。。。。(9割以上とる覚悟で受けたので結構凹んでる)
通常は2-3週間くらいで結果らしいので、それまで仕事が手に付きません
(テスト前も手につかないとか言ってたのでどんだけ仕事してないん)
試験内容は、守秘義務やらなんやらで語ることはできませんが
どんなことを中心に覚えておいたか備忘録(また受けることになったとき用)
丸暗記した公式をつらつらと
数式っていうのは、日常生活でみかけることがないので、知らない数式がでると若干パニック(あきらめ)になりますし、公式丸暗記の効果はそのものが選択肢出てきたら時間短縮にもなりますので、何度何度も見直して記憶定着に時間をかけました
丸暗記の労力を減らすため細かい条件とかは一旦抜きで
確率分布
一見ややこしいけど、いろんなところでよく出てくるやつ
対数尤度は特に
ベルヌーイ分布
確率関数:
期待値:𝑝
𝑝 の最尤推定:
負の対数尤度:
マルチヌーイ分布
負の対数尤度:
一変量正規分布の確率密度(平均 μ 、分散 𝜎^2)
ベイズの定理
活性化関数と損失関数の微分
それぞれの関数自体は必須として、微分の式も覚えておいて損なし!
シグモイド関数:
tanh(ハイパボリックタンジェント):
平均二乗誤差:
交差エントロピー誤差:
ソフトマックス交差エントロピー誤差:
GANの最適化
丸暗記の策
覚えなければいけないことはたくさんあるわけですが、この数式というのは中途半端に覚えるとかえって混乱しがちなので丸暗記が得策
Python コードは書くしかない(写経)
【DeepLearning特訓】GAN 敵対的生成ネットワーク
E資格向けの自習アウトプット
自分用メモ
GAN 敵対的生成ネットワークは、2014年にイアン・グッドフェロー氏らが「Generative Adversarial Network」という論文で発表
生成モデルと識別モデルの組み合わせ、敵対させ競い合わせることで精度を上げていく手法
・生成(Generator)モデル:見破られないようなニセモノを作る
・識別(Discriminator)モデル:訓練データを使ってニセモノを見破ろうとする
「偽造犯と警察」とか「怪盗と探偵」とか「ルパンと銭形」とかそんなライバル同士が切磋琢磨していって、結果として騙す側(トリック)巧妙になっていくような関係
GAN のアーキテクチャ
1.ノイズを乱数からサンプリングする
2.Generator で Fakeデータを生成
3.Realデータと Fakeデータを Discriminator に識別させる
4.学習方針
- Generator(生成モデル)は、識別判定のロスが大きくなるように ➔うまく騙せた
- Discriminator(識別モデル)は、識別判定のロスが小さくなるように ➔みやぶった
GAN の目的関数(損失関数)
いつものごとく導出の過程の理解は一旦おいておいて
以下をセットで覚えておく
Generator ネットワーク 𝐺:𝑧→𝑥'
Discriminator ネットワーク 𝐷:𝑥→(0,1)
Discriminator:Realデータ真(1)、Fakeデータ偽(0)の時の、Discriminatorの予測に対する交差エントロピー
見破れてるのか
Generator:Realデータ真(1)、Fakeデータ真(1)の時の、Discriminatorの予測に対する交差エントロピー
うまく騙せてるのか
このあたりは、考えると沼っていくので、実装しながら理解することにする
GAN の種類
DCGAN(Deep Convolutinal GAN):CNNを使う
LAPGAN(Laplacian Pyramid):低解像度と高解像度の画像の差を比較
Conditional GAN:訓練時に教師データのラベル情報を用いて、生成するクラスを指定できる
StarGAN:マルチドメインに適用できるように拡張
この他にもたくさん研究されているらしい
TensorFlow で実装しながら頭を整理
TensorFlow公式に DCGAN のチュートリアルがあったので、こちらで参考に実装してみる
www.tensorflow.org
今回はこのあたりを使う
import tensorflow as tf from tensorflow.keras import layers from tensorflow.keras.datasets import mnist, fashion_mnist import matplotlib.pyplot as plt
データセット
データセットの準備、今回は Fashion MNIST を使ってみる
# データのロード (x_train, t_train), (x_test, t_test) = fashion_mnist.load_data() # 設定 BUFFER_SIZE = x_train.shape[0] # 60000 BATCH_SIZE = 256 x_train = x_train.reshape(BUFFER_SIZE, 28, 28, 1).astype('float32') x_train = (x_train - 127.5) / 127.5 # Normalize [-1, 1] train_dataset = tf.data.Dataset.from_tensor_slices(x_train).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)
どんな画像か確認しておく
fig = plt.figure(figsize=(4,4)) for i in range(16): plt.subplot(4, 4, i+1) plt.imshow(x_train[i, :, :, 0] * 127.5 + 127.5, cmap='gray') plt.axis('off') plt.show()
Generator ネットワーク
ノイズを受け取って、CNN の逆畳み込みで画像を作っていく
# Generator # noise から画像を作る def make_generator_model(): model = tf.keras.Sequential() model.add(layers.Dense(7*7*256, use_bias=False, input_shape=(100,))) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU()) model.add(layers.Reshape((7,7,256))) assert model.output_shape == (None, 7,7,256) # Noneはバッチサイズ model.add(layers.Conv2DTranspose(128, (5,5), strides=1, padding='same', use_bias=False)) assert model.output_shape == (None, 7,7,128) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU()) model.add(layers.Conv2DTranspose(64, (5,5), strides=2, padding='same', use_bias=False)) assert model.output_shape == (None, 14,14,64) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU()) model.add(layers.Conv2DTranspose(1, (5,5), strides=2, padding='same', use_bias=False)) assert model.output_shape == (None, 28,28,1) return model
None はバッチサイズがはいる
generator = make_generator_model() generator.summary()
Model: "sequential_2" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_2 (Dense) (None, 12544) 1254400 _________________________________________________________________ batch_normalization_3 (Batch (None, 12544) 50176 _________________________________________________________________ leaky_re_lu_5 (LeakyReLU) (None, 12544) 0 _________________________________________________________________ reshape_1 (Reshape) (None, 7, 7, 256) 0 _________________________________________________________________ conv2d_transpose_3 (Conv2DTr (None, 7, 7, 128) 819200 _________________________________________________________________ batch_normalization_4 (Batch (None, 7, 7, 128) 512 _________________________________________________________________ leaky_re_lu_6 (LeakyReLU) (None, 7, 7, 128) 0 _________________________________________________________________ conv2d_transpose_4 (Conv2DTr (None, 14, 14, 64) 204800 _________________________________________________________________ batch_normalization_5 (Batch (None, 14, 14, 64) 256 _________________________________________________________________ leaky_re_lu_7 (LeakyReLU) (None, 14, 14, 64) 0 _________________________________________________________________ conv2d_transpose_5 (Conv2DTr (None, 28, 28, 1) 1600 ================================================================= Total params: 2,330,944 Trainable params: 2,305,472 Non-trainable params: 25,472 _________________________________________________________________
試し画像を一枚だけ作ってみる
noise = tf.random.normal([1, 100]) generated_image = generator(noise, training=False) plt.imshow(generated_image[0, :, :, 0], cmap='gray')
学習してないので、当然わけわからん Fake 画像が表示される
Discriminatorネットワーク
CNN で畳み込んで特徴量を抽出していく
# Discriminator # 真の場合には正の数値を、偽の場合は負の数値を返す def make_discriminator_model(): model = tf.keras.Sequential() model.add(layers.Conv2D(64, (5,5), strides=2, padding='same', input_shape=[28,28,1])) model.add(layers.LeakyReLU()) model.add(layers.Dropout(0.3)) model.add(layers.Conv2D(128, (5,5), strides=2, padding='same')) model.add(layers.LeakyReLU()) model.add(layers.Dropout(0.3)) model.add(layers.Flatten()) model.add(layers.Dense(1)) return model
discriminator = make_discriminator_model() discriminator.summary()
Model: "sequential_3" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_2 (Conv2D) (None, 14, 14, 64) 1664 _________________________________________________________________ leaky_re_lu_8 (LeakyReLU) (None, 14, 14, 64) 0 _________________________________________________________________ dropout_2 (Dropout) (None, 14, 14, 64) 0 _________________________________________________________________ conv2d_3 (Conv2D) (None, 7, 7, 128) 204928 _________________________________________________________________ leaky_re_lu_9 (LeakyReLU) (None, 7, 7, 128) 0 _________________________________________________________________ dropout_3 (Dropout) (None, 7, 7, 128) 0 _________________________________________________________________ flatten_1 (Flatten) (None, 6272) 0 _________________________________________________________________ dense_3 (Dense) (None, 1) 6273 ================================================================= Total params: 212,865 Trainable params: 212,865 Non-trainable params: 0 _________________________________________________________________
適当な Fake 画像の適当な特徴量
decision = discriminator(generated_image) decision
<tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[1.2810372]], dtype=float32)>
損失関数とオプティマイザー
【損失関数の考え方】
Generatorでは、fake_loss を Fakeデータを Real と判定できたか(ちゃんと騙せたか)
Discriminatorでは、Realロス と Fakeロス の和
- real_loss は 訓練データを Real 判定できたか
- fake_loss は Fakeデータを Fake 判定できたか(見破ったか)
# 損失関数とオプティマイザー cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True) def discriminator_loss(real_output, fake_output): real_loss = cross_entropy(tf.ones_like(real_output), real_output) fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output) total_loss = real_loss + fake_loss return total_loss def generator_loss(fake_output): return cross_entropy(tf.ones_like(fake_output), fake_output) generator_optimizer = tf.keras.optimizers.Adam(1e-4) discriminator_optimizer = tf.keras.optimizers.Adam(1e-4)
トレーニングループ
def train_step(images): noise = tf.random.normal([BATCH_SIZE, noise_dim]) with tf.GradientTape() as gen_tape, tf.GradientTape() as dis_tape: generated_images = generator(noise, training=True) real_output = discriminator(images, training=True) fake_output = discriminator(generated_images, training=True) dis_loss = discriminator_loss(real_output, fake_output) gen_loss = generator_loss(fake_output) # 勾配の保存 gradients_of_discriminator = dis_tape.gradient(dis_loss, discriminator.trainable_variables) gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables) # パラメータ更新 discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables)) generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables)) # エポック数分のループ def train(dataset, epochs): for epoch in range(epochs): for image_batch in dataset: gen_loss, dis_loss = train_step(image_batch) print('EPOCH:{}, {}, {},'.format(epoch, gen_loss, dis_loss)) generate_and_save_images(generator, epoch+1, seed) # Save the model every 15 epochs if (epoch + 1) % 15 == 0: checkpoint.save(file_prefix = checkpoint_dir) # Fake画像(生成画像)の表示と保存 def generate_and_save_images(model, epoch, test_input): predictions = model(test_input, training=False) fig = plt.figure(figsize=(4,4)) for i in range(predictions.shape[0]): plt.subplot(4, 4, i+1) plt.imshow(predictions[i, :, :, 0] * 127.5 + 127.5, cmap='gray') plt.axis('off') plt.savefig('output/dcgan_image_at_epoch_{:04d}.png'.format(epoch)) plt.show()
# トレーニング設定 EPOCHS = 50 noise_dim = 100 num_examples_to_generate = 16 seed = tf.random.normal([num_examples_to_generate, noise_dim])
トレーニング実行
train(train_dataset, EPOCHS)
エポック 10、エポック 50、エポック 100 のそれぞれの Fake画像
それっぽいものが出来てきています
構造としてはシンプルなのに、オリジナルの画像が作られてくるのすごい
さいごに
構造をざっくり理解するために書いてきましたが、つまるところ Generate された分布と入力されたデータの分布を近づけていくということが重要なようです
(訓練データそのものを作るわけではない)
生成データは実用的実におもしろい、試験が終わったら実装してみたい
これからは強化学習