TransWikia.com

How to draw BiLSTM neural network in latex?

TeX - LaTeX Asked by negin on December 9, 2020

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

enter image description here

2 Answers

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{hc_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{hc_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] (bint_eval:n {##1 + 1})--(b##1);
        draw[lstmarrow] (f##1)--(fint_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})--(bint_use:Nl_step_int);
    draw[lstmarrow] (0, fp_eval:n {-2 * l_y_space_fp})--(f1);
    draw[lstmarrow] (fint_use:Nl_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!

Answered by Alan Xiang on December 9, 2020

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}

Answered by js bibra on December 9, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP