TikZ绘图实例——LSTM元胞结构图

it2023-09-18  65

文章目录

写在前面TikZ是什么?学习的心得体会LSTM元胞结构图的绘制

写在前面

总结一下最近学习 T i k Z \mathrm{Ti}k\mathrm{Z} TikZ时候的一些心得,以及使用 T i k Z \mathrm{Ti}k\mathrm{Z} TikZ绘制LSTM元胞结构的一个小例子。在之前的文章中,我曾经尝试过使用 T i k Z \mathrm{Ti}k\mathrm{Z} TikZ绘制组合数学中的棋盘格(有兴趣的话请看《LaTeX TikZ绘图包——组合数学中棋盘格的画法》),经过一周多的学习(啃文档),终于大概理解了 T i k Z \mathrm{Ti}k\mathrm{Z} TikZ的精妙,在一篇stackflow的问答中(How do I draw an LSTM cell in Tikz?)

Windows 10 x64

MiKTeX 20.10+TeXworks

TikZ是什么?

T i k Z \mathrm{Ti}k\mathrm{Z} TikZ T i k Z \mathrm{Ti}k\mathrm{Z} TikZ ist kein Zeichenprogramm)是以PGF(portable graphic format)为后端的一个绘图前端,用于绘制矢量图(几何,图论等),由Till Tantau教授等开发,以 TeX \TeX TEX为引擎,在矢量图绘图方面十分强大,可惜学习曲线比较陡峭,而且目前没有相关的中文书籍(下面的官方文档中译版内容不全),所以只能多看多练,当然也可以借助 T i k Z E d t \mathrm{Ti}k\mathrm{ZEdt} TikZEdt编辑器可视化生成图形。

GitHub主页;CTAN主页;官方文档(2020.10刚刚更新);官方文档中译版(最新版本2020.7);绘图案例合集;

学习的心得体会

从一开始逐字逐句看文档,到后来结合文档中的具体例子一点一点实现,感觉自己对其绘图的语句有一点点理解了, T i k Z \mathrm{Ti}k\mathrm{Z} TikZ绘图的主要结构其实理解成web前端,内容(html)与样式(CSS)分离,这样可以方便地扩展图形,再到后来需要一些装饰,都可以在 T i k Z s e t \mathrm{Ti}k\mathrm{Zset} TikZset中实现,之后如果要再添加一些功能,就需要一些更高级的扩展包来实现了,这里类比一下JS应该不过分😆.

总之,引用stack exchange的一句话, T i k Z \mathrm{Ti}k\mathrm{Z} TikZ真的会让人上瘾!看那些精美的图形,是否你也跃跃欲试了呢?

LSTM元胞结构图的绘制

以下是一个 T i k Z \mathrm{Ti}k\mathrm{Z} TikZ绘图的小例子,参考了stackexchange网站的代码,加上了一些自己喜欢的配置(配色丑,见谅……),总体来说在代码实现上不难。

%cite by https://tex.stackexchange.com/questions/432312/how-do-i-draw-an-lstm-cell-in-tikz \documentclass[tikz,border=10pt]{standalone} % 使用宏包:bm用于加粗数学符号,ctex用于中文支持,xcolor用于配色 \usepackage{bm,ctex,xcolor} % 使用TikZ内部的扩展包:calc计算两点间等分点,arrows.meta用于定制箭头样式,shapes用于椭圆的生成 \usetikzlibrary{calc, positioning, arrows.meta, shapes} % 定义新命令 \vars{var1}{var2}用于符号的定制 \newcommand{\vars}[2]{${\bm#1}_{\bm#2}$} \begin{document} \begin{tikzpicture}[ % 定义样式 myfont/.style={ font=\footnotesize\sffamily }, frame/.style={% 外部边框(圆角矩形)的样式 rectangle, rounded corners=5mm, draw,gray, fill=lime!45, very thick, }, add/.style={% 加操作符的样式 circle, draw, thick, fill=yellow!60, inner sep=.5pt, minimum height =3mm, }, prod/.style={% 乘操作符的样式 circle, draw, thick, fill=lightgray!40!blue!30, inner sep=.5pt, minimum height =3mm, }, function/.style={% 信息处理函数(tanh)的样式 ellipse, draw, thick, fill=cyan!30, inner sep=1pt }, cell/.style={%C_t和C_{t-1}的样式 circle,draw,fill=magenta!30, line width = .75pt, minimum width=8mm, inner sep=1pt, }, hidden/.style={% h_t和h_{t-1}的样式 circle,draw,fill=orange!50, line width = .75pt, minimum width=8mm, inner sep=1pt, }, input/.style={% x_t的样式 circle,draw, fill=teal!30, line width = .75pt, minimum width=8mm, inner sep=1pt, }, actfunc/.style={% 激活函数的样式 rectangle, draw, fill=pink!30, minimum width=4.25mm, minimum height=3.75mm, inner sep=1pt, thick, }, ArrowC1/.style={% 线段的圆角样式 rounded corners=2mm, >=Stealth[round], very thick, }, ArrowC2/.style={% 弧度略大的圆角样式 rounded corners=3mm, >=Stealth[round], very thick, }, ] % 图形绘制部分 % 绘制外部圆角边框 \node [frame, minimum height =4cm, minimum width=6cm] at (0,0) {}; % 绘制激活函数结点 \node [actfunc] (ibox1) at (-2,-0.8) {$\bm\sigma$}; \node [actfunc] (ibox2) at (-1.35,-0.8) {$\bm\sigma$}; \node [actfunc, minimum width=9mm] (ibox3) at (-0.45,-0.8) {$\bm\tanh$}; \node [actfunc] (ibox4) at (0.5,-0.8) {$\bm\sigma$}; % 绘制操作符结点 \node [prod] (mux1) at (-2,1.5) {$\bm\times$}; \node [add] (add1) at (-0.5,1.5) {$\bm+$}; \node [prod] (mux2) at (-0.5,0) {$\bm\times$}; \node [prod] (mux3) at (1.5,0) {$\bm\times$}; \node [function] (func1) at (1.5,0.75) {$\bm\tanh$}; % 绘制神经元外部输入节点 \node[cell, label={[myfont]above:长时记忆输入}] (c) at (-4,1.5) {\vars{c}{t-1}}; \node[hidden, label={[myfont]above:隐层输入}] (h) at (-4,-1.5) {\vars{h}{t-1}}; \node[input, label={[myfont]right:输入}] (x) at (-2.5,-3) {\vars{x}{t}}; % 绘制神经元外部输出节点 \node[cell, label={[myfont]above:长时记忆输出}] (c2) at (4,1.5) {\vars{c}{t}}; \node[hidden, label={[myfont]below:短时记忆输出}] (h2) at (4,-1.5) {\vars{h}{t}}; \node[hidden, label={[myfont]left:输出}] (x2) at (2.5,3) {\vars{h}{t}}; % 绘制各节点之间的连接线 % 使用相交和位移 % 绘制C_{t-1}到C_t的线 \draw [->, ArrowC1] (c) -- (mux1) -- (add1) -- (c2); % 绘制输入线段 \draw [ArrowC2] (h) -| (ibox4); \draw [ArrowC1] (h) -| (ibox1); \draw [ArrowC1] (h) -| (ibox2); \draw [ArrowC1] (h) -| (ibox3); \draw [ArrowC1] (x) -- (x |- h) -| (ibox1); % 内部线段(带箭头) \draw [->, ArrowC2] (ibox1) -- (mux1); \node [label=left:$\bm{f_t}$,right=1.5pt] () at ($(ibox1)!.5!(mux1)$) {}; \draw [->, ArrowC2] (ibox2) |- (mux2); \node [label=left:$\bm{i_t}$, right=2pt] () at (ibox2 |- mux2) {}; \draw [->, ArrowC2] (ibox3) -- (mux2); \node [label=right:$\bm{\tilde{C}_t}$, left=.5pt] () at ($(ibox3)!.5!(mux2)$) {}; \draw [->, ArrowC2] (ibox4) |- (mux3); \node [label=left:$\bm{o_t}$, right=2pt] () at (ibox4 |- mux3) {}; \draw [->, ArrowC2] (mux2) -- (add1); \draw [->, ArrowC1] (add1) -| (func1); \draw [->, ArrowC2] (func1) -- (mux3); %输出线段 \draw [->, ArrowC2] (mux3) |- (h2); %标记出现缺口线段的下端点 \draw (c2 -| x2) ++(0,-0.15) coordinate (i1); \draw [-, ArrowC2] (h2 -| x2) -| (i1); \draw [->, ArrowC2] (i1)++(0,0.3) -- (x2); \end{tikzpicture} \end{document}

编译结果:

最新回复(0)