「convnet-drawer」を使ってGoogle Colaboratory上で手軽にニューラルネットワークの構造を描く方法

<img width="498" alt="nn-draw.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/087786b6-8954-4811-b377-f781f3fe7881.png">

# 「convnet-drawer」とは？
 @yu4u さん作成のニューラルネットワークの構造を良い感じに可視化してくれるソフトです。以前から存在は知っていたのですが、まだ試せていなかったので試してみました。Google Colaboratory（Google Colab）上で動かすと良い感じだったので、手軽に試せるようなNotebookも作成してみました。

　Google Colabに関しての説明は以下ブログ記事を参照して下さい。

[Google Colaboratoryを使えば環境構築不要・無料でPythonの機械学習ができて最高](https://karaage.hatenadiary.jp/entry/2018/03/21/073000)


# ニューラルネットワークの構造を描画する方法
　ここから、「convnet-drawer」をGoogle Colab上で使ってニューラルネットワークを描画する方法を紹介していきます。

　参考にした情報は、 @yu4u さんのソフトのコードと以下の記事です。

[畳み込みニューラルネットワークをKeras風に定義するとアーキテクチャの図をパワーポイントで保存してくれるツールを作った](https://qiita.com/yu4u/items/75ea0e5e1587f10bc014)

　作成したGoogle ColabのNotebookのリンクは以下です。
[convnet_drawer_on_google_colab.ipynb](https://colab.research.google.com/drive/1FEsWfwMz4sYFpWJX8RoSQKpK4fNMR1q2?usp=sharing)

　上記を実行していってもらえば、だいたい分かると思うのですが、一応簡単に説明をしていきます。以降は、Google Colab上で実行する前提です。

　ニューラルネットワークを描画する方法は、大きく2以下の2通りあります。

- 0からモデルを作成する方法
- Kerasで作ったモデルを読み込む方法

　それぞれ説明していきます。
　
## 準備
　「convnet-drawer」をcloneします。オリジナルでなく、私がforkしたものを使用しています。これは、Kerasモデルを読み込む際に、描画できない層をスキップするために少しカスタムしているためです（描画できない層が含まれているKerasモデルを使うとき以外はオリジナルのリポジトリでOKです）。

```sh
!cd /content
!git clone https://github.com/karaage0703/convnet-drawer
%cd convnet-drawer
!git checkout -b custom_keras_util origin/custom_keras_util
```

## 0からモデルを作って可視化する方法
　最初に0からモデルを作って可視化する方法です。

　ライブラリをインポートします。

```python
from convnet_drawer import Model, Conv2D, MaxPooling2D, Flatten, Dense
```

 モデルを作成します。Kerasと同じ要領でモデルを作成します。

 ただ、活性化層（Activation）層やDropout層など対応していない層はエラーになるので、削除するかコメントアウトしましょう。今回はコメントアウトしています。

　モデルはMNISTで使われるような画像認識の小さなモデルです。

```python
model = Model(input_shape=(32, 32, 3))

model.add(Conv2D(32, (3, 3), padding='same'))
# model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3)))
# model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
# model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(128))
# model.add(Activation('relu'))
# model.add(Dropout(0.5))
model.add(Dense(10))
# model.add(Activation('softmax'))
```

モデルをsvg形式で保存して描画しましょう。

```python
model.save_fig("example.svg")
from IPython.display import *
display_svg(SVG('example.svg'))
```

　これで良い感じに描画できます。最高ですね。

<img width="498" alt="nn-draw.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/087786b6-8954-4811-b377-f781f3fe7881.png">

　Matplotlibで描画したい場合は、以下を実行しておいて。

```python
import matplotlib.pyplot as plt
from convnet_drawer import Line, Text

def plot_model(model):
    model.build()
    fig1 = plt.figure(figsize=(5,5),dpi=100)
    ax1 = fig1.add_subplot(111, aspect='equal')
    ax1.axis('off')
    plt.xlim(model.x, model.x + model.width)
    plt.ylim(model.y + model.height, model.y)

    for feature_map in model.feature_maps + model.layers:
        for obj in feature_map.objects:
            if isinstance(obj, Line):
                if obj.dasharray == 1:
                    linestyle = ":"
                elif obj.dasharray == 2:
                    linestyle = "--"
                else:
                    linestyle = "-"
                plt.plot([obj.x1, obj.x2], [obj.y1, obj.y2], color=[c / 255 for c in obj.color], lw=obj.width,
                         linestyle=linestyle)
            elif isinstance(obj, Text):
                ax1.text(obj.x, obj.y, obj.body, horizontalalignment="center", verticalalignment="bottom",
                         size=2 * obj.size / 3, color=[c / 255 for c in obj.color])
```

　描画は以下です。

```python
plot_model(model)
```


![matplotlib.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/028908a6-53f7-4c49-da6a-d9f6d062aefb.png)

　表示されました。サイズとかは適当に自分で調整しましょう。

　漫画風にしたい場合は、以下みたいに実行しましょう。


```python
with plt.xkcd():
  plot_model(model)
```


![manga.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/7047b9d3-3607-18d3-ac63-77c11fa64e6e.png)

　これはかわいいですね。

## Kerasで作ったモデルを読み込む方法（keras-util使用）
　[Qiitaの記事](https://qiita.com/yu4u/items/75ea0e5e1587f10bc014)のコメントで @wakame1367 さんが「convnet-drawer」にKerasモデルを読み込めるPRを出されているのを発見したのでこちらも試してみました。

　Kerasを読み込むソフト(keras_util）とKerasをインポートします。

```python
import keras_util
from tensorflow.python.keras.layers.convolutional import Conv2D, MaxPooling2D
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers.core import Dense, Dropout, Activation, Flatten
```

　Kerasでモデルを作成しましょう。

```python
model = Sequential()

model.add(Conv2D(32, (3, 3), padding='same', input_shape=(32, 32, 3)))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(10))
model.add(Activation('softmax'))

model.compile(optimizer='adam',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
```

　モデルをconvnet-drawerで変換して描画します。

```python
net = keras_util.convert_drawer_model(model)
net.save_fig("sample.svg")
from IPython.display import *
display_svg(SVG('sample.svg'))
```

　Kerasモデルでも描画することができました。対応していない、活性化層やDropout層は勝手にスキップされます。

<img width="498" alt="nn-draw.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/087786b6-8954-4811-b377-f781f3fe7881.png">


# まとめ
　「convnet-drawer」をGoogle Colabで動かす方法を簡単に紹介してみました。自分で作った小さいネットワークを良い感じに可視化してくれるのは嬉しいですね。

　ただ、最新の巨大なニューラルネットワークだと可視化するのは難しく、可視化したところでよくわからないかなとは思います。あくまでポイントポイントの描画に使うのが良いのかなと思います。