许多AI开发者在训练模型时偏爱 PyTorch 的灵活性和易用性。针对用户提出的“特斯拉使用 PyTorch 还是 TensorFlow”的问题,虽然早期特斯拉Autopilot使用了基于 C++/CUDA 的定制化基础设施,但目前业界普遍认为其核心的神经网络训练流程已经广泛使用 PyTorch(甚至包括其自研的 Dojo 超算基础设施)。然而,训练阶段的 Python 框架优势,到了高要求、低延迟的生产部署环境(如汽车嵌入式系统或高并发后端服务)时,却可能成为瓶颈。
关键挑战:训练与部署的鸿沟
PyTorch 模型通常依赖 Python 运行时,这在高并发、资源受限或需要极致低延迟的环境中是不可接受的。生产环境往往需要移除 Python 依赖,直接使用 C++ 或其他原生语言进行部署。
对于 PyTorch 用户来说,解决这一问题的标准且高性能的方法就是使用 TorchScript 序列化模型,并通过 LibTorch(PyTorch 的 C++ 前端 API)进行推理。
步骤一:在 Python 中将模型转换为 TorchScript
TorchScript 是 PyTorch 模型的一种序列化和优化格式。它允许我们将模型从 Python 运行时中分离出来,生成一个独立、可执行的图结构。我们主要使用 torch.jit.trace 或 torch.jit.script 方法。
以下是一个使用 trace 方法将简单 MLP 模型转换并保存的示例:
import torch
import torch.nn as nn
# 1. 定义一个简单的模型
class SimpleMLP(nn.Module):
def __init__(self):
super(SimpleMLP, self).__init__()
self.fc1 = nn.Linear(10, 64)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(64, 2)
def forward(self, x):
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
return x
# 2. 实例化模型并加载权重 (假设已训练)
model = SimpleMLP()
# model.load_state_dict(torch.load('model_weights.pth')) # 实际应用中需要加载权重
model.eval()
# 3. 创建一个示例输入张量
example_input = torch.randn(1, 10)
# 4. 使用 JIT Trace 转换模型
# Trace 要求输入模型是静态图结构(不包含依赖控制流的逻辑)
traced_script_module = torch.jit.trace(model, example_input)
# 5. 保存序列化的模型
traced_script_module.save("mlp_model.pt")
print("模型已成功保存为 mlp_model.pt")
步骤二:使用 LibTorch (C++) 进行高性能部署
保存的 mlp_model.pt 文件现在可以在任何支持 LibTorch 的 C++ 环境中加载和运行,无需 Python 依赖。
2.1 C++ 推理代码 (main.cpp)
LibTorch 依赖 C++ 的标准库和特定的 PyTorch 头文件。以下代码展示了如何加载模型、准备输入张量、执行推理并处理输出。
#include <torch/script.h> // LibTorch JIT API
#include <torch/torch.h> // LibTorch Tensor API
#include <iostream>
#include <memory>
int main() {
// 1. 加载 TorchScript 模型
std::shared_ptr<torch::jit::script::Module> module = nullptr;
try {
// 确保 mlp_model.pt 在当前目录下
module = torch::jit::load("mlp_model.pt");
} catch (const c10::Error& e) {
std::cerr << "Error loading the model:\n";
std::cerr << e.what() << std::endl;
return -1;
}
std::cout << "Model loaded successfully!\n";
// 2. 准备输入张量
// 形状必须与 tracing 时使用的 example_input (1x10) 匹配
std::vector<torch::jit::IValue> inputs;
// 创建一个 1x10 的随机浮点数张量作为输入数据
// 注意:在实际应用中,这里会是你的传感器数据或预处理后的特征
torch::Tensor input_tensor = torch::rand({1, 10});
inputs.push_back(input_tensor);
// 3. 执行推理
// module->forward 返回一个 IValue,需要转换为具体的 Tensor
torch::Tensor output = module->forward(inputs).toTensor();
// 4. 处理输出
std::cout << "Input size: " << input_tensor.sizes() << "\n";
std::cout << "Output size: " << output.sizes() << "\n";
// 打印结果
std::cout << "Output result: \n";
for (int i = 0; i < output.size(1); ++i) {
std::cout << output[0][i].item<float>() << " ";
}
std::cout << "\n";
std::cout << "Inference complete in C++ environment.\n";
return 0;
}
2.2 编译配置 (CMakeLists.txt)
为了编译上面的 C++ 代码,我们需要 CMake 来定位 LibTorch 库。
cmake_minimum_required(VERSION 3.14)
project(LibTorchInference)
# 假设 LibTorch 已经被下载并解压到一个已知路径,例如 $ENV{LIBTORCH_DIR}
# 实际项目中,你需要设置一个环境变量或路径指向 LibTorch 根目录
set(CMAKE_PREFIX_PATH "$ENV{LIBTORCH_DIR}")
find_package(Torch REQUIRED)
# 设置 C++ 14 标准
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")
add_executable(inference main.cpp)
target_link_libraries(inference "${TORCH_LIBRARIES}")
2.3 运行编译
确保你已经下载了适合你的操作系统的 LibTorch C++ 发行版,并设置了 LIBTORCH_DIR 环境变量。
# 假设你的 LibTorch 库在 ~/libtorch
export LIBTORCH_DIR=~/libtorch
# 1. 创建 build 目录
mkdir build
cd build
# 2. 运行 cmake
cmake ..
# 3. 编译
cmake --build .
# 4. 运行 C++ 程序
./inference
总结
虽然 PyTorch 在训练研究和迭代速度上表现出色,但为了实现如特斯拉 Autopilot 这类对性能和可靠性要求极高的部署场景,将模型转换到高性能的原生语言(如 C++)中运行是必须的。通过 TorchScript 和 LibTorch 的组合,PyTorch 生态系统完美弥合了研究灵活性与生产性能之间的差距,实现了高性能、无 Python 依赖的模型部署。
汤不热吧