从零入门 AI+逻辑推理 2024Datawhale AI夏令营第三期 学习笔记2

#AI夏令营 #大模型技术 #baseline

继续记录第三期AI逻辑推理的第二次学习

本次学习的主题是对baseline的精读,内容主要是了解baseline的用途,并对本次train进行一个代码的解释。

一、大模型的基本介绍

大模型,又称大语言模型,是一种人工智能模型,作用就是是为人类服务的。

大模型既有着上下文学习、指令遵循和逻辑推理等能力,又有着大规模、多语言支持、多领域应用等多方面的特点。

而关于大模型推理能力的介绍,它目前能理解一个基本的逻辑,然后根据这些逻辑去思考问题,仍还处在一个成长的过程中,就像我们的小学初中高中阶段一样,仍然有进步的空间,需要不断地挖掘与发现。

现在大语言模型推理使用的方法是提示工程,提示工程是一种关注提示词开发和优化,帮助用户将大语言模型用于各个场景的学科,使用提示工程来进行大模型推理是一个不错的选择,毕竟提示工程在实现和大语言模型交互、对接,以及理解大语言模型能力方面都起着不可或缺的作用。

二、train主要代码解释

主要代码分为环境配置、答案生成和纠错与结果文件的生成三部分,运用的都是python的一些基本知识和库,如果学过的,有python基础的,你会发现这些语法并不难看懂,最难也就是库的运用与库函数调用这方面,不懂的话就根据注释来理解也行。

2.1 环境配置

下面是需要安装的库、配置的API和导入的环境

!pip install scipy openai tiktoken retry dashscope loguruxi

# 注意:这里需要填入你的key~ 咱们在第二步申请的。

dashscope.api_key="sk-"
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 = 'qwen2-7b-instruct'

2.2 答案生成部分

答案生成部分包含了处理函数、返回结果抽取、多线程处理和答案生成的启动。

首先是处理函数的代码,处理用api调用模型推理判断,

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()

接着是返回结果抽取的代码

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 process_datas(datas,MODEL_NAME):
    results = []
    # 定义线程池 选择16线程
    with ThreadPoolExecutor(max_workers=16) as executor:
        # 这里我们使用future_data 存储每个线程的数据
        future_data = {}
        # 这里的lens记录了调用api的次数,也就是我们每个问题背景下的所有子问题之和。
        lens = 0
        # 送入多线程任务
        # 这里每个data下是一个问题背景,其中包含多个子问题。
        for data in tqdm(datas, desc="Submitting tasks", total=len(datas)):
            problem = data['problem']
            # 这里面我们用enumerate方法每次循环得到问题的序号id和实际的问题。
            for id,question in enumerate(data['questions']):
                prompt = get_prompt(problem, 
                                    question['question'], 
                                    question['options'],
                                    )
                # 这里送入线程池等待处理,使用api_retry,向api_retry传入MODEL_NAME, prompt参数
                future = executor.submit(api_retry, MODEL_NAME, prompt)
                # 每个线程我们存储对应的json问题数据以及问题序号id,这样我们就能定位出执行的是哪个子问题
                future_data[future] = (data,id)
                time.sleep(0.6)  # 控制每0.6秒提交一个任务 防止接口超过并发数
                lens += 1
        # 处理多线程任务
        for future in tqdm(as_completed(future_data), total=lens, desc="Processing tasks"):
            # print('data',data)
            # 取出每个线程中的字典数据及对应的问题id
            data = future_data[future][0]
            problem_id = future_data[future][1]
            try:
                # 获取api运行结果
                res  = future.result()
                # 抽取大语言模型返回结果
                extract_response = extract(res)
                # print('res',extract_response)
                # 装入answer字段
                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
    
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')

2.3 纠错与结果文件的生成

纠错与结果文件生成部分的目的是保证代码运行完后对代码进行纠错,纠错完生成文件,结果文件用于打卡提交。

纠错部分

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)

结果文件的存储与生成

with open('upload.jsonl', 'w') as writer:
    for sample in sorted_data:
        writer.write(json.dumps(sample, ensure_ascii=False))
        writer.write('\n')

三、总结与感悟

本次任务的内容是了解baseline的用途以及对train主要代码的解释学习,通过学习和观看晚上的直播后我对baseline和大模型有了更深的理解,我希望能够继续学习下去,获取更多有用的知识来提升自己,更希望和各位一起交流交流,学习学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值