微调小型Llama 3.2(十亿参数)模型取代GPT-4o

别忘了关注作者,关注后您会变得更聪明,不关注就只能靠颜值了 ^_^。
一位年轻的儿科医生与一位经验丰富的医师,谁更能有效治疗婴儿的咳嗽?
两者都具备治疗咳嗽的能力,但儿科医生由于专攻儿童医学,或许在诊断婴儿疾病方面更具优势。这也正如小模型在某些特定任务上的表现,往往经过微调后能够比大型模型更为出色,尽管大型模型号称可以处理任何问题。
最近,我面临了一个必须在两者之间做出选择的场景。
我正在开发一个查询路由系统,用于将用户的请求引导至合适的部门,然后由人工继续对话。从技术角度看,这是一个文本分类任务。虽然GPT-4o及其小版本在这类任务上表现优秀,但它的使用成本较高,且由于是封闭模型,我无法在自己的环境中进行微调。尽管OpenAI提供了微调服务,但对我来说,成本仍然过于昂贵。
每百万个Token的训练费用为25美元,而我的训练数据量很快就达到了数百万个Token。再加上微调后的模型使用费用比普通模型高50%,这对我的小型项目而言,预算无疑是无法承受的。因此,我必须寻找一个替代方案。
相比之下,开源模型在处理分类任务时同样表现不俗,且训练成本相对较低,尤其是在使用GPU时。经过慎重考虑,我决定转向小型模型。小型LLM通过微调可以在有限的预算下实现令人满意的效果,这是我目前最为理想的选择。
小型模型可以在普通硬件上运行,微调所需的GPU也不必过于昂贵。更为重要的是,小模型的训练和推理速度远快于大型LLM。
经过一番调研,我挑选了几款候选模型——Phi3.5、DistillBERT和GPT-Neo,但最终选择了Meta Llama 3.2的1B模型。这个选择并非完全理性,部分原因可能是最近关于这个模型的讨论较多。不过,实践出真知,我决定通过实测来检验效果。
在接下来的部分,我将分享我微调Llama 3.2–1B指令模型与使用少样本提示的GPT-4o的对比结果。
微调Llama 3.2 1B模型(免费实现微调)
微调模型的确可能需要较高的成本,但如果选择合适的策略,还是能够大幅降低开支。针对我的情况,我采用了参数优化的微调(PEFT)策略,而不是完全参数微调。完全微调会重新训练模型中的全部1B参数,成本太高,且可能导致“灾难性遗忘”,即模型丢失预训练时学到的部分知识。而PEFT策略则聚焦于仅微调部分参数,大大减少了时间和资源的消耗。
其中,“低秩适应”(LORA)技术是目前较为流行的微调方法。LORA允许我们仅对某些特定层的部分参数进行微调,这样的训练不仅高效且效果明显。
此外,通过模型量化,我们可以将模型的参数压缩为float16甚至更小的格式,这不仅减少了内存消耗,还能提高计算速度。当然,精度可能会有所下降,但对于我的任务来说,这一折衷是可以接受的。
接下来,我将在免费的Colab和Kaggle平台上进行了微调。这些平台提供的GPU资源虽然有限,但对于像我这样的小模型训练任务已经足够,关键它们免费。
Llama-3.2微调与GPT-4o少样本提示的对比
微调Llama 3.2 1B模型的过程相对简单。我参考了Unsloth提供的Colab笔记本,并做了部分修改。原笔记本微调的是3B参数的模型,而我将其改为1B参数的Llama-3.2–Instruct,因为我想测试较小模型在分类任务上的表现。接着,我将数据集替换为我自己的数据,用于训练。
# Beforefrom unsloth.chat_templates import standardize_sharegptdataset = standardize_sharegpt(dataset)dataset = dataset.map(formatting_prompts_func, batched = True,)# Afterfrom datasets import Datasetdataset = Dataset.from_json("/content/insurance_training_data.json")dataset = dataset.map(formatting_prompts_func, batched = True,)
最稳妥的做法是选择一个与笔记本初始设计相符的数据集,例如下面的这个。
{"conversations": [{'role': 'user', 'content': <user_query>}{'role': 'assistant', 'content': <department>}]}
到这里为止,这两处调整已经足够让你用自己的数据微调模型了。
评估微调后的模型
接下来是关键的一步:评估测试。
评估LLM是一项广泛且富有挑战性的工作,也是LLM开发中最为重要的技能之一。我将再出一篇文章,在其中详细讨论过如何评估LLM应用,别忘了关注作者,关注后您会变得更聪明,不关注就只能靠颜值了 ^_^。
不过,为了简洁起见,这次我会采用经典的混淆矩阵方式进行评估。只需在笔记本的末尾添加下面的代码即可。
from langchain.prompts import FewShotPromptTemplatefrom langchain_openai import ChatOpenAIfrom langchain_core.prompts import PromptTemplatefrom pydantic import BaseModel# 1. A function to generate response with the fine-tuned modeldef generate_response(user_query):# Enable faster inference for the language modelFastLanguageModel.for_inference(model)# Define the message templatemessages = [{"role": "system", "content": "You are a helpful assistant who can route the following query to the relevant department."},{"role": "user", "content": user_query},]# Apply the chat template to tokenize the input and prepare for generationtokenized_input = tokenizer.apply_chat_template(messages,tokenize=True,add_generation_prompt=True, # Required for text generationreturn_tensors="pt").to("cuda") # Send input to the GPU# Generate a response using the modelgenerated_output = model.generate(input_ids=tokenized_input,max_new_tokens=64,use_cache=True, # Enable cache for faster generationtemperature=1.5,min_p=0.1)# Decode the generated tokens into human-readable textdecoded_response = tokenizer.batch_decode(generated_output, skip_special_tokens=True)[0]# Extract the assistant's response (after system/user text)assistant_response = decoded_response.split("\n\n")[-1]return assistant_response# 2. Generate Responeses with OpenAI GPT-4o# Define the prompt template for the exampleexample_prompt_template = PromptTemplate.from_template("User Query: {user_query}\n{department}")# Initialize OpenAI LLM (ensure the OPENAI_API_KEY environment variable is set)llm = ChatOpenAI(temperature=0, model="gpt-4o")# Define few-shot examplesexamples = [{"user_query": "I recently had an accident and need to file a claim for my vehicle. Can you guide me through the process?", "department": "Claims"},...]# Create a few-shot prompt templatefew_shot_prompt_template = FewShotPromptTemplate(examples=examples,example_prompt=example_prompt_template,prefix="You are an intelligent assistant for an insurance company. Your task is to route customer queries to the appropriate department.",suffix="User Query: {user_query}",input_variables=["user_query"])# Define the department model to structure the outputclass Department(BaseModel):department: str# Function to predict the appropriate department based on user querydef predict_department(user_query):# Wrap LLM with structured outputstructured_llm = llm.with_structured_output(Department)# Create the chain for generating predictionsprediction_chain = few_shot_prompt_template | structured_llm# Invoke the chain with the user query to get the departmentresult = prediction_chain.invoke(user_query)return result.department# 3. Read your evaluation dataset and predict departmentsimport jsonwith open("/content/insurance_bot_evaluation_data (1).json", "r") as f:eval_data = json.load(f)for ix, item in enumerate(eval_data):print(f"{ix+1} of {len(eval_data)}")item['open_ai_response'] = generate_response(item['user_query'])item['llama_response'] = item['open_ai_response']# 4. Compute the precision, recall, accuracy, and F1 scores for the predictions.# 4.1 Using Open AIfrom sklearn.metrics import precision_score, recall_score, accuracy_score, f1_scoretrue_labels = [item['department'] for item in eval_data]predicted_labels_openai = [item['open_ai_response'] for item in eval_data]# Calculate the scores for open_ai_responseprecision_openai = precision_score(true_labels, predicted_labels_openai, average='weighted')recall_openai = recall_score(true_labels, predicted_labels_openai, average='weighted')accuracy_openai = accuracy_score(true_labels, predicted_labels_openai)f1_openai = f1_score(true_labels, predicted_labels_openai, average='weighted')print("OpenAI Response Scores:")print("Precision:", precision_openai)print("Recall:", recall_openai)print("Accuracy:", accuracy_openai)print("F1 Score:", f1_openai)# 4.2 Using Fine-tuned Llama 3.2 1B Instructtrue_labels = [item['department'] for item in eval_data]predicted_labels_llama = [item['llama_response'] for item in eval_data]# Calculate the scores for llama_responseprecision_llama = precision_score(true_labels, predicted_labels_llama, average='weighted', zero_division=0)recall_llama = recall_score(true_labels, predicted_labels_llama, average='weighted', zero_division=0)accuracy_llama = accuracy_score(true_labels, predicted_labels_llama)f1_llama = f1_score(true_labels, predicted_labels_llama, average='weighted', zero_division=0)print("Llama Response Scores:")print("Precision:", precision_llama)print("Recall:", recall_llama)print("Accuracy:", accuracy_llama)print("F1 Score:", f1_llama)
以上代码非常清晰明了。我们编写了一个函数,利用微调后的模型进行部门预测。同时,也为OpenAI GPT-4o构建了一个类似的函数。
接着,我们使用这些函数对评估数据集生成预测结果。
评估数据集中包含了预期的分类,现在我们也获得了模型生成的分类,这为接下来的指标计算提供了基础。
接下来,我们将进行这些计算。
以下是结果:
OpenAI Response Scores:Precision: 0.9Recall: 0.75Accuracy: 0.75F1 Score: 0.818Llama Response Scores:Precision: 0.88Recall: 0.73Accuracy: 0.79F1 Score: 0.798
结果显示,微调后的模型表现几乎接近GPT-4o。对于一个只有1B参数的小型模型来说,这已经相当令人满意了。
尽管GPT-4o的表现确实更好,但差距非常微小。
此外,如果在少样本提示中提供更多示例,GPT-4o的结果可能会进一步提升。不过,由于我的示例有时比较长,甚至包括几段文字,这会显著增加成本,毕竟OpenAI是按输入Token计费的。
总结
我现在对小型LLM非常认可。它们运行速度快,成本低,而且在大多数使用场景中都能满足需求,尤其是在不进行微调的情况下。
在这篇文章中,我讨论了如何微调Llama 3.2 1B模型。该模型可以在较为普通的硬件上运行,而且微调成本几乎为零。我当前的任务是文本分类。
当然,这并不意味着小型模型能够全面超越像GPT-4o这样的巨型模型,甚至也不一定能胜过Meta Llama的8B、11B或90B参数的模型。较大的模型拥有更强的多语言理解能力、视觉指令处理能力,以及更加广泛的世界知识。
我的看法是,如果这些“超级能力”不是你当前的需求,为什么不选择一个小型LLM呢?”
相关文章:

微调小型Llama 3.2(十亿参数)模型取代GPT-4o
微调Llama VS GPT-4o 别忘了关注作者,关注后您会变得更聪明,不关注就只能靠颜值了 ^_^。 一位年轻的儿科医生与一位经验丰富的医师,谁更能有效治疗婴儿的咳嗽? 两者都具备治疗咳嗽的能力,但儿科医生由于专攻儿童医学…...

【JavaEE】【IO】文件操作
目录 一、文件1.1 文件的概念1.2 文件的操作1.3 路径1.4 文件分类 二、Java中的文件元信息、路径操作2.1 属性2.2 构造方法2.3 方法2.3.1 文件路径2.3.2 文件判断2.3.3 文件创建删除2.3.4 其他操作 三、文件读写操作3.1 流(Stream)3.1.1 字节流3.1.1.1 I…...
commonjs和esmodule的导入导出细节
CommonJS和ES Module是JavaScript中两种不同的模块系统,它们在导入导出细节上存在差异,以下是两者的具体对比以及方便区分记忆的方法: 1. 导入导出细节 CommonJS 导出:使用module.exports或exports对象来导出模块中的变量、函数…...

【热门】用ChatGPT做智慧农业云平台——农业ERP管控系统
随着科技的进步,原有农业种植方式已经不能满足社会发展的需要,必须对传统的农业进行技术更新和改造。经过多年的实践,人们总结出一种新的种植方法——温室农业,即“用人工设施控制环境因素,使作物获得最适宜的生长条件,从而延长生产季节,获得最佳的产出”。这种农业生产方式…...

Android从上帝视角来看PackageManagerService
戳蓝字“牛晓伟”关注我哦! 用心坚持输出易读、有趣、有深度、高质量、体系化的技术文章,技术文章也可以有温度。 前言 阅读该篇之前,建议先阅读下面的系列文章: Android深入理解包管理–PackageManagerService和它的“小伙伴…...

阵列式位移计与传统测斜仪相比的优势
在岩土工程监测领域,位移测量是确保工程质量和安全的重要环节。传统的测斜仪,如活水平固定测斜仪和固定式测斜仪,尽管在一定程度上满足了工程监测的需求,但某些方面限制了其应用范围。随着阵列式位移计这种新型的传感器的出现&…...

第7章 网络请求和状态管理
一、Axios 1 Axios概述 Axios是一个基于Promise的HTTP库,可以发送get、post等请求,它作用于浏览器和Node.js中。当运行在浏览器时,使用XMLHttpRequest接口发送请求;当运行在Node.js时,使用HTTP对象发送请求。 Axios的…...
苍穹外卖学习笔记(二十七)
客户催单 OrderController /*** 催单*/GetMapping("/reminder/{id}")ApiOperation("催单")public Result reminder(PathVariable("id") Long id) {orderService.reminder(id);return Result.success();}OrderServer /*** 催单*/void reminder(L…...

使用exe4j打包jar包生成exe文件,GUI应用详细使用教程
使用exe4j打包jar包生成exe文件,GUI应用详细使用教程 exe4j应用教程使用方式搞副业 exe4j应用教程 《exe4j 下载地址》 exe4j是一个功能强大的多平台 Java 安装程序生成器,它可以为 Java 应用程序生成本机安装程序和应用程序启动器。exe4j 的优点在于它的易用性、广…...

go jwt 用户登录和返回用户信息 token ----important!!!
1.每一行代码都有详细注释,解释了其功能和作用。这些注释可以帮助你理解代码如何工作,特别是在处理用户登录、生成 JWT、验证 JWT 和返回用户信息的过程中。 package main // 指定这个文件是一个可执行程序import ("fmt" …...

OpenCV高级图形用户界面(12)用于更改指定窗口的大小函数resizeWindow()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::resizeWindow() 函数用于更改指定窗口的大小。这使得你可以根据需要调整窗口的宽度和高度。 注释 指定的窗口大小是指图像区域的大小。工具栏…...

babylonjs shader学习之copy shadertoy案例
shadertoy案例: 准备 const onSceneReady (scene: Scene) > {const light new HemisphericLight(light, new Vector3(0, 1, 0), scene);light.intensity 0.7;Effect.ShadersStore[planeMatVertexShader] precision highp float;attribute vec3 position;attr…...

Leetcode 1137. 第 N 个泰波那契数
原题链接:Leetcode 1137. 第 N 个泰波那契数 代码1: class Solution { public:int a[40];int tribonacci(int n) {a[0]0;a[1]1;a[2]1;if(n<1) return n;if(a[n]) return a[n];a[n]tribonacci(n-1)tribonacci(n-2)tribonacci(n-3);return a[n];} };代…...

Rust 语言持续崛起,即将冲击 TIOBE 指数前十,能否成为编程语言新王者?
Rust 语言持续崛起,即将冲击 TIOBE 指数前十,能否成为编程语言新王者? 2024 年 10 月,全球编程语言 TIOBE 排行榜再次更新,各大编程语言在各自领域中继续发挥着独特的优势。官方的标题是: Rust排名稳步攀升…...

Linux 手撕线程池
前言 线程池 是 池化技术 中很典型的一个,它旨在高效的管理和复用线程资源!在现在的计算机体系中,线程是执行任务(调度)的基本单位。然而,频繁的创建和销毁线程也会带来较大的开销,包括系统资源…...

[Unity Demo]从零开始制作空洞骑士Hollow Knight第十五集:制作更多地图,更多敌人,更多可交互对象
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、第一个代表性场景 1.制作更多敌人2.制作更多可交互对象二、第二个代表性场景 1.制作更多敌人2.制作更多可交互对象三、第三个代表性场景 1.制作更多敌人2.制…...

在Openshift上安装MetalLB
1.部署MetalLB Operator 2.部署AddressPool addresses 必须和ocp节点在同一网段 apiVersion: metallb.io/v1beta1 kind: AddressPool metadata:name: metallb-ipaddressnamespace: metallb-system spec:addresses:- 192.168.1.51-192.168.1.60- 192.168.1.61-192.168.1.70aut…...
mysql其他对象
一、存储引擎 mysql的存储引擎包括: InnoDB,MyISAM,Memory(Heap),Archive,CSV,NDB Cluster 常用的只有前两个。 InnoDB与MyISAM的区别: InnoDB 简介:Inn…...
英语单词之社会生活之聚会
一些关于聚会的单词和短语 句子 English中文What’s the plan?计划是什么?I’m going out with some friends.我要跟几个朋友一起出去。I don’t really feel like going out.我不是很想出去。What time suits you ?你什么时间合适?Where shall we m…...

Qt - 地图相关 —— 1、加载百度在线地图(附源码)
效果图 开始加载地图 1、百度地图开发者网站中注册,获取密钥 2、进入开发文档中 将下图内容保存到本地文件中,文件名为"index.html"文件即可。接着将内容中的“您的密钥”改为刚刚创建应用出来的AK密钥即可。 然后双击打开若在浏览器中正常看到下图右侧地图则说明没…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...