Datawhale AI夏令营 《基于带货视频评论的用户洞察挑战赛》Part .1.

发布于:2025-07-16 ⋅ 阅读:(14) ⋅ 点赞:(0)

1. 赛题

参赛者需要构建端到端的评论分析系统,完成三大核心任务:

  1. 商品识别
    • 输入:视频描述文本(video_desc)和标签(video_tags)
    • 输出:精准识别推广商品名称(Xfaiyx Smart Translator/Recorder)
  2. 多维情感分析
    • 维度:情感倾向(5类)、用户场景、用户疑问、用户建议
    • 挑战:处理隐晦表达如"这重量出门带着刚好"(场景暗示)
  3. 评论聚类与主题提炼
    • 对5类特定评论进行聚类分析
    • 生成5-8个具有代表性的主题词

由于这里只有很少量的数据是有标签的(商品识别中总共86个数据,大约30个有label;评论总共6400+数据,大约1700+有label),而且不同类别的分布数目相差很大,因此很明显不能从头训练模型。如果选用传统的DNN,如Seq2Seq等,即使微调也需要足够的数据,没有能力接收少量且差异化特别大的数据就能够进行分类。

因此,我们需要使用原本就具有所需的分类能力的模型——LLM

2. 商品识别——SFT 微调

主要流程为:

  1. 下载模型权重checkpoint
  2. 处理数据集dataset
  3. 微调LLM
  4. 在测试集上运行

2.1 准备第三方工具

这里作者使用了算力平台,有条件的可以本地部署,也可以直接调用大模型的API

2.1.1 安装 LLaMA-Factory

LLaMA-Factory可以很方便的进行Pre-Training, SFT, PPO, DPO等

git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e ".[torch,metrics]" --no-build-isolation

2.1.2 安装 huggingface_hub

后续checkpoint都需要从huggingface中下载,相比较本地下载再upload到服务器上,直接从官网下载会方便很多

pip install -U huggingface_hub

直接从官网下载网速会有点慢,可以使用国内镜像

vim ~/.bashrc

# vim下修改文件, 增加下方内容
export HF_ENDPOINT="https://hf-mirror.com"
# 保存并退出

source ~/.bashrc

2.2 下载模型权重

下载过程由于耗时较长,为了防止ssh关闭导致下载终止,可以使用screen开个后台

选择参数量较小的Qwen3-1.7B进行微调,在单卡下微调时长约为3分钟

huggingface-cli download --resume-download Qwen/Qwen3-1.7B --local-dir models/qwen3-1.7B

2.3 处理数据

大致思路为:

  1. 将video_desc与video_tag合并,作为模型输入
  2. 添加instruction作为prompt
  3. 选择有label的部分,作为训练集

那么直接贴代码:

import argparse
import pandas as pd
from transformers import AutoTokenizer, AutoModelForCausalLM

video_data = pd.read_csv("origin_videos_data.csv")
video_data["text"] = video_data["video_desc"].fillna("") + " " + video_data["video_tags"].fillna("")

def preprocess_data():
    text_data = video_data[["text", "product_name"]]
    text_data = text_data[text_data["product_name"].notnull()]
    
    instruction = '''
    你是一个专业的电商产品识别系统。请从视频描述中识别推广商品,必须严格选择以下选项之一:
    - Xfaiyx Smart Translator
    - Xfaiyx Smart Recorder

    规则说明:
    1. 当描述提到"翻译"、"多语言"等关键词时选择Translator
    2. 当描述出现"录音"、"转写"等关键词时选择Recorder
    3. 遇到不确定情况时选择更符合主要功能的选项

    示例:
    输入:这款设备支持实时语音转文字
    输出:Xfaiyx Smart Recorder
    '''
    text_data["instruction"] = instruction.strip()
    text_data.to_json("text_data.json", orient="records", force_ascii=False)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--preprocess", type=bool, default=False)
    parser.add_argument("--device", type=str, default="cuda")

    args = parser.parse_args()
    if args.preprocess:
        preprocess_data()

运行后数据变为:
在这里插入图片描述

2.4 微调模型

2.4.1 修改data_info

在LLaMA-Factory/data/dataset_info.json中增加自定义数据集

"dw_data_video": {
    "file_name": "DW/text_data.json",
    "formatting": "alpaca",
    "spilt": "train",
    "columns": {
      "query": "text",
      "response": "product_name",
      "prompt": "instruction"
    }
  },

参数的具体含义如下:

  • file_name : 数据集的路径
  • formatting : 数据集的格式,主流LLM训练数据的格式分为alpaca和sharegpt
  • split : 将数据集划分为train, test, val,默认仅作为train
  • columns : 指定哪个key作为模型接收的输入/输出

原本模型是以"input" : “message"作为模型接收到的输入,但dw_data_video中模型输入为"text” : “message”,因此需要修改

2.4.2 修改微调配置

设置sft配置文件,文件路径随意,但在后续训练启动命令时,需要指定文件路径

### model
model_name_or_path: models/qwen3-1.7B		# 下载预训练模型的路径
### method
stage: sft
do_train: true
finetuning_type: lora #微调方式
lora_target: all

### dataset
dataset: dw_data_video
template: qwen3    # 注意:这里的参数选项要严格与官方给出的表格一致
cutoff_len: 2048
max_samples: 1000
overwrite_cache: true
preprocessing_num_workers: 16

### output
output_dir: output/sft/lora/qwen3-1.7B-dw-data-video
logging_steps: 10
save_steps: 500
plot_loss: true
overwrite_output_dir: true

### train
per_device_train_batch_size: 16
gradient_accumulation_steps: 8
learning_rate: 1.0e-4
num_train_epochs: 10
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
ddp_timeout: 180000000
run_name: qwen3-1.7B-dw-data-video		# 用于wandb展示过程

### eval
val_size: 0.1
per_device_eval_batch_size: 1
eval_strategy: steps
eval_steps: 500

2.4.3. 启动训练

注意文件路径需要与上面创建文件时的路径一致

llamafactory-cli train LLaMA-Factory/workspace/lora/sft/sft_lora_qwen3.yaml

官方给出的代码为llamafactory-cli train xxxx.yaml,但由于我们的yaml文件存储路径不一定在官方默认路径下,因此使用完整路径更稳当
注意:启动时,pwd一定要在LLaMA-Factory文件夹下,不然会报错No such file data/dataset_info.json

2.5 运行测试集数据

import argparse
import pandas as pd
from transformers import AutoTokenizer, AutoModelForCausalLM

video_data = pd.read_csv("origin_videos_data.csv")
video_data["text"] = video_data["video_desc"].fillna("") + " " + video_data["video_tags"].fillna("")

def preprocess_data():
    text_data = video_data[["text", "product_name"]]
    text_data = text_data[text_data["product_name"].notnull()]
    
    instruction = '''
    你是一个专业的电商产品识别系统。请从视频描述中识别推广商品,必须严格选择以下选项之一:
    - Xfaiyx Smart Translator
    - Xfaiyx Smart Recorder

    规则说明:
    1. 当描述提到"翻译"、"多语言"等关键词时选择Translator
    2. 当描述出现"录音"、"转写"等关键词时选择Recorder
    3. 遇到不确定情况时选择更符合主要功能的选项

    示例:
    输入:这款设备支持实时语音转文字
    输出:Xfaiyx Smart Recorder
    '''
    text_data["instruction"] = instruction.strip()
    text_data.to_json("text_data.json", orient="records", force_ascii=False)

# 定义推理函数
def predict_product(text, device):
    instruction = (
        "你是一个专业的电商产品识别系统。请从视频描述中识别推广商品,必须严格选择以下选项之一:\n"
        "    - Xfaiyx Smart Translator\n"
        "    - Xfaiyx Smart Recorder\n\n"
        "规则说明:\n"
        "1. 当描述提到\"翻译\"、\"多语言\"等关键词时选择Translator\n"
        "2. 当描述出现\"录音\"、\"转写\"等关键词时选择Recorder\n"
        "3. 遇到不确定情况时选择更符合主要功能的选项"
    )

    input_text = f"{instruction}\n\n输入:{text}\n输出:"

    inputs = tokenizer(input_text, return_tensors="pt").to(device)

    outputs = model.generate(
        inputs.input_ids,
        max_new_tokens=20,          # 限制生成长度
        num_beams=1,                 # 使用贪婪搜索
        do_sample=False,             # 禁用随机采样
        pad_token_id=tokenizer.eos_token_id  # 设置填充token
    )

    full_output = tokenizer.decode(outputs[0], skip_special_tokens=True)
    generated_output = full_output[len(input_text):]  # 提取生成部分
    
    # 清理输出结果
    return generated_output.strip().split("\n")[0]


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--preprocess", type=bool, default=False)
    parser.add_argument("--device", type=str, default="cuda")

    args = parser.parse_args()
    if args.preprocess:
        preprocess_data()

    device = args.device

    model_path = 'output/sft/lora/qwen3-1.7B-DWData'
    tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
    model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True).to(device)

    # 遍历csv,推理并保存结果
    for index, row in video_data.iterrows():
        # 如果product_name列非空则保存product_name
        if pd.notna(row["product_name"]):
            video_data.at[index, "prediction"] = row["product_name"]
            continue
        text = row["text"]
        prediction = predict_product(text, device)
        video_data.at[index, "prediction"] = prediction

    # 用prediction列覆盖product_name列
    video_data["product_name"] = video_data["prediction"]

    # 只保存 video_id 和 product_name 列
    video_data = video_data[["video_id", "product_name"]]
    video_data.to_csv("video_data_with_predictions.csv", index=False)

那么此时输出的文件就是预测后的文件

将输出的文件和Baseline的文件上传,发现分数提高了10分左右,目前来到了180分,说明LLM微调后效果还不错

后续内容努力码字中


网站公告

今日签到

点亮在社区的每一天
去签到