在使用AutoModelForCausalLM加载本地的HuggingFace .safetensors模型时,Jupyter内核崩溃
我正在尝试在JupyterLab中使用transformers加载一个本地的大型Hugging Face模型(./ltx-2-19b-dev.safetensors,.safetensors格式),但在from_pretrained() 调用时内核会立即崩溃,且没有任何Python回溯信息。
当我运行这段代码时:
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id = "./ltx-2-19b-dev.safetensors"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id)
内核会立即重新启动,我得到一个弹窗,大致内容如下:
Untitled.ipynb的内核似乎已终止。它将自动重启。
笔记本中没有显示Python回溯 —— 它只是崩溃。
为什么 AutoModelForCausalLM.from_pretrained() 会在没有回溯的情况下让内核崩溃?
解决方案
当JupyterLab的内核崩溃时,你不会从Python那里看到错误堆栈,因为它在给出堆栈之前就被终止了。这通常发生在内存占用过高,操作系统杀死了相应进程的情形。
但除了内存不足之外,你的代码还有一个更根本的缺陷。你把safetensors文件的路径直接传给 from_pretrained(tokenizer文档 与 model文档)。这个方法要么接收来自Hugging Face hub的模型标识符(ID),要么接收一个指向本地包含模型的目录的路径。它并不接受safetensors文件作为参数!
我刚用一个更小的模型测试了你的代码,并添加了一些跟踪:
from huggingface_hub import snapshot_download
from transformers import AutoModelForCausalLM, AutoTokenizer
import tracemalloc
local_path = snapshot_download(
repo_id="Qwen/Qwen3.5-0.8B",
repo_type="model",
local_dir="./local_model",
local_dir_use_symlinks=False,
resume_download=True,
max_workers=8
)
print(f"Model downloaded to: {local_path}")
safe_tensors_path= local_path + "/model.safetensors-00001-of-00001.safetensors"
print(f"Respective safe tensors path: {safe_tensors_path}")
def track_memory(func, *args, **kwargs):
tracemalloc.start()
try:
func(*args, **kwargs)
except Exception as e:
print(f"Exception occurred: {e}")
finally:
current, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
print(f"Current memory: {current / 1024:.2f} KB")
print(f"Peak memory: {peak / 1024:.2f} KB")
def load():
tokenizer = AutoTokenizer.from_pretrained(safe_tensors_path)
model = AutoModelForCausalLM.from_pretrained(safe_tensors_path)
track_memory(load)
输出:
Model downloaded to: /content/local_model
Respective safe tensors path: /content/local_model/model.safetensors-00001-of-00001.safetensors
Exception occurred: It looks like the config file at '/content/local_model/model.safetensors-00001-of-00001.safetensors' is not a valid JSON file.
Current memory: 2.40 KB
Peak memory: 8530003.50 KB
加载一个在磁盘上大小为1.7 GB的 safetensors文件需要8.5 GB的内存。查看这个较小模型的堆栈跟踪时,你会发现你加载模型的方式是错误的,因为它把文件当成了JSON来读取。
假设你要加载这个模型 Lightricks/LTX-2,你会发现它是一个 diffuser 模型,应该使用相应的库来加载,而不是用transformers。你可以使用diffusers加载(下面给出代码片段),也可以使用原作者的代码(原作者的仓库Git链接)。
推理代码只是从Hugging Face的仓库README拷贝过来:
import torch
from diffusers import FlowMatchEulerDiscreteScheduler
from diffusers.pipelines.ltx2 import LTX2Pipeline, LTX2LatentUpsamplePipeline
from diffusers.pipelines.ltx2.latent_upsampler import LTX2LatentUpsamplerModel
from diffusers.pipelines.ltx2.utils import STAGE_2_DISTILLED_SIGMA_VALUES
from diffusers.pipelines.ltx2.export_utils import encode_video
device = "cuda:0"
width = 768
height = 512
pipe = LTX2Pipeline.from_pretrained(
"Lightricks/LTX-2", torch_dtype=torch.bfloat16
)
pipe.enable_sequential_cpu_offload(device=device)
prompt = "A beautiful sunset over the ocean"
negative_prompt = "shaky, glitchy, low quality, worst quality, deformed, distorted, disfigured, motion smear, motion artifacts, fused fingers, bad anatomy, weird hand, ugly, transition, static."
# Stage 1 default (non-distilled) inference
frame_rate = 24.0
video_latent, audio_latent = pipe(
prompt=prompt,
negative_prompt=negative_prompt,
width=width,
height=height,
num_frames=121,
frame_rate=frame_rate,
num_inference_steps=40,
sigmas=None,
guidance_scale=4.0,
output_type="latent",
return_dict=False,
)
latent_upsampler = LTX2LatentUpsamplerModel.from_pretrained(
"Lightricks/LTX-2",
subfolder="latent_upsampler",
torch_dtype=torch.bfloat16,
)
upsample_pipe = LTX2LatentUpsamplePipeline(vae=pipe.vae, latent_upsampler=latent_upsampler)
upsample_pipe.enable_model_cpu_offload(device=device)
upscaled_video_latent = upsample_pipe(
latents=video_latent,
output_type="latent",
return_dict=False,
)[0]
# Load Stage 2 distilled LoRA
pipe.load_lora_weights(
"Lightricks/LTX-2", adapter_name="stage_2_distilled", weight_name="ltx-2-19b-distilled-lora-384.safetensors"
)
pipe.set_adapters("stage_2_distilled", 1.0)
# VAE tiling is usually necessary to avoid OOM error when VAE decoding
pipe.vae.enable_tiling()
# Change scheduler to use Stage 2 distilled sigmas as is
new_scheduler = FlowMatchEulerDiscreteScheduler.from_config(
pipe.scheduler.config, use_dynamic_shifting=False, shift_terminal=None
)
pipe.scheduler = new_scheduler
# Stage 2 inference with distilled LoRA and sigmas
video, audio = pipe(
latents=upscaled_video_latent,
audio_latents=audio_latent,
prompt=prompt,
negative_prompt=negative_prompt,
num_inference_steps=3,
noise_scale=STAGE_2_DISTILLED_SIGMA_VALUES[0], # renoise with first sigma value https://github.com/Lightricks/LTX-2/blob/main/packages/ltx-pipelines/src/ltx_pipelines/ti2vid_two_stages.py#L218
sigmas=STAGE_2_DISTILLED_SIGMA_VALUES,
guidance_scale=1.0,
output_type="np",
return_dict=False,
)
encode_video(
video[0],
fps=frame_rate,
audio=audio[0].float().cpu(),
audio_sample_rate=pipe.vocoder.config.output_sampling_rate,
output_path="ltx2_lora_distilled_sample.mp4",
)