TeXでニューラルネットワークのネットワーク構成図を描画する方法


$\TeX$でニューラルネットワークのネットワーク構成図を描画する方法についてまとめたいと思います。

概要

TikZと呼ばれる$\TeX$用の描画パッケージを用いて描画します。
ベクター画像として描画されるため、拡大縮小による図の乱れが発生せず、図内にある文字がコピペ可能になるという利点があります。
また、相対位置による位置の指定やforeachが使えるため (具体例は以下の描画例Tikz の foreach を使う練習 - Qiita参照)、描画処理を効率的に記述できます。

描画例

双方向LSTM (Bi-directional LSTM / LSTMについてはわかるLSTM ~ 最近の動向と共に - Qiita参照) のネットワーク構成図を描画してみたいと思います。

コード

TODO部の指示に従って書き換えを行い、コンパイルします。

% 古いパッケージや記法のチェック用
% (コンパイル時に古いパッケージや記法を『Package nag Warning:』で始まる警告の形で指摘してくれるので, この警告が少なくなるように記述すると良い)
\RequirePackage[l2tabu, orthodox]{nag}

% latexコマンドでのコンパイル用
% TODO: 欧文の場合, 以下のコメントアウトを解除
% \documentclass{article}

% platexコマンドでのコンパイル用
% TODO: 和文の場合, 以下のコメントアウトを解除
% \documentclass[dvipdfmx]{jsarticle}

% ネットワーク構成図描画用
\usepackage{tikz}

% 省略記号
\def\ellipsis{$\cdots$}

\begin{document}
% ネットワーク構成図
\begin{figure}[tbp]
\centering

% ノード間の距離
\def\nodeDistance{1.1cm}

% 曲線の始点の角度 (°)
\def\angleStartCurve{360 * 9 / 56}

\begin{tikzpicture}[shorten >= 1pt, ->, node distance=\nodeDistance]
% 変数や省略部のスタイル
\tikzset{var/.style={minimum size=15pt}};

% ノードのスタイル
\tikzset{neuron/.style={var, draw, circle}};

% 入力部を描画
\node[var] (I-n) {$x_n$};
\node[var, left of=I-n] (I-3) {\ellipsis};
\foreach \i/\j in {2/3, 1/2}
{
    \node[var, left of=I-\j] (I-\i) {$x_\i$};
}

% 省略部のノードや変数を描画
\foreach \f/\t in {I/F-LSTM, F-LSTM/B-LSTM, B-LSTM/L-S}
{
    \node[var, above of=\f-3] (\t-3) {\ellipsis};
}
\node[var, above of=L-S-3] (O-3) {\ellipsis};

\foreach \n in {1, 2, n}
{
    % 表示されるノードや変数を描画
    \foreach \o/\f/\t in {neuron/I/F-LSTM, neuron/F-LSTM/B-LSTM, neuron/B-LSTM/L-S}
    {
        \node[\o, above of=\f-\n] (\t-\n) {};
    }
    \node[var, above of=L-S-\n] (O-\n) {$y_\n$};

    % 縦方向の線を描画
    \draw (I-\n) to [out=\angleStartCurve, in=360 - \angleStartCurve] (B-LSTM-\n);
    \draw (F-LSTM-\n) to [out=180 - \angleStartCurve, in=180 + \angleStartCurve] (L-S-\n);
    \foreach \f/\t in {I/F-LSTM, B-LSTM/L-S, L-S/O}
    {
        \path (\f-\n) edge (\t-\n);
    }
}

% 横方向の線を描画
\foreach \i/\j in {1/2, 2/3, 3/n}
{
    \foreach \n/\f/\t in {F-LSTM/\i/\j, B-LSTM/\j/\i}
    {
        \path (\n-\f) edge (\n-\t);
    }
}

% 注釈を描画
\foreach \f/\n in {I/Input, B-LSTM/Backward LSTM, F-LSTM/Foward LSTM, L-S/Linear, O/Output}
{
    \node[node distance=2 * \nodeDistance and \nodeDistance, text width=9em, text centered, right of=\f-n] (A-\f) {\n};
}
\end{tikzpicture}
\caption{Bi-directional LSTM}
\label{Fig:Bi-directional LSTM}
\end{figure}
\end{document}

コンパイル結果

参考文献