1. 项目概述:当小型语言模型遇上边缘AI
最近在折腾边缘计算设备,特别是NVIDIA Jetson系列,总想着怎么把AI能力真正“下沉”到设备端,摆脱对云服务的依赖。正好,微软发布了Phi-3系列小型语言模型,主打一个“小身材,大智慧”,参数规模从38亿到140亿不等,但性能却直逼一些大模型。一个念头就冒出来了:能不能把这俩结合一下,在Jetson上跑一个完全本地的、能对话的AI助手?这不仅仅是技术上的“炫技”,其背后的实用场景非常清晰——想象一下,一个离线可用的智能客服机器人部署在零售店的Jetson设备上,或者一个隐私安全的个人知识库助手运行在家用服务器上,甚至是一个嵌入到机器人里、能理解自然语言指令的“大脑”。这个项目,就是要把这个想法落地。
简单来说,我们的目标是在NVIDIA Jetson平台(如Jetson Orin Nano/NX/AGX)上,部署微软Phi-3模型,并构建一个具有对话交互能力的Chatbot应用。整个过程将完全在本地完成,无需联网调用任何API,充分释放边缘设备的AI潜能。无论你是嵌入式开发者、AI应用爱好者,还是对隐私敏感、希望拥有完全可控AI助手的用户,这个实践都能给你提供一条清晰的路径。接下来,我会详细拆解从环境准备、模型转换、服务部署到应用集成的每一步,并分享我在这个过程中踩过的坑和总结的经验。
2. 核心思路与方案选型
在Jetson上跑LLM,听起来很酷,但绝不是把模型文件拖进去就能跑起来的。我们需要一个端到端的方案,来应对计算资源有限、软件生态特殊等挑战。我的核心思路可以概括为:“轻量模型 + 高效推理引擎 + 简洁应用层”。
2.1 为什么是Phi-3?
市面上小型语言模型不少,比如Llama 2/3的7B版本、Gemma 2B/7B等。选择Phi-3,主要是基于以下几点考量:
- 性能与尺寸的绝佳平衡:Phi-3-mini(3.8B参数)在多项基准测试中的表现,堪比甚至超越了一些70亿参数的模型。对于Jetson Orin Nano(8GB/16GB)这类设备,3.8B模型是能在可用内存内流畅运行的上限,而Phi-3-small(7B)和Phi-3-medium(14B)则为更高端的Jetson Orin NX/AGX提供了选择。
- 对Transformer架构的优化:Phi-3采用了更高效的注意力机制和模型结构设计,减少了推理时的计算量和内存占用。这对于算力宝贵的边缘设备至关重要。
- 开放的模型权重与许可:模型在Hugging Face上开源,采用MIT许可证,商业使用友好,没有额外的法律风险。
- 与ONNX Runtime的深度集成:微软官方提供了Phi-3的ONNX格式模型,并能通过ONNX Runtime进行高效推理。ONNX Runtime对NVIDIA GPU(包括Jetson的CUDA)有很好的支持,且内存管理更为高效。
2.2 为什么是NVIDIA Jetson?
Jetson系列是NVIDIA为边缘AI和机器人打造的模块化系统(SoM)。其核心优势在于:
- 集成GPU:拥有与桌面级GPU同源的NVIDIA GPU核心(基于Ampere或更新的架构),支持CUDA、TensorRT,专为并行计算和AI推理优化。
- 完整的AI软件栈:预装或可轻松安装JetPack SDK,包含CUDA、cuDNN、TensorRT等核心库,为模型部署提供了“开箱即用”的环境。
- 低功耗与小型化:适合嵌入到各种终端设备中,实现真正的边缘智能。
2.3 技术栈选型详解
基于以上分析,我确定了以下技术栈:
- 模型格式:ONNX。这是关键一步。原始的PyTorch模型(
.pth)在Jetson上直接加载和推理效率不高,且内存占用大。转换为ONNX格式后,可以利用ONNX Runtime进行静态图优化和算子融合,显著提升推理速度并降低内存峰值。微软官方提供了Phi-3的ONNX版本,省去了我们自己转换的麻烦,但我们需要知道如何正确加载和使用它。 - 推理引擎:ONNX Runtime with CUDA Execution Provider。这是微软推出的高性能推理引擎,对ONNX模型支持最好。我们将其编译或安装为支持Jetson GPU(CUDA)的版本,让模型计算完全跑在Jetson的GPU上。
- 应用框架:FastAPI + 自定义会话管理。为了提供一个可交互的Chatbot接口,我选择用FastAPI构建一个轻量级的Web后端。它异步性能好,代码简洁。前端可以是一个简单的HTML页面,或者通过API被其他应用调用。会话管理(记录对话历史、处理上下文)需要我们自己实现。
- 辅助工具:Hugging Face Transformers (Tokenizer)。虽然模型推理用ONNX Runtime,但文本的Token化(将文字转换为模型能理解的数字ID)和解码(将模型输出的ID转换回文字),我们仍然使用Hugging Face的
transformers库中的Tokenizer,因为它与Phi-3模型完全兼容且使用方便。
注意:有人可能会想到用TensorRT进一步加速。理论上,将ONNX模型用TensorRT转换并推理,速度会更快。但这个过程(尤其是对于LLM)比较复杂,涉及动态形状支持、插件编写等,且Phi-3的官方ONNX模型可能包含一些需要特殊处理的算子。为了优先保证项目的可复现性和稳定性,本项目第一阶段采用ONNX Runtime。在后续优化部分,我会探讨TensorRT的可能性。
3. 环境准备与依赖安装
工欲善其事,必先利其器。在Jetson上搭建Python AI环境,有一些特定的坑点需要避开。
3.1 Jetson系统基础设置
假设你已经在Jetson设备上刷好了最新的JetPack SDK(例如JetPack 5.1.2或6.0)。首先进行一些基础优化:
# 1. 更新系统包 sudo apt update && sudo apt upgrade -y # 2. 增加交换空间(SWAP) - 对于内存较小的Orin Nano(8GB)非常关键! # LLM加载和推理时内存消耗巨大,物理内存不足时会使用交换空间,避免进程被OOM Killer杀死。 sudo fallocate -l 8G /swapfile # 创建一个8GB的交换文件,可根据磁盘空间调整 sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile # 为了永久生效,将下面一行添加到 /etc/fstab # /swapfile none swap sw 0 0 # 3. 安装系统依赖 sudo apt install -y python3-pip python3-dev python3-venv build-essential libopenblas-dev libjpeg-dev zlib1g-dev3.2 创建Python虚拟环境
强烈建议使用虚拟环境,以隔离项目依赖,避免与系统Python包冲突。
python3 -m venv phi3-chatbot-env source phi3-chatbot-env/bin/activate3.3 安装PyTorch和TorchVision
这是最易出错的一步。绝对不能直接用pip install torch,这会安装x86_64架构的版本。必须安装NVIDIA为Jetson预编译的版本。访问 NVIDIA官方论坛 找到对应你JetPack版本和Python版本的PyTorch wheel文件链接。
例如,对于JetPack 5.1.2 (Python 3.8):
# 示例链接,请务必替换为对应你系统的最新链接 wget https://developer.download.nvidia.com/compute/redist/jp/v512/pytorch/torch-2.1.0a0+41361538.nv23.06-cp38-cp38-linux_aarch64.whl pip install torch-2.1.0a0+41361538.nv23.06-cp38-cp38-linux_aarch64.whl # 安装对应的torchvision sudo apt install -y libjpeg-dev zlib1g-dev libpython3-dev libavcodec-dev libavformat-dev libswscale-dev git clone --branch v0.16.0 https://github.com/pytorch/vision torchvision # 使用与PyTorch匹配的版本 cd torchvision pip install .安装完成后,验证CUDA是否可用:
import torch print(torch.__version__) print(torch.cuda.is_available()) # 应该输出 True print(torch.cuda.get_device_name(0)) # 应该显示你的Jetson GPU型号,如 “Orin”3.4 安装ONNX Runtime for Jetson
同样,需要安装ARM64架构的、支持CUDA的版本。从ONNX Runtime的GitHub Release页面找到适用于Jetson的版本。
# 示例,安装适用于JetPack 5.1.2 (Python 3.8)的 onnxruntime-gpu pip install onnxruntime-gpu==1.16.3验证安装:
import onnxruntime as ort print(ort.get_device()) # 应该能识别出GPU设备3.5 安装其他Python依赖
pip install fastapi uvicorn transformers sentencepiece protobuf pydantic # transformers: 用于加载tokenizer # sentencepiece: Phi-3 tokenizer所需的依赖 # fastapi & uvicorn: Web服务框架 # pydantic: 数据验证4. 模型获取与加载优化
环境就绪后,核心就是处理模型本身。
4.1 下载Phi-3 ONNX模型
微软官方将Phi-3的ONNX模型发布在Hugging Face Hub上。我们可以使用transformers库的AutoModel类,并指定export=True参数来下载和导出,但更直接的方式是找到已经导出的ONNX模型文件。
以microsoft/Phi-3-mini-4k-instruct为例,其ONNX模型通常可以在Hugging Face模型页面的“Files and versions”中找到,或者由社区用户上传。一个可靠的选择是使用optimum库(由Hugging Face出品,用于模型优化和导出)来导出。
首先安装optimum和onnxruntime-tools:
pip install optimum[onnxruntime] onnxruntime-tools然后,使用以下Python脚本导出模型(在性能更强的机器上运行,如你的开发PC):
from optimum.onnxruntime import ORTModelForCausalLM from transformers import AutoTokenizer model_id = "microsoft/Phi-3-mini-4k-instruct" onnx_path = "./phi3-mini-onnx" # 导出模型到ONNX格式 model = ORTModelForCausalLM.from_pretrained(model_id, export=True) model.save_pretrained(onnx_path) # 保存tokenizer tokenizer = AutoTokenizer.from_pretrained(model_id) tokenizer.save_pretrained(onnx_path) print(f"Model and tokenizer saved to {onnx_path}")将导出的onnx_path文件夹(包含.onnx模型文件和tokenizer配置)整个复制到你的Jetson设备上。
实操心得:直接在Jetson上执行导出可能会因内存不足而失败。建议在拥有足够内存和显存的x86机器上完成导出,再传输到Jetson。导出的ONNX模型是静态图,已经过优化,在Jetson上加载速度更快。
4.2 在Jetson上加载ONNX模型
在Jetson上,我们不再需要optimum,只需要onnxruntime-gpu和transformers(用于tokenizer)。
import onnxruntime as ort from transformers import AutoTokenizer import numpy as np class Phi3OnnxModel: def __init__(self, model_path): self.model_path = model_path # 1. 创建ONNX Runtime会话,指定CUDA执行提供者 providers = [ ('CUDAExecutionProvider', { 'device_id': 0, 'arena_extend_strategy': 'kNextPowerOfTwo', 'gpu_mem_limit': 4 * 1024 * 1024 * 1024, # 限制GPU内存使用为4GB,根据你的设备调整 'cudnn_conv_algo_search': 'EXHAUSTIVE', 'do_copy_in_default_stream': True, }), 'CPUExecutionProvider' # 备用CPU ] sess_options = ort.SessionOptions() sess_options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL # 对于多线程,可以尝试设置 intra_op_num_threads 和 inter_op_num_threads # sess_options.intra_op_num_threads = 4 print(f"Loading ONNX model from {model_path}...") self.session = ort.InferenceSession(model_path, sess_options=sess_options, providers=providers) print("Model loaded.") # 2. 加载对应的tokenizer self.tokenizer = AutoTokenizer.from_pretrained(model_path) # Phi-3的tokenizer需要添加特殊token if self.tokenizer.pad_token is None: self.tokenizer.pad_token = self.tokenizer.eos_token # 3. 获取模型输入输出名称 self.input_names = [inp.name for inp in self.session.get_inputs()] self.output_names = [out.name for out in self.session.get_outputs()] print(f"Input names: {self.input_names}") print(f"Output names: {self.output_names}")关键参数解析:
CUDAExecutionProvider: 告诉ONNX Runtime使用GPU。gpu_mem_limit:非常重要。Jetson内存共享,必须显式限制GPU内存使用量,为系统和其它进程留出空间,否则极易导致内存溢出而崩溃。4GB对于Phi-3-mini是一个相对安全的起点,你可以根据设备总内存调整。arena_extend_strategy: 内存分配策略,kNextPowerOfTwo有助于减少内存碎片。GraphOptimizationLevel.ORT_ENABLE_ALL: 启用所有图优化,提升性能。
4.3 实现文本生成逻辑
ONNX模型的前向传播是静态的,我们需要自己实现文本生成的循环(自回归生成)。
def generate(self, prompt, max_length=200, temperature=0.7, top_p=0.9): """ 生成文本的核心函数。 prompt: 输入提示词 max_length: 生成的最大token数 temperature: 温度参数,控制随机性 (越高越随机) top_p: 核采样参数,控制候选词集合 """ # Tokenize输入,并转换为numpy数组(ONNX Runtime的输入要求) inputs = self.tokenizer(prompt, return_tensors="np", padding=True, truncation=True) input_ids = inputs['input_ids'] attention_mask = inputs['attention_mask'] # 初始化生成的序列 generated_ids = input_ids for step in range(max_length): # 准备当前步的输入 # ONNX模型通常需要 past_key_values 来处理长序列,但Phi-3的ONNX导出可能是无状态的。 # 这里假设是一个简单的逐token生成。更复杂的实现需要处理past_key_values。 # 实际中,需要根据模型具体的输入输出来调整。 ort_inputs = { self.input_names[0]: generated_ids, # 通常是 input_ids self.input_names[1]: attention_mask, # 通常是 attention_mask } # 运行推理 ort_outputs = self.session.run(self.output_names, ort_inputs) # ort_outputs[0] 通常是 logits,形状为 (batch_size, seq_len, vocab_size) next_token_logits = ort_outputs[0][0, -1, :] # 取最后一个位置的logits # 应用温度调节和top-p采样 next_token_logits = next_token_logits / temperature filtered_logits = self._apply_top_p(next_token_logits, top_p) probabilities = np.exp(filtered_logits) / np.sum(np.exp(filtered_logits)) # 采样下一个token next_token_id = np.random.choice(len(probabilities), p=probabilities) # 将新token添加到序列中 new_token_arr = np.array([[next_token_id]], dtype=np.int64) generated_ids = np.concatenate([generated_ids, new_token_arr], axis=1) # 更新attention_mask(新token位置为1) attention_mask = np.concatenate([attention_mask, np.array([[1]], dtype=np.int64)], axis=1) # 如果生成了结束符,则停止 if next_token_id == self.tokenizer.eos_token_id: break # 将生成的token IDs解码为文本 generated_text = self.tokenizer.decode(generated_ids[0], skip_special_tokens=True) return generated_text def _apply_top_p(self, logits, top_p): """实现top-p(核采样)过滤""" sorted_logits = np.sort(logits)[::-1] cumulative_probs = np.cumsum(np.exp(sorted_logits) / np.sum(np.exp(logits))) # 移除累积概率大于top_p的token sorted_indices_to_remove = cumulative_probs > top_p # 保留第一个超过阈值的token,所以将其设为False sorted_indices_to_remove[1:] = sorted_indices_to_remove[:-1].copy() sorted_indices_to_remove[0] = False # 将需要移除的token的logits设为负无穷 indices_to_remove = np.argsort(logits)[::-1][sorted_indices_to_remove] logits[indices_to_remove] = -float('Inf') return logits注意事项:上述生成循环是一个简化版本。实际中,为了高效处理长对话,模型需要支持
past_key_values(KV缓存)来避免重复计算之前token的注意力。微软提供的Phi-3 ONNX模型可能已经将past_key_values作为输入和输出。你需要仔细检查模型的输入输出名称(通过session.get_inputs()),并实现一个支持KV缓存的生成循环,这能极大提升生成速度,尤其是在多轮对话中。这部分的代码会更复杂,需要根据具体的模型导出方式调整。
5. 构建Chatbot Web服务
有了模型生成能力,我们用一个轻量的Web服务把它包装起来,提供API接口。
5.1 使用FastAPI创建后端
# app.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel from typing import List, Optional import uvicorn from phi3_onnx_model import Phi3OnnxModel # 导入我们之前写的类 app = FastAPI(title="Phi-3 Chatbot on Jetson") # 全局加载模型(启动时加载一次) MODEL_PATH = "./phi3-mini-onnx/model.onnx" # 你的ONNX模型路径 chat_model = Phi3OnnxModel(MODEL_PATH) # 定义请求/响应数据结构 class ChatMessage(BaseModel): role: str # "user" or "assistant" content: str class ChatRequest(BaseModel): messages: List[ChatMessage] max_tokens: Optional[int] = 200 temperature: Optional[float] = 0.7 top_p: Optional[float] = 0.9 class ChatResponse(BaseModel): message: ChatMessage finish_reason: str # "stop" or "length" # 简单的对话历史管理(内存中,重启丢失) conversation_histories = {} def build_prompt_from_messages(messages): """将消息列表转换为Phi-3 Instruct模型接受的提示格式""" # Phi-3 Instruct 格式:<|user|>\n{user_message}<|end|>\n<|assistant|>\n formatted_parts = [] for msg in messages: if msg.role == "user": formatted_parts.append(f"<|user|>\n{msg.content}<|end|>\n") elif msg.role == "assistant": formatted_parts.append(f"<|assistant|>\n{msg.content}<|end|>\n") else: formatted_parts.append(f"{msg.content}") # 处理system消息等 # 最后加上助理的开头,引导模型开始生成 formatted_parts.append("<|assistant|>\n") return "".join(formatted_parts) @app.post("/v1/chat/completions") async def create_chat_completion(request: ChatRequest, session_id: Optional[str] = None): try: # 如果有session_id,则获取历史对话,否则从当前请求的消息开始 if session_id and session_id in conversation_histories: all_messages = conversation_histories[session_id] + request.messages else: all_messages = request.messages if not session_id: session_id = "default_session" # 构建完整提示 prompt = build_prompt_from_messages(all_messages) # 调用模型生成 generated_text = chat_model.generate( prompt, max_length=request.max_tokens, temperature=request.temperature, top_p=request.top_p ) # 提取模型本次生成的内容(从最后一个<|assistant|>之后开始) # 这里简化处理,实际可能需要更精细的解析来剥离提示模板 assistant_response = generated_text[len(prompt):].split('<|end|>')[0].strip() # 更新对话历史 new_assistant_msg = ChatMessage(role="assistant", content=assistant_response) all_messages.append(new_assistant_msg) # 限制历史长度,防止内存爆炸(例如只保留最近10轮对话) if len(all_messages) > 20: all_messages = all_messages[-20:] conversation_histories[session_id] = all_messages # 构建响应 return ChatResponse( message=new_assistant_msg, finish_reason="stop" if len(assistant_response) < request.max_tokens else "length" ) except Exception as e: raise HTTPException(status_code=500, detail=f"Generation error: {str(e)}") @app.get("/health") async def health_check(): return {"status": "healthy", "device": "NVIDIA Jetson"} if __name__ == "__main__": # 获取本机IP,方便其他设备访问 import socket hostname = socket.gethostname() local_ip = socket.gethostbyname(hostname) print(f"Starting server. Access at: http://{local_ip}:8000") uvicorn.run(app, host="0.0.0.0", port=8000)5.2 运行与测试服务
在Jetson上运行:
source phi3-chatbot-env/bin/activate python app.py服务启动后,你可以在同一网络下的其他设备(如笔记本电脑、手机)上,通过浏览器或curl进行测试:
# 测试健康检查 curl http://<jetson_ip>:8000/health # 测试聊天接口 curl -X POST http://<jetson_ip>:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "messages": [ {"role": "user", "content": "你好,请介绍一下你自己。"} ], "max_tokens": 100 }'你也可以编写一个简单的HTML前端页面,通过JavaScript调用这个API,实现一个交互式的聊天界面。
6. 性能调优与问题排查实录
在Jetson上部署LLM,性能优化和问题排查是家常便饭。以下是我在实践中总结的关键点和常见问题。
6.1 性能瓶颈分析与优化
- 首次推理速度慢:ONNX Runtime在第一次执行模型时,会对计算图进行优化和内核选择,导致首次推理(
session.run)特别慢。这是正常现象。后续的推理速度会稳定下来。可以考虑在服务启动后,用一个简单的提示词先“预热”一下模型。 - 内存(显存)不足(OOM):这是最常见的问题。
- 症状:程序崩溃,日志中可能有
CUDA out of memory或进程被系统杀死。 - 解决方案:
- 设置
gpu_mem_limit:如前所述,在创建InferenceSession时严格限制GPU内存使用。 - 启用交换空间:确保创建了足够大的交换文件(如8GB-16GB)。
- 降低批处理大小(batch_size):确保你的生成逻辑是批处理大小为1。
- 使用更小的模型:如果Phi-3-mini仍然OOM,可以考虑对模型进行INT8量化(见下文)。
- 监控工具:使用
tegrastats命令实时监控Jetson的内存和GPU使用情况:sudo tegrastats。
- 设置
- 症状:程序崩溃,日志中可能有
- 生成速度慢:
- 原因:自回归生成是串行的,每个token都依赖前一个token的结果。Token/s(每秒生成的token数)是核心指标。
- 优化方向:
- 启用KV缓存:确保你的生成循环正确利用了模型的
past_key_values输入输出,避免重复计算,这是提升速度最有效的方法。 - 调整生成参数:降低
max_length,使用do_sample=False进行贪婪解码(速度最快但结果可能单调)。 - 探索TensorRT:终极优化手段。使用
trtexec工具将ONNX模型转换为TensorRT引擎(.plan文件),并使用TensorRT的Python API进行推理。这通常能带来显著的延迟降低和吞吐量提升,但转换过程复杂,且需要确保模型的所有算子都被TensorRT支持。
- 启用KV缓存:确保你的生成循环正确利用了模型的
6.2 模型量化(INT8)以进一步压缩
如果内存和速度仍然不满足要求,可以对模型进行INT8量化,将权重和激活从FP16转换为INT8,模型体积和内存占用减半,推理速度也能提升。
ONNX Runtime提供了量化工具。基本步骤是:
- 准备一个校准数据集(几百条文本即可)。
- 使用
onnxruntime.quantization.quantize_dynamic进行动态量化(对权重进行量化,对激活进行动态量化),或者使用更复杂的静态量化。 - 加载量化后的
.onnx模型进行推理。
量化会带来轻微的性能损失,但对于边缘设备,这种权衡往往是值得的。Phi-3-mini经过INT8量化后,在Jetson Orin Nano上运行会更加游刃有余。
6.3 常见问题与解决方案速查表
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 导入onnxruntime失败 | 安装了错误的架构版本(x86_64) | 确认安装的是onnxruntime-gpu的ARM64版本。使用`pip list |
CUDA out of memory | GPU内存不足 | 1. 检查并设置gpu_mem_limit。2. 增加交换空间。 3. 使用 tegrastats监控内存使用峰值。4. 考虑量化模型。 |
| 首次生成极慢 | ONNX Runtime首次图优化 | 正常现象。在服务启动后添加一个预热推理步骤。 |
| 生成结果乱码或重复 | Tokenizer不匹配或生成逻辑有误 | 1. 确保使用的tokenizer与模型完全匹配(从同一模型路径加载)。 2. 检查 temperature和top_p参数是否过小导致确定性过高。3. 调试生成循环,确保输入给模型的 input_ids和attention_mask格式正确。 |
| 服务请求无响应 | 请求超时或进程卡死 | 1. 检查Jetson的CPU/内存负载是否过高。 2. 查看服务日志是否有异常。 3. 尝试减少 max_tokens,缩短单次生成长度。 |
| 无法连接到服务 | 防火墙或网络问题 | 1. 确保Jetson的8000端口已开放 (sudo ufw allow 8000)。2. 确认客户端使用的Jetson IP地址正确。 |
6.4 我的实操心得与避坑指南
- 环境隔离是生命线:Jetson的系统Python环境很脆弱,任何
pip install的冲突都可能导致整个环境崩溃。务必使用虚拟环境。 - 内存管理是头等大事:Jetson是统一内存架构,GPU和CPU共享内存。不要只看
nvidia-smi,要用tegrastats看整体内存压力。gpu_mem_limit参数是你的救命稻草。 - 预热是关键:在服务正式处理用户请求前,先让模型跑一两个简单的推理,让ONNX Runtime完成初始化优化,能避免第一个用户等待过久。
- 从最小模型开始:不要一上来就挑战Phi-3-medium。先用Phi-3-mini跑通整个流程,验证性能,再考虑升级。
- 日志要详细:在模型加载、推理开始/结束、内存状态等关键节点打印日志,这样出问题时你能快速定位到阶段。
- 考虑使用Docker:虽然本项目未涉及,但对于生产部署,将整个环境(Python、依赖、模型)打包成Docker镜像,可以保证环境一致性,简化部署。NVIDIA提供了针对Jetson的L4T基础镜像。
这个项目将强大的小型语言模型与专业的边缘AI硬件结合,打开了许多离线、低延迟、高隐私AI应用的大门。虽然过程中需要精细地调整内存、优化推理流程,但看到一段段文本在小小的Jetson设备上流畅生成时,那种成就感是无可替代的。你可以在此基础上,继续探索模型量化、TensorRT加速、或者为你的机器人、智能设备定制专属的对话能力。