5.5.4 Llama-2语言模型操作
编写下面的代码,功能是加载、配置 Llama-2 语言模型以及其对应的分词器,准备好模型为后续的对话生成任务做好准备。
model_name = "../input/llama-2/pytorch/7b-hf/1"
compute_dtype = getattr(torch, "float16")
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=compute_dtype,
bnb_4bit_use_double_quant=True,
)
model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map=device,
torch_dtype=compute_dtype,
quantization_config=bnb_config,
)
model.config.use_cache = False
model.config.pretraining_tp = 1
tokenizer = AutoTokenizer.from_pretrained(model_name,
trust_remote_code=True,
)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
model, tokenizer = setup_chat_format(model, tokenizer)
上述代码的实现流程如下:
(1)model_name = "../input/llama-2/pytorch/7b-hf/1":设置Llama-2 语言模型的路径。
(2)compute_dtype = getattr(torch, "float16"):从 Torch 库中获取 float16 数据类型,作为计算时的数据类型。
(3)创建了一个 BitsAndBytesConfig 对象 bnb_config,用于配置量化相关参数:
load_in_4bit=True:以 4 位格式加载模型权重。 bnb_4bit_quant_type="nf4":使用 "nf4" 量化类型。 bnb_4bit_compute_dtype=compute_dtype:使用之前获取的 float16 数据类型进行计算。 bnb_4bit_use_double_quant=True:使用双量化。(4)使用 AutoModelForCausalLM.from_pretrained()方法加载预训练的 Llama-2 语言模型,并配置量化参数和设备信息。
(5)禁用模型的缓存,以确保每次预测都是基于最新的输入。
(6)将预训练令牌概率设置为1,以便模型在生成对话时保持更加开放的状态。
(7)使用 AutoTokenizer.from_pretrained()方法加载与模型对应的分词器,并配置填充相关参数。
(8)最后,调用 setup_chat_format() 函数来进一步配置模型和分词器的格式。
执行后会输出如下加载 Llama-2 语言模型过程中的进度信息,展示加载的进度和每个碎片加载所花费的时间。
Loading checkpoint shards: 100%2/2 [03:20<00:00, 91.76s/it]
5.5.5 情感标签预测
(1)编写函数 predict(test, model, tokenizer),功能是对测试数据进行情感标签的预测。通过这个函数,可以使用已加载的 Llama-2 模型对测试数据进行情感标签的预测,从而评估模型在情感分析任务上的性能。
def predict(test, model, tokenizer):
y_pred = []
for i in tqdm(range(len(X_test))):
prompt = X_test.iloc[i]["text"]
pipe = pipeline(task="text-generation",
model=model,
tokenizer=tokenizer,
max_new_tokens = 1,
temperature = 0.0,
)
result = pipe(prompt)
answer = result[0]['generated_text'].split("=")[-1]
if "positive" in answer:
y_pred.append("positive")
elif "negative" in answer:
y_pred.append("negative")
elif "neutral" in answer:
y_pred.append("neutral")
else:
y_pred.append("none")
return y_pred
在上述代码中,函数predict(test, model, tokenizer)会遍历测试数据集中的每个样本,并使用 Llama-2 模型生成一个新的令牌以预测对应的情感标签。具体步骤如下:
获取测试数据中的每个样本的提示文本。 使用 Hugging Face 的管道(pipeline)方法进行文本生成,以生成一个新的令牌。 从生成的文本中提取预测的情感标签。 将预测的情感标签添加到预测列表中。 返回预测的情感标签列表。(2)调用前面定义的函数predict(),使用加载好的模型和分词器对测试数据进行情感标签的预测,并将预测结果存储在变量 y_pred 中。
y_pred = predict(test, model, tokenizer)
(3)调用前面定义的函数evaluate(),评估模型对测试数据的情感标签预测结果。
evaluate(y_true, y_pred)
函数evaluate()会计算模型的准确率、每个情感标签的准确率、生成分类报告和混淆矩阵,并打印输出这些评估结果。执行后会输出:
Accuracy: 0.373
Accuracy for label 0: 0.027
Accuracy for label 1: 0.937
Accuracy for label 2: 0.157
Classification Report:
precision recall f1-score support
0 0.89 0.03 0.05 300
1 0.34 0.94 0.50 300
2 0.67 0.16 0.25 300
accuracy 0.37 900
macro avg 0.63 0.37 0.27 900
weighted avg 0.63 0.37 0.27 900
Confusion Matrix:
[[ 8 287 5]
[ 1 281 18]
[ 0 253 47]]
5.5.6 大模型微调(Fine-tuning)
(1)准备微调的设置李新喜,初始化了一个 Simple Fine-tuning Trainer (SFTTrainer) 对象用于微调模型。使用 Parameter-Efficient Fine-Tuning (PEFT) 方法训练大型语言模型,PEFT 方法旨在通过调整少量参数来微调模型,与完全微调整个模型相比,它能够节省时间并减少计算和存储开销。此外,PEFT 方法还可以缓解遗忘问题,这在完全微调语言模型时经常会发生。
output_dir="trained_weigths"
# 指定保存训练过程中模型权重和日志的目录。
peft_config = LoraConfig(
lora_alpha=16,
lora_dropout=0.1,
r=64,
bias="none",
target_modules="all-linear",
task_type="CAUSAL_LM",
)
# 配置 PEFT 方法的参数,包括 LoRA 矩阵的学习率、dropout 等参数。
training_arguments = TrainingArguments(
output_dir=output_dir, # 保存训练日志和检查点的目录
num_train_epochs=3, # 训练周期数
per_device_train_batch_size=1, # 每个设备上每批样本数
gradient_accumulation_steps=8, # 更新模型参数之前累积梯度的步数
gradient_checkpointing=True, # 使用梯度检查点以节省内存
optim="paged_adamw_32bit",
save_steps=0,
logging_steps=25, # 每 10 步记录一次训练指标
learning_rate=2e-4, # 学习率,基于 QLoRA 论文
weight_decay=0.001,
fp16=True,
bf16=False,
max_grad_norm=0.3, # 最大梯度范数,基于 QLoRA 论文
max_steps=-1,
warmup_ratio=0.03, # 学习率预热比例,基于 QLoRA 论文
group_by_length=True,
lr_scheduler_type="cosine", # 使用余弦退火学习率调度器
report_to="tensorboard", # 报告指标到 tensorboard
evaluation_strategy="epoch" # 每个周期保存检查点
)
# 配置训练模型的参数,包括训练周期数、批次大小、学习率、梯度累积步数等。
trainer = SFTTrainer(
model=model,
args=training_arguments,
train_dataset=train_data,
eval_dataset=eval_data,
peft_config=peft_config,
dataset_text_field="text",
tokenizer=tokenizer,
max_seq_length=1024,
packing=False,
dataset_kwargs={
"add_special_tokens": False,
"append_concat_token": False,
}
)
# 初始化 SFTTrainer 对象,传入模型、训练参数、训练数据集、评估数据集、PEFT 配置等,并设置数据集参数。
# 初始化 SFTTrainer 对象,传入模型、训练参数、训练数据集、评估数据集、PEFT 配置等,并设置数据集参数。
(2)通过方法train()启动微调过程,即开始训练模型。通过调用此方法,模型将根据指定的训练参数(例如训练周期数、学习率、批次大小等)和训练数据集进行微调。在训练过程中,模型将逐步学习如何更好地适应特定的任务或数据集,以提高其性能。
trainer.train()
执行后会输出:
You're using a LlamaTokenizerFast tokenizer. Please note that with a fast tokenizer, using the `__call__` method is faster than using a method to encode the text followed by a call to the `pad` method to get a padded encoding.
[336/336 1:01:27, Epoch 2/3]
Epoch Training Loss Validation Loss
0 0.802000 0.700182
2 0.516500 0.714122
TrainOutput(global_step=336, training_loss=0.7176062436330886, metrics={'train_runtime': 3700.9349, 'train_samples_per_second': 0.73, 'train_steps_per_second': 0.091, 'total_flos': 1.0717884041527296e+16, 'train_loss': 0.7176062436330886, 'epoch': 2.99})
(3)通过下面的两行代码保存微调后的模型和分词器。其中trainer.save_model()用于保存微调后的模型到指定的输出目录,tokenizer.save_pretrained(output_dir)用于保存微调后的分词器到指定的输出目录。
trainer.save_model()
tokenizer.save_pretrained(output_dir)
执行后会输出:
('trained_weigths/tokenizer_config.json',
'trained_weigths/special_tokens_map.json',
'trained_weigths/tokenizer.model',
'trained_weigths/added_tokens.json',
'trained_weigths/tokenizer.json')
(4)启用TensorBoard 可视化工具,加载指定目录下的日志文件,以便在 TensorBoard 中查看训练过程中的指标和图表。
%load_ext tensorboard
%tensorboard --logdir logs/runs
TensorBoard 是 TensorFlow 提供的一个强大的可视化工具,可以帮助用户更直观地理解模型的训练情况。执行效果如图5-3所示,这是一个交互式图形的静态图像。要查看交互版本,请复制此内核并在编辑器中打开它。
图5-3 模型训练的可视化图
(5)释放内存和清理资源,避免内存泄漏和占用过多的系统资源。
import gc
del [model, tokenizer, peft_config, trainer, train_data, eval_data, bnb_config, training_arguments]
del [df, X_train, X_eval]
del [TrainingArguments, SFTTrainer, LoraConfig, BitsAndBytesConfig]
for _ in range(100):
torch.cuda.empty_cache()
gc.collect()
对上述代码的具体说明如下所示:
删除之前创建的模型、分词器、PEFT 配置、训练器、训练数据集、评估数据集等对象,以释放它们所占用的内存。 删除pandas 数据框和其他变量,以释放它们占用的内存。 通过循环调用 torch.cuda.empty_cache()和 gc.collect()函数来清理 GPU 内存和 Python 垃圾回收,以确保释放的内存被彻底清理。(6)执行下面的系统命令,用于在 NVIDIA GPU 系统上查看当前 GPU 的状态和使用情况。
!nvidia-smi
执行后会显示当前系统中所有 NVIDIA GPU 的详细信息,包括 GPU 的型号、显存使用情况、温度、驱动程序版本等信息。
Sat Mar 23 22:52:36 2024
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.129.03 Driver Version: 535.129.03 CUDA Version: 12.2 |
|-----------------------------------------+----------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+======================+======================|
| 0 Tesla P100-PCIE-16GB Off | 00000000:00:04.0 Off | 0 |
| N/A 57C P0 41W / 250W | 1926MiB / 16384MiB | 0% Default |
| | | N/A |
+-----------------------------------------+----------------------+----------------------+
+---------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=======================================================================================|
+---------------------------------------------------------------------------------------+
(7)加载微调后的模型,并通过 PEFT 库中的类AutoPeftModelForCausalLM实现自动加载和优化操作。然后,将加载的模型合并并保存到新的目录中,并保存了相应的分词器,以备后续使用。
from peft import AutoPeftModelForCausalLM
finetuned_model = "./trained_weigths/"
compute_dtype = getattr(torch, "float16")
tokenizer = AutoTokenizer.from_pretrained("/kaggle/input/llama-2/pytorch/7b-hf/1")
model = AutoPeftModelForCausalLM.from_pretrained(
finetuned_model,
torch_dtype=compute_dtype,
return_dict=False,
low_cpu_mem_usage=True,
device_map=device,
)
merged_model = model.merge_and_unload()
merged_model.save_pretrained("./merged_model",safe_serialization=True, max_shard_size="2GB")
tokenizer.save_pretrained("./merged_model")
执行后会输出:
Loading checkpoint shards: 100%2/2 [00:05<00:00, 2.58s/it]
Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.
('./merged_model/tokenizer_config.json',
'./merged_model/special_tokens_map.json',
'./merged_model/tokenizer.model',
'./merged_model/added_tokens.json',
'./merged_model/tokenizer.json')
5.5.7 模型测试
(1)调用函数predict()对测试集进行预测,并使用函数evaluate()评估模型在测试集上的性能。函数predict()使用了合并后的模型 merged_model 和分词器 tokenizer 对测试集进行预测,并返回了预测结果 y_pred。然后,函数evaluate()利用真实标签 y_true 和预测标签 y_pred 对模型的性能进行评估,包括计算准确率、精确度、召回率等指标。
y_pred = predict(test, merged_model, tokenizer)
evaluate(y_true, y_pred)
执行后会输出:
100%|██████████| 900/900 [03:51<00:00, 3.89it/s]
Accuracy: 0.847
Accuracy for label 0: 0.890
Accuracy for label 1: 0.870
Accuracy for label 2: 0.780
Classification Report:
precision recall f1-score support
0 0.96 0.89 0.92 300
1 0.73 0.87 0.79 300
2 0.88 0.78 0.83 300
accuracy 0.85 900
macro avg 0.86 0.85 0.85 900
weighted avg 0.86 0.85 0.85 900
Confusion Matrix:
[[267 31 2]
[ 10 261 29]
[ 1 65 234]]
(2)下面的这段代码将测试集中的文本、真实标签和预测标签组合成一个 DataFrame,并将其保存为 CSV 文件test_predictions.csv,以便后续分析和比较模型的预测结果。DataFrame 包括三列:'text' 列包含测试集中的文本,'y_true' 列包含真实的情感标签,'y_pred' 列包含模型预测的情感标签。CSV 文件中不包含行索引。
evaluation = pd.DataFrame({'text': X_test["text"],
'y_true':y_true,
'y_pred': y_pred},
)
evaluation.to_csv("test_predictions.csv", index=False)
执行后可以比较微调后模型和基准模型(一个基于 CONV1D + 双向 LSTM 的模型)的评估结果,以确定微调后模型是否比基准模型更优秀。
Accuracy: 0.623 Accuracy for label 0: 0.620 Accuracy for label 1: 0.590 Accuracy for label 2: 0.660
Classification Report: precision recall f1-score support
0 0.79 0.62 0.69 300
1 0.61 0.59 0.60 300
2 0.53 0.66 0.59 300
accuracy 0.62 900
macro avg 0.64 0.62 0.63 900 weighted avg 0.64 0.62 0.63 900
Confusion Matrix:
[[186 39 75]\ [ 23 177 100]\ [ 27 75 198]]
本项目已完结:
(5-5-01)金融市场情绪分析:使用Llama 2 大模型实现财经信息的情感分析微调(1)-CSDN博客