SchoolWork-LaTeX/深度学习/实验/Retrieval_task/实验报告.tex

110 lines
6.9 KiB
TeX
Raw Normal View History

2024-09-02 17:47:53 +08:00
\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 sizeEMB表示嵌入维度。
\end{figure}
由于query和fact的每一行是对应的所以将query和fact通过编码器后的向量在对角线的位置表示查询和文档对应时的相似度正例而非对角线的位置表示非对应时的相似度负例所以此矩阵应该和单位矩阵相近所以可以用交叉熵损失。在实际代码中使用了小于1的margin来代替1形成对角阵。
这里只使用简单的线性层加残差连接是因为试了很多种结构比如更深的带残差块的线性层比如TransformerDecoder only效果都没有简单的线性层效果好。
\section{实验结果}
以下召回率都是指Recall@3
% 训练集和验证集比例为8:2batch 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}