Commit 0d913798 by zengxin

chapter 10

parent 198c7441
......@@ -15,9 +15,9 @@
\node[rnnnode,minimum height=0.5\base,fill=green!30!white,anchor=west] (eemb\x) at ([xshift=0.4\base]eemb\y.east) {\tiny{$e_x()$}};
\foreach \x in {1,2,...,3}
\node[rnnnode,fill=blue!30!white,anchor=south] (enc\x) at ([yshift=0.3\base]eemb\x.north) {};
\node[] (enclabel1) at (enc1) {\tiny{$\textbf{h}_{m-2}$}};
\node[] (enclabel2) at (enc2) {\tiny{$\textbf{h}_{m-1}$}};
\node[rnnnode,fill=purple!30!white] (enclabel3) at (enc3) {\tiny{$\textbf{h}_{m}$}};
\node[] (enclabel1) at (enc1) {\tiny{$\vectorn{h}_{m-2}$}};
\node[] (enclabel2) at (enc2) {\tiny{$\vectorn{h}_{m-1}$}};
\node[rnnnode,fill=purple!30!white] (enclabel3) at (enc3) {\tiny{$\vectorn{h}_{m}$}};
\node[wordnode,left=0.4\base of enc1] (init1) {$\cdots$};
\node[wordnode,left=0.4\base of eemb1] (init2) {$\cdots$};
......@@ -29,7 +29,7 @@
\foreach \x in {1,2,...,3}
\node[rnnnode,minimum height=0.5\base,fill=green!30!white,anchor=south] (demb\x) at ([yshift=\base]enc\x.north) {\tiny{$e_y()$}};
\foreach \x in {1,2,...,3}
\node[rnnnode,fill=blue!30!white,anchor=south] (dec\x) at ([yshift=0.3\base]demb\x.north) {{\tiny{$\textbf{s}_\x$}}};
\node[rnnnode,fill=blue!30!white,anchor=south] (dec\x) at ([yshift=0.3\base]demb\x.north) {{\tiny{$\vectorn{s}_\x$}}};
\foreach \x in {1,2,...,3}
\node[rnnnode,minimum height=0.5\base,fill=red!30!white,anchor=south] (softmax\x) at ([yshift=0.3\base]dec\x.north) {\tiny{Softmax}};
\node[wordnode,right=0.4\base of demb3] (end1) {$\cdots$};
......@@ -73,7 +73,7 @@
\draw[-latex'] (enc3.north) .. controls +(north:0.3\base) and +(east:\base) .. (bridge) .. controls +(west:2.7\base) and +(west:0.3\base) .. (dec1.west);
{
\node [anchor=east] (line1) at ([xshift=-3em,yshift=0.5em]softmax1.west) {\scriptsize{基于RNN的隐层状态$\textbf{s}_i$}};
\node [anchor=east] (line1) at ([xshift=-3em,yshift=0.5em]softmax1.west) {\scriptsize{基于RNN的隐层状态$\vectorn{s}_i$}};
\node [anchor=north west] (line2) at ([yshift=0.3em]line1.south west) {\scriptsize{预测目标词的概率}};
\node [anchor=north west] (line3) at ([yshift=0.3em]line2.south west) {\scriptsize{通常,用Softmax函数}};
\node [anchor=north west] (line4) at ([yshift=0.3em]line3.south west) {\scriptsize{实现 $\textrm{P}(y_i|...)$}};
......@@ -90,7 +90,7 @@
\node [anchor=west] (line21) at ([xshift=1.3em,yshift=1.5em]enc3.east) {\scriptsize{源语编码器最后一个}};
\node [anchor=north west] (line22) at ([yshift=0.3em]line21.south west) {\scriptsize{循环单元的输出被}};
\node [anchor=north west] (line23) at ([yshift=0.3em]line22.south west) {\scriptsize{看作是句子的表示,}};
\node [anchor=north west] (line24) at ([yshift=0.3em]line23.south west) {\scriptsize{记为$\textbf{C}$}};
\node [anchor=north west] (line24) at ([yshift=0.3em]line23.south west) {\scriptsize{记为$\vectorn{C}$}};
}
\begin{pgfonlayer}{background}
......
......@@ -9,14 +9,14 @@
\node [pos=0.4,left,xshift=-36em,yshift=7em,font=\small] (original0) {\quad 源语(中文)输入:};
\node [pos=0.4,left,xshift=-22em,yshift=7em,font=\small] (original1) {
\begin{tabular}[t]{l}
\parbox{14em}{``我''、``很''、``好''、``<eos>'' }
\parbox{14em}{“我”、“很”、“好”、“<eos>” }
\end{tabular}
};
%译文1--------------mt1
\node[font=\small] (mt1) at ([xshift=0em,yshift=-1em]original0.south) {目标语(英文)输出:};
\node[font=\small] (ts1) at ([xshift=0em,yshift=-1em]original1.south) {
\begin{tabular}[t]{l}
\parbox{14em}{``I''、``am''、``fine''、``<eos>''}
\parbox{14em}{“I”、“am”、“fine”、“<eos>”}
\end{tabular}
};
......
......@@ -8,26 +8,26 @@
\begin{scope}
\node [anchor=west,draw,fill=red!20!white,inner sep=3pt,minimum width=2em,minimum height=1.2em] (h1) at (0,0) {\scriptsize{$\textbf{h}_1$}};
\node [anchor=west,draw,fill=red!20!white,inner sep=3pt,minimum width=2em,minimum height=1.2em] (h2) at ([xshift=1em]h1.east) {\scriptsize{$\textbf{h}_2$}};
\node [anchor=west,draw,fill=red!20!white,inner sep=3pt,minimum width=2em,minimum height=1.2em] (h1) at (0,0) {\scriptsize{$\vectorn{h}_1$}};
\node [anchor=west,draw,fill=red!20!white,inner sep=3pt,minimum width=2em,minimum height=1.2em] (h2) at ([xshift=1em]h1.east) {\scriptsize{$\vectorn{h}_2$}};
\node [anchor=west,inner sep=0pt,minimum width=3em] (h3) at ([xshift=0.5em]h2.east) {\scriptsize{...}};
\node [anchor=west,draw,fill=red!20!white,inner sep=3pt,minimum width=2em,minimum height=1.2em] (h4) at ([xshift=0.5em]h3.east) {\scriptsize{$\textbf{h}_m$}};
\node [anchor=west,draw,fill=red!20!white,inner sep=3pt,minimum width=2em,minimum height=1.2em] (h4) at ([xshift=0.5em]h3.east) {\scriptsize{$\vectorn{h}_m$}};
\node [anchor=south,circle,minimum size=1.0em,draw,ublue,thick] (sum) at ([yshift=2em]h2.north east) {};
\draw [thick,-,ublue] (sum.north) -- (sum.south);
\draw [thick,-,ublue] (sum.west) -- (sum.east);
\node [anchor=south,draw,fill=green!20!white,inner sep=3pt,minimum width=2em,minimum height=1.2em] (th1) at ([yshift=2em,xshift=-1em]sum.north west) {\scriptsize{$\textbf{s}_{j-1}$}};
\node [anchor=west,draw,fill=green!20!white,inner sep=3pt,minimum width=2em,minimum height=1.2em] (th2) at ([xshift=2em]th1.east) {\scriptsize{$\textbf{s}_{j}$}};
\node [anchor=south,draw,fill=green!20!white,inner sep=3pt,minimum width=2em,minimum height=1.2em] (th1) at ([yshift=2em,xshift=-1em]sum.north west) {\scriptsize{$\vectorn{s}_{j-1}$}};
\node [anchor=west,draw,fill=green!20!white,inner sep=3pt,minimum width=2em,minimum height=1.2em] (th2) at ([xshift=2em]th1.east) {\scriptsize{$\vectorn{s}_{j}$}};
\draw [->] (h1.north) .. controls +(north:0.8) and +(west:1) .. (sum.190) node [pos=0.3,left] {\scriptsize{$\alpha_{1,j}$}};
\draw [->] (h1.north) .. controls +(north:0.8) and +(west:1) .. (sum.190) node [pos=0.2,left] {\scriptsize{$\alpha_{1,j}$}};
\draw [->] (h2.north) .. controls +(north:0.6) and +(220:0.2) .. (sum.220) node [pos=0.2,right] {\scriptsize{$\alpha_{2,j}$}};
\draw [->] (h4.north) .. controls +(north:0.8) and +(east:1) .. (sum.-10) node [pos=0.1,left] (alphan) {\scriptsize{$\alpha_{m,j}$}};
\draw [->] ([xshift=-1.5em]th1.west) -- ([xshift=-0.1em]th1.west);
\draw [->] ([xshift=0.1em]th1.east) -- ([xshift=-0.1em]th2.west);
\draw [->] ([xshift=0.1em]th2.east) -- ([xshift=1.5em]th2.east);
\draw [->] (sum.north) .. controls +(north:0.8) and +(west:0.2) .. ([yshift=-0.4em,xshift=-0.1em]th2.west) node [pos=0.2,right] (ci) {\scriptsize{$\textbf{C}_{j}$}};
\draw [->] (sum.north) .. controls +(north:0.8) and +(west:0.2) .. ([yshift=-0.4em,xshift=-0.1em]th2.west) node [pos=0.2,right] (ci) {\scriptsize{$\vectorn{C}_{j}$}};
\node [anchor=south,inner sep=1pt] (output) at ([yshift=0.8em]th2.north) {\scriptsize{输出层}};
\draw [->] ([yshift=0.1em]th2.north) -- ([yshift=-0.1em]output.south);
......@@ -39,11 +39,11 @@
\node [anchor=north] (enc42) at ([yshift=0.5em]enc4.south) {\scriptsize{(位置$4$)}};
{
\node [anchor=west] (math1) at ([xshift=5em,yshift=1em]th2.east) {$\textbf{C}_j = \sum_{i} \alpha_{i,j} \textbf{h}_i \ \ $};
\node [anchor=west] (math1) at ([xshift=5em,yshift=1em]th2.east) {$\vectorn{C}_j = \sum_{i} \alpha_{i,j} \vectorn{h}_i \ \ $};
}
{
\node [anchor=north west] (math2) at ([yshift=-2em]math1.south west) {$\alpha_{i,j} = \frac{\exp(\beta_{i,j})}{\sum_{i'} \exp(\beta_{i',j})}$};
\node [anchor=north west] (math3) at ([yshift=-0em]math2.south west) {$\beta_{i,j} = a(\textbf{s}_{j-1}, \textbf{h}_i)$};
\node [anchor=north west] (math3) at ([yshift=-0em]math2.south west) {$\beta_{i,j} = a(\vectorn{s}_{j-1}, \vectorn{h}_i)$};
}
\begin{pgfonlayer}{background}
......
......@@ -2,9 +2,9 @@
\begin{scope}
\small{
\node [anchor=south west,minimum width=15em] (source) at (0,0) {\textbf{source}: 我\ \ \ \ \ \ \ \ \ \ \ \ 感到\ \ \ \ 满意};
\node [anchor=south west,minimum width=15em] (source) at (0,0) {\textbf{源语}: 我\ \ \ \ \ \ \ \ \ \ \ \ 感到\ \ \ \ 满意};
{
\node [anchor=south west,minimum width=15em] (target) at ([yshift=12em]source.north west) {\textbf{target}: I\ \ am\ \ \ satisfied\ \ \ with\ \ \ you};
\node [anchor=south west,minimum width=15em] (target) at ([yshift=12em]source.north west) {\textbf{目标语}: I\ \ am\ \ \ satisfied\ \ \ with\ \ \ you};
}
{
\node [anchor=center,minimum width=9.6em,minimum height=1.8em,draw,rounded corners=0.3em] (hidden) at ([yshift=6em]source.north) {};
......@@ -24,7 +24,7 @@
\node [anchor=west,minimum width=1.5em,minimum size=1.5em] (cell08) at (cell06.east){\small{
\hspace{0.6em}
\begin{tabular}{l}
源语言句子的``表示''
源语句子的“表示”
\end{tabular}
}
};
......
......@@ -80,9 +80,9 @@
\draw[<-] ([yshift=0.1em,xshift=1em]t6.north) -- ([yshift=1.2em,xshift=1em]t6.north);
\draw [->] ([yshift=3em]s6.north) -- ([yshift=4em]s6.north) -- ([yshift=4em]t1.north) node [pos=0.5,fill=green!30,inner sep=2pt] (c1) {\scriptsize{表示$\textbf{C}_1$}} -- ([yshift=3em]t1.north) ;
\draw [->] ([yshift=3em]s5.north) -- ([yshift=5.3em]s5.north) -- ([yshift=5.3em]t2.north) node [pos=0.5,fill=green!30,inner sep=2pt] (c2) {\scriptsize{表示$\textbf{C}_2$}} -- ([yshift=3em]t2.north) ;
\draw [->] ([yshift=3.5em]s3.north) -- ([yshift=6.6em]s3.north) -- ([yshift=6.6em]t4.north) node [pos=0.5,fill=green!30,inner sep=2pt] (c3) {\scriptsize{表示$\textbf{C}_i$}} -- ([yshift=3.5em]t4.north) ;
\draw [->] ([yshift=3em]s6.north) -- ([yshift=4em]s6.north) -- ([yshift=4em]t1.north) node [pos=0.5,fill=green!30,inner sep=2pt] (c1) {\scriptsize{表示$\vectorn{C}_1$}} -- ([yshift=3em]t1.north) ;
\draw [->] ([yshift=3em]s5.north) -- ([yshift=5.3em]s5.north) -- ([yshift=5.3em]t2.north) node [pos=0.5,fill=green!30,inner sep=2pt] (c2) {\scriptsize{表示$\vectorn{C}_2$}} -- ([yshift=3em]t2.north) ;
\draw [->] ([yshift=3.5em]s3.north) -- ([yshift=6.6em]s3.north) -- ([yshift=6.6em]t4.north) node [pos=0.5,fill=green!30,inner sep=2pt] (c3) {\scriptsize{表示$\vectorn{C}_i$}} -- ([yshift=3.5em]t4.north) ;
\node [anchor=north] (smore) at ([yshift=3.5em]s3.north) {...};
\node [anchor=north] (tmore) at ([yshift=3.5em]t4.north) {...};
......
......@@ -104,9 +104,9 @@
%\visible<3->
{
% coverage score formula node
\node [anchor=north west] (formula) at ([xshift=-0.3\hnode,yshift=-1.5\hnode]attn11.south) {\small{不同$\textbf{C}_j$所对应的源语言词的权重是不同的}};
\node [anchor=north west] (example) at (formula.south west) {\footnotesize{$\textbf{C}_2=0.4 \times \textbf{h}(\textrm{``你''}) + 0.4 \times \textbf{h}(\textrm{``什么''}) +$}};
\node [anchor=north west] (example2) at ([yshift=0.4em]example.south west) {\footnotesize{$\ \ \ \ \ \ \ \ 0 \times \textbf{h}(\textrm{``都''}) + 0.1 \times \textbf{h}(\textrm{`` 没''}) + ..$}};
\node [anchor=north west] (formula) at ([xshift=-0.3\hnode,yshift=-1.5\hnode]attn11.south) {\small{不同$\vectorn{C}_j$所对应的源语言词的权重是不同的}};
\node [anchor=north west] (example) at (formula.south west) {\footnotesize{$\vectorn{C}_2=0.4 \times \vectorn{h}(\textrm{“你”}) + 0.4 \times \vectorn{h}(\textrm{“什么”}) +$}};
\node [anchor=north west] (example2) at ([yshift=0.4em]example.south west) {\footnotesize{$\ \ \ \ \ \ \ \ 0 \times \vectorn{h}(\textrm{“都”}) + 0.1 \times \vectorn{h}(\textrm{“ 没”}) + ..$}};
}
%\visible<3->
......@@ -138,12 +138,12 @@
%\visible<2->
{
\node[anchor=west] (sc1) at ([xshift=0.9\hnode]attn16.east) {$\textbf{C}_1 = \sum_{i=1}^{8} \alpha_{i1} \textbf{h}_{i}$};
\node[anchor=west] (sc1) at ([xshift=0.9\hnode]attn16.east) {$\vectorn{C}_1 = \sum_{i=1}^{8} \alpha_{i1} \vectorn{h}_{i}$};
}
%\visible<3->
{
\node[anchor=west] (sc2) at ([xshift=0.9\hnode,yshift=0.0\hnode]attn26.east) {$\textbf{C}_2 = \sum_{i=1}^{8} \alpha_{i2} \textbf{h}_{i}$};
\node[anchor=west] (sc2) at ([xshift=0.9\hnode,yshift=0.0\hnode]attn26.east) {$\vectorn{C}_2 = \sum_{i=1}^{8} \alpha_{i2} \vectorn{h}_{i}$};
}
\end{tikzpicture}
\ No newline at end of file
......@@ -78,8 +78,8 @@
\end{scope}
\begin{scope}
\node[wordnode,anchor=south] () at (aux71) {$\mathbf{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\mathbf{x}_t$};
\node[wordnode,anchor=south] () at (aux71) {$\vectorn{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\vectorn{x}_t$};
\end{scope}
......
......@@ -91,8 +91,8 @@
\end{scope}
\begin{scope}
\node[wordnode,anchor=south] () at (aux71) {$\mathbf{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\mathbf{x}_t$};
\node[wordnode,anchor=south] () at (aux71) {$\vectorn{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\vectorn{x}_t$};
\end{scope}
......
......@@ -109,11 +109,11 @@
\end{scope}
\begin{scope}
\node[wordnode,anchor=south] () at (aux71) {$\mathbf{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\mathbf{x}_t$};
\node[wordnode,anchor=south] () at (aux71) {$\vectorn{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\vectorn{x}_t$};
{
\node[wordnode,anchor=east] () at (aux87) {$\mathbf{h}_{t}$};
\node[wordnode,anchor=south] () at (aux78) {$\mathbf{h}_{t}$};
\node[wordnode,anchor=east] () at (aux87) {$\vectorn{h}_{t}$};
\node[wordnode,anchor=south] () at (aux78) {$\vectorn{h}_{t}$};
}
\end{scope}
......
......@@ -84,9 +84,9 @@
\end{scope}
\begin{scope}
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux21) {$\mathbf{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\mathbf{x}_t$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux51) {$\mathbf{c}_{t-1}$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux21) {$\vectorn{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\vectorn{x}_t$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux51) {$\vectorn{c}_{t-1}$};
\end{scope}
......
......@@ -99,9 +99,9 @@
\end{scope}
\begin{scope}
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux21) {$\mathbf{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\mathbf{x}_t$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux51) {$\mathbf{c}_{t-1}$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux21) {$\vectorn{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\vectorn{x}_t$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux51) {$\vectorn{c}_{t-1}$};
\end{scope}
......
......@@ -113,11 +113,11 @@
\end{scope}
\begin{scope}
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux21) {$\mathbf{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\mathbf{x}_t$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux51) {$\mathbf{c}_{t-1}$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux21) {$\vectorn{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\vectorn{x}_t$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux51) {$\vectorn{c}_{t-1}$};
{
\node[wordnode,anchor=south] () at ([xshift=-0.5\base]aux59) {$\mathbf{c}_{t}$};
\node[wordnode,anchor=south] () at ([xshift=-0.5\base]aux59) {$\vectorn{c}_{t}$};
}
\end{scope}
......
......@@ -131,15 +131,15 @@
\end{scope}
\begin{scope}
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux21) {$\mathbf{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\mathbf{x}_t$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux51) {$\mathbf{c}_{t-1}$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux21) {$\vectorn{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\vectorn{x}_t$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux51) {$\vectorn{c}_{t-1}$};
{
\node[wordnode,anchor=south] () at ([xshift=-0.5\base]aux59) {$\mathbf{c}_{t}$};
\node[wordnode,anchor=south] () at ([xshift=-0.5\base]aux59) {$\vectorn{c}_{t}$};
}
{
\node[wordnode,anchor=east] () at (aux68) {$\mathbf{h}_{t}$};
\node[wordnode,anchor=south] () at ([xshift=-0.5\base]aux29) {$\mathbf{h}_{t}$};
\node[wordnode,anchor=east] () at (aux68) {$\vectorn{h}_{t}$};
\node[wordnode,anchor=south] () at ([xshift=-0.5\base]aux29) {$\vectorn{h}_{t}$};
}
\end{scope}
......
......@@ -123,7 +123,7 @@
\draw [->,thick] ([xshift=0.2em,yshift=0.1em]hidden.north west) -- (target.south west);
\draw [->,thick] ([xshift=-0.2em,yshift=0.1em]hidden.north east) -- (target.south east);
\node [anchor=south] () at ([yshift=0.3em]hidden.north) {\scriptsize{$\hat{\mathbf{s}}=\mathbf{Ws}$}};
\node [anchor=south] () at ([yshift=0.3em]hidden.north) {\scriptsize{$\hat{\vectorn{s}}=\vectorn{Ws}$}};
}
{
......
......@@ -12,17 +12,17 @@
\tikzstyle{rnode} = [draw,minimum width=3.5em,minimum height=1.2em]
\node [rnode,anchor=south west,fill=red!20!white] (value1) at (0,0) {\scriptsize{$\textbf{h}(\textrm{``你''})$}};
\node [rnode,anchor=south west,fill=red!20!white] (value2) at ([xshift=1em]value1.south east) {\scriptsize{$\textbf{h}(\textrm{``什么''})$}};
\node [rnode,anchor=south west,fill=red!20!white] (value3) at ([xshift=1em]value2.south east) {\scriptsize{$\textbf{h}(\textrm{``也''})$}};
\node [rnode,anchor=south west,fill=red!20!white] (value4) at ([xshift=1em]value3.south east) {\scriptsize{$\textbf{h}(\textrm{``没''})$}};
\node [rnode,anchor=south west,fill=red!20!white] (value1) at (0,0) {\scriptsize{$\vectorn{h}(\textrm{“你”})$}};
\node [rnode,anchor=south west,fill=red!20!white] (value2) at ([xshift=1em]value1.south east) {\scriptsize{$\vectorn{h}(\textrm{“什么”})$}};
\node [rnode,anchor=south west,fill=red!20!white] (value3) at ([xshift=1em]value2.south east) {\scriptsize{$\vectorn{h}(\textrm{“也”})$}};
\node [rnode,anchor=south west,fill=red!20!white] (value4) at ([xshift=1em]value3.south east) {\scriptsize{$\vectorn{h}(\textrm{“没”})$}};
\node [rnode,anchor=south west,fill=green!20!white] (key1) at ([yshift=0.2em]value1.north west) {\scriptsize{$\textbf{h}(\textrm{``你''})$}};
\node [rnode,anchor=south west,fill=green!20!white] (key2) at ([yshift=0.2em]value2.north west) {\scriptsize{$\textbf{h}(\textrm{``什么''})$}};
\node [rnode,anchor=south west,fill=green!20!white] (key3) at ([yshift=0.2em]value3.north west) {\scriptsize{$\textbf{h}(\textrm{``也''})$}};
\node [rnode,anchor=south west,fill=green!20!white] (key4) at ([yshift=0.2em]value4.north west) {\scriptsize{$\textbf{h}(\textrm{``没''})$}};
\node [rnode,anchor=south west,fill=green!20!white] (key1) at ([yshift=0.2em]value1.north west) {\scriptsize{$\vectorn{h}(\textrm{“你”})$}};
\node [rnode,anchor=south west,fill=green!20!white] (key2) at ([yshift=0.2em]value2.north west) {\scriptsize{$\vectorn{h}(\textrm{“什么”})$}};
\node [rnode,anchor=south west,fill=green!20!white] (key3) at ([yshift=0.2em]value3.north west) {\scriptsize{$\vectorn{h}(\textrm{“也”})$}};
\node [rnode,anchor=south west,fill=green!20!white] (key4) at ([yshift=0.2em]value4.north west) {\scriptsize{$\vectorn{h}(\textrm{“没”})$}};
\node [rnode,anchor=east] (query) at ([xshift=-2em]key1.west) {\scriptsize{$\textbf{s}(\textrm{``you''})$}};
\node [rnode,anchor=east] (query) at ([xshift=-2em]key1.west) {\scriptsize{$\vectorn{s}(\textrm{“you”})$}};
\node [anchor=east] (querylabel) at ([xshift=-0.2em]query.west) {\scriptsize{query}};
\draw [->] ([yshift=1pt,xshift=6pt]query.north) .. controls +(90:1em) and +(90:1em) .. ([yshift=1pt]key1.north);
......
......@@ -141,15 +141,15 @@
\end{scope}
\begin{scope}
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux21) {$\mathbf{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\mathbf{x}_t$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux51) {$\mathbf{c}_{t-1}$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux21) {$\vectorn{h}_{t-1}$};
\node[wordnode,anchor=west] () at (aux12) {$\vectorn{x}_t$};
\node[wordnode,anchor=south] () at ([xshift=0.5\base]aux51) {$\vectorn{c}_{t-1}$};
{
\node[wordnode,anchor=south] () at ([xshift=-0.5\base]aux59) {$\mathbf{c}_{t}$};
\node[wordnode,anchor=south] () at ([xshift=-0.5\base]aux59) {$\vectorn{c}_{t}$};
}
{
\node[wordnode,anchor=east] () at (aux68) {$\mathbf{h}_{t}$};
\node[wordnode,anchor=south] () at ([xshift=-0.5\base]aux29) {$\mathbf{h}_{t}$};
\node[wordnode,anchor=east] () at (aux68) {$\vectorn{h}_{t}$};
\node[wordnode,anchor=south] () at ([xshift=-0.5\base]aux29) {$\vectorn{h}_{t}$};
}
\end{scope}
......@@ -170,19 +170,19 @@
\begin{scope}
{
% forget gate formula
\node[formulanode,anchor=south east,text width=10em] () at ([shift={(4\base,1.5\base)}]aux51) {遗忘门\\$\mathbf{f}_t=\sigma(\mathbf{W}_f[\mathbf{h}_{t-1},\mathbf{x}_t]+\mathbf{b}_f)$};
\node[formulanode,anchor=south east,text width=10em] () at ([shift={(4\base,1.5\base)}]aux51) {遗忘门\\$\vectorn{f}_t=\sigma(\vectorn{W}_f[\vectorn{h}_{t-1},\vectorn{x}_t]+\vectorn{b}_f)$};
}
{
% input gate formula
\node[formulanode,anchor=north east,text width=10em] () at ([shift={(4\base,-1.5\base)}]aux21) {输入门\\$\mathbf{i}_t=\sigma(\mathbf{W}_i[\mathbf{h}_{t-1},\mathbf{x}_t]+\mathbf{b}_i)$\\$\hat{\mathbf{c}}_t=\mathrm{tanh}(\mathbf{W}_c[\mathbf{h}_{t-1},\mathbf{x}_t]+\mathbf{b}_c)$};
\node[formulanode,anchor=north east,text width=10em] () at ([shift={(4\base,-1.5\base)}]aux21) {输入门\\$\vectorn{i}_t=\sigma(\vectorn{W}_i[\vectorn{h}_{t-1},\vectorn{x}_t]+\vectorn{b}_i)$\\$\hat{\vectorn{c}}_t=\mathrm{tanh}(\vectorn{W}_c[\vectorn{h}_{t-1},\vectorn{x}_t]+\vectorn{b}_c)$};
}
{
% cell update formula
\node[formulanode,anchor=south west,text width=10em] () at ([shift={(-4\base,1.5\base)}]aux59) {记忆更新\\$\mathbf{c}_{t}=\mathbf{f}_t\cdot \mathbf{c}_{t-1}+\mathbf{i}_t\cdot \hat{\mathbf{c}}_t$};
\node[formulanode,anchor=south west,text width=10em] () at ([shift={(-4\base,1.5\base)}]aux59) {记忆更新\\$\vectorn{c}_{t}=\vectorn{f}_t\cdot \vectorn{c}_{t-1}+\vectorn{i}_t\cdot \hat{\vectorn{c}}_t$};
}
{
% output gate formula
\node[formulanode,anchor=north west,text width=10em] () at ([shift={(-4\base,-1.5\base)}]aux29) {输出门\\$\mathbf{o}_t=\sigma(\mathbf{W}_o[\mathbf{h}_{t-1},\mathbf{x}_t]+\mathbf{b}_o)$\\$\mathbf{h}_{t}=\mathbf{o}_t\cdot \mathrm{tanh}(\mathbf{c}_{t})$};
\node[formulanode,anchor=north west,text width=10em] () at ([shift={(-4\base,-1.5\base)}]aux29) {输出门\\$\vectorn{o}_t=\sigma(\vectorn{W}_o[\vectorn{h}_{t-1},\vectorn{x}_t]+\vectorn{b}_o)$\\$\vectorn{h}_{t}=\vectorn{o}_t\cdot \mathrm{tanh}(\vectorn{c}_{t})$};
}
\end{scope}
\end{tikzpicture}
......
......@@ -14,9 +14,9 @@
\node[rnnnode,minimum height=0.5\base,fill=green!30!white,anchor=west] (eemb\x) at ([xshift=0.4\base]eemb\y.east) {\tiny{$e_x()$}};
\foreach \x in {1,2,...,3}
\node[rnnnode,fill=blue!30!white,anchor=south] (enc\x) at ([yshift=0.3\base]eemb\x.north) {};
\node[] (enclabel1) at (enc1) {\tiny{$\textbf{h}_{m-2}$}};
\node[] (enclabel2) at (enc2) {\tiny{$\textbf{h}_{m-1}$}};
\node[rnnnode,fill=purple!30!white] (enclabel3) at (enc3) {\tiny{$\textbf{h}_{m}$}};
\node[] (enclabel1) at (enc1) {\tiny{$\vectorn{h}_{m-2}$}};
\node[] (enclabel2) at (enc2) {\tiny{$\vectorn{h}_{m-1}$}};
\node[rnnnode,fill=purple!30!white] (enclabel3) at (enc3) {\tiny{$\vectorn{h}_{m}$}};
\node[wordnode,left=0.4\base of enc1] (init1) {$\cdots$};
\node[wordnode,left=0.4\base of eemb1] (init2) {$\cdots$};
......@@ -28,7 +28,7 @@
\foreach \x in {1,2,...,3}
\node[rnnnode,minimum height=0.5\base,fill=green!30!white,anchor=south] (demb\x) at ([yshift=\base]enc\x.north) {\tiny{$e_y()$}};
\foreach \x in {1,2,...,3}
\node[rnnnode,fill=blue!30!white,anchor=south] (dec\x) at ([yshift=0.3\base]demb\x.north) {{\tiny{$\textbf{s}_\x$}}};
\node[rnnnode,fill=blue!30!white,anchor=south] (dec\x) at ([yshift=0.3\base]demb\x.north) {{\tiny{$\vectorn{s}_\x$}}};
\foreach \x in {1,2,...,3}
\node[rnnnode,minimum height=0.5\base,fill=red!30!white,anchor=south] (softmax\x) at ([yshift=0.3\base]dec\x.north) {\tiny{Softmax}};
\node[wordnode,right=0.4\base of demb3] (end1) {$\cdots$};
......
......@@ -30,7 +30,7 @@
\sectionnewpage
\section{神经机器翻译的发展简史}
\parinterval 纵观机器翻译的发展历程,神经机器翻译诞生较晚。无论是早期的基于规则的方法,还是逐渐发展起来的基于实例的方法,再或是上世纪末的统计方法,每次机器翻译框架级的创新都需要很长时间的酝酿,而技术走向成熟甚至需要更长的时间。但是,神经机器翻译的出现和后来的发展速度多少有些``出人意料''。神经机器翻译的概念出现在2013-2014年间,当时机器翻译领域的主流方法仍然是统计机器翻译。虽然那个时期深度学习已经在图像、语音等领域取得令人瞩目的效果,但是对于自然语言处理来说深度学习仍然不是主流,并且当时的研究者对神经机器翻译这种方法还有一些排斥。
\parinterval 纵观机器翻译的发展历程,神经机器翻译诞生较晚。无论是早期的基于规则的方法,还是逐渐发展起来的基于实例的方法,再或是上世纪末的统计方法,每次机器翻译框架级的创新都需要很长时间的酝酿,而技术走向成熟甚至需要更长的时间。但是,神经机器翻译的出现和后来的发展速度多少有些“出人意料”。神经机器翻译的概念出现在2013-2014年间,当时机器翻译领域的主流方法仍然是统计机器翻译。虽然那个时期深度学习已经在图像、语音等领域取得令人瞩目的效果,但是对于自然语言处理来说深度学习仍然不是主流,并且当时的研究者对神经机器翻译这种方法还有一些排斥。
\parinterval 不过,有人也意识到了神经机器翻译在表示学习等方面的优势。特别是以Yoshua Bengio团队为代表的研究力量对包括机器翻译在内的序列到序列问题进行了广泛而深入的研究,注意力机制等新的模型不断被推出。这使得神经机器翻译系统在翻译品质上逐渐体现出优势,甚至超越了当时的统计机器翻译系统。正当大家在讨论神经机器翻译是否能取代统计机器翻译成为下一代机器翻译范式的时候,谷歌、百度等企业推出以神经机器翻译技术为内核的在线机器翻译服务,在很多场景下的翻译品质显著超越了当时最好的统计机器翻译系统。这也引发了学术界和产业界对神经机器翻译的讨论。随着关注度的不断升高,神经机器翻译的研究吸引了更多的科研机构和企业的投入,神经机器翻译系统的翻译品质得到进一步提升。
......@@ -65,7 +65,7 @@
% NEW SUB-SECTION 10.1.1
%----------------------------------------------------------------------------------------
\subsection{神经机器翻译的起源}
\parinterval 从广义上讲,神经机器翻译是一种基于人工神经网络的方法,它把翻译过程描述为可以用人工神经网络表示的函数。所有的训练和推断都在这些函数上进行。由于神经机器翻译中的神经网络可以用连续可微函数表示,因此这类方法也可以用基于梯度的方法进行优化,相关技术非常成熟。更为重要的是,在神经网络的设计中,研究者引入了{\small\bfnew{分布式表示}} \index{分布式表示}(Distributed Representation)\index{Distributed Representation}的概念,这也是近些年自然语言处理领域的重要成果之一。传统统计机器翻译仍然把词序列看作离散空间里的由多个特征函数描述的点,类似于$n$-gram语言模型,这类模型对数据稀疏问题非常敏感。此外,人工设计特征也在一定程度上限制了模型对问题的表示能力。神经机器翻译把文字序列表示为实数向量,一方面避免了特征工程繁重的工作,另一方面使得系统可以对文字序列的``表示''进行学习。可以说,神经机器翻译的成功很大程度上源自`` 表示学习''这种自然语言处理的新范式的出现。在表示学习的基础上,注意力机制、深度神经网络等技术都被应用于神经机器翻译,使其得以进一步发展。
\parinterval 从广义上讲,神经机器翻译是一种基于人工神经网络的方法,它把翻译过程描述为可以用人工神经网络表示的函数。所有的训练和推断都在这些函数上进行。由于神经机器翻译中的神经网络可以用连续可微函数表示,因此这类方法也可以用基于梯度的方法进行优化,相关技术非常成熟。更为重要的是,在神经网络的设计中,研究者引入了{\small\bfnew{分布式表示}} \index{分布式表示}(Distributed Representation)\index{Distributed Representation}的概念,这也是近些年自然语言处理领域的重要成果之一。传统统计机器翻译仍然把词序列看作离散空间里的由多个特征函数描述的点,类似于$n$-gram语言模型,这类模型对数据稀疏问题非常敏感。此外,人工设计特征也在一定程度上限制了模型对问题的表示能力。神经机器翻译把文字序列表示为实数向量,一方面避免了特征工程繁重的工作,另一方面使得系统可以对文字序列的“表示”进行学习。可以说,神经机器翻译的成功很大程度上源自“ 表示学习”这种自然语言处理的新范式的出现。在表示学习的基础上,注意力机制、深度神经网络等技术都被应用于神经机器翻译,使其得以进一步发展。
\parinterval 虽然神经机器翻译中大量的使用了人工神经网络方法,但是它并不是最早在机器翻译中使用人工神经网络的框架。实际上,人工神经网络在机器翻译中应用的历史要远早于现在的神经机器翻译。 在统计机器翻译时代,也有很多研究者利用人工神经网络进行机器翻译系统模块的构建\upcite{devlin-etal-2014-fast,Schwenk_continuousspace},比如,Jacob Devlin等人就成功地在统计机器翻译系统中使用了基于神经网络的联合表示模型,取得了令人振奋的结果,这项工作也获得了ACL2014的最佳论文奖(Best Paper Award)。
......@@ -116,7 +116,7 @@
\vspace{-0.3em}
\parinterval 可以明显地看到译文2更加通顺,意思的表达更加准确,翻译质量明显高于译文1。这个例子基本反应出统计机器翻译和神经机器翻译的差异性。当然,这里并不是要讨论统计机器翻译和神经机器翻译孰优孰劣。但是,很多场景中都不难发现神经机器翻译可以生成非常流畅的译文,易于人工阅读和修改。
\parinterval 在很多量化的评价中也可以看到神经机器翻译的优势。回忆一下第四章提到的机器翻译质量的自动评估指标中,使用最广泛的一种指标是BLEU。在统计机器翻译时代,在由美国国家标准和科技机构(NIST)举办的汉英机器翻译评测中(比如汉英MT08数据集),基于统计方法的翻译系统若能够得到30\%以上的BLEU值就已经是当时最顶尖的结果了。而现在的神经机器翻译系统,则可以轻松的将BLEU提高至45\%以上。
\parinterval 在很多量化的评价中也可以看到神经机器翻译的优势。回忆一下第四章提到的机器翻译质量的自动评估指标中,使用最广泛的一种指标是BLEU。在统计机器翻译时代,在由美国国家标准和科技机构(NIST)举办的汉英机器翻译评测中(比如汉英MT08数据集),30\%以上的BLEU值对于基于统计方法的翻译系统来说就已经是当时最顶尖的结果了。而现在的神经机器翻译系统,则可以轻松的将BLEU提高至45\%以上。
%----------------------------------------------
\begin{figure}[htp]
......@@ -133,7 +133,7 @@
\begin{figure}[htp]
\centering
\input{./Chapter10/Figures/figure-score-of-mter}
\caption{不同系统在不同长度句子上的mTER分值(得分越低越好)}
\caption{不同系统在不同长度句子上的mTER分值(得分越低越好)\upcite{Bentivogli2016NeuralVP}}
\label{fig:10-4}
\end{figure}
%----------------------------------------------
......@@ -225,12 +225,12 @@ NMT & $ 21.7^{\ast}$ & $18.7^{\ast}$ & -1
\vspace{0.5em}
\parinterval (二)不需要特征工程,特征学习更加全面
\parinterval 经典的统计机器翻译可以通过判别式模型引入任意特征,不过这些特征需要人工设计,因此这个过程也被称为{\small\bfnew{特征工程}} \index{特征工程}(Feature Engineering)\index{Feature Engineering}。特征工程依赖大量的人工,特别是对不同语种、不同场景的翻译任务,所采用的特征可能不尽相同,这也使得设计有效的特征成为了统计机器翻译时代最主要的工作之一。但是,由于人类自身的思维和认知水平的限制,人工设计的特征可能不全面,甚至会遗漏一些重要的翻译现象。神经机器翻译并不依赖任何人工特征的设计,或者说它的特征都隐含在分布式表示中。这些``特征''都是自动学习得到的,因此神经机器翻译并不会受到人工思维的限制,学习到的特征对问题描述更加全面。
\parinterval 经典的统计机器翻译可以通过判别式模型引入任意特征,不过这些特征需要人工设计,因此这个过程也被称为{\small\bfnew{特征工程}} \index{特征工程}(Feature Engineering)\index{Feature Engineering}。特征工程依赖大量的人工,特别是对不同语种、不同场景的翻译任务,所采用的特征可能不尽相同,这也使得设计有效的特征成为了统计机器翻译时代最主要的工作之一。但是,由于人类自身的思维和认知水平的限制,人工设计的特征可能不全面,甚至会遗漏一些重要的翻译现象。神经机器翻译并不依赖任何人工特征的设计,或者说它的特征都隐含在分布式表示中。这些“特征”都是自动学习得到的,因此神经机器翻译并不会受到人工思维的限制,学习到的特征对问题描述更加全面。
\vspace{0.5em}
\parinterval (三)不含隐含结构假设,端到端学习对问题建模更加直接
\parinterval 传统的自然语言处理任务会对问题进行隐含结构假设。比如,进行翻译时,统计机器翻译会假设翻译过程由短语的拼装完成。这些假设可以大大化简问题的复杂度,但是另一方面也带来了各种各样的约束条件。错误的隐含假设往往会导致建模错误。神经机器翻译是一种端到端模型,它并不依赖任何隐含结构假设。这样,模型并不会受到错误的隐含结构的引导。从某种意义上说,端到端学习可以让模型更加`` 自由''地进行学习,因此往往可以学到很多传统认知上不容易理解或者不容易观测到的现象。
\parinterval 传统的自然语言处理任务会对问题进行隐含结构假设。比如,进行翻译时,统计机器翻译会假设翻译过程由短语的拼装完成。这些假设可以大大化简问题的复杂度,但是另一方面也带来了各种各样的约束条件。错误的隐含假设往往会导致建模错误。神经机器翻译是一种端到端模型,它并不依赖任何隐含结构假设。这样,模型并不会受到错误的隐含结构的引导。从某种意义上说,端到端学习可以让模型更加“ 自由”地进行学习,因此往往可以学到很多传统认知上不容易理解或者不容易观测到的现象。
\vspace{0.5em}
\parinterval (四)模型结构统一,存储消耗更小
......@@ -246,7 +246,7 @@ NMT & $ 21.7^{\ast}$ & $18.7^{\ast}$ & -1
\sectionnewpage
\section{编码器-解码器框架}
\parinterval 说到神经机器翻译就不得不提{\small\bfnew{编码器-解码器模型}}\index{编码器-解码器模型}(Encoder-Decoder Paradigm)\index{Encoder-Decoder Paradigm},或{\small\bfnew{编码器-解码器框架}} \index{编码器-解码器框架}。本质上,编码器-解码器模型是描述输入-输出之间关系的一种方式。编码器-解码器这个概念在日常生活中并不少见。例如在电视系统上为了便于视频的传播,会使用各种编码器将视频编码成数字信号,在客户端,相应的解码器组件会把收到的数字信号解码为视频。另外一个更贴近生活的例子是电话,它通过对声波和电信号进行相互转换,达到传递声音的目的。这种``先编码,再解码''的思想被应用到密码学、信息论等多个领域。
\parinterval 说到神经机器翻译就不得不提{\small\bfnew{编码器-解码器模型}}\index{编码器-解码器模型}(Encoder-Decoder Paradigm)\index{Encoder-Decoder Paradigm},或{\small\bfnew{编码器-解码器框架}} \index{编码器-解码器框架}。本质上,编码器-解码器模型是描述输入-输出之间关系的一种方式。编码器-解码器这个概念在日常生活中并不少见。例如在电视系统上为了便于视频的传播,会使用各种编码器将视频编码成数字信号,在客户端,相应的解码器组件会把收到的数字信号解码为视频。另外一个更贴近生活的例子是电话,它通过对声波和电信号进行相互转换,达到传递声音的目的。这种“先编码,再解码”的思想被应用到密码学、信息论等多个领域。
\parinterval 不难看出,机器翻译问题也完美的贴合编码器-解码器结构的特点。可以将源语言编码为类似信息传输中的数字信号,然后利用解码器对其进行转换,生成目标语言。下面就来看一下神经机器翻译是如何在编码器-解码器框架下进行工作的。
......@@ -255,9 +255,9 @@ NMT & $ 21.7^{\ast}$ & $18.7^{\ast}$ & -1
%----------------------------------------------------------------------------------------
\subsection{框架结构}
\parinterval 编码器-解码器框架是一种典型的基于``表示''的模型。编码器的作用是将输入的文字序列通过某种转换变为一种新的``表示''形式,这种``表示''包含了输入序列的所有信息。之后,解码器把这种``表示''重新转换为输出的文字序列。这其中的一个核心问题是表示学习,即:如何定义对输入文字序列的表示形式,并自动学习这种表示,同时应用它生成输出序列。一般来说,不同的表示学习方法可以对应不同的机器翻译模型,比如,在最初的神经机器翻译模型中,源语言句子都被表示为一个独立的向量,这时表示结果是静态的;而在注意力机制中,源语言句子的表示是动态的,也就是翻译目标语的每个单词时都会使用不同的表示结果。
\parinterval 编码器-解码器框架是一种典型的基于“表示”的模型。编码器的作用是将输入的文字序列通过某种转换变为一种新的“表示”形式,这种“表示”包含了输入序列的所有信息。之后,解码器把这种“表示”重新转换为输出的文字序列。这其中的一个核心问题是表示学习,即:如何定义对输入文字序列的表示形式,并自动学习这种表示,同时应用它生成输出序列。一般来说,不同的表示学习方法可以对应不同的机器翻译模型,比如,在最初的神经机器翻译模型中,源语言句子都被表示为一个独立的向量,这时表示结果是静态的;而在注意力机制中,源语言句子的表示是动态的,也就是翻译目标语的每个单词时都会使用不同的表示结果。
\parinterval\ref{fig:10-5}是一个应用编码器-解码器结构来解决机器翻译问题的简单实例。给定一个中文句子``我\ \ \ 感到\ 满意'',编码器会将这句话编码成一个实数向量(0.2,-1,6,5,0.7,-2),这个向量就是源语言句子的``表示''结果。虽然有些不可思议,但是神经机器翻译模型把这个向量等同于输入序列。向量中的数字并没有实际的意义,然而解码器却能从中提取到源语句子中所包含的信息。也有研究者把向量的每一个维度看作是一个``特征'',这样源语言句子就被表示成多个``特征''的联合,而且这些特征可以被自动学习。有了这样的源语言句子的``表示'',解码器可以把这个实数向量作为输入,然后逐词生成目标语句子``I am satisfied with you''
\parinterval\ref{fig:10-5}是一个应用编码器-解码器结构来解决机器翻译问题的简单实例。给定一个中文句子“我\ \ \ 感到\ 满意”,编码器会将这句话编码成一个实数向量(0.2,-1,6,5,0.7,-2),这个向量就是源语句子的“表示”结果。虽然有些不可思议,但是神经机器翻译模型把这个向量等同于输入序列。向量中的数字并没有实际的意义,然而解码器却能从中提取到源语句子中所包含的信息。也有研究者把向量的每一个维度看作是一个“特征”,这样源语句子就被表示成多个“特征”的联合,而且这些特征可以被自动学习。有了这样的源语句子的“表示”,解码器可以把这个实数向量作为输入,然后逐词生成目标语句子“I am satisfied with you”
%----------------------------------------------
\begin{figure}[htp]
......@@ -268,7 +268,7 @@ NMT & $ 21.7^{\ast}$ & $18.7^{\ast}$ & -1
\end{figure}
%----------------------------------------------
\parinterval 在源语句子的表示形式确定之后,需要设计相应的编码器和解码器结构。在大多数情况下,神经机器翻译系统中的编码器由词嵌入层和中间网络层组成。当输入一串单词序列时,词嵌入层会将以一维空间表示的离散的单词映射到连续的多维表示空间,这个过程也被称为词嵌入。之后中间层会对词嵌入向量进行更深层的抽象,得到输入单词序列的中间表示。中间层的实现方式有很多,比如:循环神经网络、卷积神经网络、Transformer等模型都是常用的结构。解码器的结构基本上和编码器是一致的,只不过多了输出层,用于输出每个目标语位置的单词生成概率。
\parinterval 在源语句子的表示形式确定之后,需要设计相应的编码器和解码器结构。在大多数情况下,神经机器翻译系统中的编码器由词嵌入层和中间网络层组成。当输入一串单词序列时,词嵌入层会将以一维空间表示的离散的单词映射到连续的多维表示空间,这个过程也被称为词嵌入。之后中间层会对词嵌入向量进行更深层的抽象,得到输入单词序列的中间表示。中间层的实现方式有很多,比如:循环神经网络、卷积神经网络、Transformer等模型都是常用的结构。解码器的结构基本上和编码器是一致的,只不过多了输出层,用于输出每个目标语位置的单词生成概率。
\parinterval 现在,编码器-解码器框架已经成为了神经机器翻译系统的标准架构。当然,也有一些研究工作在探索编码器-解码器框架之外的结构\upcite{Li2020NeuralMT},但是还没有太多颠覆性的进展。因此,本章仍然以编码器-解码器框架为基础对相关模型和方法进行介绍。
......@@ -277,9 +277,9 @@ NMT & $ 21.7^{\ast}$ & $18.7^{\ast}$ & -1
%----------------------------------------------------------------------------------------
\subsection{表示学习}
\parinterval 编码器-解码器框架的创新之处在于,将传统基于符号的离散型知识转化为分布式的连续型知识。比如,对于一个句子,它可以由离散的符号所构成的文法规则来生成,也可以直接被表示为一个实数向量记录句子的各个``属性''。这种分布式的实数向量可以不依赖任何离散化的符号系统,简单来说,它就是一个函数,把输入的词串转化为实数向量。更为重要的是,这种分布式表示可以被自动学习。或者从某种意义上说,编码器-解码器框架的作用之一就是学习输入序列的表示。表示结果学习的好与坏很大程度上会影响神经机器翻译系统的性能。
\parinterval 编码器-解码器框架的创新之处在于,将传统基于符号的离散型知识转化为分布式的连续型知识。比如,对于一个句子,它可以由离散的符号所构成的文法规则来生成,也可以直接被表示为一个实数向量记录句子的各个“属性”。这种分布式的实数向量可以不依赖任何离散化的符号系统,简单来说,它就是一个函数,把输入的词串转化为实数向量。更为重要的是,这种分布式表示可以被自动学习。或者从某种意义上说,编码器-解码器框架的作用之一就是学习输入序列的表示。表示结果学习的好与坏很大程度上会影响神经机器翻译系统的性能。
\parinterval\ref{fig:10-6}形象地对比了统计机器翻译和神经机器翻译的表示模型的区别。传统的统计机器翻译(a)通过短语或者规则组合来获得更大的翻译片段,直至覆盖整个句子。这本质上是在一个离散的结构空间中不断组合的过程。神经机器翻译(b)与之不同,它并没有所谓的``组合''的过程,整个句子的处理是直接在连续空间上进行计算得到的。这二者的区别也体现了符号系统与神经网络系统的区别。前者更适合处理离散化的结构表示,后者更适合处理连续化的表示。
\parinterval\ref{fig:10-6}形象地对比了统计机器翻译和神经机器翻译的表示模型的区别。传统的统计机器翻译(a)通过短语或者规则组合来获得更大的翻译片段,直至覆盖整个句子。这本质上是在一个离散的结构空间中不断组合的过程。神经机器翻译(b)与之不同,它并没有所谓的“组合”的过程,整个句子的处理是直接在连续空间上进行计算得到的。这二者的区别也体现了符号系统与神经网络系统的区别。前者更适合处理离散化的结构表示,后者更适合处理连续化的表示。
%----------------------------------------------
\begin{figure}[htp]
......@@ -290,7 +290,7 @@ NMT & $ 21.7^{\ast}$ & $18.7^{\ast}$ & -1
\end{figure}
%----------------------------------------------
\parinterval 实际上,编码器-解码器模型也并不是表示学习实现的唯一途径。比如,在第五章提到的神经语言模型实际上也是一种有效的学习句子表示的方法,它所衍生出的预训练模型可以从大规模单语数据上学习句子的表示形式。这种学习会比使用少量的双语数据进行编码端和解码端的学习更加充分。相比机器翻译任务,语言模型相当于一个编码器的学习 \footnote{相比神经机器翻译的编码器,神经语言模型会多出一个输出层,这时可以直接把神经语言模型的中间层的输出作为编码器的输出。},可以无缝嵌入到神经机器翻译模型中。不过,值得注意的是,机器翻译的目的是解决双语字符串之间的映射问题,因此它所使用的句子表示是为了更好地进行翻译。从这个角度说,机器翻译中的表示学习又和语言模型中的表示学习有不同。不过,这里不会深入讨论神经语言模型和预训练与神经机器翻译之间的异同,感兴趣的读者可以参看第章的相关内容。
\parinterval 实际上,编码器-解码器模型也并不是表示学习实现的唯一途径。比如,在第五章提到的神经语言模型实际上也是一种有效的学习句子表示的方法,它所衍生出的预训练模型可以从大规模单语数据上学习句子的表示形式。这种学习会比使用少量的双语数据进行编码端和解码端的学习更加充分。相比机器翻译任务,语言模型相当于一个编码器的学习 \footnote{相比神经机器翻译的编码器,神经语言模型会多出一个输出层,这时可以直接把神经语言模型的中间层的输出作为编码器的输出。},可以无缝嵌入到神经机器翻译模型中。不过,值得注意的是,机器翻译的目的是解决双语字符串之间的映射问题,因此它所使用的句子表示是为了更好地进行翻译。从这个角度说,机器翻译中的表示学习又和语言模型中的表示学习有不同。不过,这里不会深入讨论神经语言模型和预训练与神经机器翻译之间的异同,感兴趣的读者可以参看第章的相关内容。
\parinterval 还有一点,在神经机器翻译中,句子的表示形式可以有很多选择。使用单个向量表示一个句子是一种最简单的方法。当然,也可以用矩阵、高阶张量完成表示。甚至,在解码时动态地生成源语言的表示结果。这部分技术也会在随后的内容中进行介绍。
......@@ -299,13 +299,13 @@ NMT & $ 21.7^{\ast}$ & $18.7^{\ast}$ & -1
%----------------------------------------------------------------------------------------
\subsection{简单的运行实例}
\parinterval 为了对编码器-解码器框架和神经机器翻译的运行过程有一个直观的认识,这里演示一个简单的翻译实例。这里采用标准的循环神经网络作为编码器和解码器的结构。假设系统的输入和输出为:
\parinterval 为了对编码器-解码器框架和神经机器翻译的运行过程有一个直观的认识,这里采用标准的循环神经网络作为编码器和解码器的结构演示一个简单的翻译实例。假设系统的输入和输出为:
\vspace{0.5em}
\parinterval \hspace{5em} 源语(中文)输入:\{``我'',\ ``很'',\ ``好'',\ ``<eos>''\}
\parinterval \hspace{5em} 源语(中文)输入:\{“我”,\ “很”,\ “好”,\ “<eos>”\}
\vspace{0.3em}
\parinterval \hspace{5em} 目标语(英文)输出:\{``I'',\ ``am'',\ ``fine'',\ ``<eos>''\}
\parinterval \hspace{5em} 目标语(英文)输出:\{“I”,\ “am”,\ “fine”,\ “<eos>”\}
\vspace{0.5em}
\noindent 其中,<eos>(End of Sequence)表示序列的终止,<sos>(Start of Sequence)表示序列的开始。
......@@ -319,18 +319,18 @@ NMT & $ 21.7^{\ast}$ & $18.7^{\ast}$ & -1
\end{figure}
%----------------------------------------------
\parinterval 翻译过程的神经网络结构如图\ref{fig:10-7}所示,其中左边是编码器,右边是解码器。编码器会顺序处理源语言单词,将每个单词都表示成一个实数向量,也就是每个单词的词嵌入结果(绿色方框)。在词嵌入的基础上运行循环神经网络(蓝色方框)。在编码下一个时间步状态的时候,上一个时间步的隐藏状态会作为历史信息传入给循环神经网络。这样,句子中每个位置的信息都被向后传递,最后一个时间步的隐藏状态(红色方框)就包含了整个源语言句子的信息,也就得到了编码器的编码结果$\ \dash\ $源语言句子的分布式表示。
\parinterval 翻译过程的神经网络结构如图\ref{fig:10-7}所示,其中左边是编码器,右边是解码器。编码器会顺序处理源语言单词,将每个单词都表示成一个实数向量,也就是每个单词的词嵌入结果(绿色方框)。在词嵌入的基础上运行循环神经网络(蓝色方框)。在编码下一个时间步状态的时候,上一个时间步的隐藏状态会作为历史信息传入给循环神经网络。这样,句子中每个位置的信息都被向后传递,最后一个时间步的隐藏状态(红色方框)就包含了整个源语句子的信息,也就得到了编码器的编码结果$\ \dash\ $源语句子的分布式表示。
\parinterval 解码器直接把源语言句子的分布式表示作为输入的隐层状态,之后像编码器一样依次读入目标语言单词,这是一个标准的循环神经网络的执行过程。与编码器不同的是,解码器会有一个输出层,用于根据当前时间步的隐层状态生成目标语单词及其概率分布。可以看到,解码端当前时刻的输出单词与下一个时刻的输入单词是一样的。从这个角度说,解码器也是一种神经语言模型,只不过它会从另外一种语言(源语言)获得一些信息,而不是仅仅做单语句子的生成。具体来说,当生成第一个单词``I''时,解码器利用了源语言句子表示(红色方框)和目标语的起始词``<sos>''。在生成第二个单词``am''时,解码器利用了上一个时间步的隐藏状态(隐藏层变量)和已经生成的``I''的信息。这个过程会循环执行,直到生成完整的目标语句子。
\parinterval 解码器直接把源语句子的分布式表示作为输入的隐层状态,之后像编码器一样依次读入目标语单词,这是一个标准的循环神经网络的执行过程。与编码器不同的是,解码器会有一个输出层,用于根据当前时间步的隐层状态生成目标语单词及其概率分布。可以看到,解码端当前时刻的输出单词与下一个时刻的输入单词是一样的。从这个角度说,解码器也是一种神经语言模型,只不过它会从另外一种语言(源语言)获得一些信息,而不是仅仅做单语句子的生成。具体来说,当生成第一个单词“I”时,解码器利用了源语句子表示(红色方框)和目标语的起始词“<sos>”。在生成第二个单词“am”时,解码器利用了上一个时间步的隐藏状态(隐藏层变量)和已经生成的“I”的信息。这个过程会循环执行,直到生成完整的目标语句子。
\parinterval 从这个例子可以看出,神经机器翻译的流程其实并不复杂:首先通过编码器神经网络将源语言句子编码成实数向量,然后解码器神经网络利用源语言句子的表示结果逐词生成译文。几乎所有的神经机器翻译系统都是类似架构。
\parinterval 从这个例子可以看出,神经机器翻译的流程其实并不复杂:首先通过编码器神经网络将源语句子编码成实数向量,然后解码器神经网络利用源语句子的表示结果逐词生成译文。几乎所有的神经机器翻译系统都是类似架构。
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION 10.2.4
%----------------------------------------------------------------------------------------
\subsection{机器翻译范式的对比}
\parinterval 对于不同类型的机器翻译方法,人类所扮演的作用是不同的。在统计机器翻译时代,往往需要人工来定义翻译时所需要的特征和翻译单元,翻译中的每一个步骤对于人来说都是透明的,翻译过程具有一定的可解释性。而在神经机器翻译时代,神经机器翻译将所有的工作都交给神经网络,翻译的过程完全由神经网络计算得到。在整个神经网络的运行过程中并不需要人工先验知识,其中所生成的中间表示也只有神经网络自身才可以理解。有时候也会把神经机器翻译系统看作``黑盒''。所谓``黑盒''并不是指神经网络计算的过程不可见,而是这种复杂的计算过程无法控制也很难解释。那么是神经机器翻译会魔法吗,不需要任何人为的干预就可以进行翻译吗?其实不然,相对于统计机器翻译,真正变化的是人类使用知识的形式。
\parinterval 对于不同类型的机器翻译方法,人类所扮演的作用是不同的。在统计机器翻译时代,往往需要人工来定义翻译时所需要的特征和翻译单元,翻译中的每一个步骤对于人来说都是透明的,翻译过程具有一定的可解释性。而在神经机器翻译时代,神经机器翻译将所有的工作都交给神经网络,翻译的过程完全由神经网络计算得到。在整个神经网络的运行过程中并不需要人工先验知识,其中所生成的中间表示也只有神经网络自身才可以理解。有时候也会把神经机器翻译系统看作“黑盒”。所谓“黑盒”并不是指神经网络计算的过程不可见,而是这种复杂的计算过程无法控制也很难解释。那么是神经机器翻译会魔法吗,不需要任何人为的干预就可以进行翻译吗?其实不然,相对于统计机器翻译,真正变化的是人类使用知识的形式。
%----------------------------------------------
\begin{table}[htp]
......@@ -400,11 +400,11 @@ NMT & $ 21.7^{\ast}$ & $18.7^{\ast}$ & -1
\centerline{中午\ \ 吃饭\ \ \ \ \ \ \ 下午\ 篮球\ \ \ 现在\ \ 饿\ \ \ \underline{\quad \quad \quad}}
\vspace{0.8em}
\parinterval 显然,根据上下文中提到的``没吃饭''、``很饿'',最佳的答案是``吃 饭''或者``吃 东西''。也就是,对序列中某个位置的答案进行预测时需要记忆当前时刻之前的序列信息,因此,{\small\bfnew{循环神经网络}}\index{循环神经网络}(Recurrent Neural Network, RNN)\index{Recurrent Neural Network, RNN}应运而生。实际上循环神经网络有着极为广泛的应用,例如语音识别、语言建模以及即将要介绍的神经机器翻译。
\parinterval 显然,根据上下文中提到的“没吃饭”、“很饿”,最佳的答案是“吃 饭”或者“吃 东西”。也就是,对序列中某个位置的答案进行预测时需要记忆当前时刻之前的序列信息,因此,{\small\bfnew{循环神经网络}}\index{循环神经网络}(Recurrent Neural Network, RNN)\index{Recurrent Neural Network, RNN}应运而生。实际上循环神经网络有着极为广泛的应用,例如语音识别、语言建模以及即将要介绍的神经机器翻译。
\parinterval 第五章已经对循环神经网络的基本知识进行过介绍。这里再回顾一下。简单来说,循环神经网络由循环单元组成。对于序列中的任意时刻,都有一个循环单元与之对应,它会融合当前时刻的输入和上一时刻循环单元的输出,生成当前时刻的输出。这样每个时刻的信息都会被传递到下一时刻,这也间接达到了记录历史信息的目的。比如,对于序列$\seq{x}=\{x_1, x_2,..., x_m\}$,循环神经网络会按顺序输出一个序列$\vectorn{h}=\{ \vectorn{h}_1, \vectorn{h}_2,..., \vectorn{h}_m \}$,其中$\vectorn{h}_i$表示$i$时刻循环神经网络的输出(通常为一个向量)。
\parinterval\ref{fig:10-9}展示了一个循环神经网络处理序列问题的实例。当前时刻循环单元的输入由上一个时刻的输入和当前时刻的输入组成,因此也可以理解为,网络当前时刻计算得到的输出是由之前的序列共同决定的,即网络在不断地传递信息的过程中记忆了历史信息。以最后一个时刻的循环单元为例,它在对``开始''这个单词的信息进行处理时,参考了之前所有词(``<sos>\ \ 我们'')的信息。
\parinterval\ref{fig:10-9}展示了一个循环神经网络处理序列问题的实例。当前时刻循环单元的输入由上一个时刻的输入和当前时刻的输入组成,因此也可以理解为,网络当前时刻计算得到的输出是由之前的序列共同决定的,即网络在不断地传递信息的过程中记忆了历史信息。以最后一个时刻的循环单元为例,它在对“开始”这个单词的信息进行处理时,参考了之前所有词(“<sos>\ \ 我们”)的信息。
%----------------------------------------------
\begin{figure}[htp]
......@@ -415,7 +415,7 @@ NMT & $ 21.7^{\ast}$ & $18.7^{\ast}$ & -1
\end{figure}
%----------------------------------------------
\parinterval 在神经机器翻译里使用循环神经网络也很简单。只需要把源语言句子和目标语言句子分别看作两个序列,之后使用两个循环神经网络分别对其进行建模。这个过程如图\ref{fig:10-10}所示。图中,下半部分是编码器,上半部分是解码器。编码器利用循环神经网络对源语言序列逐词进行编码处理,同时利用循环单元的记忆能力,不断累积序列信息,遇到终止符<eos>后便得到了包含源语言句子全部信息的表示结果。解码器利用编码器的输出和起始符<sos>开始逐词的进行解码,即逐词翻译,每得到一个译文单词,便将其作为当前时刻解码端循环单元的输入,这也是一个典型的神经语言模型的序列生成过程。解码器通过循环神经网络不断地累积已经得到的译文的信息,并继续生成下一个单词,直到遇到结束符<eos>,便得到了最终完整的译文。
\parinterval 在神经机器翻译里使用循环神经网络也很简单。只需要把源语句子和目标语句子分别看作两个序列,之后使用两个循环神经网络分别对其进行建模。这个过程如图\ref{fig:10-10}所示。图中,下半部分是编码器,上半部分是解码器。编码器利用循环神经网络对源语言序列逐词进行编码处理,同时利用循环单元的记忆能力,不断累积序列信息,遇到终止符<eos>后便得到了包含源语言句子全部信息的表示结果。解码器利用编码器的输出和起始符<sos>开始逐词的进行解码,即逐词翻译,每得到一个译文单词,便将其作为当前时刻解码端循环单元的输入,这也是一个典型的神经语言模型的序列生成过程。解码器通过循环神经网络不断地累积已经得到的译文的信息,并继续生成下一个单词,直到遇到结束符<eos>,便得到了最终完整的译文。
%----------------------------------------------
\begin{figure}[htp]
......@@ -439,10 +439,10 @@ NMT & $ 21.7^{\ast}$ & $18.7^{\ast}$ & -1
\end{eqnarray}
\vspace{-0.5em}
\noindent 其中,$ \seq{y}_{<j }$表示目标语第$j$个位置之前已经生成的译文单词序列。$ \funp{P} ( y_j | \seq{y}_{<j }, \seq{x})$可以被解释为:根据源语句子$\seq{x} $和已生成的目标语言译文片段$\seq{y}_{<j }=\{ y_1, y_2,..., y_{j-1} \}$,生成第$j$个目标语言单词$y_j$的概率。举个简单的例子,已知源文为$\seq{x} =$\{\textrm{``我'', ``很好''}\},则译文$\seq{y}=$\{``I’m'', ``fine''\}的概率为:
\noindent 其中,$ \seq{y}_{<j }$表示目标语第$j$个位置之前已经生成的译文单词序列。$ \funp{P} ( y_j | \seq{y}_{<j }, \seq{x})$可以被解释为:根据源语句子$\seq{x} $和已生成的目标语言译文片段$\seq{y}_{<j }=\{ y_1, y_2,..., y_{j-1} \}$,生成第$j$个目标语言单词$y_j$的概率。举个简单的例子,已知源文为$\seq{x} =$\{\textrm{“我”, “很好”}\},则译文$\seq{y}=$\{“I’m”, “fine”\}的概率为:
\begin{eqnarray}
\funp{P} ( \{{\textrm{``I'm'',``fine''}}\}|\{\textrm{``我'', ``很好''}\}) & = & \funp{P} (\textrm{``I'm''}| \{\textrm{``我'', ``很好''}\} ) \cdot \nonumber \\
& & \funp{P} (\textrm{``fine''}|\textrm{``I'm''},\{\textrm{``我'', ``很好''}\})
\funp{P} ( \{{\textrm{“I'm”,“fine”}}\}|\{\textrm{“我”, “很好”}\}) & = & \funp{P} (\textrm{“I'm”}| \{\textrm{“我”, “很好”}\} ) \cdot \nonumber \\
& & \funp{P} (\textrm{“fine”}|\textrm{“I'm”},\{\textrm{“我”, “很好”}\}) \nonumber \\
\label{eq:10-3}
\end{eqnarray}
......@@ -472,7 +472,7 @@ $\funp{P}({y_j | \vectorn{s}_{j-1} ,y_{j-1},\vectorn{C}})$由Softmax实现,Sof
\vspace{0.5em}
\end{itemize}
\parinterval 上面提到的问题中,\ref{sec:9.5.2}已经介绍过输入层(词嵌入)和输出层(Softmax)的内容,\ref{sec:10.3.2}节将介绍常用的循环神经网络结构(表示学习模型结构)。
\parinterval 上面提到的问题中,第九章已经介绍过输入层(词嵌入)和输出层(Softmax)的内容,\ref{sec:10.3.2}节将介绍常用的循环神经网络结构(表示学习模型结构)。
%----------------------------------------------
\begin{figure}[htp]
......@@ -516,7 +516,7 @@ $\funp{P}({y_j | \vectorn{s}_{j-1} ,y_{j-1},\vectorn{C}})$由Softmax实现,Sof
\parinterval RNN结构使得当前时刻循环单元的状态包含了之前时间步的状态信息。但是这种对历史信息的记忆并不是无损的,随着序列变长,RNN的记忆信息的损失越来越严重。在很多长序列处理任务中(如长文本生成)都观测到了类似现象。对于这个问题,Hochreiter和Schmidhuber提出了{\small\bfnew{长短时记忆}}\index{长短时记忆}(Long Short-term Memory)\index{Long Short-Term Memory}模型,也就是常说的LSTM模型\upcite{HochreiterLong}
\parinterval LSTM模型是RNN模型的一种改进。相比RNN仅传递前一时刻的状态$\vectorn{h}_{t-1}$,LSTM会同时传递两部分信息:状态信息$\vectorn{h}_{t-1}$和记忆信息$\vectorn{c}_{t-1}$。这里,$\vectorn{c}_{t-1}$是新引入的变量,它也是循环单元的一部分,用于显性的记录需要记录的历史内容,$\vectorn{h}_{t-1}$$\vectorn{c}_{t-1}$在循环单元中会相互作用。LSTM通过``门''单元来动态地选择遗忘多少以前的信息和记忆多少当前的信息。LSTM中所使用的门结构如图\ref{fig:10-15}所示,包括遗忘门,输入门和输出门。图中$\sigma$代表Sigmoid函数,它将函数输入映射为0-1范围内的实数,用来充当门控信号。
\parinterval LSTM模型是RNN模型的一种改进。相比RNN仅传递前一时刻的状态$\vectorn{h}_{t-1}$,LSTM会同时传递两部分信息:状态信息$\vectorn{h}_{t-1}$和记忆信息$\vectorn{c}_{t-1}$。这里,$\vectorn{c}_{t-1}$是新引入的变量,它也是循环单元的一部分,用于显性的记录需要记录的历史内容,$\vectorn{h}_{t-1}$$\vectorn{c}_{t-1}$在循环单元中会相互作用。LSTM通过“门”单元来动态地选择遗忘多少以前的信息和记忆多少当前的信息。LSTM中所使用的门结构如图\ref{fig:10-15}所示,包括遗忘门,输入门和输出门。图中$\sigma$代表Sigmoid函数,它将函数输入映射为0-1范围内的实数,用来充当门控信号。
%----------------------------------------------
\begin{figure}[htp]
......@@ -540,9 +540,9 @@ $\funp{P}({y_j | \vectorn{s}_{j-1} ,y_{j-1},\vectorn{C}})$由Softmax实现,Sof
\label{eq:10-12}
\end{eqnarray}
这里,$\vectorn{W}_f$是权值,$\vectorn{b}_f$是偏置,$[\vectorn{h}_{t-1},\vectorn{x}_{t}]$表示两个向量的拼接。该公式可以解释为,对$[\vectorn{h}_{t-1},\vectorn{x}_{t}]$进行变换,并得到一个实数向量$\vectorn{f}_t$$\vectorn{f}_t$的每一维都可以被理解为一个``门'',它决定可以有多少信息被留下(或遗忘)。
这里,$\vectorn{W}_f$是权值,$\vectorn{b}_f$是偏置,$[\vectorn{h}_{t-1},\vectorn{x}_{t}]$表示两个向量的拼接。该公式可以解释为,对$[\vectorn{h}_{t-1},\vectorn{x}_{t}]$进行变换,并得到一个实数向量$\vectorn{f}_t$$\vectorn{f}_t$的每一维都可以被理解为一个“门”,它决定可以有多少信息被留下(或遗忘)。
\vspace{0.5em}
\item {\small\sffamily\bfseries{记忆更新}}\index{记忆更新}。首先,要生成当前时刻需要新增加的信息,该部分由输入门完成,其结构如图\ref{fig:10-15}(b)红色线部分,图中``$\bigotimes$''表示进行点乘操作。输入门的计算分为两部分,首先利用$\sigma$决定门控参数$\vectorn{i}_t$,然后通过Tanh函数得到新的信息$\hat{\vectorn{c}}_t$,具体公式如下:
\item {\small\sffamily\bfseries{记忆更新}}\index{记忆更新}。首先,要生成当前时刻需要新增加的信息,该部分由输入门完成,其结构如图\ref{fig:10-15}(b)红色线部分,图中$\bigotimes$表示进行点乘操作。输入门的计算分为两部分,首先利用$\sigma$决定门控参数$\vectorn{i}_t$,然后通过Tanh函数得到新的信息$\hat{\vectorn{c}}_t$,具体公式如下:
\begin{eqnarray}
\vectorn{i}_t = \sigma (\vectorn{W}_i [\vectorn{h}_{t-1},\vectorn{x}_{t}] + \vectorn{b}_i )
\label{eq:10-13}
......@@ -552,7 +552,7 @@ $\funp{P}({y_j | \vectorn{s}_{j-1} ,y_{j-1},\vectorn{C}})$由Softmax实现,Sof
\label{eq:10-14}
\end{eqnarray}
之后,用$\vectorn{i}_t$点乘$\hat{\vectorn{c}}_t$,得到当前需要记忆的信息,记为$\vectorn{i}_t \cdot \hat{\vectorn{c}}_t$。接下来需要更新旧的信息$\vectorn{c}_{t-1}$,得到新的记忆信息$\vectorn{c}_t$,更新的操作如图\ref{fig:10-15}(c)红色线部分所示,``$\bigoplus$''表示相加。具体规则是通过遗忘门选择忘记一部分上文信息$\vectorn{f}_t$,通过输入门计算新增的信息$\vectorn{i}_t \cdot \hat{\vectorn{c}}_t$,然后根据``$\bigotimes$''门与``$\bigoplus$''门进行相应的乘法和加法计算:
之后,用$\vectorn{i}_t$点乘$\hat{\vectorn{c}}_t$,得到当前需要记忆的信息,记为$\vectorn{i}_t \cdot \hat{\vectorn{c}}_t$。接下来需要更新旧的信息$\vectorn{c}_{t-1}$,得到新的记忆信息$\vectorn{c}_t$,更新的操作如图\ref{fig:10-15}(c)红色线部分所示,$\bigoplus$”表示相加。具体规则是通过遗忘门选择忘记一部分上文信息$\vectorn{f}_t$,通过输入门计算新增的信息$\vectorn{i}_t \cdot \hat{\vectorn{c}}_t$,然后根据“$\bigotimes$”门与“$\bigoplus$门进行相应的乘法和加法计算:
\begin{eqnarray}
\vectorn{c}_t = \vectorn{f}_t \cdot \vectorn{c}_{t-1} + \vectorn{i}_t \cdot \hat{\vectorn{c}_t}
\label{eq:10-15}
......@@ -615,7 +615,7 @@ $\funp{P}({y_j | \vectorn{s}_{j-1} ,y_{j-1},\vectorn{C}})$由Softmax实现,Sof
\label{eq:10-21}
\end{eqnarray}
\noindent 这里,$\vectorn{u}_t$是更新门中得到的权重,将$\vectorn{u}_t$作用于$\hat{\vectorn{h}}_t$表示对当前时刻的状态进行``遗忘'',舍弃一些不重要的信息,将$(1-\vectorn{u}_t)$作用于$\vectorn{h}_{t-1}$,用于对上一时刻隐藏状态进行选择性记忆。
\noindent 这里,$\vectorn{u}_t$是更新门中得到的权重,将$\vectorn{u}_t$作用于$\hat{\vectorn{h}}_t$表示对当前时刻的状态进行“遗忘”,舍弃一些不重要的信息,将$(1-\vectorn{u}_t)$作用于$\vectorn{h}_{t-1}$,用于对上一时刻隐藏状态进行选择性记忆。
\parinterval GRU的输入输出和RNN类似,其采用与LSTM类似的门控思想,达到捕获长距离依赖信息的目的。此外,GRU比LSTM少了一个门结构,而且参数只有$\vectorn{W}_r$$\vectorn{W}_u$$\vectorn{W}_h$。因此,GRU具有比LSTM高的运算效率,在系统研发中也经常被使用。
......@@ -644,7 +644,7 @@ $\funp{P}({y_j | \vectorn{s}_{j-1} ,y_{j-1},\vectorn{C}})$由Softmax实现,Sof
\subsubsection{多层循环神经网络}
\parinterval 实际上,对于单词序列所使用的循环神经网络是一种很``深''的网络,因为从第一个单词到最后一个单词需要经过至少句子长度相当层数的神经元。比如,一个包含几十个词的句子也会对应几十个神经元层。但是,在很多深度学习应用中,更习惯把对输入序列的同一种处理作为``一层''。比如,对于输入序列,构建一个RNN,那么这些循环单元就构成了网络的``一层''。当然,这里并不是要混淆概念。只是要明确,在随后的讨论中,``层''并不是指一组神经元的全连接,它一般指的是网络的拓扑结构。
\parinterval 实际上,对于单词序列所使用的循环神经网络是一种很“深”的网络,因为从第一个单词到最后一个单词需要经过至少句子长度相当层数的神经元。比如,一个包含几十个词的句子也会对应几十个神经元层。但是,在很多深度学习应用中,更习惯把对输入序列的同一种处理作为“一层”。比如,对于输入序列,构建一个RNN,那么这些循环单元就构成了网络的“一层”。当然,这里并不是要混淆概念。只是要明确,在随后的讨论中,“层”并不是指一组神经元的全连接,它一般指的是网络的拓扑结构。
\parinterval 单层循环神经网络对输入序列进行了抽象,为了得到更深入的抽象能力,可以把多个循环神经网络叠在一起,构成多层循环神经网络。比如,图\ref{fig:10-19}就展示基于两层循环神经网络的解码器和编码器结构。通常来说,层数越多模型的表示能力越强,因此在很多基于循环神经网络的机器翻译系统中一般会使用4$\sim$8层的网络。但是,过多的层也会增加模型训练的难度,甚至导致模型无法进行训练。第十一章还会对这个问题进行深入讨论。
......@@ -669,7 +669,7 @@ $\funp{P}({y_j | \vectorn{s}_{j-1} ,y_{j-1},\vectorn{C}})$由Softmax实现,Sof
\label{eq:10-30}
\end{eqnarray}
\noindent 其中,$\vectorn{w}_{step}$表示更新前的模型参数,$\vectorn{w}_{step+1}$表示更新后的模型参数,$L(\vectorn{w}_{step})$表示模型相对于$\vectorn{w}_{step}$的损失,$\frac{\partial L(\vectorn{w}_{step})} {\partial \vectorn{w}_{step} }$表示损失函数的梯度,$\alpha$是更新的步进值。也就是说,给定一定量的训练数据,不断执行公式\ref{eq:10-30}的过程。反复使用训练数据,直至模型参数达到收敛或者损失函数不再变化。通常,把公式的一次执行称为``一步''更新/训练,把访问完所有样本的训练称为``一轮''训练。
\noindent 其中,$\vectorn{w}_{step}$表示更新前的模型参数,$\vectorn{w}_{step+1}$表示更新后的模型参数,$L(\vectorn{w}_{step})$表示模型相对于$\vectorn{w}_{step}$的损失,$\frac{\partial L(\vectorn{w}_{step})} {\partial \vectorn{w}_{step} }$表示损失函数的梯度,$\alpha$是更新的步进值。也就是说,给定一定量的训练数据,不断执行公式\ref{eq:10-30}的过程。反复使用训练数据,直至模型参数达到收敛或者损失函数不再变化。通常,把公式的一次执行称为“一步”更新/训练,把访问完所有样本的训练称为“一轮”训练。
\parinterval 将公式\ref{eq:10-30}应用于神经机器翻译有几个基本问题需要考虑:1)损失函数的选择;2)参数初始化的策略,也就是如何设置$\vectorn{w}_0$;3)优化策略和学习率调整策略;4)训练加速。下面对这些问题进行讨论。
......@@ -677,9 +677,15 @@ $\funp{P}({y_j | \vectorn{s}_{j-1} ,y_{j-1},\vectorn{C}})$由Softmax实现,Sof
% NEW SUBSUB-SECTION
%----------------------------------------------------------------------------------------
\subsubsection{损失函数}
\subsubsection{1.损失函数}
\parinterval 因为神经机器翻译在每个目标语位置都会输出一个概率分布,表示这个位置上不同单词出现的可能性,因此需要知道当前位置输出的分布相比于标准答案的``损失''。对于这个问题,常用的是交叉熵损失函数。令$\vectorn{y}$表示机器翻译模型输出的分布,$\hat{\vectorn{y}}$ 表示标准答案,则交叉熵损失可以被定义为$L_{\textrm{ce}}(\vectorn{y},\hat{\vectorn{y}}) = - \sum_{k=1}^{|V|} \vectorn{y}[k] \textrm{log} (\hat{\vectorn{y}}[k])$,其中$\vectorn{y}[k]$$\hat{\vectorn{y}}[k]$分别表示向量$\vectorn{y}$$\hat{\vectorn{y}}$的第$k$维,$|V|$表示输出向量的维度(等于词表大小)。对于一个模型输出的概率分布$\vectorn{Y} = \{ \vectorn{y}_1,\vectorn{y}_2,..., \vectorn{y}_n \}$和标准答案分布$\widehat{\vectorn{Y}}=\{ \hat{\vectorn{y}}_1, \hat{\vectorn{y}}_2,...,\hat{\vectorn{y}}_n \}$,损失函数可以被定义为
\parinterval 因为神经机器翻译在每个目标语位置都会输出一个概率分布,表示这个位置上不同单词出现的可能性,因此需要知道当前位置输出的分布相比于标准答案的“损失”。对于这个问题,常用的是交叉熵损失函数。令$\vectorn{y}$表示机器翻译模型输出的分布,$\hat{\vectorn{y}}$ 表示标准答案,则交叉熵损失可以被定义为:
\begin{eqnarray}
L_{\textrm{ce}}(\vectorn{y},\hat{\vectorn{y}}) = - \sum_{k=1}^{|V|} \vectorn{y}[k] \textrm{log} (\hat{\vectorn{y}}[k])
\label{eq:10-3222}
\end{eqnarray}
\noindent 其中$\vectorn{y}[k]$$\hat{\vectorn{y}}[k]$分别表示向量$\vectorn{y}$$\hat{\vectorn{y}}$的第$k$维,$|V|$表示输出向量的维度(等于词表大小)。对于一个模型输出的概率分布$\vectorn{Y} = \{ \vectorn{y}_1,\vectorn{y}_2,..., \vectorn{y}_n \}$和标准答案分布$\widehat{\vectorn{Y}}=\{ \hat{\vectorn{y}}_1, \hat{\vectorn{y}}_2,...,\hat{\vectorn{y}}_n \}$,损失函数可以被定义为:
\begin{eqnarray}
L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_j,\hat{\vectorn{y}}_j)
\label{eq:10-31}
......@@ -693,7 +699,7 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
% NEW SUBSUB-SECTION
%----------------------------------------------------------------------------------------
\subsubsection{参数初始化}
\subsubsection{2.参数初始化}
\parinterval 神经网络的参数主要是各层中的线性变换矩阵和偏置。在训练开始时,需要对参数进行初始化。但是,由于神经机器翻译的网络结构复杂,因此损失函数往往不是凸函数,不同初始化会导致不同的优化结果。而且在大量实践中已经发现,神经机器翻译模型对初始化方式非常敏感,性能优异的系统往往需要特定的初始化方式。
......@@ -703,9 +709,9 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
\vspace{0.5em}
\item LSTM遗忘门偏置初始化为1,也就是始终选择遗忘记忆$\vectorn{c}$,这样可以有效防止初始化时$\vectorn{c}$里包含的错误信号传播到后面的所有时刻。
\vspace{0.5em}
\item 网络中的其他偏置一般都初始化为0,可以有效防止加入过大或过小的偏置后使得激活函数的输出跑到``饱和区'',也就是梯度接近0的区域,防止训练一开始就无法跳出局部极小的区域。
\item 网络中的其他偏置一般都初始化为0,可以有效防止加入过大或过小的偏置后使得激活函数的输出跑到“饱和区”,也就是梯度接近0的区域,防止训练一开始就无法跳出局部极小的区域。
\vspace{0.5em}
\item 网络的权重矩阵$\vectorn{w}$一般使用Xavier参数初始化方法\upcite{pmlr-v9-glorot10a},可以有效稳定训练过程,特别是对于比较``深''的网络。令$d_{in}$$d_{out}$分别表示$\vectorn{w}$的输入和输出的维度大小,则该方法的具体实现如下:
\item 网络的权重矩阵$\vectorn{w}$一般使用Xavier参数初始化方法\upcite{pmlr-v9-glorot10a},可以有效稳定训练过程,特别是对于比较“深”的网络。令$d_{in}$$d_{out}$分别表示$\vectorn{w}$的输入和输出的维度大小,则该方法的具体实现如下:
\begin{eqnarray}
\vectorn{w} \sim U(-\sqrt{ \frac{6} { d_{in} + d_{out} } } , \sqrt{ \frac{6} { d_{in} + d_{out} } })
\label{eq:10-32}
......@@ -719,10 +725,10 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
% NEW SUBSUB-SECTION
%----------------------------------------------------------------------------------------
\vspace{-2.5em}
\subsubsection{优化策略}
\subsubsection{3.优化策略}
%\vspace{0.5em}
\parinterval 公式\ref{eq:10-30}展示了最基本的优化策略,也被称为标准的SGD优化器。实际上,训练神经机器翻译模型时,还有非常多的优化器可以选择,在第章也有详细介绍,这里考虑Adam优化器。 Adam 通过对梯度的{\small\bfnew{一阶矩估计}}\index{一阶矩估计}(First Moment Estimation)\index{First Moment Estimation}{\small\bfnew{二阶矩估计}}\index{二阶矩估计}(Second Moment Estimation)\index{Second Moment Estimation}进行综合考虑,计算出更新步长。
\parinterval 公式\ref{eq:10-30}展示了最基本的优化策略,也被称为标准的SGD优化器。实际上,训练神经机器翻译模型时,还有非常多的优化器可以选择,在第章也有详细介绍,这里考虑Adam优化器。 Adam 通过对梯度的{\small\bfnew{一阶矩估计}}\index{一阶矩估计}(First Moment Estimation)\index{First Moment Estimation}{\small\bfnew{二阶矩估计}}\index{二阶矩估计}(Second Moment Estimation)\index{Second Moment Estimation}进行综合考虑,计算出更新步长。
\parinterval\ref{tab:10-8}从效果上对比了Adam和SGD的区别。通常,Adam收敛的比较快,不同任务基本上可以使用一套配置进行优化,虽性能不算差,但很难达到最优效果。相反,SGD虽能通过在不同的数据集上进行调整,来达到最优的结果,但是收敛速度慢。因此需要根据不同的需求来选择合适的优化器。若需要快得到模型的初步结果,选择Adam较为合适,若是需要在一个任务上得到最优的结果,选择SGD更为合适。
......@@ -744,10 +750,10 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
% NEW SUBSUB-SECTION
%----------------------------------------------------------------------------------------
\vspace{-2.5em}
\subsubsection{梯度裁剪}
\subsubsection{4.梯度裁剪}
%\vspace{0.5em}
\parinterval 需要注意的是,训练循环神经网络时,反向传播使得网络层之间的梯度重复相乘,在网络层数过深时,如果连乘因子小于1可能造成梯度指数级的减少,甚至趋近于0,导致网络无法优化,也就是梯度消失问题。当连乘因子大于1时,可能会导致梯度的乘积变得异常大,造成梯度爆炸的问题。在这种情况下需要使用``梯度裁剪''来防止梯度超过阈值。梯度裁剪在第五章已经介绍过,这里简单回顾一下。梯度裁剪的具体公式如下:
\parinterval 需要注意的是,训练循环神经网络时,反向传播使得网络层之间的梯度重复相乘,在网络层数过深时,如果连乘因子小于1可能造成梯度指数级的减少,甚至趋近于0,导致网络无法优化,也就是梯度消失问题。当连乘因子大于1时,可能会导致梯度的乘积变得异常大,造成梯度爆炸的问题。在这种情况下需要使用“梯度裁剪”来防止梯度超过阈值。梯度裁剪在第九章已经介绍过,这里简单回顾一下。梯度裁剪的具体公式如下:
\vspace{-0.5em}
\begin{eqnarray}
\vectorn{w}' = \vectorn{w} \cdot \frac{\gamma} {\textrm{max}(\gamma,\| \vectorn{w} \|_2)}
......@@ -761,7 +767,7 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
% NEW SUBSUB-SECTION
%----------------------------------------------------------------------------------------
\subsubsection{学习率策略}
\subsubsection{5.学习率策略}
\vspace{0.5em}
\parinterval 在公式\ref{eq:10-30}中, $\alpha$决定了每次参数更新时更新的步幅大小,称之为{\small\bfnew{学习率}}\index{学习率}(Learning Rate)\index{Learning Rate}。学习率作为基于梯度方法中的重要超参数,它决定目标函数能否收敛到较好的局部最优点以及收敛的速度。合理的学习率能够使模型快速、稳定地达到较好的状态。但是,如果学习率太小,收敛过程会很慢;而学习率太大,则模型的状态可能会出现震荡,很难达到稳定,甚至使模型无法收敛。图\ref{fig:10-28} 对比了不同学习率对优化过程的影响。
......@@ -787,7 +793,7 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
\end{figure}
%----------------------------------------------
\parinterval\ref{fig:10-29}展示了一种常用的学习率调整策略。它分为两个阶段:预热阶段和衰减阶段。模型训练初期梯度通常很大,如果直接使用较大的学习率很容易让模型陷入局部最优。学习率的预热阶段便是通过在训练初期使学习率从小到大逐渐增加来减缓在初始阶段模型``跑偏''的现象。一般来说,初始学习率太高会使得模型进入一种损失函数曲面非常不平滑的区域,进而使得模型进入一种混乱状态,后续的优化过程很难取得很好的效果。一个常用的学习率预热方法是{\small\bfnew{逐渐预热}}\index{逐渐预热}(Gradual Warmup)\index{Gradual Warmup}。假设预热的更新次数为$T'$,初始学习率为$\alpha_0$,则预热阶段第$t$次更新的学习率为:
\parinterval\ref{fig:10-29}展示了一种常用的学习率调整策略。它分为两个阶段:预热阶段和衰减阶段。模型训练初期梯度通常很大,如果直接使用较大的学习率很容易让模型陷入局部最优。学习率的预热阶段便是通过在训练初期使学习率从小到大逐渐增加来减缓在初始阶段模型“跑偏”的现象。一般来说,初始学习率太高会使得模型进入一种损失函数曲面非常不平滑的区域,进而使得模型进入一种混乱状态,后续的优化过程很难取得很好的效果。一个常用的学习率预热方法是{\small\bfnew{逐渐预热}}\index{逐渐预热}(Gradual Warmup)\index{Gradual Warmup}。假设预热的更新次数为$T'$,初始学习率为$\alpha_0$,则预热阶段第$t$次更新的学习率为:
%\vspace{0.5em}
\begin{eqnarray}
\alpha_t = \frac{t}{T'} \alpha_0 \quad,\quad 1 \leq t \leq T'
......@@ -801,10 +807,10 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
% NEW SUBSUB-SECTION
%----------------------------------------------------------------------------------------
%\vspace{0.5em}
\subsubsection{并行训练}
\subsubsection{6.并行训练}
%\vspace{0.5em}
\parinterval 机器翻译是自然语言处理中很``重''的任务。因为数据量巨大而且模型较为复杂,模型训练的时间往往很长。比如,使用一千万句的训练数据,性能优异的系统往往需要几天甚至一周的时间。更大规模的数据会导致训练时间更长。特别是使用多层网络同时增加模型容量时(比如增加隐层宽度时),神经机器翻译的训练会更加缓慢。对于这个问题,一个思路是从模型训练算法上进行改进。比如前面提到的Adam就是一种高效的训练策略。另一种思路是利用多设备进行加速,也称作分布式训练。
\parinterval 机器翻译是自然语言处理中很“重”的任务。因为数据量巨大而且模型较为复杂,模型训练的时间往往很长。比如,使用一千万句的训练数据,性能优异的系统往往需要几天甚至一周的时间。更大规模的数据会导致训练时间更长。特别是使用多层网络同时增加模型容量时(比如增加隐层宽度时),神经机器翻译的训练会更加缓慢。对于这个问题,一个思路是从模型训练算法上进行改进。比如前面提到的Adam就是一种高效的训练策略。另一种思路是利用多设备进行加速,也称作分布式训练。
\vspace{0.5em}
%----------------------------------------------
......@@ -820,7 +826,7 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
\end{table}
%----------------------------------------------
\parinterval 常用的多设备并行化加速方法有数据并行和模型并行,其优缺点的简单对比如表\ref{tab:10-9}所示。数据并行是指把同一个批次的不同样本分到不同设备上进行并行计算。其优点是并行度高,理论上有多大的批次就可以有多少个设备并行计算,但模型体积不能大于单个设备容量的极限。而模型并行是指把``模型''切分成若干模块后分配到不同设备上并行计算。其优点是可以对很大的模型进行运算,但只能有限并行,比如,如果按层对模型进行分割,那么有多少层就需要多少个设备,同时这两种方法可以一起使用进一步提高神经网络的训练速度。具体来说:
\parinterval 常用的多设备并行化加速方法有数据并行和模型并行,其优缺点的简单对比如表\ref{tab:10-9}所示。数据并行是指把同一个批次的不同样本分到不同设备上进行并行计算。其优点是并行度高,理论上有多大的批次就可以有多少个设备并行计算,但模型体积不能大于单个设备容量的极限。而模型并行是指把“模型”切分成若干模块后分配到不同设备上并行计算。其优点是可以对很大的模型进行运算,但只能有限并行,比如,如果按层对模型进行分割,那么有多少层就需要多少个设备,同时这两种方法可以一起使用进一步提高神经网络的训练速度。具体来说:
\begin{itemize}
\vspace{0.5em}
......@@ -837,7 +843,7 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
%----------------------------------------------
\vspace{-0.5em}
\item {\small\bfnew{模型并行}}\index{模型并行}。另一种思路是,把较大的模型分成若干小模型,之后在不同设备上训练小模型。对于循环神经网络,不同层的网络天然就是一个相对独立的模型,因此非常适合使用这种方法。比如,对于$l$层的循环神经网络,把每层都看做一个小模型,然后分发到$l$个设备上并行计算。在序列较长的时候,该方法使其运算时间变为原来的${1}/{l}$。图\ref{fig:10-31}以三层循环网络为例展示了对句子``你\ \ 不错\ 。''进行模型并行的过程。其中,每一层网络都被放到了一个设备上。当模型根据已经生成的第一个词``你''预测下一个词时(图\ref{fig:10-31}(a)),同层的下一个时刻的计算和对``你''的第二层的计算就可以同时开展(图\ref{fig:10-31}(b))。以此类推,就完成了模型的并行计算。
\item {\small\bfnew{模型并行}}\index{模型并行}。另一种思路是,把较大的模型分成若干小模型,之后在不同设备上训练小模型。对于循环神经网络,不同层的网络天然就是一个相对独立的模型,因此非常适合使用这种方法。比如,对于$l$层的循环神经网络,把每层都看做一个小模型,然后分发到$l$个设备上并行计算。在序列较长的时候,该方法使其运算时间变为原来的${1}/{l}$。图\ref{fig:10-31}以三层循环网络为例展示了对句子“你\ \ 不错\ 。”进行模型并行的过程。其中,每一层网络都被放到了一个设备上。当模型根据已经生成的第一个词“你”预测下一个词时(图\ref{fig:10-31}(a)),同层的下一个时刻的计算和对“你”的第二层的计算就可以同时开展(图\ref{fig:10-31}(b))。以此类推,就完成了模型的并行计算。
\vspace{0.5em}
\end{itemize}
......@@ -846,7 +852,7 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
\centering
\begin{tabular}{l l}
\subfigure[]{\input{./Chapter10/Figures/figure-process01}} &\subfigure[]{\input{./Chapter10/Figures/figure-process02}} \\
\subfigure[]{\input{./Chapter10/Figures/figure-process03}} &\subfigure[]{\input{./Chapter10/Figures/figure-process04}} \\
%\subfigure[]{\input{./Chapter10/Figures/figure-process03}} &\subfigure[]{\input{./Chapter10/Figures/figure-process04}} \\
%\subfigure[]{\input{./Chapter10/Figures/figure-process05}} &\subfigure[]{\input{./Chapter10/Figures/figure-process06}}\\
\end{tabular}
%\caption{一个三层循环神经网络的模型并行过程}
......@@ -858,7 +864,7 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
\centering
\begin{tabular}{l l}
%\subfigure[]{\input{./Chapter10/Figures/figure-process01}} &\subfigure[]{\input{./Chapter10/Figures/figure-process02}} \\
%\subfigure[]{\input{./Chapter10/Figures/figure-process03}} &\subfigure[]{\input{./Chapter10/Figures/figure-process04}} \\
\subfigure[]{\input{./Chapter10/Figures/figure-process03}} &\subfigure[]{\input{./Chapter10/Figures/figure-process04}} \\
\subfigure[]{\input{./Chapter10/Figures/figure-process05}} &\subfigure[]{\input{./Chapter10/Figures/figure-process06}}
\end{tabular}
\caption{一个三层循环神经网络的模型并行过程}
......@@ -914,7 +920,7 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
%----------------------------------------------
\vspace{0.2em}
\parinterval 解码端的每一步Softmax层会输出所有单词的概率,由于是基于贪心的方法,这里会选择概率最大(top-1)的单词作为输出。这个过程可以参考图\ref{fig:10-33}的内容。选择分布中概率最大的单词``Have''作为得到的第一个单词,并再次送入解码器,作为第二步的输入同时预测下一个单词。以此类推,直到生成句子的终止符为止,就得到了完整的译文。
\parinterval 解码端的每一步Softmax层会输出所有单词的概率,由于是基于贪心的方法,这里会选择概率最大(top-1)的单词作为输出。这个过程可以参考图\ref{fig:10-33}的内容。选择分布中概率最大的单词“Have”作为得到的第一个单词,并再次送入解码器,作为第二步的输入同时预测下一个单词。以此类推,直到生成句子的终止符为止,就得到了完整的译文。
\parinterval 贪婪搜索的优点在于速度快。在对翻译速度有较高要求的场景中,贪婪搜索是一种十分有效的对系统加速的方法。而且贪婪搜索的原理非常简单,易于快速原型。不过,由于每一步只保留一个最好的局部结果,贪婪搜索往往会带来翻译品质上的损失。
......@@ -922,7 +928,7 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
\begin{figure}[htp]
\centering
\input{./Chapter10/Figures/figure-decode-the-word-probability-distribution-at-the-first-position}
\caption{解码第一个位置输出的单词概率分布(``Have''的概率最高)}
\caption{解码第一个位置输出的单词概率分布(“Have”的概率最高)}
\label{fig:10-33}
\end{figure}
%----------------------------------------------
......@@ -934,15 +940,15 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
\subsubsection{束搜索}
\vspace{0.5em}
\parinterval 束搜索是一种启发式图搜索算法。相比于全搜索,它可以减少搜索所占用的空间和时间,在每一步扩展的时候,剪掉一些质量比较差的结点,保留下一些质量较高的结点。具体到机器翻译任务,对于每一个目标语位置,束搜索选择了概率最大的前$K$个单词进行扩展(其中$K$叫做束宽度,或简称为束宽)。如图\ref{fig:10-34}所示,假设\{$y_1, y_2,..., y_n$\}表示生成的目标语序列,且$K=3$,则束搜索的具体过程为:在预测第一个位置时,可以通过模型得到$y_1$的概率分布,选取概率最大的前3个单词作为候选结果(假设分别为``have'', ``has'', ``it'')。在预测第二个位置的单词时,模型针对已经得到的三个候选结果(``have'', ``has'', ``it'')计算第二个单词的概率分布。例如,可以在将``have''作为第二步的输入,计算$y_2$的概率分布。此时,译文序列的概率为
\parinterval 束搜索是一种启发式图搜索算法。相比于全搜索,它可以减少搜索所占用的空间和时间,在每一步扩展的时候,剪掉一些质量比较差的结点,保留下一些质量较高的结点。具体到机器翻译任务,对于每一个目标语位置,束搜索选择了概率最大的前$K$个单词进行扩展(其中$K$叫做束宽度,或简称为束宽)。如图\ref{fig:10-34}所示,假设\{$y_1, y_2,..., y_n$\}表示生成的目标语序列,且$K=3$,则束搜索的具体过程为:在预测第一个位置时,可以通过模型得到$y_1$的概率分布,选取概率最大的前3个单词作为候选结果(假设分别为“have”, “has”, “it”)。在预测第二个位置的单词时,模型针对已经得到的三个候选结果(“have”, “has”, “it”)计算第二个单词的概率分布。例如,可以在将“have”作为第二步的输入,计算$y_2$的概率分布。此时,译文序列的概率为
\begin{eqnarray}
\funp{P} (y_2,y_1 | \vectorn{x}) & = & \funp{P} (y_2, \textrm{``have''} | \vectorn{x}) \nonumber \\
& = & \funp{P}(y_2 | \textrm{``have''} , \vectorn{x}) \cdot \funp{P} (\textrm{``have''} | \vectorn{x})
\funp{P} (y_2,y_1 | \vectorn{x}) & = & \funp{P} (y_2, \textrm{“have”} | \vectorn{x}) \nonumber \\
& = & \funp{P}(y_2 | \textrm{“have”} , \vectorn{x}) \cdot \funp{P} (\textrm{“have”} | \vectorn{x})
\label{eq:10-38}
\end{eqnarray}
\noindent 类似的,对``has''和``it''进行同样的操作,分别计算得到$ \funp{P} (y_2, \textrm{``have''} | \vectorn{x})$$ \funp{P} (y_2, \textrm{``has''} | \vectorn{x})$\\ $ \funp{P} (y_2, \textrm{``it''} | \vectorn{x})$,因为$y_2$对应$|V|$种可能,总共可以得到$3 \times |V|$种结果。然后从中选取使序列概率$\funp{P}(y_2,y_1| \vectorn{x})$最大的前三个$y_2$作为新的输出结果,这样便得到了前两个位置的top-3译文。在预测其他位置时也是如此,不断重复此过程直到推断结束。可以看到,束搜索的搜索空间大小与束宽度有关,也就是:束宽度越大,搜索空间越大,更有可能搜索到质量更高的译文,但同时搜索会更慢。束宽度等于3,意味着每次只考虑三个最有可能的结果,贪婪搜索实际上便是集束宽度为1的情况。在神经机器翻译系统实现中,一般束宽度设置在4~8之间。
\noindent 类似的,对“has”和“it”进行同样的操作,分别计算得到$ \funp{P} (y_2, \textrm{“have”} | \vectorn{x})$$ \funp{P} (y_2, \textrm{“has”} | \vectorn{x})$\\ $ \funp{P} (y_2, \textrm{“it”} | \vectorn{x})$,因为$y_2$对应$|V|$种可能,总共可以得到$3 \times |V|$种结果。然后从中选取使序列概率$\funp{P}(y_2,y_1| \vectorn{x})$最大的前三个$y_2$作为新的输出结果,这样便得到了前两个位置的top-3译文。在预测其他位置时也是如此,不断重复此过程直到推断结束。可以看到,束搜索的搜索空间大小与束宽度有关,也就是:束宽度越大,搜索空间越大,更有可能搜索到质量更高的译文,但同时搜索会更慢。束宽度等于3,意味着每次只考虑三个最有可能的结果,贪婪搜索实际上便是集束宽度为1的情况。在神经机器翻译系统实现中,一般束宽度设置在4~8之间。
%----------------------------------------------
\begin{figure}[htp]
......@@ -959,19 +965,19 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
\subsubsection{长度惩罚}
\parinterval 这里用$ \funp{P} (\vectorn{y} | \vectorn{x}) = \prod_{j=1}^n \funp{P}(y_j | \vectorn{y}_{<j},\vectorn{x}) $作为翻译模型。直接实现这个公式有一个明显的缺点:当句子过长时乘法运算容易产生溢出,也就是多个数相乘可能会产生浮点数无法表示的运算结果。为了解决这个问题,可以利用对数操作将乘法转换为加法,得到新的概率公式:$\textrm{log \funp{P}}(\vectorn{y} | \vectorn{x}) = \sum_{j=1}^n \textrm{log \funp{P}} (y_j | \vectorn{y}_{<j}, \vectorn{x}) $,对数函数不会改变函数的单调性,因此在具体实现时,通常用$\textrm{log \funp{P}}(\vectorn{y} | \vectorn{x})$表示句子的得分,而不用$\funp{P}(\vectorn{y} | \vectorn{x})$
\parinterval 这里用$ \funp{P} (\vectorn{y} | \vectorn{x}) = \prod_{j=1}^n \funp{P}(y_j | \vectorn{y}_{<j},\vectorn{x}) $作为翻译模型。直接实现这个公式有一个明显的缺点:当句子过长时乘法运算容易产生溢出,也就是多个数相乘可能会产生浮点数无法表示的运算结果。为了解决这个问题,可以利用对数操作将乘法转换为加法,得到新的概率公式:$\textrm{log } \funp{P}(\vectorn{y} | \vectorn{x}) = \sum_{j=1}^n \textrm{log }\funp{P} (y_j | \vectorn{y}_{<j}, \vectorn{x}) $,对数函数不会改变函数的单调性,因此在具体实现时,通常用$\textrm{log }\funp{P} (\vectorn{y} | \vectorn{x})$表示句子的得分,而不用$\funp{P}(\vectorn{y} | \vectorn{x})$
\parinterval 不管是使用$\funp{P}(\vectorn{y} | \vectorn{x})$还是$\textrm{log \funp{P}}(\vectorn{y} | \vectorn{x})$计算句子得分,还面临两个问题:
\parinterval 不管是使用$\funp{P}(\vectorn{y} | \vectorn{x})$还是$\textrm{log } \funp{P}(\vectorn{y} | \vectorn{x})$计算句子得分,还面临两个问题:
\begin{itemize}
\vspace{0.5em}
\item $\funp{P}(\vectorn{y} | \vectorn{x})$的范围是[0,1],如果句子过长,那么句子的得分就是很多个小于1的数相乘,或者说取log之后很多个小于0的数相加。这也就是说,句子的得分会随着长度的增加而变小,即模型倾向于生成短句子。
\vspace{0.5em}
\item 模型本身并没有考虑每个源语言单词被使用的程度,比如一个单词可能会被翻译很多``次''。这个问题在统计机器翻译中并不存在,因为所有词在翻译中必须被``覆盖''到。但是早期的神经机器翻译模型没有所谓覆盖度的概念,因此也无法保证每个单词被翻译的``程度''是合理的\upcite{li-etal-2018-simple,TuModeling}
\item 模型本身并没有考虑每个源语言单词被使用的程度,比如一个单词可能会被翻译很多“次”。这个问题在统计机器翻译中并不存在,因为所有词在翻译中必须被“覆盖”到。但是早期的神经机器翻译模型没有所谓覆盖度的概念,因此也无法保证每个单词被翻译的“程度”是合理的\upcite{li-etal-2018-simple,TuModeling}
\vspace{0.5em}
\end{itemize}
\parinterval 为了解决上面提到的问题,可以使用其他特征与$\textrm{log \funp{P}}(\vectorn{y} | \vectorn{x})$一起组成新的模型得分$\textrm{score} ( \vectorn{y} , \vectorn{x})$。针对模型倾向于生成短句子的问题,常用的做法是引入惩罚机制。比如,可以定义一个惩罚因子,形式如下:
\parinterval 为了解决上面提到的问题,可以使用其他特征与$\textrm{log } \funp{P} (\vectorn{y} | \vectorn{x})$一起组成新的模型得分$\textrm{score} ( \vectorn{y} , \vectorn{x})$。针对模型倾向于生成短句子的问题,常用的做法是引入惩罚机制。比如,可以定义一个惩罚因子,形式如下:
\begin{eqnarray}
\textrm{lp}(\vectorn{y}) = \frac {(5+ |\vectorn{y}|)^{\alpha}} {(5+1)^{\alpha}}
\label{eq:10-39}
......@@ -987,11 +993,11 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
\parinterval 最终,模型得分定义如下:
\begin{eqnarray}
\textrm{score} ( \vectorn{y} , \vectorn{x}) = \frac{\textrm{log \funp{P}}(\vectorn{y} | \vectorn{x})} {\textrm{lp}(\vectorn{y})} + \textrm{cp}(\vectorn{y} , \vectorn{x})
\textrm{score} ( \vectorn{y} , \vectorn{x}) = \frac{\textrm{log} \funp{P}(\vectorn{y} | \vectorn{x})} {\textrm{lp}(\vectorn{y})} + \textrm{cp}(\vectorn{y} , \vectorn{x})
\label{eq:10-41}
\end{eqnarray}
\noindent 显然,当目标语$y$过短时,$\textrm{lp}(\vectorn{y})$的值越小,因为$\textrm{log \funp{P}}(\vectorn{y} | \vectorn{x})$是负数,所以句子得分$\textrm{score} ( \vectorn{y} , \vectorn{x})$越小。也就是说,模型会惩罚译文过短的结果。当覆盖度较高时,同样会使得分变低。通过这样的惩罚机制,使模型得分更为合理,从而帮助模型选择出质量更高的译文。
\noindent 显然,当目标语$y$过短时,$\textrm{lp}(\vectorn{y})$的值越小,因为$\textrm{log } \funp{P}(\vectorn{y} | \vectorn{x})$是负数,所以句子得分$\textrm{score} ( \vectorn{y} , \vectorn{x})$越小。也就是说,模型会惩罚译文过短的结果。当覆盖度较高时,同样会使得分变低。通过这样的惩罚机制,使模型得分更为合理,从而帮助模型选择出质量更高的译文。
%----------------------------------------------------------------------------------------
......@@ -1040,15 +1046,15 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
\section{注意力机制}
\label{sec:10.3.4}
\parinterval 第二章提到过``上帝是不公平的'',这个观点主要是表达了:世界上事物之间的联系不是均匀的,有些事物之间的联系会很强,而其他的联系可能很弱。自然语言也完美地契合了这个观点。比如,再重新看一下前面提到的根据上下文补全缺失单词的例子,
\parinterval 第二章提到过“上帝是不公平的”,这个观点主要是表达了:世界上事物之间的联系不是均匀的,有些事物之间的联系会很强,而其他的联系可能很弱。自然语言也完美地契合了这个观点。比如,再重新看一下前面提到的根据上下文补全缺失单词的例子,
\vspace{0.8em}
\centerline{中午\ \ 吃饭\ \ \ \ \ \ \ 下午\ 篮球\ \ \ 现在\ \ 饿\ \ \ \underline{\quad \quad \quad}}
\vspace{0.8em}
\noindent 之所以能想到在横线处填``吃饭''、``吃东西''很有可能是因为看到了``没\ 吃饭''、 ``很\ 饿''等关键信息。也就是这些关键的片段对预测缺失的单词起着关键性作用。而预测``吃饭''与前文中的`` 中午''、``又''之间的联系似乎不那么紧密。也就是说,在形成 ``吃饭''的逻辑时,在潜意识里会更注意``没吃饭''、``很饿''等关键信息。也就是我们的关注度并不是均匀地分布在整个句子上的。
\noindent 之所以能想到在横线处填“吃饭”、“吃东西”很有可能是因为看到了“没\ 吃饭”、 “很\ 饿”等关键信息。也就是这些关键的片段对预测缺失的单词起着关键性作用。而预测“吃饭”与前文中的“ 中午”、“又”之间的联系似乎不那么紧密。也就是说,在形成 “吃饭”的逻辑时,在潜意识里会更注意“没吃饭”、“很饿”等关键信息。也就是我们的关注度并不是均匀地分布在整个句子上的。
\parinterval 这个现象可以用注意力机制进行解释。注意力机制的概念来源于生物学的一些现象:当待接收的信息过多时,人类会选择性地关注部分信息而忽略其他信息。它在人类的视觉、听觉、嗅觉等方面均有体现,当我们在感受事物时,大脑会自动过滤或衰减部分信息,仅关注其中少数几个部分。例如,当看到图\ref{fig:10-20}时,往往不是``均匀地''看图像中的所有区域,可能最先注意到的是大狗头上戴的帽子,然后才会关注图片中其他的部分。
\parinterval 这个现象可以用注意力机制进行解释。注意力机制的概念来源于生物学的一些现象:当待接收的信息过多时,人类会选择性地关注部分信息而忽略其他信息。它在人类的视觉、听觉、嗅觉等方面均有体现,当我们在感受事物时,大脑会自动过滤或衰减部分信息,仅关注其中少数几个部分。例如,当看到图\ref{fig:10-20}时,往往不是“均匀地”看图像中的所有区域,可能最先注意到的是大狗头上戴的帽子,然后才会关注图片中其他的部分。
\parinterval 那么注意力机制和神经机器翻译又有什么关系呢?它如何解决神经机器翻译的问题呢?下面就一起来看一看。
......@@ -1076,7 +1082,7 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
\vspace{0.5em}
\end{itemize}
\parinterval 看一个翻译实例,如图\ref{fig:10-21},目标语中的``very long''仅依赖于源文中的``很长''。这时如果将所有源语编码成一个固定的实数向量,``很长''的信息就很可能被其他词的信息淹没掉,而翻译``very long''时也无法区分不同源语单词的贡献。
\parinterval 看一个翻译实例,如图\ref{fig:10-21},目标语中的“very long”仅依赖于源文中的“很长”。这时如果将所有源语编码成一个固定的实数向量,“很长”的信息就很可能被其他词的信息淹没掉,而翻译“very long”时也无法区分不同源语单词的贡献。
%----------------------------------------------
\begin{figure}[htp]
......@@ -1087,7 +1093,7 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
\end{figure}
%----------------------------------------------
\parinterval 显然,以上问题的根本原因在于所使用的表示模型还比较``弱''。因此需要一个更强大的表示模型,在生成目标语单词时能够有选择地获取源语言句子中更有用的部分。更准确的说,对于要生成的目标语单词,相关性更高的源语言片段应该在源语言句子的表示中体现出来,而不是将所有的源语言单词一视同仁。在神经机器翻译中引入注意力机制正是为了达到这个目的\upcite{bahdanau2014neural,DBLP:journals/corr/LuongPM15}。实际上,除了机器翻译,注意力机制也被成功地应用于图像处理、语音识别、自然语言处理等其他任务。而正是注意力机制的引入,使得包括机器翻译在内很多自然语言处理系统得到了飞跃发展。
\parinterval 显然,以上问题的根本原因在于所使用的表示模型还比较“弱”。因此需要一个更强大的表示模型,在生成目标语单词时能够有选择地获取源语言句子中更有用的部分。更准确的说,对于要生成的目标语单词,相关性更高的源语言片段应该在源语言句子的表示中体现出来,而不是将所有的源语言单词一视同仁。在神经机器翻译中引入注意力机制正是为了达到这个目的\upcite{bahdanau2014neural,DBLP:journals/corr/LuongPM15}。实际上,除了机器翻译,注意力机制也被成功地应用于图像处理、语音识别、自然语言处理等其他任务。而正是注意力机制的引入,使得包括机器翻译在内很多自然语言处理系统得到了飞跃发展。
%----------------------------------------------
\begin{figure}[htp]
......@@ -1134,7 +1140,7 @@ L(\vectorn{Y},\widehat{\vectorn{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\vectorn{y}_
\label{eq:10-23}
\end{eqnarray}
$a(\cdot)$可以被看作是目标语言表示和源语言表示的一种``统一化'',即把源语言和目标语言表示映射在同一个语义空间,进而语义相近的内容有更大的相似性。该函数有多种计算方式,比如,向量乘、向量夹角、单词神经网络等,数学表达如下:
$a(\cdot)$可以被看作是目标语言表示和源语言表示的一种“统一化”,即把源语言和目标语言表示映射在同一个语义空间,进而语义相近的内容有更大的相似性。该函数有多种计算方式,比如,向量乘、向量夹角、单词神经网络等,数学表达如下:
\begin{eqnarray}
a (\vectorn{s},\vectorn{h}) = \left\{ \begin{array}{ll}
\vectorn{s} \vectorn{h}^{\textrm{T}} & \textrm{向量乘} \\
......@@ -1170,7 +1176,7 @@ a (\vectorn{s},\vectorn{h}) = \left\{ \begin{array}{ll}
\vspace{0.5em}
\end{itemize}
\parinterval\ref{fig:10-25}展示了一个上下文向量的计算过程实例。首先,计算目标语第一个单词``Have''与源语中的所有单词的相关性,即注意力权重,对应图中第一列$\alpha_{i,1}$,则当前时刻所使用的上下文向量$\vectorn{C}_1 = \sum_{i=1}^8 \alpha_{i,1} \vectorn{h}_i$;然后,计算第二个单词``you''的注意力权重对应第二列$\alpha_{i,2}$,其上下文向量$\vectorn{C}_2 = \sum_{i=1}^8 \alpha_{i,2} \vectorn{h}_i$,以此类推,可以得到任意目标语位置$j$的上下文向量$\vectorn{C}_j$。很容易看出,不同目标语单词的上下文向量对应的源语言词的权重$\alpha_{i,j}$是不同的,不同的注意力权重为不同位置赋予了不同重要性,对应了注意力机制的思想。
\parinterval\ref{fig:10-25}展示了一个上下文向量的计算过程实例。首先,计算目标语第一个单词“Have”与源语中的所有单词的相关性,即注意力权重,对应图中第一列$\alpha_{i,1}$,则当前时刻所使用的上下文向量$\vectorn{C}_1 = \sum_{i=1}^8 \alpha_{i,1} \vectorn{h}_i$;然后,计算第二个单词“you”的注意力权重对应第二列$\alpha_{i,2}$,其上下文向量$\vectorn{C}_2 = \sum_{i=1}^8 \alpha_{i,2} \vectorn{h}_i$,以此类推,可以得到任意目标语位置$j$的上下文向量$\vectorn{C}_j$。很容易看出,不同目标语单词的上下文向量对应的源语言词的权重$\alpha_{i,j}$是不同的,不同的注意力权重为不同位置赋予了不同重要性,对应了注意力机制的思想。
%----------------------------------------------
\begin{figure}[htp]
......@@ -1197,8 +1203,8 @@ a (\vectorn{s},\vectorn{h}) = \left\{ \begin{array}{ll}
\label{tab:10-7}
\begin{tabular}{ l | l }
\rule{0pt}{13pt} 引入注意力之前 &引入注意力之后 \\ \hline
\rule{0pt}{16pt} $\textrm{``have''} = \argmax_{y_1} \funp{P} (y_1 | \vectorn{C} , y_0)$ &$\textrm{``have''} = \argmax_{y_1} \funp{P} (y_1 | \vectorn{C}_1 , y_0)$ \\
\rule{0pt}{16pt} $\textrm{``you''} = \argmax_{y_2} \funp{P} (y_2 | \vectorn{s}_1 , y_1)$ &$\textrm{``you''} = \argmax_{y_2} \funp{P} (y_2 | \vectorn{s}_1, \vectorn{C}_2 , y_1)$ \\
\rule{0pt}{16pt} $\textrm{“have”} = \argmax_{y_1} \funp{P} (y_1 | \vectorn{C} , y_0)$ &$\textrm{“have”} = \argmax_{y_1} \funp{P} (y_1 | \vectorn{C}_1 , y_0)$ \\
\rule{0pt}{16pt} $\textrm{“you”} = \argmax_{y_2} \funp{P} (y_2 | \vectorn{s}_1 , y_1)$ &$\textrm{“you”} = \argmax_{y_2} \funp{P} (y_2 | \vectorn{s}_1, \vectorn{C}_2 , y_1)$ \\
\end{tabular}
\end{table}
%----------------------------------------------
......@@ -1225,7 +1231,7 @@ a (\vectorn{s},\vectorn{h}) = \left\{ \begin{array}{ll}
\end{figure}
%----------------------------------------------
\parinterval 也可以用这个系统描述翻译中的注意力问题,其中,$\mathrm{query}$即目标语言位置$j$的某种表示,$\mathrm{key}$$\mathrm{value}$即源语言每个位置$i$上的${\vectorn{h}_i}$(这里$\mathrm{key}$$\mathrm{value}$是相同的)。但是,这样的系统在机器翻译问题上并不好用,因为目标语言的表示和源语言的表示都在多维实数空间上,所以无法要求两个实数向量像字符串一样进行严格匹配,或者说这种严格匹配的模型可能会导致$\mathrm{query}$几乎不会命中任何的$\mathrm{key}$。既然无法严格精确匹配,注意力机制就采用了一个``模糊''匹配的方法。这里定义每个$\mathrm{key}_i$$\mathrm{query}$都有一个0~1之间的匹配度,这个匹配度描述了$\mathrm{key}_i$$\mathrm{query}$之间的相关程度,记为$\alpha_i$。而查询的结果(记为$\overline{\mathrm{value}}$)也不再是某一个单元的$\mathrm{value}$,而是所有单元$\mathrm{value}$$\alpha_i$的加权和:
\parinterval 也可以用这个系统描述翻译中的注意力问题,其中,$\mathrm{query}$即目标语言位置$j$的某种表示,$\mathrm{key}$$\mathrm{value}$即源语言每个位置$i$上的${\vectorn{h}_i}$(这里$\mathrm{key}$$\mathrm{value}$是相同的)。但是,这样的系统在机器翻译问题上并不好用,因为目标语言的表示和源语言的表示都在多维实数空间上,所以无法要求两个实数向量像字符串一样进行严格匹配,或者说这种严格匹配的模型可能会导致$\mathrm{query}$几乎不会命中任何的$\mathrm{key}$。既然无法严格精确匹配,注意力机制就采用了一个“模糊”匹配的方法。这里定义每个$\mathrm{key}_i$$\mathrm{query}$都有一个0~1之间的匹配度,这个匹配度描述了$\mathrm{key}_i$$\mathrm{query}$之间的相关程度,记为$\alpha_i$。而查询的结果(记为$\overline{\mathrm{value}}$)也不再是某一个单元的$\mathrm{value}$,而是所有单元$\mathrm{value}$$\alpha_i$的加权和:
\begin{eqnarray}
\overline{\mathrm{value}} = \sum_i \alpha_i \cdot {\mathrm{value}}_i
\label{eq:10-27}
......@@ -1244,7 +1250,7 @@ a (\vectorn{s},\vectorn{h}) = \left\{ \begin{array}{ll}
\end{figure}
%----------------------------------------------
\parinterval 最后,从统计学的角度,如果把$\alpha_i$作为每个$\mathrm{value}_i$出现的概率的某种估计,即:($ \funp{P} \mathrm{value}_i$) $= \alpha_i$,于是可以把公式\ref{eq:10-27}重写为:
\parinterval 最后,从统计学的角度,如果把$\alpha_i$作为每个$\mathrm{value}_i$出现的概率的某种估计,即:$ \funp{P} (\mathrm{value}_i$) $= \alpha_i$,于是可以把公式\ref{eq:10-27}重写为:
\begin{eqnarray}
\overline{\mathrm{value}} = \sum_i \funp{P} ( {\mathrm{value}}_i) \cdot {\mathrm{value}}_i
\label{eq:10-28}
......@@ -1276,7 +1282,7 @@ a (\vectorn{s},\vectorn{h}) = \left\{ \begin{array}{ll}
\vspace{0.5em}
\item 注意力机制的使用是机器翻译乃至整个自然语言处理近几年获得成功的重要因素之一\upcite{Liu_2019_CVPR,DBLP:journals/corr/abs-1811-00498,MoradiInterrogating}。早期,有研究者尝试将注意力机制和统计机器翻译的词对齐进行统一\upcite{WangNeural}。近两年,也有研究已经发现注意力模型可以捕捉一些语言现象\upcite{DBLP:journals/corr/abs-1905-09418},比如,在Transformer的多头注意力中,不同头往往会捕捉到不同的信息,比如,有些头对低频词更加敏感,有些头更适合词意消歧,甚至有些头可以捕捉句法信息。此外,由于注意力机制增加了模型的复杂性,而且随着网络层数的增多,神经机器翻译中也存在大量的冗余,因此研发轻量的注意力模型也是具有实践意义的方向\upcite{Xiao2019SharingAW}
\vspace{0.5em}
\item 一般来说,神经机器翻译的计算过程是没有人工干预的,翻译流程也无法用人类的知识直接进行解释,因此一个有趣的方向是在神经机器翻译中引入先验知识,使得机器翻译的行为更``像''人。比如,可以使用句法树来引入人类的语言学知识\upcite{Yang2017TowardsBH,Wang2019TreeTI},基于句法的神经机器翻译也包含大量的树结构的神经网络建模\upcite{DBLP:journals/corr/abs-1809-01854,DBLP:journals/corr/abs-1808-09374}。此外,也可以把用户定义的词典或者翻译记忆加入到翻译过程来\upcite{DBLP:journals/corr/ZhangZ16c,Dai2019TransformerXLAL},使得用户的约束可以直接反映到机器翻译的结果上来。先验知识的种类还有很多,包括词对齐\upcite{li-etal-2019-word,Zhang2017PriorKI}、篇章信息\upcite{Werlen2018DocumentLevelNM,DBLP:journals/corr/abs-1805-10163}等等,都是神经机器翻译中能够使用的信息。
\item 一般来说,神经机器翻译的计算过程是没有人工干预的,翻译流程也无法用人类的知识直接进行解释,因此一个有趣的方向是在神经机器翻译中引入先验知识,使得机器翻译的行为更“像”人。比如,可以使用句法树来引入人类的语言学知识\upcite{Yang2017TowardsBH,Wang2019TreeTI},基于句法的神经机器翻译也包含大量的树结构的神经网络建模\upcite{DBLP:journals/corr/abs-1809-01854,DBLP:journals/corr/abs-1808-09374}。此外,也可以把用户定义的词典或者翻译记忆加入到翻译过程来\upcite{DBLP:journals/corr/ZhangZ16c,Dai2019TransformerXLAL},使得用户的约束可以直接反映到机器翻译的结果上来。先验知识的种类还有很多,包括词对齐\upcite{li-etal-2019-word,Zhang2017PriorKI}、篇章信息\upcite{Werlen2018DocumentLevelNM,DBLP:journals/corr/abs-1805-10163}等等,都是神经机器翻译中能够使用的信息。
\vspace{0.5em}
\item 神经机器翻译依赖成本较高的GPU设备,因此对模型的裁剪和加速也是很多系统研发人员所感兴趣的方向。比如,从工程上,可以考虑减少运算强度,比如使用低精度浮点数或者整数进行计算,或者引入缓存机制来加速模型的推断\upcite{DBLP:journals/corr/abs-1906-00532,DBLP:journals/corr/CourbariauxB16};也可以通过对模型参数矩阵的剪枝,甚至对模块的剪枝,来减小整个模型的体积\upcite{Zhang2018SpeedingUN,DBLP:journals/corr/SeeLM16};另一种方法是知识精炼。利用大模型训练小模型,这样往往可以得到比单独训练小模型更好的效果\upcite{DBLP:journals/corr/ChenLCL17,Hinton2015Distilling,Sun2019PatientKD}
\vspace{0.5em}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论