C++ 前端#
PyTorch C++ 前端是一个用于 CPU 和 GPU 张量计算的 C++17 库,具有自动微分功能,并为最先进的机器学习应用提供了高级构建模块。
描述#
PyTorch C++ 前端可以被视为 PyTorch Python 前端的 C++ 版本,为机器学习和神经网络提供自动微分及各种更高级的抽象。具体而言,它由以下组件组成:
组件 |
描述 |
|---|---|
|
支持自动微分、高效的 CPU 和 GPU 张量 |
|
用于神经网络建模的一组可组合模块 |
|
用于训练模型的优化算法,如 SGD、Adam 或 RMSprop |
|
数据集、数据管道以及多线程异步数据加载器 |
|
用于存储和加载模型检查点的序列化 API |
|
将 C++ 模型绑定到 Python 的胶水层 |
|
对 TorchScript JIT 编译器的纯 C++ 访问 |
端到端示例#
这是一个在 MNIST 数据集上定义并训练简单神经网络的简单端到端示例
#include <torch/torch.h>
// Define a new Module.
struct Net : torch::nn::Module {
Net() {
// Construct and register two Linear submodules.
fc1 = register_module("fc1", torch::nn::Linear(784, 64));
fc2 = register_module("fc2", torch::nn::Linear(64, 32));
fc3 = register_module("fc3", torch::nn::Linear(32, 10));
}
// Implement the Net's algorithm.
torch::Tensor forward(torch::Tensor x) {
// Use one of many tensor manipulation functions.
x = torch::relu(fc1->forward(x.reshape({x.size(0), 784})));
x = torch::dropout(x, /*p=*/0.5, /*train=*/is_training());
x = torch::relu(fc2->forward(x));
x = torch::log_softmax(fc3->forward(x), /*dim=*/1);
return x;
}
// Use one of many "standard library" modules.
torch::nn::Linear fc1{nullptr}, fc2{nullptr}, fc3{nullptr};
};
int main() {
// Create a new Net.
auto net = std::make_shared<Net>();
// Create a multi-threaded data loader for the MNIST dataset.
auto data_loader = torch::data::make_data_loader(
torch::data::datasets::MNIST("./data").map(
torch::data::transforms::Stack<>()),
/*batch_size=*/64);
// Instantiate an SGD optimization algorithm to update our Net's parameters.
torch::optim::SGD optimizer(net->parameters(), /*lr=*/0.01);
for (size_t epoch = 1; epoch <= 10; ++epoch) {
size_t batch_index = 0;
// Iterate the data loader to yield batches from the dataset.
for (auto& batch : *data_loader) {
// Reset gradients.
optimizer.zero_grad();
// Execute the model on the input data.
torch::Tensor prediction = net->forward(batch.data);
// Compute a loss value to judge the prediction of our model.
torch::Tensor loss = torch::nll_loss(prediction, batch.target);
// Compute gradients of the loss w.r.t. the parameters of our model.
loss.backward();
// Update the parameters based on the calculated gradients.
optimizer.step();
// Output the loss and checkpoint every 100 batches.
if (++batch_index % 100 == 0) {
std::cout << "Epoch: " << epoch << " | Batch: " << batch_index
<< " | Loss: " << loss.item<float>() << std::endl;
// Serialize your model periodically as a checkpoint.
torch::save(net, "net.pt");
}
}
}
}
要查看更多使用 PyTorch C++ 前端的完整示例,请参阅示例代码仓库。
设计哲学#
PyTorch C++ 前端的设计理念是:Python 前端非常出色,应尽可能使用;但在某些场景下,性能和可移植性要求使得使用 Python 解释器变得不可行。例如,对于低延迟、高性能或多线程环境(如视频游戏或生产服务器),Python 并非理想选择。C++ 前端的目标是在不牺牲 Python 前端用户体验的前提下,解决这些用例。
因此,C++ 前端在编写时考虑了以下几个哲学目标:
在设计、命名、约定和功能上紧密模仿 Python 前端。虽然两个前端之间可能会有偶尔的差异(例如,我们删除了一些已弃用的功能或修复了 Python 前端中的“缺陷”),但我们保证,将 Python 模型移植到 C++ 的工作应仅在于翻译语言特性,而无需修改功能或行为。
优先考虑灵活性和用户友好性,而非微优化。在 C++ 中,你通常可以获得最优代码,但代价是极其糟糕的用户体验。灵活性和动态性是 PyTorch 的核心,C++ 前端力求保留这种体验,在某些情况下会牺牲性能(或“隐藏”性能调节开关)以保持 API 的简单和可解释性。我们希望那些并非以编写 C++ 为生的研究人员也能使用我们的 API。
特别提醒:Python 并不一定比 C++ 慢!Python 前端在处理几乎所有计算密集型任务(尤其是任何类型的数值运算)时都会调用 C++,而这些操作占据了程序运行的大部分时间。如果你更倾向于编写 Python,并且能够承担使用 Python 的开销,我们建议使用 PyTorch 的 Python 接口。然而,如果你更倾向于编写 C++,或者由于多线程、延迟或部署要求而必须编写 C++,PyTorch 的 C++ 前端提供了一个与 Python 版本同样便捷、灵活、友好且直观的 API。两个前端服务于不同的用例,相辅相成,且任何一方都不是为了无条件地取代另一方。
安装#
关于如何安装 C++ 前端库发行版(包括如何构建依赖于 LibTorch 的最小应用程序的示例)的说明,可以通过点击此链接找到。