提升自然语言转换为 SQL 查询(NL2SQL)准确度的探索-- LLaMA-Factory 蒸馏 DeepSeek 模型的方法介绍

背景

提升自然语言转换为 SQL 查询可能的3个方向有:1. Prompt 工程,以用户角色提供充足的上下文信息;2. 建设知识库,以系统角色提供上下文信息;3. 增强模型的NL2SQL能力 。

在第3个方向上,我们发现:本地部署的 deepseek-r1:32b 的 NL2SQL 的准确度与满血版的在线 deepseek-r1:671b 存在较大差距。这说明模型能力会影响 NL2SQL 准确性。

本文通过蒸馏 DeepSeek 模型,探索:通过提升模型专业能力,能够提高 NL2SQL 的准确度

蒸馏模型与探索过程

由于测试服务器的性能限制,本文采用 DeepSeek-R1-Distill-Qwen-7B 模型进行蒸馏。

本文通过对 DeepSeek-R1-Distill-Qwen-7B 模型进行本地部署,使用 NL2SQL 数据集 Spider 数据集进行训练和蒸馏,对比本地蒸馏 DeepSeek 模型与满血 DeepSeek 模型在数据集 Spider 上的转换准确度,来验证:通过提升模型专业能力,能够提高 NL2SQL 的准确度。

探索的步骤如下:

  • 本地部署 DeepSeek-R1-Distill-Qwen-7B 模型
  • 使用 NL2SQL 数据集:Spider 进行训练,蒸馏出模型:DeepSeek-R1-Distill-Qwen-7B__Spider
  • 对比 DeepSeek-R1-Distill-Qwen-7B__Spider 与 满血在线 deepseek-r1:671b 在 Spider 数据集上的 NL2SQL 准确度。

1.本地部署 DeepSeek-R1-Distill-Qwen-7B 模型

a. 安装 Ollama

注意:设置端口和IP访问策略,保障网络安全
curl -fsSL https://ollama.com/install.sh | sh

ollama run deepseek-r1:32b

b. 下载 DeepSeek-R1-Distill-Qwen-7B 到本地

https://hf-mirror.com/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B/tree/main

2. 数据集预处理

a. 下载 Spider 数据集

https://github.com/taoyds/spider/tree/master/evaluation_examples/examples

b. 使用以下 Python 脚本,将 Spider 数据集转换成 LLama-Factory 蒸馏模型需要的格式

def load_json_data(json_file_path):
    with open(json_file_path, "r", encoding="utf-8") as f:
        json_data = json.load(f)
    return json_data


def convert_spider_to_llamafactory(spider_data):
    converted_data = []
    for item in spider_data:
        # 将 db_id 拼接到 instruction 中
        instruction = f"Using the database '{item['db_id']}', translate the following natural language question into a SQL query."
        input_text = item["question"]
        output_text = item["query"]
        
        converted_item = {
            "instruction": instruction,
            "input": input_text,
            "output": output_text
        }
        converted_data.append(converted_item)

    return converted_data
    

dataset_source_file = "train_spider.json"
dataset_target_file = "llama_train_spider.json"

json_data = load_json_data(dataset_source_file)
converted_json_data = convert_spider_to_llamafactory(json_data)

# 生成 llama_train_spider.json,证
save_json_data(converted_json_data, dataset_target_file) 

3. 蒸馏 DeepSeek-R1-Distill-Qwen-7B__Spider

a. 下载安装 LLaMA-Factory

git clone https://gitee.com/james-hadoop/LLaMA-Factory.git

cd LLaMA-Factory

pip install -e ".[torch,metrics]" -i https://pypi.tuna.tsinghua.edu.cn/simple

llamafactory-cli help

b. 将数据集,注册到 LLaMA-Factory

cd LLaMA-Factory

vi data/data_info.json

data_info.json 文件内容片段

{
  "llama_train_spider": {
    "file_name": "llama_train_spider.json"
  },
  "llama_chase_train": {
    "file_name": "llama_chase_train.json"
  },
  "identity": {
    "file_name": "identity.json"
  },
  "alpaca_en_demo": {
    "file_name": "alpaca_en_demo.json"
  },
  "alpaca_zh_demo": {
    "file_name": "alpaca_zh_demo.json"
  }
}

c. 训练模型

nohup \
    llamafactory-cli train \
    --model_name_or_path ~/DeepSeek-R1-Distill-Qwen-7B \ # 模型的路径
    --output_dir ~/DeepSeek-R1-Distill-Qwen-7B__Spider/train \ # 生成的模型路径
    --dataset_dir data \
    --dataset llama_train_spider \ # llama_train_spider 数据集
    --cutoff_len 2048 \
    --stage sft \
    --do_train True \
    --preprocessing_num_workers 16 \
    --template deepseek3 \
    --flash_attn auto \
    --learning_rate 5e-05 \
    --num_train_epochs 10.0 \ # 模型训练的轮数
    --seed 168 \
    --max_samples 100000 \
    --per_device_train_batch_size 2 \
    --gradient_accumulation_steps 8 \
    --lr_scheduler_type cosine \
    --max_grad_norm 1.0 \
    --logging_steps 5 \
    --save_steps 100 \
    --warmup_steps 0 \
    --packing False \
    --report_to none \
    --bf16 True \
    --plot_loss True \
    --trust_remote_code True \
    --ddp_timeout 180000000 \
    --include_num_input_tokens_seen True \
    --optim adamw_torch \
    --finetuning_type lora \
    --lora_rank 8 \
    --lora_alpha 16 \
    --lora_dropout 0 \
    --lora_target all \
    &
    ```

d. 模型训练成功后,编辑模型导出配置文件

cd LLaMA-Factory/examples/merge_lora

vi deepseek_r1_7b__spider.yaml

deepseek_r1_7b__spider.yaml 文件内容

### Note: DO NOT use quantized model or quantization_bit when merging lora adapters

### model
model_name_or_path: ~/DeepSeek-R1-Distill-Qwen-7B # 基准模型的路径
adapter_name_or_path: ~/DeepSeek-R1-Distill-Qwen-7B__Spider/train # 训练生成的模型的路径
template: llama3
trust_remote_code: true

### export
export_dir: ~/DeepSeek-R1-Distill-Qwen-7B__Spider/export # 模型导出的路径
export_size: 5
export_device: cpu
export_legacy_format: false

这个步骤执行成功之后,将会在 ~/DeepSeek-R1-Distill-Qwen-7B__Spider/export 这个路径下生成蒸馏后的模型。

4. 将 Hugging Face 模型转换成 Ollama 模型

由于上述步骤生成的模型是 Hugging Face 模型,而本文选择了 Ollama + AnythingLLM 作为演示工具,因此需要将 HF 模型转换成 Ollma 模型。

a. 下载部署llama.cpp

git clone https://gitee.com/shuilongying/llama.cpp.git

cd llama.cpp

mkdir build

cd build

cmake ..

make

b. 将 HF 模型转换成 Ollama 模型

cd llama.cpp

python convert_hf_to_gguf.py ~/DeepSeek-R1-Distill-Qwen-7B__Spider/export

c. Ollama 加载模型

ollama create DeepSeek-R1-Distill-Qwen-7B__Spider -f ./Modelfile

d. 使用 AnythingLLM 验证模型正常使用

5. 效果对比

通过下面满血 DeepSeek 与 蒸馏 DeepSeek 模型生成的 SQL 可以发现:在 Spider 数据集上进行 NL2SQL,蒸馏模型的准确度更高。

标准答案SQL

-- 标准答案来自 Spider 数据集
SELECT T3.born_state FROM department AS T1 JOIN management AS T2 ON T1.department_id  =  T2.department_id JOIN head AS T3 ON T2.head_id  =  T3.head_id WHERE T1.name  =  'Treasury' INTERSECT SELECT T3.born_state FROM department AS T1 JOIN management AS T2 ON T1.department_id  =  T2.department_id JOIN head AS T3 ON T2.head_id  =  T3.head_id WHERE T1.name  =  'Homeland Security'
满血 DeepSeek(左) Vs 蒸馏 DeepSeek(右)

与左边满血 DeepSeek 相比,右边的蒸馏 DeepSeek 模型与上面的标准答案 SQL 更接近。

结论

  1. 通过效果对比,可以看出,经过本地蒸馏出来的 DeepSeek 模型在特定的语言环境下,效果比满血版的 DeepSeek 模型更好。
  2. 训练和蒸馏本地 deepseek-r1 模型,提升 NL2SQL 准确度技术上是可行的。

展望

  1. 由于测试环境显存限制(22GB左右),本文基于 DeepSeek-R1-Distill-Qwen-7B 模型进行蒸馏,模型能力上限不高。如果使用显存更大的环境来蒸馏模型,能够提升模型能力的上限,提升 NL2SQL 的准确度。
  2. 在使用蒸馏模型的同时,建设元数据知识库、提供更加充分且准确的上下文信息,是进一步提升 NL2SQL 的准确度的方向。
展示评论