0

I want to draw BILSTM neural network architecture in latex as shown in picture. Can someone help me?

enter image description here

5
  • 1
    Here is some inspiration: tex.stackexchange.com/questions/228724 Commented Sep 26, 2020 at 14:24
  • What did you try so far? Commented Sep 26, 2020 at 14:24
  • @ Oleg Lobachev I don't know how should I code for that in latex.
    – negin
    Commented Sep 26, 2020 at 14:27
  • @negin -- please have look if the answer meets your requirement
    – js bibra
    Commented Sep 28, 2020 at 1:38
  • @ js bibra Thanks for your help.
    – negin
    Commented Sep 28, 2020 at 14:48

2 Answers 2

4

Take a look at this sample.

enter image description here

\documentclass{standalone}
\usepackage{tikz}
\usepackage{expl3}
\usepackage{amsmath, amssymb}
\usepackage{xcolor}

\usetikzlibrary{arrows}

\begin{document}

% styles
\tikzset{
    circlenode/.style={
        circle,
        draw,
        minimum width=1.2cm
    },
    lstmarrow/.style={
        -latex,
        color=green
    },
    textnode/.style={
        anchor=west,
        xshift=-0.8cm
    }
}

\ExplSyntaxOn

% number of time steps
\int_new:N \l_step_int
\int_set:Nn \l_step_int {3}

% x spacing and y spacing
\fp_new:N \l_x_space_fp
\fp_set:Nn \l_x_space_fp {2.5}
\fp_new:N \l_y_space_fp
\fp_set:Nn \l_y_space_fp {2.0}

% LSTM time step offset function
\cs_set:Npn \get_lstm_time:n #1 {
    \int_set:Nn \l_tmpa_int {#1 - 2}
    \int_compare:nNnTF {\l_tmpa_int} = {0} {
        % expands to nothing if the time step is 0
    }{
        \int_compare:nNnTF {\l_tmpa_int} > {0} {
            % show plus sign if greater than 0
            +\int_use:N \l_tmpa_int
        } {
            \int_use:N \l_tmpa_int
        }
    }
}

% LSTM input/output node function
\cs_set:Npn \get_lstm_io:nn #1#2 {
    $
    % add ellipsis
    \int_compare:nNnT {#2} = {1} {
        \cdots
    }
    #1 \c_math_subscript_token {t \get_lstm_time:n {#2}}
    % add ellipsis
    \int_compare:nNnT {#2} = {\l_step_int} {
        \cdots
    }
    $
}

\newcommand{\drawlstm}{
    % append nodes
    \int_step_inline:nn {\l_step_int} {
        % outputs
        \node (o##1) at (\fp_eval:n {##1 * \l_x_space_fp}, 0.0) 
        {\get_lstm_io:nn {y} {##1}};
        % backward layer
        \node[circlenode] (b##1) 
        at (\fp_eval:n {##1 * \l_x_space_fp}, \fp_eval:n {-1 * \l_y_space_fp}) 
        {$\overleftarrow{h\c_math_subscript_token {t \get_lstm_time:n {##1}}}$};
        % forward layer
        \node[circlenode] (f##1) 
        at (\fp_eval:n {##1 * \l_x_space_fp}, \fp_eval:n {-2 * \l_y_space_fp}) 
        {$\overrightarrow{h\c_math_subscript_token {t \get_lstm_time:n {##1}}}$};
        % inputs
        \node (i##1) at (\fp_eval:n {##1 * \l_x_space_fp}, \fp_eval:n {-3 * \l_y_space_fp}) 
        {\get_lstm_io:nn {x} {##1}};
    }
    % draw arrows
    \int_step_inline:nn {\l_step_int - 1} {
        \draw[lstmarrow] (b\int_eval:n {##1 + 1})--(b##1);
        \draw[lstmarrow] (f##1)--(f\int_eval:n {##1 + 1});
    }
    \int_step_inline:nn {\l_step_int} {
        % modify bend left value, if necessary
        \path[lstmarrow] (i##1) edge[bend~left=50] node {} (b##1);
        % modify bend right value, if necessary
        \path[lstmarrow] (f##1) edge[bend~right=50] node {} (o##1);
        \draw[lstmarrow] (i##1)--(f##1);
        \draw[lstmarrow] (b##1)--(o##1);
    }
    % draw edge arrows
    \draw[lstmarrow] (b1)--(0, \fp_eval:n {-1 * \l_y_space_fp});
    \draw[lstmarrow] (\fp_eval:n {(\l_step_int + 1) * \l_x_space_fp}, \fp_eval:n {-1 * \l_y_space_fp})--(b\int_use:N\l_step_int);
    \draw[lstmarrow] (0, \fp_eval:n {-2 * \l_y_space_fp})--(f1);
    \draw[lstmarrow] (f\int_use:N\l_step_int)--(\fp_eval:n {(\l_step_int + 1) * \l_x_space_fp}, \fp_eval:n {-2 * \l_y_space_fp});
    % draw text nodes
    \node[textnode] at (\fp_eval:n {-1 * \l_x_space_fp}, 0)
    {Outputs};
    \node[textnode] at (\fp_eval:n {-1 * \l_x_space_fp}, \fp_eval:n {-1 * \l_y_space_fp})
    {Backward~Layer};
    \node[textnode] at (\fp_eval:n {-1 * \l_x_space_fp}, \fp_eval:n {-2 * \l_y_space_fp})
    {Forward~Layer};
    \node[textnode] at (\fp_eval:n {-1 * \l_x_space_fp}, \fp_eval:n {-3 * \l_y_space_fp})
    {Inputs};
}


\ExplSyntaxOff

\begin{tikzpicture}
\drawlstm
\end{tikzpicture}
\end{document}

By changing \l_step_int, you can generate a even bigger illustration:

enter image description here

Have fun!

3
  • @ Realy thanks.
    – negin
    Commented Sep 27, 2020 at 8:50
  • @AlanXiang arrow horizontal row1 last column wrong direction
    – js bibra
    Commented Sep 28, 2020 at 0:55
  • @jsbibra Updated.
    – Alan Xiang
    Commented Sep 28, 2020 at 14:11
1

Easier for me with matrix of nodes(circular) -- the code can off course be reduced further with a loop for the edges

enter image description here

\documentclass[tikz, margin=3mm]{standalone}
\usetikzlibrary{positioning,calc}
\usetikzlibrary {shapes,matrix}

    \begin{document}
    \begin{tikzpicture}[
    terminal/.style={
        circle,
        minimum size=1.5cm,
        very thick,
        draw=blue,
        anchor=center,
    },
    ass/.style={
        ->,>=stealth,line width=2pt, green!50!black
    },
    bigass/.style={
        ass,out=170,in=190,looseness=1.2,
    },
    bigasss/.style={
        ass,out=10,in=350,looseness=1.2,
    },
    ]
    \matrix[row sep=1cm,column sep=2cm] {%
        %Zeroth row:
    \node[] (s00) {Outputs};&   \node [](s01) {$\ldots{y_{t-1}}$};  &\node [](s02) 
     {$\ldots{y_{t}}$}; &\node [](s03) {$\ldots{y_{t+1}}$}; &\node [](s04) {}; \\
        % First row:
    \node[] (s10) {Backward Layer};&    \node [terminal](s11) {$\overleftarrow{h_{t- 
   1}}$};   &\node [terminal](s12) {$\overleftarrow{h_{t}}$}; &\node [terminal](s13) 
     {$\overleftarrow{h_{t+1}}$}; &\node [](s14) {};\\
        % Second row:
    \node[] (s20) {Forward Layer};& \node [terminal](s21) {$\overrightarrow{h_{t 
    -1}}$}; & \node [terminal](s22) {$\overrightarrow{h_{t}}$};&\node [terminal](s23) 
        {$\overrightarrow{h_{t+1}}$};&\node [](s24) {};\\
        %Third row:
    \node[] (s30) {Inputs};&    \node [](s31) {$\ldots{x_{t-1}}$};  &\node [](s32) 
     {$\ldots{x_{t}}$}; &\node [](s33) {$\ldots{x_{t+1}}$}; &\node [](s34) {};\\
    };
    \draw   (s14) edge[ass] (s13);
    \draw   (s13) edge[ass] (s12);
    \draw   (s12) edge[ass] (s11);
    \draw   (s11) edge[ass] (s10);
    \draw   (s20) edge[ass] (s21);
    \draw   (s21) edge[ass] (s22);
    \draw   (s22) edge[ass] (s23);
    \draw   (s23) edge[ass] (s24);
    \draw   (s11) edge[ass] (s01);
    \draw   (s12) edge[ass] (s02);
    \draw   (s13) edge[ass] (s03);
    \draw   (s31) edge[ass] (s21);
    \draw   (s32) edge[ass] (s22);
    \draw   (s33) edge[ass] (s23);
    \draw   (s31.north west) edge[bigass] (s11.south west);
    \draw   (s32.north west) edge[bigass] (s12.south west);
    \draw   (s33.north west) edge[bigass] (s13.south west);
    \draw   (s23.north east) edge[bigasss] (s03.south east);
    \draw   (s22.north east) edge[bigasss] (s02.south east);
    \draw   (s21.north east) edge[bigasss] (s01.south east);
    
    \end{tikzpicture}
    \end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .