110 lines
6.9 KiB
TeX
110 lines
6.9 KiB
TeX
|
\documentclass[a4paper]{ctexart}
|
|||
|
\usepackage[margin=1in]{geometry}
|
|||
|
\usepackage{booktabs}
|
|||
|
\usepackage{hyperref}
|
|||
|
\usepackage{graphicx}
|
|||
|
\usepackage[numbers]{gbt7714}
|
|||
|
\RequirePackage[outputdir=./latex-output]{minted}
|
|||
|
\setlength{\belowcaptionskip}{1em}
|
|||
|
|
|||
|
\title{《深度学习》实验报告}
|
|||
|
\author{姓名:岳锦鹏\qquad 学号:10213903403\qquad 专业:统计学-计算机\qquad 学院:统计学院}
|
|||
|
\date{2024年6月8日}
|
|||
|
\ctexset {
|
|||
|
section = {
|
|||
|
name = {,、},
|
|||
|
format += \raggedright,
|
|||
|
number = \chinese{section},
|
|||
|
},
|
|||
|
subsection = {
|
|||
|
% name = {(,)},
|
|||
|
number = \arabic{subsection}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
\begin{document}
|
|||
|
\maketitle
|
|||
|
\section{实验环境}
|
|||
|
\noindent requirements.txt:
|
|||
|
\begin{minted}[frame=leftline, framesep=1em, framerule=1pt]{python}
|
|||
|
numpy
|
|||
|
paddlepaddle-gpu
|
|||
|
scikit-learn
|
|||
|
tqdm
|
|||
|
\end{minted}
|
|||
|
这些代码库的作用是什么已经显而易见了,其中 \mintinline{Python}{scikit-learn (sklearn)} 只是用来分训练验证集的。
|
|||
|
|
|||
|
\section{实验过程}
|
|||
|
\subsection{实验思路}
|
|||
|
\subsubsection{确定首次召回个数}
|
|||
|
先尝试了一下完全不使用baseline的方法,直接从全部的几千个文档中召回3个文档,发现效果完全不如baseline,于是想到了采用二次召回,第一次采用baseline的方法,从几千个文档中召回一部分,第二次再从召回的这些文档中选出3个。关于第一次召回多少,我首先做了按照baseline的方式直接计算余弦相似度的top k召回率的实验,结果如 表 \ref{first retrieve num} 所示,可以看到当首次召回数量达到500个时已经有很高的召回率了,所以后续的实验都在首次召回500个文章下进行。
|
|||
|
\begin{table}[h]
|
|||
|
\centering \caption{直接计算余弦相似度的召回率} \label{first retrieve num}
|
|||
|
\begin{tabular}{cc}
|
|||
|
\toprule
|
|||
|
Recall@100 & 0.75 \\
|
|||
|
Recall@500 & 0.93 \\
|
|||
|
Recall@5000 & 0.99 \\
|
|||
|
\bottomrule
|
|||
|
\end{tabular}
|
|||
|
\end{table}
|
|||
|
|
|||
|
\subsubsection{二次召回方案选择}
|
|||
|
从500个里召回3个,仍然是一个复杂的任务,尝试过几种方案:
|
|||
|
\begin{enumerate}
|
|||
|
\item 将其当做分类问题,输入一个查询,500个文章,输出这500个文章的概率。缺点是效率可能较低,而且实验后发现效果也不好;
|
|||
|
\item 双塔编码(cross encoder)和point wise 对比学习\cite{jianshu},给定一个查询和一个文章,模型给出一个得分,对于查询和对应的文章(正例),得分应该更高;对于查询和不对应的文章(负例),得分应该更低,这里的负例一般是从文章库中随机选取。实验后发现不管正负例的比例是多少,效果都不好;
|
|||
|
\item 单塔编码,query通过查询编码器,fact通过文章编码器,之后计算编码后的向量的余弦相似度,如果不使用对比学习会导致模型把所有的文章都编码得非常相似,所以这里还是需要使用对比学习。那么如何选取负例?实验过还是从文章库中随机选取负例,效果还是不好,于是查找资料,发现了这样一篇文章:\cite{aistudio},里面提到了In-batch Negatives策略,即将一个批次内其他样本都作为负例,尝试后发现效果有很大提升,从baseline的0.2121提升到了0.4059。
|
|||
|
\end{enumerate}
|
|||
|
|
|||
|
最终选择了单塔编码的方案,并且使用了In-batch Negatives策略。
|
|||
|
\subsection{数据预处理部分}
|
|||
|
先使用 \mintinline{Python}{sklearn} 中的 \mintinline{Python}{train_test_split} 按8:2的比例分出训练集和验证集。对于训练集和验证集,先把首次召回500个的工作全部完成,即对于每一个查询,先召回500个文章,存放在内存中,训练时在这500 $\times $ num of queries 个样本里训练。
|
|||
|
\subsection{模型构建}
|
|||
|
这里需要做的就是在单塔编码中,如何编码查询,如何编码文章。其实非常简单,就是多层全连接层,使用ReLU作为激活函数,并且使用了残差连接,如图 \ref{model structure} 所示。
|
|||
|
\begin{figure}[h]
|
|||
|
\centering
|
|||
|
\includegraphics[width=1\linewidth]{模型结构图.png}
|
|||
|
\caption{模型结构图}\label{model structure}
|
|||
|
(图中的N表示batch size,EMB表示嵌入维度。)
|
|||
|
\end{figure}
|
|||
|
|
|||
|
由于query和fact的每一行是对应的,所以将query和fact通过编码器后的向量,在对角线的位置表示查询和文档对应时的相似度(正例),而非对角线的位置表示非对应时的相似度(负例),所以此矩阵应该和单位矩阵相近,所以可以用交叉熵损失。在实际代码中使用了小于1的margin来代替1形成对角阵。
|
|||
|
|
|||
|
这里只使用简单的线性层加残差连接,是因为试了很多种结构,比如更深的带残差块的线性层,比如Transformer(Decoder only),效果都没有简单的线性层效果好。
|
|||
|
|
|||
|
\section{实验结果}
|
|||
|
(以下召回率都是指Recall@3)
|
|||
|
|
|||
|
% 训练集和验证集比例为8:2,batch size设为1024,训练370轮,优化器为Adam,在验证集上的召回率为0.48165760869565216,提交后(在测试集上)的召回率为0.452148。
|
|||
|
|
|||
|
% 不区分训练集和验证集,batch size设为4096,训练1300轮,优化器为Adam,提交后(在测试集上)的召回率为0.529622。
|
|||
|
|
|||
|
% 不区分训练集和验证集,batch size设为2048,训练2500步(iter steps)(不是轮(epochs)了),优化器为Adam,提交后(在测试集上)的召回率为0.523275。
|
|||
|
|
|||
|
% 不区分训练集和验证集,batch size设为2048,训练2600步,优化器为AdamW,提交后(在测试集上)的召回率为0.523926。
|
|||
|
|
|||
|
% 不区分训练集和验证集,batch size设为2048,训练5100步,优化器为AdamW,将模型参数与输入输出的数据类型从float32改为float64,提交后(在测试集上)的召回率为0.584635。
|
|||
|
|
|||
|
结果如表 \ref{hyper-parameters} 所示。
|
|||
|
\begin{table}[h]
|
|||
|
\centering
|
|||
|
\caption{尝试不同的超参数}\label{hyper-parameters}
|
|||
|
\begin{tabular}{cccccccc}
|
|||
|
\toprule
|
|||
|
序号 & 是否有验证集 & batch size & epoch / step & 优化器 & 数据类型 & 验证集召回率 & 测试集召回率 \\
|
|||
|
\midrule
|
|||
|
0 & \multicolumn{4}{c}{baseline 无需训练} & float32 & / & 0.212077 \\
|
|||
|
1 & 是 & 1024 & 370 epochs & Adam & float32 & 0.481658 & 0.452148 \\
|
|||
|
2 & 否 & 4096 & 1300 epochs & Adam & float32 & / & 0.529622 \\
|
|||
|
3 & 否 & 2048 & 2500 steps & Adam & float32 & / & 0.523275 \\
|
|||
|
4 & 否 & 2048 & 2600 steps & AdamW & float32 & / & 0.523926 \\
|
|||
|
5 & 否 & 2048 & 5100 steps & AdamW & float64 & / & 0.584635 \\
|
|||
|
6 & 否 & 8192 & 9500 steps & AdamW & float64 & / & \textbf{0.606283} \\
|
|||
|
\bottomrule
|
|||
|
\end{tabular}
|
|||
|
\end{table}
|
|||
|
|
|||
|
\bibliography{ref}
|
|||
|
|
|||
|
\end{document}
|