微调亚马逊 Titan Text Express 由亚马逊 Bedrock 提供

这个笔记本应该可以很好地与 SageMaker Studio 中的 Data Science 3.0 内核一起使用。也使用 ml.c5.2xlarge 由于所需的内存资源

在这个笔记本中,我们将微调由亚马逊 Bedrock 提供的 Amazon Titan Text Lite 模型用于摘要用例。 我们可以从基础模型列表中选择,或微调我们之前微调过的模型之一。

先决条件

  • 确保我们已经执行了 00_setup.ipynb 笔记本。
  • 确保我们使用的是与 00_setup.ipynb 笔记本相同的内核和实例。

警告: 这个笔记本将创建预置吞吐量来测试微调的模型。因此,请确保在笔记本的最后一节中删除预置吞吐量,否则我们将被收取费用,即使我们没有使用它。

!pip install -qU bert_score
# 重启内核以使软件包生效
from IPython.core.display import HTML
HTML("<script>Jupyter.notebook.kernel.restart()</script>")
## 从 `00_setup.ipynb` 笔记本中获取变量。 
%store -r role_arn
%store -r s3_train_uri
%store -r s3_validation_uri
%store -r s3_test_uri
%store -r bucket_name
import pprint
pprint.pp(role_arn)
pprint.pp(s3_train_uri)
pprint.pp(s3_validation_uri)
pprint.pp(s3_test_uri)
pprint.pp(bucket_name)

设置

import warnings
warnings.filterwarnings('ignore')
import json
import os
import sys
import boto3
import time
session = boto3.session.Session()
region = session.region_name
sts_client = boto3.client('sts')
s3_client = boto3.client('s3')
aws_account_id = sts_client.get_caller_identity()["Account"]
bedrock = boto3.client(service_name="bedrock")
bedrock_runtime = boto3.client(service_name="bedrock-runtime")
test_file_name = "test-cnn-10.jsonl"
data_folder = "fine-tuning-datasets"

选择要微调的模型

我们需要提供要微调的模型的 base_model_id。我们可以使用 list_foundation_models API 获取它,如下所示:

for model in bedrock.list_foundation_models(
    byCustomizationType="FINE_TUNING")["modelSummaries"]:
    for key, value in model.items():
        print(key, ":", value)
    print("-----\n")
base_model_id = "amazon.titan-text-lite-v1:0:4k"

接下来,我们需要提供 customization_job_namecustom_model_namecustomization_role,这些将用于创建微调作业。

from datetime import datetime
ts = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")

customization_job_name = f"model-finetune-job-{ts}"
custom_model_name = f"finetuned-model-{ts}"
customization_role = role_arn

创建微调作业

注意: 微调作业将需要大约 1 小时才能完成。

Amazon Titan 文本模型自定义超参数:

  • epochs: 通过整个训练数据集的迭代次数,可以取 1-10 之间的任何整数值,默认值为 5。
  • batchSize: 在更新模型参数之前处理的样本数,可以取 1-64 之间的任何整数值,默认值为 1。
  • learningRate: 更新模型参数的速率,可以取 0.0-1.0 之间的浮点值,默认值设置为 1.00E-5。
  • learningRateWarmupSteps: 学习率逐步增加到指定速率的迭代次数,可以取 0-250 之间的任何整数值,默认值为 5。

有关设置超参数的指南,请参考此处 提供的指南。

# 从"FINE_TUNING"或"CONTINUED_PRE_TRAINING"中选择自定义类型。 
customization_type = "FINE_TUNING"
# 定义微调 Titan 文本模型的超参数
hyper_parameters = {
        "epochCount": "2",
        "batchSize": "1",
        "learningRate": "0.00003",
    }


s3_bucket_config=f's3://{bucket_name}/outputs/output-{custom_model_name}'
# 指定训练、验证(可选)和输出的数据路径
training_data_config = {"s3Uri": s3_train_uri}

validation_data_config = {
        "validators": [{
            # "name": "validation",
            "s3Uri": s3_validation_uri
        }]
    }

output_data_config = {"s3Uri": s3_bucket_config}


# 创建自定义作业
training_job_response = bedrock.create_model_customization_job(
    customizationType=customization_type,
    jobName=customization_job_name,
    customModelName=custom_model_name,
    roleArn=customization_role,
    baseModelIdentifier=base_model_id,
    hyperParameters=hyper_parameters,
    trainingDataConfig=training_data_config,
    validationDataConfig=validation_data_config,
    outputDataConfig=output_data_config
)
training_job_response

检查微调作业状态

fine_tune_job = bedrock.get_model_customization_job(jobIdentifier=customization_job_name)["status"]
print(fine_tune_job)

while fine_tune_job == "InProgress":
    time.sleep(60)
    fine_tune_job = bedrock.get_model_customization_job(jobIdentifier=customization_job_name)["status"]
    print (fine_tune_job)
    time.sleep(60)
fine_tune_job = bedrock.get_model_customization_job(jobIdentifier=customization_job_name)
pprint.pp(fine_tune_job)
output_job_name = "model-customization-job-"+fine_tune_job['jobArn'].split('/')[-1]
output_job_name

现在我们准备好创建<code>预置吞吐量</code> ,这是在我们可以对微调模型进行推理之前需要的。

预置吞吐量概述

我们在模型单元(MU)中指定预置吞吐量。一个模型单元提供特定的吞吐量级别for指定的模型。给定文本模型的 MU 的吞吐量级别指定了以下内容:

  • 每分钟的总输入令牌数 - 一个 MU 在一分钟内可以处理的所有请求的输入令牌数。

  • 每分钟的总输出令牌数 - 一个 MU 在一分钟内可以生成的所有请求的输出令牌数。

模型单元配额取决于我们为预置吞吐量指定的承诺级别。

  • 对于没有承诺的自定义模型,每个预置吞吐量可用一个模型单元的配额。我们可以为每个帐户创建最多两个预置吞吐量。

  • 对于有承诺的基础或自定义模型,默认配额为 0 个模型单元。要请求增加,请使用限制增加表单

检索自定义模型

一旦自定义作业完成,我们就可以检查现有的自定义模型,并检索我们的微调模型的 modelArn。

# 列出我们的自定义模型
bedrock.list_custom_models()
model_id = bedrock.get_custom_model(modelIdentifier=custom_model_name)['modelArn']
model_id

创建预置吞吐量

注意: 创建预置吞吐量将需要大约 20-30 分钟才能完成。

我们需要创建预置吞吐量才能评估模型性能。我们可以通过[控制台].(https://docs.aws.amazon.com/bedrock/latest/userguide/prov-cap-console.html)或使用以下 API 调用来执行此操作:

import boto3 
boto3.client(service_name='bedrock')
provisioned_model_id = bedrock.create_provisioned_model_throughput(
 modelUnits=1,
 provisionedModelName='test-model', 
 modelId=model_id
)['provisionedModelArn']     
status_provisioning = bedrock.get_provisioned_model_throughput(provisionedModelId = provisioned_model_id)['status']
import time
while status_provisioning == 'Creating':
    time.sleep(60)
    status_provisioning = bedrock.get_provisioned_model_throughput(provisionedModelId=provisioned_model_id)['status']
    print(status_provisioning)
    time.sleep(60)

调用自定义模型

在调用之前,让我们从我们的测试数据中获取样本提示。

# 提供提示文本 
test_file_path = f'{data_folder}/{test_file_name}'
with open(test_file_path) as f:
    lines = f.read().splitlines()
test_prompt = json.loads(lines[3])['prompt']
reference_summary = json.loads(lines[3])['completion']
pprint.pp(test_prompt)
print(reference_summary)
prompt = f"""
{test_prompt}
"""
base_model_arn = f'arn:aws:bedrock:{region}::foundation-model/amazon.titan-text-lite-v1'

请确保按照此处 的说明构建模型输入,遵循 titan 文本模型所需的格式。 请注意"模型调用请求正文字段"部分中的 “body” 变量,我们将其作为有效负载传递给上面训练的自定义模型。

body = json.dumps(
    {
    "inputText": prompt,
    "textGenerationConfig": {
        "maxTokenCount": 2048,
        "stopSequences": ['User:'],
        "temperature": 0,
        "topP": 0.9
    }
    }
        )

accept = 'application/json'
contentType = 'application/json'

fine_tuned_response = bedrock_runtime.invoke_model(body=body, 
                                        modelId=provisioned_model_id, 
                                        accept=accept, 
                                        contentType=contentType)

base_model_response = bedrock_runtime.invoke_model(body=body, 
                                        modelId=base_model_arn, 
                                        accept=accept, 
                                        contentType=contentType)

fine_tuned_response_body = json.loads(fine_tuned_response.get('body').read())
base_model_response_body = json.loads(base_model_response.get('body').read())

print("Base model response: ", base_model_response_body["results"][0]["outputText"] + '\n')
print("Fine tuned model response:", fine_tuned_response_body["results"][0]["outputText"]+'\n')
print("Reference summary from test data: " , reference_summary)

评估模型性能

在这一部分,我们将使用 BertScore 指标来评估微调模型与基础模型的性能,以检查微调是否提高了结果。

  • BERTScore: 根据 BERT (Bidirectional Encoder Representations from Transformers) 这个强大的语言模型的输出,计算摘要和参考文本之间的相似性。Medium 文章链接
base_model_generated_response = [base_model_response_body["results"][0]["outputText"]]
fine_tuned_generated_response = [fine_tuned_response_body["results"][0]["outputText"]]
from bert_score import score
reference_summary = [reference_summary]
fine_tuned_model_P, fine_tuned_R, fine_tuned_F1 = score(fine_tuned_generated_response, reference_summary, lang="en")
base_model_P, base_model_R, base_model_F1 = score(base_model_generated_response, reference_summary, lang="en")
print("F1 score: base model ", base_model_F1)
print("F1 score: fine-tuned model", fine_tuned_F1)

结论

从上面的分数和查看基础模型摘要、微调模型摘要和参考摘要来看,很明显微调模型会提高在其训练任务上的结果。我们只使用了 1K 条记录进行训练,100 条验证记录和 2 个 epoch,就能获得更好的结果。 我们可能需要先调整 learning_rate,可视化训练和验证指标以了解训练作业的性能,然后再增加数据的大小。

提示: 请参考提供的指南根据我们的任