Jetson Nano部署DeepSeek大模型:ARM边缘计算实战指南
1. 项目概述:为什么要在Jetson Nano上折腾DeepSeek?
最近手头有个闲置的Jetson Nano开发板,看着它4GB的内存和相对羸弱的CPU,总觉得让它跑跑简单的视觉Demo有点大材小用,或者说,没把它的潜力榨干。正好DeepSeek这类开源大模型火得不行,我就琢磨着,能不能把这“老伙计”变成一个本地的、能跑起来的AI对话终端?毕竟,云端API调用有延迟、有费用,还涉及隐私,如果能在本地设备上跑通一个可用的模型,哪怕能力弱一些,对于学习、调试或者一些简单的离线任务,意义还是很大的。
这个项目的核心目标,就是在基于ARM架构的NVIDIA Jetson Nano开发板上,成功部署并运行DeepSeek大语言模型。这里说的“运行”,不是指调用云端API,而是指通过Ollama这类工具,将模型文件拉取到本地,并在Jetson Nano的硬件上完成推理。整个过程会涉及到ARM64环境的适配、CUDA的配置、Ollama的安装与模型拉取,以及最后在终端或通过API进行测试。对于拥有类似边缘计算设备(如树莓派、其他Jetson系列)的开发者来说,这是一次非常典型的“边缘AI”实践,能让你深刻理解从云端模型到边缘部署的全链路挑战和解决方案。
2. 环境准备与深度解析:Jetson Nano的“底子”与挑战
在开始动手之前,我们必须对Jetson Nano的硬件和系统环境有一个清醒的认识。这不是一台x86的PC,它的每一步操作都可能遇到ARM架构带来的“惊喜”。
2.1 硬件与系统基础盘点
我使用的是一台Jetson Nano 4GB开发者套件版。它的核心配置如下:
- CPU : 四核ARM Cortex-A57 @ 1.43 GHz。这个性能大概相当于几年前的中端手机处理器,处理复杂编译任务时会比较慢。
- GPU : 128核NVIDIA Maxwell架构GPU。这是我们的主力,所有AI推理计算都指望它了。虽然架构老,但支持CUDA,这就是价值所在。
- 内存 : 4GB LPDDR4。这是最大的瓶颈!大模型动辄需要数GB甚至数十GB的内存,4GB意味着我们只能运行参数量较小的模型版本(通常是7B参数以下的量化版)。
- 存储 : 我为其配备了一张64GB的microSD卡。系统、软件、模型都放在这里。读写速度会直接影响体验,建议使用Class 10或UHS-I以上规格的卡。
系统方面,我刷写了NVIDIA官方提供的JetPack 4.6.1镜像(具体版本号可能随时间更新,请以官网最新为准)。这个镜像包含了Ubuntu 18.04 LTS、CUDA 10.2、cuDNN 8.x等一整套为Jetson优化的软件栈。 非常重要的一点:请务必使用NVIDIA官方提供的镜像,而不是自己安装Ubuntu再配驱动,那会是一场灾难。 官方镜像已经做好了内核、驱动、CUDA的深度集成。
开机后,第一件事是检查基础环境:
# 查看系统版本和内核
cat /etc/os-release
uname -a
# 查看CUDA和GPU信息
nvcc --version # 如果提示命令未找到,可能需要将/usr/local/cuda/bin加入PATH
nvidia-smi
nvidia-smi
这个命令很关键,它能告诉你GPU是否被正确识别、驱动是否加载、以及当前GPU的内存使用情况。在Jetson Nano上,它的输出可能不像服务器显卡那样信息丰富,但只要能显示GPU型号和少量内存信息,就说明基础环境是OK的。
2.2 依赖安装与系统优化
Jetson Nano的默认镜像为了节省空间,很多开发工具没有预装。我们需要先补全一些基础依赖。
# 更新软件源并升级现有包
sudo apt-get update
sudo apt-get upgrade -y
# 安装编译、下载等基础工具
sudo apt-get install -y \
curl \
wget \
git \
build-essential \
libssl-dev \
zlib1g-dev \
libbz2-dev \
libreadline-dev \
libsqlite3-dev \
llvm \
libncurses5-dev \
libncursesw5-dev \
xz-utils \
tk-dev \
libffi-dev \
liblzma-dev \
python3-openssl
接下来是Python环境。系统自带了Python 3.6,但有些新工具可能要求更高版本。我选择使用
pyenv
来管理多版本Python,这样更灵活,也不会破坏系统自带的Python。
# 安装pyenv
curl https://pyenv.run | bash
# 将pyenv初始化脚本添加到shell配置文件中(如 ~/.bashrc)
echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc
source ~/.bashrc
# 安装一个较新的Python版本,例如Python 3.10.13
# 注意:在Jetson Nano上编译Python非常耗时,可能需要1-2小时
pyenv install 3.10.13
# 设置为全局默认版本
pyenv global 3.10.13
# 验证
python --version
pip --version
注意 :在ARM设备上从源码编译Python是一个极其漫长的过程,期间CPU会满载,开发板可能会比较热。请确保供电充足(最好使用桶形电源而非Micro USB供电),并耐心等待。如果中途失败,多半是内存不足,可以尝试增加swap空间。
系统优化项 :
-
交换空间(Swap)
:4GB内存跑大模型很容易爆掉。增加Swap空间相当于用存储空间模拟内存,能防止进程因内存不足(OOM)被系统杀死。但SD卡速度慢,Swap用多了会卡顿,这是权衡。
# 创建一个8GB的交换文件 sudo fallocate -l 8G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile # 为了开机自动挂载,将下面一行添加到 /etc/fstab # /swapfile none swap sw 0 0 -
电源模式
:Jetson Nano有两种电源模式:5W和10W(Max-N)。10W模式能解锁CPU和GPU的更高频率,性能更好,但需要足够的散热。如果你使用了风扇散热片,建议设置为10W模式。
sudo nvpmodel -m 0 # 0代表10W模式(Max-N),1代表5W模式 sudo jetson_clocks # 启用风扇并设置静态时钟(性能模式)
3. Ollama的安装与配置:在ARM64上的特别之旅
Ollama是目前在本地运行大模型非常流行的工具,它简化了模型下载、加载和提供API的整个过程。但官方安装脚本主要针对x86_64架构,我们需要为ARM64(特别是Jetson的aarch64)进行手动安装。
3.1 手动安装Ollama
Ollama本身是一个Go语言编写的二进制文件,我们需要下载适用于ARM64的版本。
# 前往Ollama的GitHub发布页,找到最新的Linux ARM64版本下载链接
# 例如(链接可能过期,请检查最新版本):
curl -L -o ollama-linux-arm64 https://github.com/ollama/ollama/releases/download/v0.1.40/ollama-linux-arm64
# 赋予执行权限并移动到系统路径
chmod +x ollama-linux-arm64
sudo mv ollama-linux-arm64 /usr/local/bin/ollama
# 验证安装
ollama --version
如果
/usr/local/bin
不在你的PATH中,可以将其加入,或者直接使用绝对路径
/usr/local/bin/ollama
。
3.2 配置Ollama服务与国内镜像
为了让Ollama在后台持续运行并提供服务,我们将其设置为系统服务。
# 创建Ollama服务用户(可选,但推荐)
sudo useradd -r -s /bin/false -m -d /usr/share/ollama ollama
# 创建服务文件
sudo tee /etc/systemd/system/ollama.service << EOF
[Unit]
Description=Ollama Service
After=network-online.target
[Service]
Type=exec
User=ollama
Group=ollama
ExecStart=/usr/local/bin/ollama serve
Restart=always
RestartSec=3
Environment="PATH=/usr/local/bin:/usr/bin:/bin"
Environment="OLLAMA_HOST=0.0.0.0" # 允许非本地连接,方便其他设备访问
Environment="OLLAMA_ORIGINS=*" # 允许所有来源的CORS请求(开发环境,生产需限制)
# 可选:如果你配置了国内镜像源,可以在这里设置
# Environment="OLLAMA_MODELS=/path/to/your/local/models" # 自定义模型存储路径
[Install]
WantedBy=default.target
EOF
# 重新加载systemd配置
sudo systemctl daemon-reload
# 启用服务开机自启
sudo systemctl enable ollama
# 启动服务
sudo systemctl start ollama
# 查看服务状态
sudo systemctl status ollama
如果状态显示为
active (running)
,说明服务启动成功。默认情况下,Ollama的API服务会运行在
11434
端口。
关于模型下载 :直接从Ollama官方拉取模型对于国内用户可能非常慢甚至不可行。这里有两个解决方案:
-
使用国内镜像源(推荐) :一些社区维护了Ollama模型的镜像。你可以在运行
ollama pull命令前,通过环境变量或修改配置来指定镜像站。例如(镜像站地址需自行寻找可用的):export OLLAMA_MODEL_SOURCE="https://mirror.example.com/ollama" ollama pull deepseek-coder:6.7b请注意,镜像站的可用性和完整性需要自行甄别。
-
手动导入模型文件 :先从其他网络环境好的机器下载模型文件(通常是
Modelfile和多个二进制分片),然后传输到Jetson Nano上,使用ollama create和ollama run来手动创建模型。具体步骤可以参考Ollama官方文档关于“从GGUF文件创建”的部分。这需要你对模型文件格式有一定了解。
实操心得 :在Jetson Nano上,我强烈建议先在其他电脑(比如x86的笔记本)上,用Ollama把需要的模型
pull下来。模型文件通常存储在~/.ollama/models目录下。然后将这个目录整个打包,通过SCP或者U盘拷贝到Jetson Nano的对应位置(注意用户权限,如果是ollama用户运行服务,则需要将文件放在/usr/share/ollama/.ollama/models或类似路径,并修改所有者)。这能节省大量时间和避免网络问题。
4. 拉取与运行DeepSeek模型:选择与适配的博弈
Ollama支持很多模型,但并非所有模型都适合Jetson Nano。我们需要考虑两个关键约束: 内存 和 架构 。
4.1 模型选择:量化版本是唯一出路
原始的DeepSeek Coder 6.7B或DeepSeek-V2等模型,仅FP16精度就需要超过13GB的GPU内存,这远远超出了Jetson Nano的4GB物理内存+8GB Swap的能力。因此,我们必须使用 量化模型 。
量化是一种模型压缩技术,通过降低模型权重(参数)的数值精度(例如从FP16降到INT4、INT8)来大幅减少模型大小和内存占用,同时尽可能保持模型性能。常见的量化格式有GGUF(llama.cpp社区推动)、GPTQ、AWQ等。Ollama主要支持GGUF格式。
对于Jetson Nano 4GB,我的经验是:
-
7B参数模型
:可以尝试
q4_0或q4_K_M等4位量化版本。加载后,GPU内存占用大约在3-4GB,会非常紧张,推理速度慢,且极易触发Swap导致卡顿。 -
更小的模型(如1B-3B)
:是更实际的选择。例如
deepseek-coder:1.3b、phi系列、tinyllama等。它们能在有限内存下提供更流畅的交互体验。
假设我们决定尝试
deepseek-coder:6.7b
的量化版。首先需要查看Ollama支持的该模型的标签(tag)。
# 搜索deepseek相关模型(需要网络)
ollama list | grep deepseek
# 或者去Ollama官网查看模型库:https://ollama.com/library
# 假设我们找到了一个合适的标签,例如 `deepseek-coder:6.7b-q4_0`
# 拉取模型(这将开始下载,耗时很长)
ollama pull deepseek-coder:6.7b-q4_0
重要提示
:在Jetson Nano上直接执行
ollama pull
很可能因为网络或内存问题失败。如前所述,
强烈建议在其它机器上拉取后拷贝过来
。
4.2 手动处理模型文件(备用方案)
如果Ollama官方库没有你想要的特定量化版本,或者你想使用自己转换的GGUF模型,可以手动操作。
-
获取GGUF模型文件
:从Hugging Face等社区平台下载对应模型的GGUF格式文件(例如
deepseek-coder-6.7b-instruct.Q4_K_M.gguf)。 -
创建Modelfile
:这是一个告诉Ollama如何加载模型的配置文件。
将上述内容保存为# Modelfile 示例 FROM /绝对/路径/到/你的/deepseek-coder-6.7b-instruct.Q4_K_M.gguf # 设置一些参数 PARAMETER temperature 0.7 PARAMETER top_p 0.9 PARAMETER num_ctx 2048 # 上下文长度,根据模型能力和内存调整,越小越省内存Modelfile文件。 -
创建并运行模型
:
# 在Modelfile所在目录执行 ollama create my-deepseek -f ./Modelfile # 运行模型 ollama run my-deepseek
4.3 首次运行与性能观察
当你第一次执行
ollama run
时,Ollama会加载模型到内存。这是最紧张的时刻。
# 在终端中交互式运行
ollama run deepseek-coder:6.7b-q4_0
# 或者运行你自定义的模型
# ollama run my-deepseek
观察终端输出。你会看到加载进度条。同时,打开另一个终端,运行以下命令监控系统资源:
# 监控GPU使用情况
watch -n 1 nvidia-smi
# 监控内存和Swap使用情况
watch -n 1 free -h
# 监控整体系统负载
htop
如果模型成功加载并出现了提示符(例如
>>>
),恭喜你,最艰难的一步已经完成!你可以尝试输入一些简单的编程问题或对话。
性能预期管理 :在Jetson Nano上运行6.7B的4位量化模型,生成速度可能只有1-3个token/秒。对于简单的代码补全或问答尚可接受,但进行长文本对话会非常需要耐心。更小的模型(如1.3B)速度会快很多,可能达到10-20 token/秒。
5. 高级配置与优化:榨干每一分性能
基础运行只是第一步,要让体验更好,还需要一些优化。
5.1 调整Ollama运行参数
通过环境变量或在
ollama run
时传递参数,可以调整模型运行方式,以更好地适应Jetson Nano。
-
限制运行线程 :默认Ollama可能会使用所有CPU核心,在ARM上有时反而会因调度开销降低效率。可以尝试限制使用的CPU核心数。
# 通过numa控制,但Jetson Nano是单节点,更简单的方法是使用taskset # 首先,找到ollama serve进程的PID ps aux | grep ollama # 然后,用taskset绑定到特定CPU核心(例如核心0和1) sudo taskset -cp 0,1 <PID>更一劳永逸的方法是在systemd服务文件
[Service]部分添加:Environment="OMP_NUM_THREADS=2" # 限制OpenMP线程数 TasksMax=50% # 限制CPU使用率(systemd特性) -
调整模型加载参数 :在
Modelfile或运行命令中,可以调整关键参数来平衡速度和内存。ollama run deepseek-coder:6.7b-q4_0 --num_ctx 1024 --num_batch 256 --num_gpu_layers 20-
--num_ctx 1024:将上下文长度从默认的2048减半,显著减少内存占用。 -
--num_batch 256:处理提示时的批次大小,影响内存和速度。 -
--num_gpu_layers 20:指定将模型的前20层放在GPU上运行,其余在CPU。这个数字需要反复试验,放太多GPU内存不够,放太少GPU加速效果差。对于6.7B模型,在4GB Jetson上,10-30层是一个可以尝试的范围。
-
5.2 使用API接口与外部工具集成
Ollama默认在
http://127.0.0.1:11434
提供与OpenAI兼容的API。这意味着你可以用任何支持OpenAI API的客户端来连接它。
使用curl测试API :
curl http://127.0.0.1:11434/api/generate -d '{
"model": "deepseek-coder:6.7b-q4_0",
"prompt": "用Python写一个快速排序函数",
"stream": false
}'
配置VS Code或Cursor等编辑器 :许多现代代码编辑器支持配置本地大模型作为补全或聊天助手。
-
在VS Code中安装
Continue或CodeGPT等插件。 -
在插件设置中,将API Base URL设置为
http://localhost:11434/v1(注意/v1后缀)。 - API Key可以留空或随意填写。
-
模型名称填写你在Ollama中拉取的模型名,如
deepseek-coder:6.7b-q4_0。
这样,你就可以在熟悉的编辑器环境中,获得由本地Jetson Nano提供的代码补全和建议了,虽然速度不快,但隐私性极佳。
5.3 编写自动化脚本与管理多个模型
当你有多个模型或需要定期执行某些任务时,脚本非常有用。
一个简单的对话脚本
(
chat_with_deepseek.py
):
import requests
import json
def ask_ollama(prompt, model="deepseek-coder:6.7b-q4_0", host="localhost", port=11434):
url = f"http://{host}:{port}/api/generate"
payload = {
"model": model,
"prompt": prompt,
"stream": False,
"options": {
"num_ctx": 1024,
"temperature": 0.7
}
}
try:
response = requests.post(url, json=payload, timeout=300) # 设置长超时
response.raise_for_status()
return response.json()["response"]
except requests.exceptions.RequestException as e:
return f"Error: {e}"
if __name__ == "__main__":
while True:
user_input = input("\nYou: ")
if user_input.lower() in ['exit', 'quit']:
break
print("\nDeepSeek: ", end='', flush=True)
answer = ask_ollama(user_input)
print(answer)
模型管理脚本 :用于切换不同任务所需的模型。
#!/bin/bash
# switch_model.sh
MODEL_NAME=$1
# 停止当前可能运行的ollama服务(粗暴但有效)
sudo systemctl stop ollama
# 等待进程完全结束
sleep 3
# 这里可以做一些清理工作,比如清空GPU内存(如果有其他进程占用)
# 实际上ollama停止后,GPU内存会被释放
# 启动服务并运行指定模型
sudo systemctl start ollama
sleep 5 # 等待服务启动
ollama run $MODEL_NAME
6. 常见问题与排查实录:我踩过的那些坑
在这一路上,我遇到了不少问题,这里把典型的几个和解决方法记录下来,希望能帮你节省时间。
6.1 内存不足(OOM)问题
症状
:运行
ollama run
时,进程被杀死,终端显示
Killed
,或者系统变得极其卡顿,然后Ollama服务崩溃。
dmesg
日志中能看到
Out of memory
相关记录。
排查与解决 :
- 确认模型大小 :首先确保你拉的模型是量化版(q4, q5, q8等),并且参数规模(如6.7B)对于4GB内存来说已经是极限。优先尝试更小的模型(如1.3B, 3B)。
- 增加Swap空间 :如前所述,将Swap扩大到8GB甚至16GB(如果SD卡空间足够)。这不能提升速度,但能防止进程被直接杀死。
-
调整模型参数
:这是最有效的手段。在运行或创建模型时,强制减少上下文长度
num_ctx(例如从4096降到1024或512)。这能线性减少内存占用。 -
卸载无用进程
:关闭图形界面(如果不需要),进入纯命令行模式,可以节省不少内存。使用
sudo systemctl set-default multi-user.target然后重启。 -
监控工具
:养成使用
htop和nvidia-smi的习惯,在运行模型前先看看空闲内存有多少。
6.2 模型加载失败或输出乱码
症状
:模型能拉取,但运行时报错,例如
unexpected tensor type
,或者生成的内容全是乱码、重复字符。
排查与解决 :
-
模型文件损坏
:这是最常见的原因,尤其是在网络不好时拉取的模型。解决方法是用
ollama rm <model-name>删除模型,然后重新拉取(建议在稳定网络环境下进行)。或者使用ollama pull的--insecure参数跳过某些校验(不推荐)。 -
量化格式不兼容
:Ollama的GGUF加载器可能对某些非常新的或特殊的量化格式支持不好。尝试换一个更通用的量化类型,例如从
q4_K_M换成q4_0。 -
Modelfile配置错误
:如果你是自己创建Modelfile,检查
FROM指令指向的GGUF文件路径是否正确,文件是否有读取权限。
6.3 Ollama服务无法启动或端口占用
症状
:执行
sudo systemctl status ollama
显示失败,或者用
curl
测试API连接超时。
排查与解决 :
-
检查端口占用
:
11434端口可能被其他程序占用。使用sudo netstat -tlnp | grep 11434查看。 -
检查服务日志
:使用
sudo journalctl -u ollama -f实时查看服务日志,里面通常有具体的错误信息。 -
权限问题
:如果修改了模型存储路径,或者用不同用户运行过Ollama,可能导致权限混乱。检查
/usr/share/ollama目录及其子目录的所有者和权限,确保运行Ollama服务的用户(如ollama)有读写权限。 -
二进制文件兼容性
:确保下载的Ollama二进制文件是ARM64版本,而不是x86_64版本。可以用
file /usr/local/bin/ollama命令检查。
6.4 推理速度极慢
症状 :模型能运行,但生成每个词都要等好几秒甚至十几秒。
排查与解决 :
-
检查是否在用GPU
:这是最关键的一点。运行模型时,观察
nvidia-smi,看GPU利用率(Volatile GPU-Util)是否在波动。如果一直是0%,说明模型完全运行在CPU上,速度必然极慢。这通常是因为num_gpu_layers参数设置为0,或者模型不支持GPU卸载。确保在运行命令或Modelfile中设置了合适的num_gpu_layers(一个大于0的值)。 -
Swap频繁使用
:如果
free -h显示Swap使用量(used)很高,且si/so(swap in/out)数值持续不为0,说明内存严重不足,系统在频繁使用低速的Swap,导致整体卡顿。此时只能换更小的模型或进一步降低num_ctx。 -
电源和散热
:确认Jetson Nano运行在10W模式(
sudo nvpmodel -m 0),并且散热良好。过热会导致CPU/GPU降频,性能下降。可以加装风扇或散热片。 -
使用更高效的量化
:在模型精度可接受的范围内,使用更激进的量化。例如,从
q8_0换到q4_0,模型体积和计算量都会减小。
6.5 网络问题与镜像源配置
症状
:
ollama pull
速度极慢,或者根本连不上。
排查与解决 :
- 使用国内镜像 :这是最有效的解决方案。积极搜索可用的Ollama国内镜像站,并通过环境变量配置。
-
手动下载再导入
:如前面反复强调的,在PC端下载好模型文件(GGUF),然后通过SCP、U盘等方式拷贝到Jetson Nano。在Jetson上使用
ollama create从本地文件创建模型。这是绕过网络问题最彻底的方法。 - 代理配置(需合规) :如果你有合规的网络访问方式,可以在系统或Ollama服务级别配置。但请注意,配置代理本身需要谨慎处理,确保符合所有相关规定。
整个项目折腾下来,最大的体会就是“妥协的艺术”。在Jetson Nano这样的资源受限边缘设备上部署大模型,你必须在模型能力、响应速度、内存占用和功耗之间反复权衡。没有完美的方案,只有最适合你当前场景的选择。对于教育演示、离线轻量问答、特定领域的代码补全,这个方案是可行且有趣的。但对于需要高响应、长上下文的生产环境,它显然力不从心。不过,这个过程本身带来的对模型部署、硬件性能、量化技术以及Linux系统调优的理解,是任何理论教程都无法替代的。最后一个小技巧,给你的Jetson Nano配一个主动散热风扇和一个可靠的5V 4A电源,它能让你在调试的路上走得更稳当。
更多推荐
所有评论(0)