抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

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,如果大语言模型回答了多个,则输出为第一个回答。

知道了这一点后,我们就可以想到改进的办法。

  1. 我们可以改变prompt的措辞。

如,我们可以改成这样:

prompt = f"""你是一个逻辑推理专家,擅长解决逻辑推理问题,能够从前后各语句之间的因果、转折、包含、递进等关系中推断出其他正确的信息。以下是一个逻辑推理的题目,形式为单项选择题。我将先给出一段基本的论断,论断都是正确的。接下来询问你几个选择题并附有几个选项,请逐步分析问题并在最后一行输出你认为正确的答案。一定注意,最后一行输出答案的格式为形如"答案是:A"的语句。所有的问题都是基于闭世界假设,即不确定,或已知的信息中未提到的信息为假(False)。一定注意,最后一行输出答案的格式为形如"答案是:A"的语句。题目如下:
  1. 当大模型输出结果不正确时,重新调用函数让大模型输出。
    使用这种方法时,要特别注意重试次数应该有一个上限(和上文尝试重连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

主函数,读取数据,没什么特别的。

评论

评论区不是无人区喵