GLM-OCR在嵌入式Linux(如Ubuntu)上的轻量级部署方案

📅 发布时间:2026/7/13 0:03:53 👁️ 浏览次数:
GLM-OCR在嵌入式Linux(如Ubuntu)上的轻量级部署方案
GLM-OCR在嵌入式Linux上的轻量级部署方案最近在折腾一个边缘计算项目需要在Jetson Nano这类资源紧张的设备上跑文字识别。市面上的OCR方案要么太重要么精度不够直到我试了GLM-OCR。它本身设计得就比较高效但想在ARM板子上跑起来还是得花点心思优化一下。这篇文章我就把自己在Ubuntu系统上从零开始部署和优化GLM-OCR的整个过程梳理出来。目标很明确让它在Jetson Nano这种内存和算力都有限的嵌入式设备上也能稳定、快速地运行起来。我们会聊到怎么为ARM架构交叉编译那些麻烦的依赖库怎么把模型“瘦身”以减少显存占用以及如何用上TensorRT这类推理加速库来提升速度。如果你手头也有类似的边缘设备想实现离线或者低带宽依赖的文字识别比如智能门禁、车载信息识别、工业质检这些场景那这篇内容应该能帮到你。1. 环境准备与基础概念在开始动手之前我们得先把“战场”打扫干净确保基础环境没问题。同时也得快速了解一下GLM-OCR是个啥以及我们为什么要选它。1.1 目标设备与环境确认我这次用的是一块Jetson Nano Developer Kit它自带了一个基于Ubuntu 18.04的系统。你的设备可能不同但核心步骤是相通的。首先打开终端确认一下系统的基本信息# 查看系统版本 cat /etc/os-release # 查看CPU架构ARM设备通常是aarch64 uname -m # 查看内存和存储空间 free -h df -h对于Jetson Nano官方推荐在刷机后先做一次完整的系统更新和基础包安装sudo apt update sudo apt upgrade -y sudo apt install -y python3-pip python3-dev build-essential cmake git wget关键点嵌入式设备存储空间有限建议在开始前清理不必要的软件包确保有至少2GB的可用空间。1.2 GLM-OCR简介与为何选择它GLM-OCR是一个基于深度学习的开源OCR工具。和那些“大块头”的模型相比它的优势在于平衡了精度和效率。模型结构相对轻量识别中文、英文、数字的混合文本效果不错特别适合部署在资源受限的环境里。为什么是它我对比过几个方案Tesseract在复杂背景下的中文识别有时不太灵光一些基于PaddleOCR的方案虽然强大但默认模型对嵌入式设备来说负担有点重。GLM-OCR就像一个“折中选手”在保证可用精度的前提下给了我们更多优化和裁剪的空间。简单来说我们的目标就是把这个“折中选手”训练得更精干让它能在边缘端灵活跑起来。2. 依赖项的交叉编译与安装在x86电脑上装Python包可能就是一两条命令的事但在ARM架构的嵌入式设备上很多预编译的轮子whl文件是没有的特别是涉及到C扩展的库。这时候“交叉编译”或者直接从源码编译就成了必选项。2.1 Python与基础科学计算栈Jetson Nano的官方系统已经预装了Python3.6。我们的第一步是确保pip可用然后安装一些最基础的包。# 确保pip是最新版本 python3 -m pip install --upgrade pip # 安装NumPy等基础库尽量使用系统源或预编译版本 pip3 install numpy scipy注意在ARM设备上直接用pip install安装numpy有时会触发漫长的源码编译。如果遇到问题可以尝试安装系统仓库提供的版本例如sudo apt install python3-numpy虽然版本可能旧一点但能确保兼容性。2.2 编译安装OpenCVOpenCV是图像处理的基石但它的依赖很多。在Jetson Nano上我们可以利用NVIDIA提供的预编译版本或者自己精简编译。方法一使用JetPack自带的OpenCV最简单# 检查是否已安装 pkg-config --modversion opencv4 # 如果已安装通常会显示版本号如4.1.1如果已经安装这一步就可以跳过。JetPack自带的OpenCV通常已经针对CUDA做了优化。方法二从源码编译精简版OpenCV如果系统没有或者你需要特定功能可以编译一个最小化的版本。这能减少库文件大小。# 1. 安装编译依赖 sudo apt install -y build-essential cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libdc1394-22-dev # 2. 下载源码这里以4.5.5为例选一个稳定版本 wget -O opencv.zip https://github.com/opencv/opencv/archive/4.5.5.zip unzip opencv.zip cd opencv-4.5.5 # 3. 创建构建目录并配置CMake禁用不需要的模块以减小体积 mkdir build cd build cmake -D CMAKE_BUILD_TYPERELEASE \ -D CMAKE_INSTALL_PREFIX/usr/local \ -D WITH_CUDAON \ # 如果设备有CUDA可以开启加速 -D CUDA_ARCH_BIN5.3 \ # Jetson Nano的算力版本 -D WITH_CUDNNON \ -D OPENCV_DNN_CUDAON \ -D WITH_FFMPEGOFF \ # 禁用视频相关减小体积 -D WITH_GTKOFF \ -D BUILD_opencv_python3ON \ -D BUILD_EXAMPLESOFF \ -D BUILD_TESTSOFF \ -D BUILD_PERF_TESTSOFF \ .. # 4. 编译并安装这个过程比较久Jetson Nano上可能要1-2小时 make -j4 # 使用4个线程编译根据你的CPU核心数调整 sudo make install2.3 处理其他Python依赖GLM-OCR可能还依赖PyTorch、TorchVision等。对于ARM设备最省事的方法是去PyTorch官网查找为对应平台预编译的版本。# 访问 https://pytorch.org/get-started/locally/选择Linux、Pip、Python、CUDA版本如10.2 # 对于Jetson NanoJetPack 4.6可以使用如下命令安装PyTorch 1.10.0 pip3 install torch1.10.0 torchvision0.11.1 -f https://download.pytorch.org/whl/cu102/torch_stable.html # 安装GLM-OCR可能需要的其他通用包 pip3 install Pillow requests如果某个包没有ARM版本的预编译轮子pip会尝试从源码编译。这时需要确保对应的编译工具如gcc, g和头文件已经安装。3. GLM-OCR的获取与模型优化环境搞定后我们就把GLM-OCR本身请下来并着手对它进行“瘦身”手术。3.1 获取源码与初步运行直接从GitHub上克隆项目是最直接的方式。git clone https://github.com/THUDM/GLM-OCR.git cd GLM-OCR按照项目README的说明安装其特定的Python依赖。pip3 install -r requirements.txt尝试运行一下官方的示例脚本验证基础环境是否OK。这一步可能会因为缺少某些依赖而报错根据提示逐一解决即可。3.2 模型量化与剪枝降低显存占用模型优化是嵌入式部署的核心。GLM-OCR的模型可能包含FP32单精度浮点数参数我们可以通过量化将其转换为INT88位整数。这能显著减少模型体积和推理时的显存占用通常只会带来微小的精度损失。使用PyTorch内置量化工具 这是一个简单的后训练量化示例在实际应用中你可能需要使用有代表性的校准数据集来获得更好的量化效果。import torch import torch.quantization # 假设你已经加载了原始模型 # model YourGLMOCRModel() # model.load_state_dict(torch.load(original_model.pth)) # model.eval() # 1. 融合模型中的一些操作如ConvBNReLU为量化做准备 # model.fuse_model() # 2. 指定量化配置 model.qconfig torch.quantization.get_default_qconfig(fbgemm) # 对于ARM CPU也可以用 qnnpack # 3. 准备量化插入观察者观察激活和权重的分布 torch.quantization.prepare(model, inplaceTrue) # 4. 用校准数据跑一遍模型这里需要你准备一些图片 # with torch.no_grad(): # for data in calibration_data_loader: # model(data) # 5. 转换模型 torch.quantization.convert(model, inplaceTrue) # 6. 保存量化后的模型 # torch.jit.save(torch.jit.script(model), quantized_model.pt)注意量化是一个有损过程。对于OCR任务轻微的精度下降可能对最终识别率影响不大但务必在部署前用你的测试数据验证一下效果。除了量化还可以考虑剪枝即移除模型中一些不重要的连接或通道。PyTorch也提供了一些实验性的剪枝工具但这需要更深入的理解和调试。3.3 模型格式转换为TensorRT准备如果我们想使用TensorRT进行极致加速就需要将PyTorch模型转换成ONNX格式然后再由TensorRT解析优化。步骤1导出模型到ONNXimport torch # 假设model是已经加载并设置为eval模式的GLM-OCR模型 dummy_input torch.randn(1, 3, 32, 320) # 模拟一个输入batch1, 通道3, 高32, 宽320根据你的模型输入调整 input_names [input] output_names [output] torch.onnx.export(model, dummy_input, glm_ocr.onnx, export_paramsTrue, opset_version11, # 选择一个合适的opset版本 do_constant_foldingTrue, input_namesinput_names, output_namesoutput_names, dynamic_axes{input: {0: batch_size}, # 支持动态batch output: {0: batch_size}})步骤2在目标设备上安装TensorRT对于Jetson NanoTensorRT通常已经包含在JetPack系统中。你可以通过dpkg -l | grep tensorrt来确认。如果没有需要从NVIDIA开发者网站下载对应版本的deb包进行安装。4. 使用TensorRT加速推理TensorRT是NVIDIA推出的高性能深度学习推理SDK。它能对模型进行层间融合、精度校准、内核自动调优等优化从而在NVIDIA GPU上实现更快的推理速度。4.1 将ONNX模型转换为TensorRT引擎安装好TensorRT后我们可以使用其自带的trtexec工具进行转换或者用Python API。方法一使用trtexec命令行工具简单# 进入TensorRT的bin目录通常路径如下 cd /usr/src/tensorrt/bin # 将ONNX模型转换为FP16精度的TensorRT引擎并指定最大batch size和工作空间 ./trtexec --onnx/path/to/your/glm_ocr.onnx \ --saveEngine/path/to/save/glm_ocr_fp16.engine \ --fp16 \ --workspace1024 # 工作空间大小(MB)根据设备内存调整你可以尝试不同的精度--fp32,--fp16,--int8来权衡速度和精度。INT8最快但需要额外的校准过程。方法二使用Python API更灵活import tensorrt as trt TRT_LOGGER trt.Logger(trt.Logger.WARNING) def build_engine(onnx_file_path, engine_file_path, fp16_modeTrue): builder trt.Builder(TRT_LOGGER) network builder.create_network(1 int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)) parser trt.OnnxParser(network, TRT_LOGGER) with open(onnx_file_path, rb) as model: if not parser.parse(model.read()): for error in range(parser.num_errors): print(parser.get_error(error)) return None config builder.create_builder_config() config.max_workspace_size 1 30 # 1GB if fp16_mode and builder.platform_has_fast_fp16: config.set_flag(trt.BuilderFlag.FP16) engine builder.build_engine(network, config) with open(engine_file_path, wb) as f: f.write(engine.serialize()) return engine4.2 编写TensorRT推理代码引擎文件生成后我们就可以编写代码来加载它并进行推理了。import tensorrt as trt import pycuda.driver as cuda import pycuda.autoinit import numpy as np class TRTInference: def __init__(self, engine_path): self.logger trt.Logger(trt.Logger.WARNING) with open(engine_path, rb) as f, trt.Runtime(self.logger) as runtime: self.engine runtime.deserialize_cuda_engine(f.read()) self.context self.engine.create_execution_context() # 分配输入输出内存这里假设只有一个输入和一个输出 self.inputs, self.outputs, self.bindings, self.stream [], [], [], cuda.Stream() for binding in self.engine: size trt.volume(self.engine.get_binding_shape(binding)) * self.engine.max_batch_size dtype trt.nptype(self.engine.get_binding_dtype(binding)) # 分配主机和设备内存 host_mem cuda.pagelocked_empty(size, dtype) device_mem cuda.mem_alloc(host_mem.nbytes) self.bindings.append(int(device_mem)) if self.engine.binding_is_input(binding): self.inputs.append({host: host_mem, device: device_mem}) else: self.outputs.append({host: host_mem, device: device_mem}) def infer(self, input_data): # 将输入数据复制到主机内存 np.copyto(self.inputs[0][host], input_data.ravel()) # 将数据从主机内存拷贝到设备内存 cuda.memcpy_htod_async(self.inputs[0][device], self.inputs[0][host], self.stream) # 执行推理 self.context.execute_async_v2(bindingsself.bindings, stream_handleself.stream.handle) # 将结果从设备内存拷贝回主机内存 cuda.memcpy_dtoh_async(self.outputs[0][host], self.outputs[0][device], self.stream) # 同步流 self.stream.synchronize() return self.outputs[0][host].reshape(output_shape) # 根据你的输出形状调整 # 使用示例 trt_model TRTInference(glm_ocr_fp16.engine) # 准备你的预处理后的图像数据 input_array # result trt_model.infer(input_array)5. 整合与边缘端部署实践现在我们把前面几步的成果串起来形成一个可以在边缘设备上运行的完整流程。5.1 构建完整的推理流水线一个完整的OCR应用不仅仅是模型推理还包括图像预处理和后处理。import cv2 import numpy as np # 假设我们使用原始的PyTorch模型进行后处理演示 # from your_model_module import PostProcessor class GLMOCRPipeline: def __init__(self, model_path, use_trtFalse): self.use_trt use_trt if use_trt: self.trt_infer TRTInference(model_path) # 使用上一节的类 else: # 加载量化后的PyTorch模型 self.model torch.jit.load(model_path) self.model.eval() # 初始化预处理和后处理模块 # self.postprocessor PostProcessor() def preprocess(self, image): 将输入的BGR图像转换为模型需要的张量 # 1. 调整大小 (例如将高度缩放到32宽度按比例缩放) h, w image.shape[:2] target_h 32 ratio w / h target_w int(target_h * ratio) resized cv2.resize(image, (target_w, target_h)) # 2. 归一化、转通道、转换为张量等 # ... (具体取决于你的模型要求) # 3. 添加batch维度 input_tensor torch.from_numpy(processed_img).unsqueeze(0) return input_tensor def infer(self, input_tensor): if self.use_trt: # 注意需要将PyTorch Tensor转为numpy array并确保内存布局连续 output self.trt_infer.infer(input_tensor.numpy()) return torch.from_numpy(output) else: with torch.no_grad(): output self.model(input_tensor) return output def postprocess(self, model_output): 将模型输出转换为文本字符串 # 这里调用你的后处理逻辑例如CTC解码、字符映射等 # text self.postprocessor.decode(model_output) # return text pass # 替换为实际代码 def run(self, image_path): img cv2.imread(image_path) if img is None: return 读取图片失败 input_tensor self.preprocess(img) output self.infer(input_tensor) text self.postprocess(output) return text # 初始化流水线 # pipeline GLMOCRPipeline(quantized_model.pt, use_trtFalse) # result pipeline.run(test_image.jpg)5.2 性能测试与优化建议部署完成后一定要进行性能测试。# 使用time命令简单测试单张图片推理时间 time python3 ocr_pipeline.py --image test.jpg在Jetson Nano上你可以使用tegrastats工具来监控GPU、CPU、内存的使用情况。tegrastats --interval 1000 # 每秒刷新一次一些优化建议批处理如果场景允许一次处理多张图片能更好地利用GPU并行能力。流水线将图像读取、预处理、推理、后处理放在不同的线程中形成流水线提高整体吞吐量。CPU亲和性设置将推理进程绑定到特定的CPU核心可以减少上下文切换带来的开销。电源模式Jetson Nano有几种电源模式5W, 10W Max等在/usr/bin/jetson_clocks脚本可以设置最大性能模式但功耗和发热会增加。5.3 常见问题与排查内存/显存不足这是最常见的问题。首先确认模型是否成功量化或剪枝。其次检查推理代码中是否有不必要的中间变量长期占用内存。可以尝试减少trtexec中的--workspace大小或者降低推理时的batch size。推理速度慢确认是否成功使用了TensorRT以及FP16/INT8模式。使用tegrastats查看GPU是否在推理时被充分使用。检查CPU频率是否被限制。精度下降明显检查量化校准数据集是否具有代表性。尝试使用FP16模式而非INT8。确认预处理和后处理逻辑与原始模型训练时完全一致。依赖库缺失使用ldd命令检查编译出的可执行文件或Python扩展模块依赖的库是否都存在。例如ldd your_program | grep not found。6. 总结走完这一整套流程从环境准备、依赖编译、模型优化到最后的TensorRT加速部署确实需要一些耐心。但看到GLM-OCR最终在Jetson Nano这样的小设备上流畅地跑起来能实时处理摄像头拍下的文字那种成就感还是挺足的。整个过程里最关键的几步我觉得是模型量化和TensorRT转换。量化直接决定了模型能不能塞进有限的显存里而TensorRT则决定了推理速度能不能达到实用要求。这两步做好边缘部署就成功了一大半。当然每套硬件、每个模型可能都会有点小脾气遇到问题多查查社区、看看日志一步步调试总能解决。希望这篇内容能给你提供一个清晰的路线图让你在把自己的AI模型部署到边缘设备时少走点弯路。如果是在更复杂的生产环境可能还需要考虑模型版本管理、服务化封装、监控告警等等那就是另一个话题了。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。