初始提交:3 款纯音频游戏 + 共享引擎 + 完整文档与资产管线
- 共享引擎(app/src/main):GestureEngine 6 手势识别、AudioEngine 三层音频 (ExoPlayer BGM 交叉淡入 / 对白 ducking / SoundPool 低延迟)、Game/GameEngine 状态机接口、MainActivity 全屏封面 + TalkBack - 《声命线》storyline:末世互动广播剧,3 幕 8 抉择点 4 结局 - 《声东击西》reflex:听声辨位反应,12 波战斗 + BGM 三档 BPM 变速 - 《暗室》escape:3x3 网格密室逃脱,钥匙→铁柜→保险丝→电箱→大门谜题链 - 文档:setup(从零搭建)/ architecture(架构)/ engine-api(引擎 API)/ asset-pipeline(资产流水线)/ games/*(三款游戏设计文档) - 资产管线:Qwen3-TTS 对白 + 程序合成音效/BGM + Mureka BGM 的 gen 脚本与台账, 全部 ogg 资产入库可复现 - env.d 环境脚本:android/tts 入库;sfx/mureka 含密钥不入库,仅提交 .example.sh 模板
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import json
|
||||
|
||||
import torch
|
||||
from safetensors import safe_open
|
||||
from safetensors.torch import load_file
|
||||
from stable_audio_3.factory import (
|
||||
create_autoencoder_from_config,
|
||||
create_diffusion_cond_from_config,
|
||||
)
|
||||
|
||||
|
||||
def copy_state_dict(model, state_dict):
|
||||
model_state_dict = model.state_dict()
|
||||
state_dict = remap_state_dict_keys(state_dict, model_state_dict)
|
||||
for key in state_dict:
|
||||
if (
|
||||
key in model_state_dict
|
||||
and state_dict[key].shape == model_state_dict[key].shape
|
||||
):
|
||||
model_state_dict[key] = state_dict[key]
|
||||
else:
|
||||
print(
|
||||
f"Key {key} not found in target state_dict or shape mismatch. Skipping."
|
||||
)
|
||||
|
||||
model.load_state_dict(model_state_dict, strict=False)
|
||||
|
||||
|
||||
def load_autoencoder(config_path: str, ckpt_path: str, device: str = "cpu"):
|
||||
"""Load only the autoencoder from a combined DiT+autoencoder checkpoint.
|
||||
|
||||
Only pretransform tensors are read from disk, directly onto the target device.
|
||||
Standalone AE-only checkpoints (e.g. stabilityai/SAME-L / SAME-S) have no prefix.
|
||||
"""
|
||||
|
||||
with open(config_path) as f:
|
||||
config = json.load(f)
|
||||
|
||||
autoencoder = create_autoencoder_from_config(config["model"], config["sample_rate"])
|
||||
|
||||
# Full DiT checkpoints nest the AE under pretransform.model.*;
|
||||
# standalone AE-only checkpoints have no prefix.
|
||||
nested_prefix = "pretransform.model."
|
||||
with safe_open(ckpt_path, framework="pt", device=device) as f:
|
||||
all_keys = list(f.keys())
|
||||
if any(k.startswith(nested_prefix) for k in all_keys):
|
||||
effective_prefix = nested_prefix
|
||||
else:
|
||||
effective_prefix = "" # standalone AE — keys are already bare
|
||||
with safe_open(ckpt_path, framework="pt", device=device) as f:
|
||||
state_dict = {
|
||||
k[len(effective_prefix) :]: f.get_tensor(k)
|
||||
for k in all_keys
|
||||
if k.startswith(effective_prefix)
|
||||
}
|
||||
|
||||
copy_state_dict(autoencoder, state_dict)
|
||||
return autoencoder.to(device)
|
||||
|
||||
|
||||
def load_diffusion_cond(
|
||||
model_config,
|
||||
ckpt_path: str,
|
||||
device: str = "cuda",
|
||||
model_half: bool = False,
|
||||
):
|
||||
model = create_diffusion_cond_from_config(model_config)
|
||||
copy_state_dict(model, load_file(ckpt_path))
|
||||
model.to(device).eval().requires_grad_(False)
|
||||
if model_half:
|
||||
model.to(torch.float16)
|
||||
return model
|
||||
|
||||
|
||||
def remap_state_dict_keys(state_dict, model_state_dict):
|
||||
remapped = {}
|
||||
for key, value in state_dict.items():
|
||||
if key not in model_state_dict:
|
||||
parts = key.split(".")
|
||||
for i in range(1, len(parts)):
|
||||
candidate = ".".join(parts[:i]) + "." + ".".join(parts[i + 1 :])
|
||||
if candidate in model_state_dict:
|
||||
key = candidate
|
||||
break
|
||||
remapped[key] = value
|
||||
return remapped
|
||||
Reference in New Issue
Block a user