Commit 7a7a9c10 by xiaotong

wording (sec 13)

parent 013010c4
......@@ -25,7 +25,7 @@
\node [anchor=north] (n11) at ([xshift=0em,yshift=-1em]n3.south) {${{y}}_{j-2}$};
\node [anchor=north] (n12) at ([xshift=0em,yshift=-1em]n4.south) {${{y}}_{j-1}$};
\node [anchor=north] (n9) at ([xshift=0em,yshift=-3em]n4.south) {\small{(a)训练阶段}};
\node [anchor=north] (n9) at ([xshift=0em,yshift=-3em]n4.south) {\small{(a) 训练阶段}};
\node [anchor=north] (x1) at ([xshift=0em,yshift=-1em]n1.south) {$\langle$sos$\rangle$};
......@@ -65,21 +65,22 @@
\node [anchor=south,minimum width=0.8em,minimum height=1.4em,fill=red!50,inner sep=0pt] (label1) at ([xshift=-0.1em,yshift=0em]y1.north) {};
\node [anchor=south,minimum width=0.8em,minimum height=2.2em,fill=red!50,inner sep=0pt] (label2) at ([xshift=-0.1em,yshift=0em]y2.north) {};
\node [anchor=south,minimum width=0.8em,minimum height=2.8em,fill=red!50,inner sep=0pt] (label3) at ([xshift=-0.1em,yshift=0em]y3.north) {};
\node [anchor=south,minimum width=0.8em,minimum height=3.2em,fill=red!50,inner sep=0pt] (label4) at ([xshift=-0.1em,yshift=0em]y4.north) {};
\node [anchor=south,minimum width=0.8em,minimum height=2.4em,fill=red!50,inner sep=0pt] (label5) at ([xshift=-0.1em,yshift=0em]y5.north) {};
\node [anchor=south,minimum width=0.8em,minimum height=1.7em,fill=red!50,inner sep=0pt] (label6) at ([xshift=-0.1em,yshift=0em]y6.north) {};
\node [anchor=south,minimum width=0.8em,minimum height=0.4em,fill=red!50,inner sep=0pt] (label8) at ([xshift=-0.1em,yshift=0em]y8.north) {};
\node [anchor=south,minimum width=0.8em,minimum height=1.4em,fill=ugreen!50,inner sep=0pt] (label1) at ([xshift=-0.1em,yshift=0em]y1.north) {};
\node [anchor=south,minimum width=0.8em,minimum height=2.2em,fill=ugreen!50,inner sep=0pt] (label2) at ([xshift=-0.1em,yshift=0em]y2.north) {};
\node [anchor=south,minimum width=0.8em,minimum height=2.8em,fill=ugreen!50,inner sep=0pt] (label3) at ([xshift=-0.1em,yshift=0em]y3.north) {};
\node [anchor=south,minimum width=0.8em,minimum height=3.2em,fill=ugreen!50,inner sep=0pt] (label4) at ([xshift=-0.1em,yshift=0em]y4.north) {};
\node [anchor=south,minimum width=0.8em,minimum height=2.4em,fill=ugreen!50,inner sep=0pt] (label5) at ([xshift=-0.1em,yshift=0em]y5.north) {};
\node [anchor=south,minimum width=0.8em,minimum height=1.7em,fill=ugreen!50,inner sep=0pt] (label6) at ([xshift=-0.1em,yshift=0em]y6.north) {};
\node [anchor=south,minimum width=0.8em,minimum height=0.4em,fill=ugreen!50,inner sep=0pt] (label8) at ([xshift=-0.1em,yshift=0em]y8.north) {};
\begin{pgfonlayer}{background}
\node [rectangle,inner sep=0.1em,rounded corners=5pt,very thick,dotted,draw=red] [fit = (n11) (n12)] (b1) {};
\node [rectangle,inner sep=0.5em,rounded corners=5pt,very thick,dotted,draw=red] [fit = (n10) (y1) (y8)] (b2) {};
\node [rectangle,inner sep=0.1em,rounded corners=5pt,very thick,dotted,draw=ugreen] [fit = (n11) (n12)] (b1) {};
\node [rectangle,inner sep=0.5em,rounded corners=5pt,very thick,dotted,draw=ugreen] [fit = (n10) (y1) (y8)] (b2) {};
\draw [->,dotted,very thick,red] ([yshift=-0em]b1.east) .. controls +(east:2) and +(west:1) .. (b2.west);
\draw [->,dotted,very thick,ugreen] ([yshift=-0em]b1.east) .. controls +(east:1.7) and +(west:1) .. ([xshift=-0.1em]b2.west);
\node [anchor=east] (inputlabel1) at ([yshift=-0.2em]b1.west) {{\color{red} \footnotesize{人工标注数据}}};
\end{pgfonlayer}
......@@ -103,7 +104,7 @@
\node [anchor=south,snode,font=\footnotesize] (n13) at ([xshift=0em,yshift=1em]n1.north) {Softmax};
\node [anchor=south,ynode] (n14) at ([xshift=0em,yshift=1em]n13.north) {$\tilde{{y}}_{1}$};
\node [anchor=north] (n9) at ([xshift=0em,yshift=-3em]n4.south) {\small{(b)解码阶段}};
\node [anchor=north] (n9) at ([xshift=0em,yshift=-3em]n4.south) {\small{(b) 推断阶段}};
\node [anchor=north] (n11) at ([xshift=0em,yshift=-1em]n3.south) {$\tilde{{y}}_{j-2}$};
\node [anchor=north] (n12) at ([xshift=0em,yshift=-1em]n4.south) {$\tilde{{y}}_{j-1}$};
......@@ -164,7 +165,8 @@
\node [rectangle,inner sep=0.5em,rounded corners=5pt,very thick,dotted,draw=ublue] [fit = (n10) (y1) (y5)] (b2) {};
\draw [->,dotted,very thick,ublue] ([xshift=-0em,yshift=-0em]b1.east) .. controls +(east:2) and +(west:1) .. (b2.west);
\draw [->,dotted,very thick,ublue] ([xshift=-0em,yshift=-0em]b1.east) .. controls +(east:1.7) and +(west:1) .. ([xshift=-0.1em]b2.west);
\node [anchor=east] (inputlabel1) at ([yshift=-0.2em]b1.west) {{\color{red} \footnotesize{系统预测结果}}};
\end{pgfonlayer}
......
......@@ -118,28 +118,7 @@
\subsection{双字节编码}
\parinterval 字节对编码或双字节编码(BPE)是一种常用的子词词表构建方法。BPE方法最早用于数据压缩,该方法将数据中常见的连续字符串替换为一个不存在的字符,之后通过构建一个替换关系的对应表,对压缩后的数据进行还原\upcite{Gage1994ANA}。机器翻译借用了这种思想,把子词切分看作是学习对自然语言句子进行压缩编码表示的问题\upcite{DBLP:conf/acl/SennrichHB16a}。其目的是,保证编码后的结果(即子词切分)占用的字节尽可能少。这样,子词单元会尽可能被不同单词复用,同时又不会因为使用过小的单元造成子词切分序列过长。使用BPE算法构建符号合并表可以分为如下几个步骤:
\begin{itemize}
\vspace{0.5em}
\item 对每个句子进行分词;
\vspace{0.5em}
\item 将分词后的每个单词进行进一步切分,划分为字符序列。同时,在每个单词结尾添加结束符<e>用于标记单词的边界。之后,统计该单词在数据中出现的次数。例如单词low在数据中出现了5次,可以将其记为‘l o w <e>’:5({\color{red}再调一下})。
\vspace{0.5em}
\item 对得到的字符集合进行统计,统计每个单词中2-gram符号出现的频次 \footnote{发生合并前,一个字符便是一个符号}。之后,选择最高频的2-gram符号,将其合并为新的符号,即新的子词。例如“A”和“B”连续出现的频次最高,则以“AB”替换所有单词内连续出现的“A”和“B”并将其加入子词词表。这样,“AB”会被作为一个整体,在之后的过程中可以与其他符号进一步合并。需要注意的是,替换和合并不会跨越单词的边界,即只对单个单词进行替换和合并。
\vspace{0.5em}
\item 不断重复上一步骤,直到子词词表大小达到预定的大小或者下一个最高频的2-gram字符的频次为1。子词词表大小是BPE的唯一的参数,它用来控制上述子词合并的规模。
\vspace{0.5em}
%----------------------------------------------
\begin{figure}[htp]
\centering
\input{./Chapter13/Figures/figure-bpe}
\caption{BPE算法运行实例}
\label{fig:7-9}
\end{figure}
%----------------------------------------------
\end{itemize}
\parinterval 字节对编码或双字节编码(BPE)是一种常用的子词词表构建方法。BPE方法最早用于数据压缩,该方法将数据中常见的连续字符串替换为一个不存在的字符,之后通过构建一个替换关系的对应表,对压缩后的数据进行还原\upcite{Gage1994ANA}。机器翻译借用了这种思想,把子词切分看作是学习对自然语言句子进行压缩编码表示的问题\upcite{DBLP:conf/acl/SennrichHB16a}。其目的是,保证编码后的结果(即子词切分)占用的字节尽可能少。这样,子词单元会尽可能被不同单词复用,同时又不会因为使用过小的单元造成子词切分序列过长。
\parinterval\ref{fig:7-9}给出了BPE算法执行的实例。其中预先设定的合并表的大小为10。在得到了符号合并表后,便需要对用字符表示的单词进行合并,得到以子词形式表示的文本。首先,将单词切分为以字符表示的符号序列,并在尾部加上终结符。然后按照符号合并表的顺序依次遍历,如果存在相同的2-gram符号组合,则对其进行合并,直至遍历结束。图1.4给出了一个使用字符合并表对单词进行子词切分的实例。红色单元为每次合并后得到的新符号,直至无法合并,或遍历结束,得到最终的合并结果。其中每一个单元为一个子词。
......@@ -412,37 +391,35 @@ R(\mathbi{w}) & = & (\big| |\mathbi{w}| {\big|}_2)^2 \\
\subsection{基于白盒攻击的方法}
\parinterval 除了在单词级别增加扰动以外,还可以在模型内部增加扰动。这里简单介绍一下利用白盒攻击方法增加模型健壮性的方法:
\parinterval 除了在单词级别增加扰动以外,还可以在模型内部增加扰动。一种简单的方法是在每一个词的词嵌入表示上,累加一个正太分布,之后将其作为模型的最终输入。同时,可以在训练目标中增加额外的训练目标。比如,迫使模型在接收到被扰动的输入后,编码器能够生成与正常输入类似的表示,解码器输出正确的翻译结果\upcite{DBLP:conf/acl/LiuTMCZ18}
\parinterval 除了引入标准的噪声外,还可以根据模型所存在的具体问题,构建不同的扰动。例如,针对输入中包含同音字错误导致的模型输出误差较大的问题,可以将单词的发音转换为一个包含$n$个发音单元的发音序列,如音素,音节等。并训练相应的嵌入矩阵将每一个发音单元转换为对应的向量表示。对发音序列中发音单元的嵌入表示进行平均后,得到当前单词的发音表示。最后将词嵌入与单词的发音表示进行加权求和,并将结果作为模型的输入\upcite{DBLP:conf/acl/LiuMHXH19}。通过这种方式可以提高模型对同音异形词的处理能力。除了在词嵌入层增加扰动,也可以在编码端输出中引入额外的噪声,能起到与在层输入中增加扰动相类似的效果\upcite{DBLP:conf/acl/LiLWJXZLL20}
\parinterval 此外,对于训练样本$(\mathbi{x},\mathbi{y})$,还可以使用基于梯度的方法来生成对抗样本$(\mathbi{x}',\mathbi{y}')$。例如,可以利用替换词与原始单词词向量之间的差值,以及候选词的梯度之间的相似度来生成对抗样本\upcite{DBLP:conf/acl/ChengJM19}。以源语言为例,生成$\mathbi{x}'$$i$个词的过程可以被描述如下:
\begin{itemize}
\vspace{0.5em}
\item 可以在每一个词的词嵌入表示上,累加一个服从正太分布的变量,之后将其作为模型的最终输入。同时,可以在训练目标中增加额外的训练目标。比如,迫使模型在接收到被扰动的输入后,编码端能够生成与正常输入类似的表示,解码端输出正确的翻译结果\upcite{DBLP:conf/acl/LiuTMCZ18}
\vspace{0.5em}
\item 除了引入标准的噪声外,还可以根据模型所存在的具体问题,构建不同的扰动。例如,针对输入中包含同音字错误导致的模型输出误差较大的问题,可以将单词的发音转换为一个包含$n$个发音单元的发音序列,如音素,音节等。并训练相应的嵌入矩阵将每一个发音单元转换为对应的向量表示。对发音序列中发音单元的嵌入表示进行平均后,得到当前单词的发音表示。最后将词嵌入与单词的发音表示进行加权求和,并将结果作为模型的输入\upcite{DBLP:conf/acl/LiuMHXH19}。通过这种方式可以提高模型对同音异形词的健壮性,得到更准确的翻译结果。此外除了在词嵌入层增加扰动,例如,在端到端模型中的编码端输出中引入额外的噪声,能起到与在层输入中增加扰动相类似的效果,增强了模型训练的健壮性\upcite{DBLP:conf/acl/LiLWJXZLL20}
\vspace{0.5em}
\item 此外还可以使用基于梯度的方法来生成对抗样本。例如,可以利用替换词与原始单词词向量之间的差值,以及候选词的梯度之间的相似度来生成对抗样本\upcite{DBLP:conf/acl/ChengJM19},具体的计算方式如下:
\begin{eqnarray}
{{x}'}_i &=& \arg\max_{{x}\in V}\textrm{sim}(\funp{e}({x})-\funp{e}({x}_i),\mathbi{g}_{{x}_i})
{{x}'}_i &=& \argmax_{{x}\in V}\textrm{sim}(\funp{e}({x})-\funp{e}({x}_i),\mathbi{g}_{{x}_i})
\label{eq:13-9} \\
\mathbi{g}_{{x}_i} &=& \bigtriangledown_{\funp{e}({x}_i)} - \log \funp{P}(\mathbi{y}|\mathbi{x};\theta)
\label{eq:13-10}
\end{eqnarray}
\noindent 其中,${x}_i$为输入中第$i$个词,$\mathbi{g}_{{x}_i}$为对应的梯度向量,$\funp{e}(\cdot)$用于获取词向量,$\textrm{sim}(\cdot,\cdot)$是用于评估两个向量之间相似度(距离)的函数,$V$为源语的词表,$\bigtriangledown$表示求梯度操作,因此公式\eqref{eq:13-10}表示求$- \log \funp{P}(\mathbi{y}|\mathbi{x};\theta)$$\funp{e}({x}_i)$的梯度。由于对词表中所有单词进行枚举时,计算成本较大。因此利用语言模型选择最可能的$n$ 个词作为候选,进而缩减匹配范围,并从中采样出源语词进行替换是一种更有效地方式。同时,为了保护模型不受解码器预测误差的影响,此时需要对模型目标端的输入做出同样的调整。与在源语端操作不同的地方时,此时会将公式\eqref{eq:13-10}中的损失替换为$- \log \funp{P}(\mathbi{y}|\mathbi{x}')$。同时,在如何利用语言模型选择候选和采样方面,也做出了相应的调整。在进行对抗性训练时,在原有的训练损失上增加了三个额外的损失,最终的训练目标为:
\noindent 其中,${x}_i$为输入序列中的第$i$个词,$\funp{e}(\cdot)$用于获取词向量,$\mathbi{g}_{{x}_i}$为翻译概率相对于$e({x}_i)$的梯度,$\textrm{sim}(\cdot,\cdot)$是用于评估两个向量之间相似度(距离)的函数,$V$为源语言的词表。由于对词表中所有单词进行枚举时,计算成本较大。因此可以利用语言模型选择最可能的$n$ 个词作为候选,并从中采样出单词完成替换。同时,为了保护模型不受解码器预测误差的影响,此时需要对模型目标语言端的输入做出同样的调整。与源语言端的操作不同,此时会将公式\eqref{eq:13-10}中的损失替换为$- \log \funp{P}(\mathbi{y}|\mathbi{x}')$,即使用生成的对抗样本$\mathbi{x}'$计算翻译概率。
\parinterval 在进行对抗性训练时,可以在原有的训练损失上增加三个额外的损失,最终的损失函数被定义为:
\begin{eqnarray}
Loss(\theta_{\textrm{mt}},\theta_{\textrm{lm}}^{\mathbi{x}},\theta_{\textrm{lm}}^{\mathbi{y}}) &=& Loss_{\textrm{clean}}(\theta_{\textrm{mt}}) + Loss_{\textrm{lm}}(\theta_{\textrm{lm}}^{\mathbi{x}}) + \nonumber \\
& & Loss_{\textrm{robust}}(\theta_{\textrm{mt}}) + Loss_{\textrm{lm}}(\theta_{\textrm{lm}}^{\mathbi{y}})
\label{eq:13-11}
\end{eqnarray}
\noindent 其中,$Loss_{\textrm{clean}}(\theta_{\textrm{mt}})$为正常情况下的损失,$Loss_{\textrm{lm}}(\theta_{\textrm{lm}}^{\mathbi{x}})$$Loss_{\textrm{lm}}(\theta_{\textrm{lm}}^{\mathbi{y}})$为生成对抗样本所用到的源语言与目标语言的模型的损失,$Loss_{\textrm{robust}}(\theta_{\textrm{mt}})$是使用修改后得到的对抗样本作为输入,并以原始的目标语作为答案时计算得到的损失。令$N$个样本,则损失函数的具体形式如下:
\noindent 其中,$Loss_{\textrm{clean}}(\theta_{\textrm{mt}})$为正常情况下的损失,$Loss_{\textrm{lm}}(\theta_{\textrm{lm}}^{\mathbi{x}})$$Loss_{\textrm{lm}}(\theta_{\textrm{lm}}^{\mathbi{y}})$为生成对抗样本所用到的源语言与目标语言的模型的损失,$Loss_{\textrm{robust}}(\theta_{\textrm{mt}})$是使用修改后得到的对抗样本作为输入,并以原始的译文$\mathbi{y}$作为答案时计算得到的损失。假设$N$个样本,则损失函数的具体形式如下:
\begin{eqnarray}
Loss_{\textrm{robust}}(\theta_{\textrm{mt}}) &=& \frac{1}{N}\sum_{(\mathbi{x},\mathbi{y})}-\log \funp{P}(\mathbi{y}|\mathbi{x}',\mathbi{z}';\theta_{\textrm{mt}})
Loss_{\textrm{robust}}(\theta_{\textrm{mt}}) &=& \frac{1}{N}\sum_{(\mathbi{x},\mathbi{y})}-\log \funp{P}(\mathbi{y}|\mathbi{x}',\mathbi{y}';\theta_{\textrm{mt}})
\label{eq:13-11}
\end{eqnarray}
\end{itemize}
\parinterval 无论是黑盒方法还是白盒方法,本质上都是通过增加噪声使得模型训练更加健壮。类似的思想在很多机器学习方法中都有体现,比如,最大熵模型中使用高斯噪声就是常用的增加模型健壮性的手段之一\upcite{chen1999gaussian}。而在深度学习时代下,对抗训练将问题定义为:有意识地构造出系统容易出错的样本,并使用这种样本训练系统,以此增加系统的抗干扰能力。
%----------------------------------------------------------------------------------------
......@@ -452,7 +429,7 @@ Loss_{\textrm{robust}}(\theta_{\textrm{mt}}) &=& \frac{1}{N}\sum_{(\mathbi{x},\
\sectionnewpage
\section{学习策略}
\parinterval 在神经机器翻译中,极大似然估计是最常用的模型参数估计方法。尽管这种方法取得了巨大的成功,但仍然面临着许多问题。比如,似然函数并不是评价翻译系统性能的指标,这使得即使在训练数据上降低似然函数的值,但在应用模型时并不一定可以获得更好的翻译结果。针对极大似然估计的问题,研究人员提出了不同方法。本节首先会对极大似然估计的问题进行论述,然后介绍解决相关问题的不同方法。
\parinterval 在神经机器翻译中,极大似然估计是最常用的模型参数估计方法。尽管这种方法取得了巨大的成功,但仍然面临着许多问题。比如,似然函数并不是评价翻译系统性能的指标,这使得即使在训练数据上优化似然函数,但在应用模型时并不一定可以获得更好的翻译结果。本节首先会对极大似然估计的问题进行论述,然后介绍一些解决相关问题的方法。
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
......@@ -460,12 +437,10 @@ Loss_{\textrm{robust}}(\theta_{\textrm{mt}}) &=& \frac{1}{N}\sum_{(\mathbi{x},\
\subsection{极大似然估计的问题}\label{subsec-15.3.1}
\parinterval 极大似然估计已成为机器翻译乃至整个自然语言处理领域中使用最广泛的训练用目标函数。但是,使用极大似然估存在{\small\bfnew{曝光偏置}}\index{曝光偏置}(Exposure Bias\index{Exposure Bias})问题和训练解码评价指标不一致问题({\color{red} Minimum Risk Training for Neural Machine Translation}),具体来说:
\parinterval 极大似然估计已成为机器翻译乃至整个自然语言处理领域中使用最广泛的训练用目标函数。但是,使用极大似然估存在{\small\bfnew{曝光偏置}}\index{曝光偏置}(Exposure Bias\index{Exposure Bias})问题和训练-推断评价指标不一致问题。具体体现在如下两个方面。
\parinterval 曝光偏置问题:在训练过程中,模型使用标注数据进行训练,因此模型在预测下一个单词时,解码器的输入是正确的译文片段。也就是,预测单词$y_j$时,系统使用了标准答案$\{{y}_1,...,{y}_{j-1}\}$作为历史信息。但是对新的句子进行翻译时,预测第$j$个单词使用的是模型自己生成的前$j-1$个单词,即$\{\tilde{{y}}_1,...,\tilde{{y}}_{j-1}\}$。这意味着,训练时使用的输入数据(目标语言端)与真实翻译时的情况不符,如图\ref{fig:13-21} 所示。由于在训练过程中暴露于标注数据,因此模型可能适应了标注数据,在推断阶段无法很好地适应模型自动生成的数据,这就是曝光偏置问题\upcite{Bengio2015ScheduledSF,Ranzato2016SequenceLT}
\begin{itemize}
\vspace{0.5em}
\item 曝光偏置问题:在训练过程中,模型使用标注数据进行训练,因此模型在预测下一个单词时,解码器的输入是正确的译文片段,也就是预测单词$y_j$时,系统使用了标准答案$\{{y}_1,...,{y}_{j-1}\}$作为历史信息。但是对新的句子进行翻译时,预测第$j$个单词使用的是模型自己生成的前$j-1$个单词,即$\{\tilde{{y}}_1,...,\tilde{{y}}_{j-1}\}$。这意味着,训练时使用的输入数据(目标语言端)与真实翻译时的情况不符,而且二者所对应的概率分布可能会存在较大差异,如图\ref{fig:13-21} 所示。由于在训练过程中暴露于标注数据,因此模型可能适应了标注数据,在推断阶段无法很好地适应模型自动生成的数据,这就是曝光偏置问题\upcite{Bengio2015ScheduledSF,Ranzato2016SequenceLT}
\vspace{0.5em}
%----------------------------------------------
\begin{figure}[htp]
......@@ -476,9 +451,7 @@ Loss_{\textrm{robust}}(\theta_{\textrm{mt}}) &=& \frac{1}{N}\sum_{(\mathbi{x},\
\end{figure}
%----------------------------------------------
\item 训练目标函数与任务评价指标不一致问题:在训练过程中,在训练数据上进行极大似然估计,而在新数据上进行推断的时候,通常使用BLEU等外部评价指标来评价模型的性能。更加理想的情况是,模型应该直接最大化性能评价指标,而不是训练集数据上的似然函数。但是很多情况下,模型性能评价指标不可微分,这使得我们无法直接利用基于梯度的方法来优化模型。在机器翻译任务中,这个问题的一种体现是,训练数据上更低的困惑度不一定能带来BLEU的提升。
\vspace{0.5em}
\end{itemize}
\parinterval 训练目标函数与任务评价指标不一致问题:在训练过程中,在训练数据上进行极大似然估计,而在新数据上进行推断的时候,通常使用BLEU等外部评价指标来评价模型的性能。更加理想的情况是,模型应该直接最大化性能评价指标,而不是训练集数据上的似然函数({\color{red} Minimum Risk Training for Neural Machine Translation})。但是很多情况下,模型性能评价指标不可微分,这使得我们无法直接利用基于梯度的方法来优化模型。在机器翻译任务中,这个问题的一种体现是,训练数据上更低的困惑度不一定能带来BLEU的提升。
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论