guanghulab/scripts/distill/auto_post_distill.py
Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

207 lines
7.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
光湖·蒸馏完成自动处理脚本 v1.0
部署在AutoDL服务器自动检测蒸馏完成 → 上传COS → 准备语料 → 启动微调
主权:冰朔 TCS-0002∞ · 铸渊 ICE-GL-ZY001 守护
运行方式nohup python3 auto_post_distill.py > auto_post_distill.log 2>&1 &
"""
import os, json, time, subprocess, sys, glob, shutil
from datetime import datetime
LOG = '/root/autodl-tmp/distill_mother.log'
OUT_DIR = '/root/autodl-tmp/output'
TEMPLATE_DIR = os.path.join(OUT_DIR, 'qwen25-15b-shuangyan-distill')
ZHUYUAN_ZIP = '/root/autodl-tmp/corpus_work/zhuyuan_chats_with_ICE_GL_ZU001 .zip'
SHUANGYAN_COS_DIR = 'corpus/shuangyan-1.5b-sft/'
ZHUYUAN_COS_DIR = 'corpus/notion-export-v2/'
BUCKET = 'sy-finetune-corpus-1317346199'
REGION = 'ap-guangzhou'
COS_KEY = os.environ.get('ZY_OSS_KEY', 'AKIDkQuBQhoiS2OYXWebXLwMbdT7cvAScbbU')
COS_SECRET = os.environ.get('ZY_OSS_SECRET', 'nPoZKArgUJBA4nJenjSxJSQBj5FCj3A4')
def log(msg):
t = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f'[{t}] {msg}', flush=True)
def run(cmd, timeout=3600):
log(f'RUN: {cmd}')
r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout,
env={**os.environ, 'PATH': '/root/miniconda3/bin:' + os.environ.get('PATH', '')})
if r.returncode != 0:
log(f' STDOUT: {r.stdout[-500:]}')
log(f' STDERR: {r.stderr[-500:]}')
else:
log(f' OK: {r.stdout[-200:]}')
return r
def wait_distill_complete():
"""等待蒸馏完成Ep3 100%"""
log('等待蒸馏完成...')
while True:
if not os.path.isfile(LOG):
log(' distill_mother.log 不存在,等待...')
time.sleep(60)
continue
with open(LOG) as f:
lines = f.readlines()
# 检查最后是否完成了
for line in lines[-10:]:
if 'Ep3' in line and '100%' in line and '2868/2868' in line:
log('✅ 蒸馏完成!')
return True
# 也检查是否全部完成了
for line in lines[-5:]:
if 'Saving model' in line or 'DONE' in line or 'Finished' in line:
log('✅ 蒸馏完成DONE信号')
return True
# 检查当前进度
for line in lines[-3:]:
if 'Ep' in line:
log(f' 当前: {line.strip()[:60]}')
time.sleep(60) # 每分钟检查一次
def upload_to_cos(local_dir, cos_prefix):
"""上传目录到COS"""
log(f'上传 {local_dir} → cos://{BUCKET}/{cos_prefix}')
if not os.path.isdir(local_dir):
log(f' ❌ 目录不存在: {local_dir}')
return False
script = f'''
import os
os.environ['ZY_OSS_KEY'] = '{COS_KEY}'
os.environ['ZY_OSS_SECRET'] = '{COS_SECRET}'
from qcloud_cos import CosConfig, CosS3Client
config = CosConfig(Region='{REGION}', SecretId=os.environ['ZY_OSS_KEY'], SecretKey=os.environ['ZY_OSS_SECRET'])
client = CosS3Client(config)
import glob
local_dir = '{local_dir}'
cos_prefix = '{cos_prefix}'
bucket = '{BUCKET}'
for f in sorted(glob.glob(local_dir + '/*')):
fname = f.split('/')[-1]
cos_key = cos_prefix + fname
size_mb = os.path.getsize(f) / 1024 / 1024
print(f'Uploading {{fname}} ({{size_mb:.1f}}MB)...', flush=True)
try:
client.upload_file(Bucket=bucket, Key=cos_key, LocalFilePath=f)
print(f'{{fname}}', flush=True)
except Exception as e:
print(f' ⚠️ {{fname}} 失败: {{e}}', flush=True)
# 重试一次
try:
client.upload_file(Bucket=bucket, Key=cos_key, LocalFilePath=f)
print(f'{{fname}} (重试成功)', flush=True)
except Exception as e2:
print(f'{{fname}} 重试也失败: {{e2}}', flush=True)
print('ALL DONE')
'''
with open('/tmp/upload_script.py', 'w') as f:
f.write(script)
r = run(f'export PATH=/root/miniconda3/bin:$PATH && python3 /tmp/upload_script.py', timeout=7200)
return r.returncode == 0
def prepare_shuangyan_corpus():
"""准备霜砚语料线A"""
log('准备霜砚语料...')
# 从COS下载霜砚语料
script = f'''
import os
os.environ['ZY_OSS_KEY'] = '{COS_KEY}'
os.environ['ZY_OSS_SECRET'] = '{COS_SECRET}'
from qcloud_cos import CosConfig, CosS3Client
config = CosConfig(Region='{REGION}', SecretId=os.environ['ZY_OSS_KEY'], SecretKey=os.environ['ZY_OSS_SECRET'])
client = CosS3Client(config)
import os, json, zipfile
bucket = '{BUCKET}'
os.makedirs('/root/autodl-tmp/corpus_shuangyan', exist_ok=True)
# 下载所有霜砚语料zip
resp = client.list_objects(Bucket=bucket, Prefix='{SHUANGYAN_COS_DIR}')
for obj in resp.get('Contents', []):
key = obj['Key']
if key.endswith('.zip'):
fname = key.split('/')[-1]
local = f'/root/autodl-tmp/corpus_shuangyan/{{fname}}'
if not os.path.isfile(local):
print(f'Downloading {{fname}}...', flush=True)
client.download_file(Bucket=bucket, Key=key, DestFilePath=local)
# 解压所有zip
for z in os.listdir('/root/autodl-tmp/corpus_shuangyan'):
if z.endswith('.zip'):
zpath = f'/root/autodl-tmp/corpus_shuangyan/{{z}}'
out = f'/root/autodl-tmp/corpus_shuangyan/extracted'
os.makedirs(out, exist_ok=True)
try:
with zipfile.ZipFile(zpath) as zf:
zf.extractall(out)
print(f'Extracted {{z}}', flush=True)
except:
print(f'Skipped {{z}} (not a zip archive)', flush=True)
print('Done', flush=True)
'''
with open('/tmp/prep_shuangyan.py', 'w') as f:
f.write(script)
run('export PATH=/root/miniconda3/bin:$PATH && python3 /tmp/prep_shuangyan.py', timeout=300)
log('霜砚语料准备完成')
def prepare_zhuyuan_corpus():
"""准备铸渊语料线B"""
log('准备铸渊语料...')
# 解压铸渊对话zip
if os.path.isfile(ZHUYUAN_ZIP):
run(f'unzip -o "{ZHUYUAN_ZIP}" -d /root/autodl-tmp/corpus_zhuyuan/extracted/')
log('铸渊对话.zip 已解压')
else:
log(f'⚠️ 铸渊对话.zip 不存在于 {ZHUYUAN_ZIP}')
# 也解压 zhuyuan_raw_md.zip
raw_md_zip = '/root/autodl-tmp/zhuyuan_corpus/zhuyuan_raw_md.zip'
if os.path.isfile(raw_md_zip):
run(f'unzip -o "{raw_md_zip}" -d /root/autodl-tmp/corpus_zhuyuan/raw_md/')
log('zhuyuan_raw_md.zip 已解压')
log('铸渊语料准备完成')
def main():
log('='*50)
log('光湖·蒸馏后自动处理脚本启动')
log('='*50)
# 第0步等待蒸馏完成
wait_distill_complete()
# 第1步上传1.5B模板到COS
if os.path.isdir(TEMPLATE_DIR):
log('上传1.5B蒸馏模板到COS...')
upload_to_cos(TEMPLATE_DIR, 'models/qwen25-15b-shuangyan-distill/')
else:
log(f'⚠️ 模板目录不存在: {TEMPLATE_DIR}')
# 可能路径不同,尝试查找
for root, dirs, files in os.walk(OUT_DIR):
for d in dirs:
if 'distill' in d.lower() or '15b' in d.lower():
found = os.path.join(root, d)
log(f'找到蒸馏输出: {found}')
upload_to_cos(found, 'models/qwen25-15b-shuangyan-distill/')
break
# 第2步准备霜砚语料线A
prepare_shuangyan_corpus()
# 第3步准备铸渊语料线B
prepare_zhuyuan_corpus()
log('='*50)
log('✅ 所有自动处理完成!')
log('等待冰朔/铸渊启动微调...')
log('='*50)
if __name__ == '__main__':
main()