背景
大语言模型在生成高质量文案方面表现优异,然而其巨大的计算资源消耗和存储需求,使得实际应用尤其是在资源受限场景中的应用充满挑战。企业在寻求高效的文案生成时,常常面临着在性能和资源之间权衡的困境。在这种背景下,模型蒸馏技术为解决这一问题提供了新的思路。模型蒸馏是一种优化技术,旨在通过将知识从大型复杂模型中提取并转移到更小、计算更高效的模型中,使得这些小型模型能够在保留大多数性能优势的情况下显著降低资源需求。这一技术在大模型文案生成领域的应用,不仅能够保持生成质量接近原有大模型,还极大地减少了计算成本和部署难度。本文介绍如何使用 EasyDistill 算法框架以及 PAI 产品,实现基于模型蒸馏的大模型文案生成,通过这种方式节省人力成本,同时提高用户体验,推动业务的可持续增长。
部署教师大语言模型
部署模型服务
您可以按照以下操作步骤,部署教师大语言模型生成对应回复。
在 PAI-Model Gallery 选择 DeepSeek-V3 模型或者其他教师大模型,在模型部署区域,系统已默认配置了模型服务信息和资源部署信息,您也可以根据需要进行修改,参数配置完成后单击部署按钮。以 DeepSeek-V3 为例,其模型卡片如下所示:
模型部署和调用
PAI 提供的 DeepSeek-V3 预置了模型的部署配置信息,可以选择 SGLang 部署/vLLM 部署/Transformers 部署,用户仅需提供推理服务的名称以及部署配置使用的资源信息即可将模型部署到 PAI-EAS 推理服务平台。
推理服务同样支持以 OpenAI API 兼容的方式调用,调用示例如下:
 from openai import OpenAI
##### API 配置 #####openai_api_key = "<EAS API KEY>"openai_api_base = "<EAS API Endpoint>/v1"
client = OpenAI(    api_key=openai_api_key,    base_url=openai_api_base,)
models = client.models.list()model = models.data[0].idprint(model)
def main():    stream = True    chat_completion = client.chat.completions.create(        messages=[            {                "role": "user",                "content": [                    {                        "type": "text",                        "text": "你好,介绍一下你自己,越详细越好。",                    }                ],            }        ],        model=model,        max_completion_tokens=1024,        stream=stream,    )    if stream:        for chunk in chat_completion:            print(chunk.choices[0].delta.content, end="")    else:        result = chat_completion.choices[0].message.content        print(result)
if __name__ == "__main__":    main()
   复制代码
 
更多细节可以参考“一键部署DeepSeek-V3、DeepSeek-R1模型”。
构建训练数据
构建 SFT 训练数据
您可以按照以下操作步骤,构建 SFT 训练数据。用户可以根据如下输入数据批量调用教师大模型,输入数据格式如下所示:
 [  {    "instruction": "xxx"  },  {    "instruction": "xxx"  },  {    "instruction": "xxx"  }]
   复制代码
 
其中,instruction 为调用大模型的 prompt,由任务模版和实际输入数据组成。这里,我们给出一个任务模版供您参考,实际内容可以根据业务场景和数据特征进行调整:
 你是短视频文案生成专家,专注于根据视频原始标题、视频内容,生成文案的标题和内容。你的任务是确保文案与视频核心内容高度匹配,并且吸引用户点击。
要求1: 信息匹配度:确保文案准确反映视频核心看点,禁止出现视频中未呈现的虚构内容。2. 情绪契合度:文案情绪需与视频内容保持一致。严肃悲伤类内容不要使用搞笑戏谑风格。3. 内容规范度:确保句意表达清晰、完整、通顺、连贯,没有出现无意义字符。4. 严格按照JSON格式输出:{   "title": "",   "body": ""}
避免出现情况1. 标题要求在10个汉字以内。2. 内容要求在30个汉字以内。3. 禁止标题党,和过度夸张的表述。4. 不得出现高敏感内容,或者低俗用语。
请严格按照JSON格式输出内容,不要在输出中加入解析和说明等其他内容。
视频原始标题和视频内容分别如下所示:
   复制代码
 
给定上述输入数据,我们可以批量调用教师大模型生成回复,示例代码如下:
 import jsonfrom openai import OpenAI
##### API 配置 #####openai_api_key = "<EAS API KEY>"openai_api_base = "<EAS API Endpoint>/v1"
client = OpenAI(    api_key=openai_api_key,    base_url=openai_api_base,)
# 获取模型models = client.models.list()model = models.data[0].idprint(model)
# 读取输入数据def read_input_data(file_path):    with open(file_path, 'r', encoding='utf-8') as file:        return json.load(file)
# 调用大模型获取输出def get_model_output(instruction):    chat_completion = client.chat.completions.create(        messages=[            {                "role": "user",                "content": [                    {                        "type": "text",                        "text": instruction,                    }                ],            }        ],        model=model,        max_completion_tokens=1024,        stream=False,    )    return chat_completion.choices[0].message.content
# 处理输入数据并生成输出def process_data(input_data):    results = []    for item in input_data:        instruction = item.get("instruction")        output = get_model_output(instruction)        results.append({            "instruction": instruction,            "output": output        })    return results
# 保存输出数据到文件def save_output_data(file_path, data):    with open(file_path, 'w', encoding='utf-8') as file:        json.dump(data, file, ensure_ascii=False, indent=2)
def main(input_file_path, output_file_path):    input_data = read_input_data(input_file_path)    output_data = process_data(input_data)    save_output_data(output_file_path, output_data)    print("Data processing complete.")
if __name__ == "__main__":    # 指定你的输入和输出文件路径    input_file_path = "input.json"    output_file_path = "output.json"    main(input_file_path, output_file_path)
   复制代码
 
当运行完上述代码后,我们得到构造好的 SFT 训练数据,格式如下:
 [  {    "instruction": "xxx",    "output": "xxx"  },  {    "instruction": "xxx",    "output": "xxx"  },  {    "instruction": "xxx",    "output": "xxx"  }]
   复制代码
 
为了保证 SFT 训练数据集的高质量,我们建议采用如下设置:
- 训练数据量至少应在 3000 条以上,而且需要尽可能覆盖输入视频的各种主题; 
- 生成文案的任务模版可以按照实际业务需求进行修改,需要根据明确的业务需求,用自然语言精确描述生成的文案要求达到的效果和避免出现的情况; 
- 为了保证生成文案的高质量,使用的教师大模型底座参数量需要尽可能高,例如使用满血版的 DeepSeek-V3,一般不需要使用深度思考的模型,例如 DeepSeek-R1 或 QwQ-32B; 
- 在输入中,视频的内容可以通过 OCR、ASR 等多种途径从原始视频中抽取出来,需要保证抽取出来的内容具有较高的准确性; 
- 建议在生成 SFT 训练数据集后人工抽样进行质量校验,并且根据校验结果,反复调整调用大模型的任务模版,以达到满意的效果。 
构建 DPO 训练数据
如果您需要通过 DPO 算法继续优化较小的学生模型,则需要构造用于 DPO 算法训练的数据集。我们可以基于构造好的 SFT 训练数据进行继续构造流程。其中,DPO 数据格式示例如下所示:
 [  {    "prompt": "xxx",    "chosen": "xxx",    "rejected": "xxx"  },  {    "prompt": "xxx",    "chosen": "xxx",    "rejected": "xxx"  },  {    "prompt": "xxx",    "chosen": "xxx",    "rejected": "xxx"  }]
   复制代码
 
其中,prompt 对应 SFT 训练数据集的 instruction,chosen 可以使用 SFT 训练数据集的 output 字段,rejected 为 DPO 算法中提供的低质量文案。在 DPO 算法的训练过程中,我们鼓励大模型生成高质量的 chosen 文案,惩罚大模型生成类似 rejected 的文案。因此,我们需要额外生成 rejected 文案。我们可以同样采用教师大模型生成 rejected 文案,利用 SFT 训练数据集作为输入,我们需要改变上文使用的任务模版。这里我们给出一个示例供您参考:
 你是视频文案生成初学者,尝试根据视频原始标题、视频内容生成不够吸引人的文案标题和内容。目标是生成逻辑不清、可能误导、不够吸引用户点击的文案。
要求1. 信息匹配度:不要求准确反映视频核心看点,甚至可以与视频内容无关。2. 情绪契合度:文案情绪可以与视频内容不一致。3. 内容规范度:表达可以不清晰、不完整、不通顺、不连贯,可以出现无意义字符。4. 可不用严格按照JSON格式输出。
视频原始标题和视频内容分别如下所示:
   复制代码
 
我们同样给出一个批量推理的脚本,生成上述数据,我们假设输入数据格式与 SFT 训练数据集相同,但是 instruction 字段采用上文生成低质量文案的任务模版:
 import jsonfrom openai import OpenAI
##### API 配置 #####openai_api_key = "<EAS API KEY>"openai_api_base = "<EAS API Endpoint>/v1"
client = OpenAI(    api_key=openai_api_key,    base_url=openai_api_base,)
# 获取模型models = client.models.list()model = models.data[0].idprint(model)
# 读取输入数据def read_input_data(file_path):    with open(file_path, 'r', encoding='utf-8') as file:        return json.load(file)
# 调用大模型获取低质量文案def get_rejected_output(instruction):    chat_completion = client.chat.completions.create(        messages=[            {                "role": "user",                "content": [                    {                        "type": "text",                        "text": instruction,                    }                ],            }        ],        model=model,        max_completion_tokens=1024,        stream=False,    )    return chat_completion.choices[0].message.content
# 处理输入数据并生成输出def process_data(input_data):    results = []    for item in input_data:        instruction = item.get("instruction")        chosen = item.get("output")        rejected = get_rejected_output(instruction)        results.append({            "prompt": instruction,            "chosen": chosen,            "rejected": rejected        })    return results
# 保存输出数据到文件def save_output_data(file_path, data):    with open(file_path, 'w', encoding='utf-8') as file:        json.dump([data], file, ensure_ascii=False, indent=2)
def main(input_file_path, output_file_path):    input_data = read_input_data(input_file_path)    output_data = process_data(input_data)    save_output_data(output_file_path, output_data)    print("Data processing complete.")
if __name__ == "__main__":    # 指定你的输入和输出文件路径    input_file_path = "input.json"    output_file_path = "output.json"    main(input_file_path, output_file_path)
   复制代码
 
为了保证 DPO 训练数据集的高质量,我们建议采用如下设置:
- 训练数据量至少应在 1000 条以上,而且需要尽可能覆盖输入视频的各种主题; 
- 生成 rejected 文案的任务模版可以按照实际业务需求进行修改,需要和 chosen 文案在质量上有明显的差距,特别可以注重生成 chosen 文案中避免出现的情况(即负向样本); 
- 为了保证生成文案质量满足要求,使用的教师大模型底座参数量需要尽可能高,例如使用满血版的 DeepSeek-V3,一般不需要使用深度思考的模型,例如 DeepSeek-R1 或 QwQ-32B; 
- 在输入中,视频的内容可以通过 OCR、ASR 等多种途径从原始视频中抽取出来,需要保证抽取出来的内容具有较高的准确性; 
- 建议在生成 DPO 训练数据集后人工抽样进行质量校验,并且根据校验结果,反复调整调用大模型的任务模版,以达到满意的效果。 
通过 SFT 算法蒸馏训练较小的学生模型
接下来我们使用 EasyDistill 算法框架,利用准备好的训练数据,训练学生模型。在 PAI-DSW 中,根据“阿里云人工智能平台PAI开源EasyDistill框架助力大语言模型轻松瘦身”一文安装 EasyDistill 算法包后使用如下命令进行 SFT 模型训练:
 python easydistill/kd/train.py --config=sft.json
   复制代码
 
其中,sft.json 为 SFT 蒸馏训练的配置文件,示例如下:
 {  "job_type": "kd_black_box_api",  "dataset": {    "labeled_path": "sft_train.json",    "template" : "chat_template_kd.jinja",    "seed": 42  },  "models": {    "student": "model/Qwen/Qwen2.5-0.5B-Instruct/"  },  "training": {    "output_dir": "result_sft/",    "num_train_epochs": 3,    "per_device_train_batch_size": 1,    "gradient_accumulation_steps": 8,    "save_steps": 1000,    "logging_steps": 1,    "learning_rate": 2e-5,    "weight_decay": 0.05,    "warmup_ratio": 0.1,    "lr_scheduler_type": "cosine"  }} 
   复制代码
 
其中,sft_train.json 为 SFT 训练数据集,model/Qwen/Qwen2.5-0.5B-Instruct/为学生模型路径,这里以 Qwen2.5-0.5B-Instruct 为示例,result_sft/为模型输出路径。您可以根据实际需要,在 training 字段中调整训练使用的超参数。
通过 DPO 算法继续优化较小的学生模型
由于 SFT 训练过程中提供给学生模型唯一的正确答案,因此这种训练存在两个限制条件:一为模型的泛化能力有限,二为缺乏更加细粒度的模型对齐。DPO 算法通过提供 chosen 和 rejected 的模型回复,进一步提升模型的对齐能力。根据准备好的 DPO 训练数据,我们在 SFT 训练完的模型 Checkpoint 基础上,使用 EasyDistill 的如下命令,进行 DPO 模型训练:
 python easydistill/rank/train.py --config=dpo.json
   复制代码
 
其中,dpo.json 为 DPO 蒸馏训练的配置文件,示例如下:
 {  "job_type": "rank_dpo_api",  "dataset": {    "labeled_path": "dpo_train.json",    "template" : "chat_template_kd.jinja",    "seed": 42  },  "models": {    "student": "result_sft/"  },  "training": {    "output_dir": "result_dpo/",    "num_train_epochs": 3,    "per_device_train_batch_size": 1,    "gradient_accumulation_steps": 8,    "save_steps": 1000,    "logging_steps": 1,    "beta": 0.1,    "learning_rate": 2e-5,    "weight_decay": 0.05,    "warmup_ratio": 0.1,    "lr_scheduler_type": "cosine"  }}
   复制代码
 
其中,dpo_train.json 为 SFT 训练数据集,result_sft/为 SFT 训练之后的学生模型路径,result_dpo/为模型输出路径。您可以根据实际需要,在 training 字段中调整训练使用的超参数。
评论