37

I'm trying to draw a neural network diagram with tikz. I found this code online:

\begin{figure}[htp]
\centering
\begin{tikzpicture}[
plain/.style={
  draw=none,
  fill=none,
  },
net/.style={
  matrix of nodes,
  nodes={
    draw,
    circle,
    inner sep=8.5pt
    },
  nodes in empty cells,
  column sep=0.6cm,
  row sep=-11pt
  },
>=latex
]
\matrix[net] (mat)
{
|[plain]| \parbox{1cm}{\centering Input\\layer} & |[plain]| \parbox{1cm}{\centering Hidden\\layer} & |[plain]| \parbox{1cm}{\centering Output\\layer} \\
& |[plain]| \\
|[plain]| & \\
& |[plain]| \\
|[plain]| & |[plain]| \\
& & \\
|[plain]| & |[plain]| \\
& |[plain]| \\
|[plain]| & \\
& |[plain]| \\
};
\foreach \ai [count=\mi ]in {2,4,...,10}
  \draw[<-] (mat-\ai-1) -- node[above] {I\mi} +(-1cm,0);
\foreach \ai in {2,4,...,10}
{\foreach \aii in {3,6,9}
  \draw[->] (mat-\ai-1) -- (mat-\aii-2);
}
\foreach \ai in {3,6,9}
  \draw[->] (mat-\ai-2) -- (mat-6-3);
\draw[->] (mat-6-3) -- node[above] {O1} +(1cm,0);
\end{tikzpicture}

\caption{ANN diagram for Speed Sign recognition.}
\label{fig_m_3}
\end{figure}

It produces the following image:

enter image description here

It has 5 input nodes but I want to generalize this drawing by having n nodes in each of the layers. So in input layer, number of node shown will be 4 with vertical '...' in middle, the hidden layer would contain 3 nodes with vertical '...' in middle and output would have 2 nodes with vertical '...' in middle. I want to maintain their conical shape. Something like this:

enter image description here

It is a really bad drawing, sorry about that, one can now imagine how bad I must be with tikz. The dots in middle are actually fully filled, in my drawing they are hollow. Any help or advice would be appreciated.

1

5 Answers 5

37

Here, we a have a festival of \foreach:

\documentclass[border=0.125cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{positioning}
\begin{document}

\tikzset{%
  every neuron/.style={
    circle,
    draw,
    minimum size=1cm
  },
  neuron missing/.style={
    draw=none, 
    scale=4,
    text height=0.333cm,
    execute at begin node=\color{black}$\vdots$
  },
}

\begin{tikzpicture}[x=1.5cm, y=1.5cm, >=stealth]

\foreach \m/\l [count=\y] in {1,2,3,missing,4}
  \node [every neuron/.try, neuron \m/.try] (input-\m) at (0,2.5-\y) {};

\foreach \m [count=\y] in {1,missing,2}
  \node [every neuron/.try, neuron \m/.try ] (hidden-\m) at (2,2-\y*1.25) {};

\foreach \m [count=\y] in {1,missing,2}
  \node [every neuron/.try, neuron \m/.try ] (output-\m) at (4,1.5-\y) {};

\foreach \l [count=\i] in {1,2,3,n}
  \draw [<-] (input-\i) -- ++(-1,0)
    node [above, midway] {$I_\l$};

\foreach \l [count=\i] in {1,n}
  \node [above] at (hidden-\i.north) {$H_\l$};

\foreach \l [count=\i] in {1,n}
  \draw [->] (output-\i) -- ++(1,0)
    node [above, midway] {$O_\l$};

\foreach \i in {1,...,4}
  \foreach \j in {1,...,2}
    \draw [->] (input-\i) -- (hidden-\j);

\foreach \i in {1,...,2}
  \foreach \j in {1,...,2}
    \draw [->] (hidden-\i) -- (output-\j);

\foreach \l [count=\x from 0] in {Input, Hidden, Ouput}
  \node [align=center, above] at (\x*2,2) {\l \\ layer};

\end{tikzpicture}

\end{document}

Although it seems unwise to have n denote the number of nodes in each layer when they could be different and the arrangement of the diagram suggests they are not.

enter image description here

5
  • Both the answers are perfect and I learned from both. But I had to choose one. I easily changed this code to my requirements. Thanks.
    – Shivam
    Jan 14, 2014 at 16:59
  • And how would one have dots to show that there are many hidden layers? Apr 8, 2017 at 17:20
  • Very minor comment: I guess the first \foreach does not need the \l because it seems not to be used.
    – user121799
    Mar 29, 2018 at 2:29
  • how can you write in the nodes?
    – peterxz
    May 13, 2020 at 18:49
  • What is the variable '\l' being used for? (it appears in the first foreach inside the tikzpicture environment but I don't see it the following commands)
    – Javi
    Jan 12, 2021 at 15:58
17

I found this package neuralnetwork, made by Mark K Cowan, which makes drawing neural networks pretty simple. For example:

\documentclass{standalone}

\usepackage{neuralnetwork}

\begin{document}
    \begin{neuralnetwork}[height=4]
        \newcommand{\x}[2]{$x_#2$}
        \newcommand{\y}[2]{$\hat{y}_#2$}
        \newcommand{\hfirst}[2]{\small $h^{(1)}_#2$}
        \newcommand{\hsecond}[2]{\small $h^{(2)}_#2$}
        \inputlayer[count=3, bias=true, title=Input\\layer, text=\x]
        \hiddenlayer[count=4, bias=false, title=Hidden\\layer 1, text=\hfirst] \linklayers
        \hiddenlayer[count=3, bias=false, title=Hidden\\layer 2, text=\hsecond] \linklayers
        \outputlayer[count=2, title=Output\\layer, text=\y] \linklayers
    \end{neuralnetwork}
\end{document}

enter image description here

4
  • 1
    The question really seems to be about the dots, although your code is very elegant. Dec 12, 2018 at 9:09
  • 8
    Package author here, glad to see it's been useful to people! You can caption a node with dots (and possibly remove the background colour) to get the desired effect, although I guess this comes 2 years late. May 9, 2020 at 23:16
  • Why not give an answer @MarkKCowan?
    – Lin
    May 14, 2021 at 2:50
  • @Lin I have barely used LaTeX for almost a decade, I think this answer is better than one I'd write nowadays. May 14, 2021 at 11:21
9

This is a solution where a dot with fully filled with black circle, whose size is changeable via minimum size=xx <dimension>, is defined as a style.

enter image description here

Code

\documentclass[]{article}
\usepackage[margin=1cm]{geometry}
\usepackage{tikz,pgfplots,pgf}
\usetikzlibrary{matrix,shapes,arrows,positioning}
\begin{document}

\begin{figure}[htp]
\centering
\begin{tikzpicture}[
plain/.style={
  draw=none,
  fill=none,
  },
dot/.style={draw,shape=circle,minimum size=3pt,inner sep=0,fill=black
  },
net/.style={
  matrix of nodes,
  nodes={
    draw,
    circle,
    inner sep=8.5pt
    },
  nodes in empty cells,
  column sep=0.6cm,
  row sep=-11pt
  },
>=latex
]
\matrix[net] (mat)
{
|[plain]| \parbox{1cm}{\centering Input\\layer} 
          & |[plain]| \parbox{1cm}{\centering Hidden\\layer} 
                       & |[plain]| \parbox{1cm}{\centering Output\\layer} \\
          & |[plain]|                 \\
|[plain]| &            & |[plain]|    \\
          & |[plain]|  &              \\
|[plain]| & |[dot]|                   \\
          & |[plain]|  & |[dot]|      \\
|[plain]| & |[dot]|    & |[plain]|    \\
|[dot]|   & |[plain]|  & |[dot]|      \\
|[dot]|   & |[dot]|    & |[plain]|    \\
|[dot]|   & |[plain]|  &              \\
|[plain]| &            & |[plain]|    \\
          & |[plain]|                 \\
};
\foreach \ai/\mi in {2/I1,4/I2,6/I3,12/In}
  \draw[<-] (mat-\ai-1) -- node[above] {\mi} +(-1cm,0);
\foreach \ai in {2,4,6,12}
{\foreach \aii/\mii in {3/H1,11/Hn}
  \draw[->] (mat-\ai-1) -- (mat-\aii-2) node[yshift=0.6cm] {\mii};
}
\foreach \ai in {3,11}
{  \draw[->] (mat-\ai-2) -- (mat-4-3);
  \draw[->] (mat-4-3) -- node[above] {O1} +(1cm,0);}
\foreach \ai in {3,11}
{  \draw[->] (mat-\ai-2) -- (mat-10-3);
  \draw[->] (mat-10-3) -- node[above] {On} +(1cm,0);}
\end{tikzpicture}

\caption{ANN diagram for Speed Sign recognition.}
\label{fig_m_3}
\end{figure}

\end{document}
1
  • And how would one have dots to show that there are many hidden layers? Apr 8, 2017 at 17:20
6

I know that this is an old question. But I just found this code by Kjell Magne Fauske on TeXample about a neural network and I think it can be helpful to future readers since it's easy to modify.

example

\documentclass{article}

\usepackage{tikz}
\begin{document}
\pagestyle{empty}

\def\layersep{2.5cm}

\begin{tikzpicture}[shorten >=1pt,->,draw=black!50, node distance=\layersep]
    \tikzstyle{every pin edge}=[<-,shorten <=1pt]
    \tikzstyle{neuron}=[circle,fill=black!25,minimum size=17pt,inner sep=0pt]
    \tikzstyle{input neuron}=[neuron, fill=green!50];
    \tikzstyle{output neuron}=[neuron, fill=red!50];
    \tikzstyle{hidden neuron}=[neuron, fill=blue!50];
    \tikzstyle{annot} = [text width=4em, text centered]

    % Draw the input layer nodes
    \foreach \name / \y in {1,...,4}
    % This is the same as writing \foreach \name / \y in {1/1,2/2,3/3,4/4}
        \node[input neuron, pin=left:Input \#\y] (I-\name) at (0,-\y) {};

    % Draw the hidden layer nodes
    \foreach \name / \y in {1,...,5}
        \path[yshift=0.5cm]
            node[hidden neuron] (H-\name) at (\layersep,-\y cm) {};

    % Draw the output layer node
    \node[output neuron,pin={[pin edge={->}]right:Output}, right of=H-3] (O) {};

    % Connect every node in the input layer with every node in the
    % hidden layer.
    \foreach \source in {1,...,4}
        \foreach \dest in {1,...,5}
            \path (I-\source) edge (H-\dest);

    % Connect every node in the hidden layer with the output layer
    \foreach \source in {1,...,5}
        \path (H-\source) edge (O);

    % Annotate the layers
    \node[annot,above of=H-1, node distance=1cm] (hl) {Hidden layer};
    \node[annot,left of=hl] {Input layer};
    \node[annot,right of=hl] {Output layer};
\end{tikzpicture}
% End of code
\end{document}
3

This might still be useful to some who would like to easily change the number of layers or nodes without creating new for loops: Using the listofitems package, one can define an array with the number of nodes per layer

\readlist\Nnod{4,3,2} % number of nodes per layer
% \Nnodlen = length of \Nnod (i.e. total number of layers)
% \Nnod[1] = element (number of nodes) at index 1
\foreachitem \N \in \Nnod{ % loop over layers
  % \N     = current element in this iteration (i.e. number of nodes for this layer)
  % \Ncnt  = index of current layer in this iteration
  \foreach \i [evaluate={\x=\Ncnt; \y=\N/2-\i+0.5;}] in {1,...,\N}{ % loop over nodes
    \draw[mynode] (\x,\y) circle (0.3 cm);
  }
}

To add layers, simply add the number of nodes in \Nnod. In the full code below, \Nstr and \Cstr can be used to define different coefficients symbols for the input, hidden and output layers. I left some more general examples on TikZ.net.

With \readlist\Nnod{4,3,2}:

Neural network with 3 layers

With \readlist\Nnod{5,4,4,4,3}:

Neural network with 5 layers

\documentclass[border=3pt,tikz]{standalone}
\usepackage{tikz}
\usepackage{etoolbox} % for \ifnumcomp
\usepackage{listofitems} % for \readlist to create arrays

\tikzset{>=latex} % for LaTeX arrow head
\colorlet{myred}{red!80!black}
\colorlet{myblue}{blue!80!black}
\colorlet{mygreen}{green!60!black}
\colorlet{mydarkred}{myred!40!black}
\colorlet{mydarkblue}{myblue!40!black}
\colorlet{mydarkgreen}{mygreen!40!black}
\tikzstyle{node}=[very thick,circle,draw=myblue,minimum size=22,inner sep=0.5,outer sep=0.6]
\tikzstyle{connect}=[->,thick,mydarkblue,shorten >=1]
\tikzset{ % node styles, numbered for easy mapping with \nstyle
  node 1/.style={node,mydarkgreen,draw=mygreen,fill=mygreen!25},
  node 2/.style={node,mydarkblue,draw=myblue,fill=myblue!20},
  node 3/.style={node,mydarkred,draw=myred,fill=myred!20},
}
\def\nstyle{int(\lay<\Nnodlen?min(2,\lay):3)} % map layer number onto 1, 2, or 3

\begin{document}


% NEURAL NETWORK
\begin{tikzpicture}[x=2.4cm,y=1.2cm]
  \readlist\Nnod{4,3,2} % array of number of nodes per layer
  \readlist\Nstr{n,m,k} % array of string number of nodes per layer
  \readlist\Cstr{x,h^{(\prev)},y} % array of coefficient symbol per layer
  \def\yshift{0.55} % shift last node for dots
  
  % LOOP over LAYERS
  \foreachitem \N \in \Nnod{
    \def\lay{\Ncnt} % alias of index of current layer
    \pgfmathsetmacro\prev{int(\Ncnt-1)} % number of previous layer
    \foreach \i [evaluate={\c=int(\i==\N); \y=\N/2-\i-\c*\yshift;
                 \x=\lay; \n=\nstyle;
                 \index=(\i<\N?int(\i):"\Nstr[\n]");}] in {1,...,\N}{ % loop over nodes
      % NODES
      \node[node \n] (N\lay-\i) at (\x,\y) {$\strut\Cstr[\n]_{\index}$};
      
      % CONNECTIONS
      \ifnumcomp{\lay}{>}{1}{ % connect to previous layer
        \foreach \j in {1,...,\Nnod[\prev]}{ % loop over nodes in previous layer
          \draw[white,line width=1.2,shorten >=1] (N\prev-\j) -- (N\lay-\i);
          \draw[connect] (N\prev-\j) -- (N\lay-\i);
        }
        \ifnum \lay=\Nnodlen
          \draw[connect] (N\lay-\i) --++ (0.5,0); % arrows out
        \fi
      }{
        \draw[connect] (0.5,\y) -- (N\lay-\i); % arrows in
      }
      
    }
    \path (N\lay-\N) --++ (0,1+\yshift) node[midway,scale=1.6] {$\vdots$}; % dots
  }
  
  % LABELS
  \node[above=3,align=center,mydarkgreen] at (N1-1.90) {Input\\[-0.2em]layer};
  \node[above=2,align=center,mydarkblue] at (N2-1.90) {Hidden\\[-0.2em]layers};
  \node[above=3,align=center,mydarkred] at (N\Nnodlen-1.90) {Output\\[-0.2em]layer};
  
\end{tikzpicture}


\end{document}
1
  • This is exactly the graph I would like to make, but I would like somehow to stress the fact that the number of layer can be general. Hence I would like have a fake layer where we would have \ldots. How would that be realizable ?
    – Olorin
    Apr 4 at 17:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.