@Datawhale 夏令营第三期 从零入门AI逻辑推理 task1 笔记打卡

作者的话:

本人是人工智能专业在读学生,受校内学长的推荐,同时也想趁着暑假的机会来提升自身本领,再加上Datawhale也与我们学校合作开展过相关活动故参加了本次夏令营,很高兴能够与那么多志同道合的同学们一起学习,一起进步。由于本人仍在学习中,水平有限,故文中的不妥之处还请大家不吝赐教。

1.赛事背景:

该比赛聚焦于通过解决复杂的逻辑推理题,测试大型语言模型的逻辑推理能力。这些逻辑题涵盖了多种关系和推理规则,能够全面评估模型的逻辑推理能力。赛题设置上,采用了多样化的逻辑题,覆盖了不同难度的逻辑推理任务,强调了逻辑推理在AI领域的重要性。比赛的研究成果将有助于评估和改进模型的逻辑推理能力。这对于开发更智能、更有效的人工智能系统具有重要意义。同时,大赛希望提供机会给选手学习和应用逻辑推理与自然语言处理的知识,培养跨学科的研究人才。

赛事链接:http://competition.sais.com.cn/competitionDetail/532231/competitionData

2.赛事任务:

本次比赛提供基于自然语言的逻辑推理问题,涉及多样的场景,包括关系预测、数值计算、谜题等,期待选手通过分析推理数据,利用机器学习、深度学习算法或者大语言模型,建立预测模型。

3.赛事分析:

解决的问题:

本次赛事的赛题是一个“用大语言模型处理推理任务”的问题,它要求选手构建一个能够完成推理任务的模型。

数据集:

提供的数据集为逻辑推理数据集,其中包含500条训练数据集和500条测试数据集。每个问题都包含若干个子问题,为单项选择的形式。目标是为每个子问题选择一个答案。

数据集的格式:

round1_train_data.jsonl : 每一行代表一条反应

测试集 round1_test_data.jsonl 不包含answer字段。

需要注意的是参赛选手可以使用开源数据,若使用了开源数据,需要在代码审核阶段提供数据来源以及相关说明。

4.task1完成步骤:

        1.在赛事网页进行报名:http://competition.sais.com.cn/competitionDetail/532231/format

        2.申领我们使用的DashScope大模型的API:https://dashscope.console.aliyun.com/apiKey

        3.使用魔塔Notebook的服务:https://www.modelscope.cn/my/mynotebook/preset

        4.使用提供的baseline代码跑通数据集

        5.提交输出结果:http://competition.sais.com.cn/competitionDetail/532231/mySubmissions

5.使用的baseline代码:

安装所需的模块:
!pip install scipy openai tiktoken retry dashscope loguru
 导包:
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,该模型在灵积平台限时免费
输入你申领的API:
# 注意:这里需要填入你的key~ 咱们在第二步申请的。
dashscope.api_key="sk-"
 定义所需的相关函数:
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
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()
# 这里定义了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
# 这里使用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]

 

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)
运行主程序:
if __name__ == '__main__':

    a = extract("""根据欧几里得算法,逐步解析计算两个数6和7的最大公约数(gcd)的步骤如下:

1. 判断6和7是否相等:不相等。
2. 判断6和7大小关系,7 > 6,所以用更大的数7减去较小的数6得到结果1。
3. 现在计算6和1的最大公约数。
4. 6 > 1,根据算法用更大的数6减去较小的数1得到结果5。
5. 再计算5和1的最大公约数。
6. 5 > 1,用5减去1得到结果4。
7. 再计算4和1的最大公约数。
8. 4 > 1,用4减去1得到结果3。
9. 再计算3和1的最大公约数。
10. 3 > 1,用3减去1得到结果2。
11. 再计算2和1的最大公约数。
12. 2 > 1,用2减去1得到结果1。
13. 最后计算1和1的最大公约数,两数相等,gcd即为这两个数,也就是1。

因此,6和7的最大公约数是1。

答案是:C.""")

    print(a)
    return_list = main('round1_test_data.jsonl', 'upload.jsonl')
判断,获取输出结果:
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
return_list
return_list = filter_problems(return_list)
sorted_data = sorted(return_list, key=lambda x: int(str(x['id'])[-3:]))
print(sorted_data)
sorted_data
判断缺失:
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)
len(missing_ids)
获取最终结果并写入jsonl文件:
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:]))
with open('upload.jsonl', 'w') as writer:
    for sample in sorted_data:
        writer.write(json.dumps(sample, ensure_ascii=False))
        writer.write('\n')
看到这句话就是成功了:
print("!!!!!! baseline1 运行成功!快去左侧下载 upload.jsonl ! 去赛事官网完成提交吧!")

6.最终结果:

7.task1总结: 

        总的来说task1的进行还是比较顺利的,只要一步一步按照文档所说的进行下去就好了。整个baseline的运行花了大概30分钟,但对于baseline代码的具体内容还没有真正的完全弄懂。

        我对于整个赛题的理解就是我们需要通过调用一个大模型的API来让其进行一系列的逻辑推理任务,但至于该如何提升它的性能,效率,该通过哪些方法来获得更好的逻辑推理效果而进一步提高分数还是一头雾水。

        通过阅读baseline代码我了解到,事实上光是调用了某个模型的API还是远远不够的,我们自己还需要进行许多额外的函数来更好的使用模型。同时对于数据集,输出结果的异常处理也是十分必要且重要的。

        目前来讲我在人工智能领域还是一个小白,所以也希望在Datawhale的AI夏令营中和其他同学们一道不断进步提升自己。

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值