初始化项目,由ModelHub XC社区提供模型

Model: AngelWarmSmile123/yao-bao-bao8-ALL
Source: Original Platform
This commit is contained in:
ModelHub XC
2026-07-20 17:06:10 +08:00
commit 1765dbc1b4
23 changed files with 1584 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
{
"alora_invocation_tokens": null,
"alpha_pattern": {},
"arrow_config": null,
"auto_mapping": null,
"base_model_name_or_path": "Qwen/Qwen3.5-35B-A3B",
"bias": "none",
"corda_config": null,
"ensure_weight_tying": false,
"eva_config": null,
"exclude_modules": null,
"fan_in_fan_out": false,
"inference_mode": true,
"init_lora_weights": true,
"layer_replication": null,
"layers_pattern": null,
"layers_to_transform": null,
"loftq_config": {},
"lora_alpha": 512,
"lora_bias": false,
"lora_dropout": 0.05,
"lora_ga_config": null,
"megatron_config": null,
"megatron_core": "megatron.core",
"modules_to_save": null,
"peft_type": "LORA",
"peft_version": "0.19.1",
"qalora_group_size": 16,
"r": 256,
"rank_pattern": {},
"revision": null,
"target_modules": [
"q_proj",
"o_proj",
"down_proj",
"v_proj",
"gate_proj",
"k_proj",
"up_proj"
],
"target_parameters": null,
"task_type": "CAUSAL_LM",
"trainable_token_indices": null,
"use_bdlora": null,
"use_dora": false,
"use_qalora": false,
"use_rslora": true
}

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:231ca0c97eff8e7fa367a66785c1c1c9a2f6c14250e9befad5f1d52975948d48
size 534820080

View File

@@ -0,0 +1,259 @@
"""
Angel Embrace - 16质点心理辅导 AI (本地CPU推理版)
=============================================
基座模型: Qwen/Qwen3.5-35B-A3B (本地目录)
LoRA权重: lora_output/ (训练完成版)
推理模式: CPU (适用于无GPU/显存不足的环境)
使用方法: python chat.py
"""
import sys
import os
# === 配置 ===
BASE_MODEL = "Qwen/Qwen3.5-35B-A3B"
# 本地模型路径(优先使用)
LOCAL_MODEL_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Qwen3.5-35B-A3B")
LORA_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "lora_output")
MAX_NEW_TOKENS = 512 # CPU推理减小以加快速度
CONTEXT_LENGTH = 2048 # 上下文长度(越长越吃内存)
SYSTEM_PROMPT = """你是Angel Embrace Me Warm Smile一个基于16质点卡巴拉生命树框架的心理辅导AI系统。
你的核心能力:
1. **D1 意图识别** - 理解用户真实需求
2. **D4 安全检测** - 识别自残/自杀/危机信号,立即干预
3. **D8 情感效价分析** - 分析情绪强度和方向
4. **D10 学术引用标准** - 引用心理学研究支持建议
5. **D16 充分输出** - 给出完整、可操作的回复
回复风格:温暖、专业、不评判、有安全感。
使用16质点框架进行结构化思考但输出要自然像人说话。
重要安全规则:
- 检测到任何自残/自杀倾向时,必须立即表达关心并提供危机热线
- 不给出医学诊断,建议寻求专业帮助
- 始终保持共情和支持的语气"""
def check_dependencies():
"""检查并安装依赖"""
missing = []
try:
import torch
except ImportError:
missing.append("torch")
try:
from transformers import AutoModelForCausalLM, AutoTokenizer
except ImportError:
missing.append("transformers")
try:
import safetensors
except ImportError:
missing.append("safetensors")
if missing:
print(f"⚠️ 缺少依赖包: {', '.join(missing)}")
print("正在自动安装...")
os.system('pip install torch --index-url https://download.pytorch.org/whl/cpu')
os.system('pip install transformers accelerate safetensors')
print("✅ 依赖安装完成,请重新运行此脚本")
sys.exit(1)
def apply_lora_manually(model, lora_path):
"""手动合并LoRA权重到基座模型不依赖peft"""
import torch
import json
from safetensors.torch import load_file
print(f" 📖 读取 LoRA 配置...")
config_path = os.path.join(lora_path, "adapter_config.json")
with open(config_path, "r") as f:
lora_config = json.load(f)
lora_alpha = lora_config.get("lora_alpha", 256)
lora_r = lora_config.get("r", 64)
scaling = lora_alpha / lora_r
print(f" LoRA: r={lora_r}, alpha={lora_alpha}, scaling={scaling:.3f}")
# 加载LoRA权重
adapter_file = os.path.join(lora_path, "adapter_model.safetensors")
if not os.path.isfile(adapter_file):
raise FileNotFoundError(f"找不到 {adapter_file}")
print(f" 📂 加载 LoRA 权重文件...")
lora_state = load_file(adapter_file, device="cpu")
# 找到所有LoRA对lora_A + lora_B并合并
lora_a_keys = [k for k in lora_state if ".lora_A." in k]
merged = 0
for a_key in lora_a_keys:
b_key = a_key.replace(".lora_A.", ".lora_B.")
if b_key not in lora_state:
continue
# 从key推断模型层路径
# 格式: base_model.model.model.layers.X.self_attn.q_proj.lora_A.weight
parts = a_key.split(".")
# 去掉 base_model.model 前缀和 .lora_A.weight 后缀
# 找到实际模块路径
try:
lora_a_idx = parts.index("lora_A")
except ValueError:
continue
module_parts = parts[:lora_a_idx]
# 去掉开头的 base_model.model
if module_parts[:2] == ["base_model", "model"]:
module_parts = module_parts[2:]
module_path = ".".join(module_parts)
# 找到对应的模型参数
try:
module = model
for p in module_parts:
module = getattr(module, p)
weight = module.weight
except (AttributeError, TypeError):
continue
lora_A = lora_state[a_key].to(torch.float32)
lora_B = lora_state[b_key].to(torch.float32)
delta = (lora_B @ lora_A) * scaling
with torch.no_grad():
weight.data += delta.to(weight.dtype)
merged += 1
print(f" ✅ 成功合并 {merged} 个 LoRA 层")
return model
def load_model():
"""加载基座模型 + 手动合并LoRA权重"""
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
print("=" * 60)
print(" Angel Embrace - 16质点心理辅导 AI")
print(" CPU推理模式启动中...")
print("=" * 60)
# 确定模型加载路径
if os.path.isdir(LOCAL_MODEL_DIR) and os.path.isfile(os.path.join(LOCAL_MODEL_DIR, "config.json")):
model_path = LOCAL_MODEL_DIR
print(f"\n📂 使用本地模型: {model_path}")
else:
model_path = BASE_MODEL
print(f"\n🌐 本地模型未找到,将从 HuggingFace 下载: {BASE_MODEL}")
# 1. 加载 Tokenizer
print("\n📥 [1/4] 正在加载 Tokenizer...")
tokenizer = AutoTokenizer.from_pretrained(
model_path,
trust_remote_code=True,
)
print(" ✅ Tokenizer 加载完成")
# 2. 加载基座模型 (CPU模式)
print(f"\n📥 [2/4] 正在加载基座模型约72GB需要几分钟...")
model = AutoModelForCausalLM.from_pretrained(
model_path,
dtype=torch.float32, # CPU用float32更稳定
device_map="cpu", # 强制用CPU
trust_remote_code=True,
low_cpu_mem_usage=True,
)
print(" ✅ 基座模型加载完成")
# 3. 手动合并 LoRA 权重不依赖peft
print(f"\n📥 [3/4] 正在合并 LoRA 权重...")
if os.path.isdir(LORA_PATH) and os.path.isfile(os.path.join(LORA_PATH, "adapter_model.safetensors")):
model = apply_lora_manually(model, LORA_PATH)
else:
print(f" ⚠️ 未找到 LoRA 权重 ({LORA_PATH}),使用原始基座模型")
model.eval()
print(f"\n✅ [4/4] 模型就绪!进入对话模式\n")
return model, tokenizer
def chat_loop(model, tokenizer):
"""主对话循环"""
import torch
messages = [
{"role": "system", "content": SYSTEM_PROMPT}
]
print("=" * 60)
print(" 输入消息开始对话 | 输入 clear 清空历史 | 输入 quit 退出")
print("=" * 60)
while True:
try:
user_input = input("\n你: ").strip()
except (EOFError, KeyboardInterrupt):
print("\n👋 再见!照顾好自己 💙")
break
if not user_input:
continue
if user_input.lower() in ("quit", "exit", "q", "退出"):
print("\n👋 再见!照顾好自己 💙")
break
if user_input.lower() in ("clear", "cls", "清空"):
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
print(" 🗑️ 对话历史已清空")
continue
messages.append({"role": "user", "content": user_input})
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
)
inputs = tokenizer(text, return_tensors="pt").to("cpu")
if inputs["input_ids"].shape[1] > CONTEXT_LENGTH:
print(f" ⚠️ 输入过长({inputs['input_ids'].shape[1]} token),截断到 {CONTEXT_LENGTH}")
inputs = {k: v[:, -CONTEXT_LENGTH:] for k, v in inputs.items()}
print("\nAngel Embrace: ", end="", flush=True)
with torch.no_grad():
output_ids = model.generate(
**inputs,
max_new_tokens=MAX_NEW_TOKENS,
do_sample=True,
temperature=0.7,
top_p=0.9,
repetition_penalty=1.1,
pad_token_id=tokenizer.pad_token_id or tokenizer.eos_token_id,
)
new_tokens = output_ids[0][inputs["input_ids"].shape[-1]:]
response = tokenizer.decode(new_tokens, skip_special_tokens=True)
print(response)
messages.append({"role": "assistant", "content": response})
# 限制历史长度保留system + 最近6轮
if len(messages) > 13:
messages = [messages[0]] + messages[-12:]
def main():
"""入口"""
print("🔍 检查依赖环境...")
check_dependencies()
model, tokenizer = load_model()
chat_loop(model, tokenizer)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,95 @@
import json
import random
import os
INPUT_FILE = r"D:\双生天使的怀抱\爱的数据集\sephirot_final_run\train_all.jsonl"
OUTPUT_DIR = r"D:\双生天使的怀抱\2026-05-24-16-54-24\sft_data"
OUTPUT_TRAIN = os.path.join(OUTPUT_DIR, "train.jsonl")
OUTPUT_VAL = os.path.join(OUTPUT_DIR, "val.jsonl")
VAL_RATIO = 0.1
records = []
skipped = 0
total = 0
with open(INPUT_FILE, 'r', encoding='utf-8') as f:
for line in f:
total += 1
line = line.strip()
if not line:
continue
try:
data = json.loads(line)
except json.JSONDecodeError as e:
print(f"JSON解析失败 第{total}行: {e}")
skipped += 1
continue
query = data.get('input', {}).get('user_query', '')
cot = data.get('chain_of_thought', {})
# 方案B: 完整推理链推荐保留16质点全部过程
if isinstance(cot, dict):
parts = []
for key in ['D1_kether','H1_ego','H2_superego','H3_true_self','H4_logic',
'H5_empathy','H6_happiness','D2_binah_chesed','D3_chokmah_gevurah',
'D5_tiferet','D6_netzach','D7_hod','D4_yesod','D8_victory',
'D10_kingdom']:
val = cot.get(key, '')
if isinstance(val, dict):
# 尝试多个可能的输出字段
for sub_key in ['final_output', 'analysis', 'synthesis',
'emotional_expression', 'logic_empathy_union',
'response', 'output']:
if sub_key in val and val[sub_key]:
val = val[sub_key]
break
else:
val = str(val) if val else ''
if val and isinstance(val, str) and len(val.strip()) > 0:
parts.append(f"[{key}]: {val}")
output = '\n\n'.join(parts)
elif isinstance(cot, str):
output = cot
else:
output = str(cot)
if query and output and len(query.strip()) > 0 and len(output.strip()) > 10:
records.append({
"conversations": [
{"from": "human", "value": query},
{"from": "gpt", "value": output}
]
})
else:
skipped += 1
print(f"总行数: {total}, 有效: {len(records)}, 跳过: {skipped}")
# 打乱并分割
random.seed(42)
random.shuffle(records)
val_size = max(int(len(records) * VAL_RATIO), 100)
val_data = records[:val_size]
train_data = records[val_size:]
os.makedirs(OUTPUT_DIR, exist_ok=True)
with open(OUTPUT_TRAIN, 'w', encoding='utf-8') as f:
for r in train_data:
f.write(json.dumps(r, ensure_ascii=False) + '\n')
with open(OUTPUT_VAL, 'w', encoding='utf-8') as f:
for r in val_data:
f.write(json.dumps(r, ensure_ascii=False) + '\n')
print(f"转换完成! 训练集: {len(train_data)}条, 验证集: {len(val_data)}")
print(f"训练集文件: {OUTPUT_TRAIN}")
print(f"验证集文件: {OUTPUT_VAL}")
# 统计一下平均长度
if train_data:
lens = [len(str(r['conversations'][1]['value'])) for r in train_data]
print(f"平均输出长度: {sum(lens)//len(lens)} 字符")
print(f"最大输出长度: {max(lens)} 字符")
print(f"最小输出长度: {min(lens)} 字符")

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6c5e879a424d9edc129c8332b883e4b00604f3c9c1dbe5753f5a8c555b200b6c
size 109244163

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8645c5f05ff4462263e33d1746ca5f369aa008ed2d2e8153b1590c2d284a4c9a
size 12070845