本次挑战基于Qwen开源大模型,利用大语言模型的学习和推理能力,完成数学、逻辑推理等问题
1.速通baseline
1)根据Datawhale官方给出的速通文档从零入门AI逻辑推理,按照步骤报名天池赛事,并开通阿里云零积平台的大模型服务。
2)使用阿里云账号登录魔搭Notebook
3)下载速通文档中的baseline01.ipynb、round1_test_data.jsonl两个文件,并上传到Notebook中,就可以开始跑代码啦~
step1:环境配置
!pip install scipy openai tiktoken retry dashscope loguru
step2:导入所需要的库
其中包括日志、多线程、api等库,最后注意MODEL_NAME需要找个免费的大模型,可以在灵积平台-计费管理查看限时免费的开源大模型。
from multiprocessing import Process, Manager
import json
import os
from pprint import pprint
import re
from tqdm import tqdm
import random
import uuid
import openai
import tiktoken
import json
import numpy as np
import requests
from retry import retry
from scipy import sparse
#from rank_bm25 import BM25Okapi
#import jieba
from http import HTTPStatus
import dashscope
from concurrent.futures import ThreadPoolExecutor, as_completed
from loguru import logger
import json
import time
from tqdm import tqdm
logger.remove() # 移除默认的控制台输出
logger.add("logs/app_{time:YYYY-MM-DD}.log", level="INFO", rotation="00:00", retention="10 days", compression="zip")
MODEL_NAME = 'qwen1.5-1.8b-chat' # 截止到7.26日下午15:00,该模型在灵积平台限时免费
step3:api-key
在灵积平台-API-KEY管理创建自己的api-key并填入。
# 注意:这里需要填入你的key~ 咱们在第二步申请的。
dashscope.api_key = "sk-****************"
step4:大模型部分
调用Qwen大模型
def call_qwen_api(MODEL_NAME, query):
# 这里采用dashscope的api调用模型推理,通过http传输的json封装返回结果
messages = [
{'role': 'user', 'content': query}]
response = dashscope.Generation.call(
MODEL_NAME,
messages=messages,
result_format='message', # set the result is message format.
)
if response.status_code == HTTPStatus.OK:
# print(response)
return response['output']['choices'][0]['message']['content']
else:
print('Request id: %s, Status code: %s, error code: %s, error message: %s' % (
response.request_id, response.status_code,
response.code, response.message
))
raise Exception()
如果请求失败,将在三秒后用retry函数重试
def api_retry(MODEL_NAME, query):
max_retries = 5
retry_delay = 60 # in seconds
attempts = 0
while attempts < max_retries:
try:
return call_qwen_api(MODEL_NAME, query)
except Exception as e:
attempts += 1
if attempts < max_retries:
logger.warning(f"Attempt {attempts} failed for text: {query}. Retrying in {retry_delay} seconds...")
time.sleep(retry_delay)
else:
logger.error(f"All {max_retries} attempts failed for text: {query}. Error: {e}")
raise
prompt推理模板如下
def get_prompt(problem, question, options):
options = '\n'.join(f"{'ABCDEFG'[i]}. {o}" for i, o in enumerate(options))
prompt = f"""你是一个逻辑推理专家,擅长解决逻辑推理问题。以下是一个逻辑推理的题目,形式为单项选择题。所有的问题都是(close-world assumption)闭世界假设,即未观测事实都为假。请逐步分析问题并在最后一行输出答案,最后一行的格式为"答案是:A"。题目如下:
### 题目:
{problem}
### 问题:
{question}
{options}
"""
# print(prompt)
return prompt
抽取函数,与推理模板相对应,用正则表达式进行匹配
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]
线程池,控制多线程运行程序
def process_datas(datas,MODEL_NAME):
results = []
with ThreadPoolExecutor(max_workers=16) as executor:
future_data = {}
lasttask = ''
lastmark = 0
lens = 0
for data in tqdm(datas, desc="Submitting tasks", total=len(datas)):
problem = data['problem']
for id,question in enumerate(data['questions']):
prompt = get_prompt(problem,
question['question'],
question['options'],
)
future = executor.submit(api_retry, MODEL_NAME, prompt)
future_data[future] = (data,id)
time.sleep(0.6) # 控制每0.5秒提交一个任务
lens += 1
for future in tqdm(as_completed(future_data), total=lens, desc="Processing tasks"):
# print('data',data)
data = future_data[future][0]
problem_id = future_data[future][1]
try:
res = future.result()
extract_response = extract(res)
# print('res',extract_response)
data['questions'][problem_id]['answer'] = extract_response
results.append(data)
# print('data',data)
except Exception as e:
logger.error(f"Failed to process text: {data}. Error: {e}")
return results
主函数,对代码进行启动
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
评估函数,对结果进行评估
def evaluate(ofn):
data = []
with open(ofn) as reader:
for line in reader:
sample = json.loads(line)
data.append(sample)
pse = 0
cnt = 0
tot = 0
for task in data:
for question in task['questions']:
if MODEL_NAME in question:
tot += 1
cnt += question[MODEL_NAME] == question['answer']
else:
pse += 1
print(cnt, tot, cnt/tot, pse)
对结果进行去重与排序
def has_complete_answer(questions):
# 这里假设完整答案的判断逻辑是:每个question都有一个'answer'键
for question in questions:
if 'answer' not in question:
return False
return True
def filter_problems(data):
result = []
problem_set = set()
for item in data:
# print('处理的item' ,item)
problem = item['problem']
if problem in problem_set:
# 找到已存在的字典
for existing_item in result:
if existing_item['problem'] == problem:
# 如果当前字典有完整答案,替换已存在的字典
if has_complete_answer(item['questions']):
existing_item['questions'] = item['questions']
existing_item['id'] = item['id']
break
else:
# 如果当前字典有完整答案,添加到结果列表
if has_complete_answer(item['questions']):
result.append(item)
problem_set.add(problem)
return result
查找缺失的序号
def find_missing_ids(dict_list):
# 提取所有序号
extracted_ids = {int(d['id'][-3:]) for d in dict_list}
# 创建0-500的序号集合
all_ids = set(range(500))
# 找出缺失的序号
missing_ids = all_ids - extracted_ids
return sorted(missing_ids)
# 示例字典列表
dict_list = sorted_data
# 找出缺失的序号
missing_ids = find_missing_ids(dict_list)
print("缺失的序号:", missing_ids)
对缺失的答案进行补充,统一填充为‘A’
data = []
with open('round1_test_data.jsonl') as reader:
for id,line in enumerate(reader):
if(id in missing_ids):
sample = json.loads(line)
for question in sample['questions']:
question['answer'] = 'A'
sorted_data.append(sample)
sorted_data = sorted(sorted_data, key=lambda x: int(str(x['id'])[-3:]))
将结果保存为upload.jsonl文件
with open('upload.jsonl', 'w') as writer:
for sample in sorted_data:
writer.write(json.dumps(sample, ensure_ascii=False))
writer.write('\n')
4)最后别忘了下载结果文件upload.jsonl,并上传到官网进行打分,大概等待一两分钟就可以查看分数啦。
2.改进思路
提示工程(Prompt Engineering)
提示工程是一种新兴的领域,专注于创建和优化提示词,以便用户能够更有效地将大型语言模型(LLM)应用于不同的场景和研究领域。通过学习和掌握提示工程,用户可以更深入地理解大型语言模型的功能及其限制。
该学科使得研究人员能够通过精心设计的提示,增强大型语言模型在处理复杂任务,比如问答和算数推理等方面的能力。同时,开发者可以利用这一学科的技术和方法,开发出能够与大型语言模型及其他工具更有效集成的应用技术。
提示工程远不止是制定和开发提示词那么简单,它还涉及到一系列与大型语言模型互动和开发相关的技能与技术。这一领域对于优化大语言模型的交互、集成以及理解其能力都至关重要。用户可以通过精于提示工程,不仅提升大型语言模型的安全使用,还能够借助特定行业知识和外部工具来扩展模型的功能和效能。
我将提示词改为:假设你是一位具有高级逻辑推理能力的专家,对解答逻辑题目非常擅长。我将给出一个逻辑推理题,它是一道单项选择题。请注意,这个问题基于“闭世界假设”,意味着如果某个事实没有在题目中明确提出,那么就假定该事实为假。利用你的知识,我需要你逐步分析这个问题,然后以最清晰和最专业的方式解释你的推理过程。请在你的回答最后,明确地以”答案是:A/B/C/D(根据实际选项填写)“的形式给出结论。现在,请开始分析以下题目:
### 题目:
{problem}
### 问题:
{question}
{options}