| from unsloth import FastLanguageModel
|
| import os
|
| import torch
|
| from datasets import load_dataset
|
| from trl import SFTConfig, SFTTrainer
|
| import random
|
|
|
|
|
|
|
|
|
|
|
| my_load_model = "Qwen3-4B-Thinking-2507"
|
| my_model_name = "QiMing-Polaris"
|
| max_seq_length = 4096
|
|
|
| print(f"Dataset: {my_model_name}")
|
|
|
| local_model_path = f"/home/aifeifei/AI_Data/develop/mini_tang/modules/{my_load_model}"
|
| local_data_dir = f"{my_model_name}"
|
| local_data_file = os.path.join(local_data_dir, f"{my_model_name}.jsonl")
|
| final_model_path = f"{my_model_name}-{my_load_model}_burden_trained_lora"
|
|
|
|
|
|
|
|
|
|
|
|
|
| dtype = (
|
| None
|
| )
|
| load_in_4bit = True
|
|
|
| print(f"✅ 步骤 1/6: 正在从本地路径 '{local_model_path}' 加载模型和分词器...")
|
| model, tokenizer = FastLanguageModel.from_pretrained(
|
| model_name=local_model_path,
|
| max_seq_length=max_seq_length,
|
| dtype=dtype,
|
| load_in_4bit=load_in_4bit,
|
| full_finetuning=False,
|
| )
|
| print("🎉 模型加载完成!")
|
|
|
|
|
| print("✅ 步骤 2/6: 正在配置 LoRA 适配器...")
|
| model = FastLanguageModel.get_peft_model(
|
| model,
|
| r=8,
|
| target_modules=[
|
| "q_proj", "k_proj", "v_proj", "o_proj",
|
| "gate_proj", "up_proj", "down_proj",
|
| ],
|
| lora_alpha=16,
|
| lora_dropout=0,
|
| bias="none",
|
| use_gradient_checkpointing="unsloth",
|
| random_state=3407,
|
| use_rslora=False,
|
| loftq_config=None,
|
| )
|
| print("🎉 LoRA 配置完成!")
|
|
|
|
|
| alpaca_prompt = """Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.
|
|
|
| ### Instruction:
|
| {}
|
|
|
| ### Input:
|
| {}
|
|
|
| ### Response:
|
| {}"""
|
|
|
|
|
| EOS_TOKEN = tokenizer.eos_token
|
|
|
|
|
|
|
|
|
| def apply_burden(text, burden_ratio=0.7):
|
| """
|
| 给一段文本绑上“铅袋”:按一定比例打乱词序。
|
| """
|
| words = text.split(' ')
|
|
|
| if len(words) > 3:
|
| num_to_shuffle = int(len(words) * burden_ratio)
|
|
|
| indices_to_shuffle = random.sample(range(len(words)), num_to_shuffle)
|
|
|
| shuffled_subset = [words[i] for i in indices_to_shuffle]
|
| random.shuffle(shuffled_subset)
|
|
|
| shuffled_words = list(words)
|
| for i, original_index in enumerate(indices_to_shuffle):
|
| shuffled_words[original_index] = shuffled_subset[i]
|
| return ' '.join(shuffled_words)
|
| return text
|
|
|
| def formatting_prompts_func(examples):
|
| all_texts = []
|
| for i in range(len(examples["instruction"])):
|
| instruction = examples["instruction"][i]
|
| input_text = examples["input"][i]
|
|
|
| output_text = examples["output"][i]
|
|
|
|
|
| burdened_instruction = apply_burden(instruction)
|
| burdened_input = apply_burden(input_text)
|
|
|
|
|
| text = alpaca_prompt.format(burdened_instruction, burdened_input, output_text) + EOS_TOKEN
|
| all_texts.append(text)
|
| return {"text": all_texts}
|
|
|
|
|
|
|
| print(f"✅ 步骤 3/6: 正在从HF '{local_data_file}' 加载并应用“负重训练”处理...")
|
| dataset = load_dataset("json", data_files=local_data_file, split="train")
|
| dataset = dataset.map(
|
| formatting_prompts_func,
|
| batched=True,
|
| remove_columns=dataset.column_names,
|
| load_from_cache_file=False,
|
| )
|
| print(f"🎉 数据集处理完成!总共生成了 {len(dataset)} 条“负重”训练样本。")
|
| print("来看一个“绑了铅袋”的样本长啥样:\n")
|
| print(dataset[0]['text'])
|
|
|
|
|
| print("\n✅ 步骤 4/5: 开始模型微调...")
|
|
|
| trainer = SFTTrainer(
|
| model=model,
|
| tokenizer=tokenizer,
|
| train_dataset=dataset,
|
| dataset_text_field="text",
|
| max_seq_length=max_seq_length,
|
| dataset_num_proc=8,
|
| packing=False,
|
| args=SFTConfig(
|
| per_device_train_batch_size=4,
|
| gradient_accumulation_steps=2,
|
| dataloader_num_workers=4,
|
| dataloader_pin_memory=True,
|
| warmup_steps=25,
|
| num_train_epochs=10,
|
| learning_rate=2e-5,
|
| fp16=not torch.cuda.is_bf16_supported(),
|
| bf16=torch.cuda.is_bf16_supported(),
|
| logging_steps=5,
|
| optim="paged_adamw_8bit",
|
| lr_scheduler_type="cosine",
|
| warmup_ratio=0.03,
|
| weight_decay=0.01,
|
| seed=3407,
|
| output_dir = f"output/{final_model_path}",
|
| report_to="none",
|
| ),
|
| )
|
| trainer.train()
|
|
|
|
|
| print("\n✅ 步骤 5/5: 微调完成...")
|
| model.save_pretrained(final_model_path)
|
| tokenizer.save_pretrained(final_model_path)
|
| print(f"🎉 “负重训练”版 LoRA 模型已保存到 '{final_model_path}' 文件夹。")
|
|
|