Hi大家好,这里依旧是默元。今天分享 Datawhale_AI夏令营 第二次任务!
上一篇笔记中我们已经大致梳理了baseline的基本结构。今天继续详细解读代码,并回答几个小问题。
代码解读(接上一篇笔记)
上一篇笔记中,对baseline代码详细解读到了# 这里使用extract抽取模获得抽取的结果
这一部分。我们接着往下看。
# 这里使用extract抽取模获得抽取的结果
def extract(input_text):
ans_pattern = re.compile(r"答案是:(.)", re.S)
problems = ans_pattern.findall(input_text)
# print(problems)
if(problems == ''):
return 'A'
return problems[0]
extract直译为提取,那么这个函数就是提取函数啦!input_text是什么?我们只知道它是“输入文本”的意思,它在哪里出现过吗?
我们使用CTRL+F找一下。
怎么回事呢?全部代码文件中,只有这里(和这个函数里面)出现了input_text,它到底是什么?
其实,input_text在这里只是一个“形式参数”,而不是一个实际参数。形式参数可以和真正的参数名字一样,也可以不一样。这一点在大部分编程语言中都有类似情况。详细可以阅读这一篇文章:
所以input_text是什么?我们要看extract函数在使用时传入参数传入了什么。所以我们后面遇到再解析。
我们再来看这个函数的功能。
re是一个python模块,re.compile函数用于编译正则表达式,生成一个 Pattern 对象,它的一般使用形式如下:
re.compile(pattern[, flag])
其中,pattern 是一个字符串形式的正则表达式,flag 是一个可选参数,表示匹配模式,比如忽略大小写,多行模式等。re.S表示使 . 匹配包括换行在内的所有字符。
更多内容可以阅读:
也就是说,在这里,我们将“返回形如 ‘答案是:(.)’ 中 . 的位置的所有字符(包括换行符在内)”。
这里我们需要结合上文的prompt看一下(在上一篇笔记中详细介绍过):
上文的 prompt 内容
prompt = f”””你是一个逻辑推理专家,擅长解决逻辑推理问题。以下是一个逻辑推理的题目,形式为单项选择题。所有的问题都是(close-world assumption)闭世界假设,即未观测事实都为假。请逐步分析问题并在最后一行输出答案,最后一行的格式为”答案是:A”。题目如下:
我们可以看到,我们让大语言模型逐步分析问题并在最后一行输出答案,最后一行的格式为”答案是:A”。那么,通过上文”答案是:(.)”的正则表达式,我们便可以提取到大语言模型作出的答案。
接下来我们做了一个判断:如果我们提取到的结果为空字符串,则返回为’A’。否则的话返回为我们提取到的第0个结果。
为什么会有第0个结果呢,难道还可能有很多结果吗?为什么还会有空字符串的情况呢?
我们可以想到,这都是因为大语言模型输出结果不准确,有时候,它可能在一段话中先后说出“答案是:A”和“答案是B”这样自相矛盾的结果,也可能根本没有遵守我们设定的格式,如回答“我认为答案是A”这样的情况。这时,baseline的处理方法是如果大语言模型没有按约定回答,则输出为A,如果大语言模型回答了多个,则输出为第一个回答。
知道了这一点后,我们就可以想到改进的办法。
- 我们可以改变prompt的措辞。
如,我们可以改成这样:
- 当大模型输出结果不正确时,重新调用函数让大模型输出。
使用这种方法时,要特别注意重试次数应该有一个上限(和上文尝试重连api次数一个道理)。这种方法我们下文会写。
我们继续看代码。
def process_datas(datas,MODEL_NAME):
results = []
定义函数process_datas,传入参数datas和MODEL_NAME。初始化一个空的results。
with ThreadPoolExecutor(max_workers=16) as executor:
ThreadPoolExecutor线程池。max_workers最大工作者数量(直译),也就是最大的同时进行的线程数量。
这一段代码使过程使用多线程执行,加快了执行速度。
def main(ifn, ofn):
if os.path.exists(ofn):
pass
data = []
# 按行读取数据
with open(ifn) as reader:
for line in reader:
sample = json.loads(line)
data.append(sample)
datas = data
# print(data)
# 均匀地分成多个数据集
return_list = process_datas(datas,MODEL_NAME)
print(len(return_list))
print("All tasks finished!")
return return_list
主函数,读取数据,没什么特别的。