适用于 PyTorch* 的 Intel® 扩展¶
适用于 PyTorch* 的 Intel® 扩展通过最新的功能优化扩展了 PyTorch*,从而在 Intel 硬件上获得额外的性能提升。优化利用了 Intel CPU 上的 AVX-512 向量神经网络指令 (AVX512 VNNI) 和英特尔® 高级矩阵扩展 (英特尔® AMX),以及 Intel 独立 GPU 上的 Intel Xe 矩阵扩展 (XMX) AI 引擎。此外,通过 PyTorch* xpu 设备,适用于 PyTorch* 的 Intel® 扩展为使用 PyTorch* 的 Intel 独立 GPU 提供了轻松的 GPU 加速。
适用于 PyTorch* 的 Intel® 扩展已作为开源项目在 Github 上发布。
CPU 的源代码可在 主分支 中找到。
GPU 的源代码可在 xpu-main 分支 中找到。
功能¶
适用于 PyTorch* 的 Intel® 扩展共享 CPU 和 GPU 的大部分功能。
易于使用的 Python API:适用于 PyTorch* 的 Intel® 扩展为用户提供了简单的 Python 前端 API 和实用程序,以便用户通过少量代码更改获得性能优化,例如图形优化和操作符优化。通常,只需要添加 2 到 3 个子句到原始代码中。
通道优先(Channels Last):与默认的 NCHW 内存格式相比,通道优先(NHWC)内存格式可以进一步加速卷积神经网络。在英特尔® 扩展 for PyTorch* 中,NHWC 内存格式已为大多数关键 CPU 算子启用,尽管并非所有算子都已合并到 PyTorch 主分支。预计它们很快就会完全合并到 PyTorch 上游。
自动混合精度 (AMP):低精度数据类型 BFloat16 已在搭载 AVX512 指令集的第三代至强可扩展服务器(又名 Cooper Lake)上得到原生支持,并且将在下一代英特尔® 至强® 可扩展处理器上得到支持,这些处理器将配备英特尔® 高级矩阵扩展 (Intel® AMX) 指令集,并进一步提升性能。英特尔® 扩展 for PyTorch* 中已大量启用对 CPU 使用自动混合精度 (AMP) 和 BFloat16 以及算子的 BFloat16 优化,并且部分已上游合并到 PyTorch 主分支。大多数这些优化将通过正在提交和审查的 PR 合并到 PyTorch 主分支。对于英特尔独立显卡,已启用使用 BFloat16 和 Float16 的自动混合精度 (AMP)。
图优化:为了进一步优化 torchscript 的性能,英特尔® 扩展 for PyTorch* 支持融合常用算子模式,例如 Conv2D+ReLU、Linear+ReLU 等。融合带来的好处将以透明的方式传递给用户。支持的详细融合模式可以在这里找到 此处。图优化将随着 oneDNN 图 API 的引入而上游合并到 PyTorch 中。
算子优化:英特尔® 扩展 for PyTorch* 还优化了算子,并为性能实现了多个自定义算子。通过 ATen 注册机制,英特尔® 扩展 for PyTorch* 中的一些 ATen 算子被其优化后的对应版本替换。此外,还为一些流行的拓扑结构实现了某些自定义算子。例如,ROIAlign 和 NMS 定义在 Mask R-CNN 中。为了提高这些拓扑结构的性能,英特尔® 扩展 for PyTorch* 还优化了这些自定义算子。
入门¶
用户只需进行少量代码更改即可开始使用英特尔® 扩展 for PyTorch*。PyTorch 命令式模式和 TorchScript 模式都受支持。本节介绍了两种模式下英特尔® 扩展 for PyTorch* API 函数的使用方法,涵盖了 Float32 和 BFloat16 数据类型。最后还将介绍 C++ 的用法。
您只需导入英特尔® 扩展 for PyTorch* 包,并将其优化函数应用于模型对象即可。如果是训练工作负载,则还需要将优化函数应用于优化器对象。
对于使用 BFloat16 数据类型的训练和推理,PyTorch 上游已启用 torch.cpu.amp 以方便支持混合精度。PyTorch 上游和英特尔® 扩展 for PyTorch* 中已广泛启用 BFloat16 数据类型以用于 CPU 算子。同时,由英特尔® 扩展 for PyTorch* 注册的 torch.xpu.amp 使得在英特尔独立显卡上轻松使用 BFloat16 和 Float16 数据类型成为可能。 torch.cpu.amp 或 torch.xpu.amp 会自动将每个算子与其相应的数据类型匹配,并返回最佳性能。
示例 – CPU¶
本节显示了在 CPU 上使用英特尔® 扩展 for PyTorch* 进行训练和推理的示例。
英特尔® 扩展 for PyTorch* 所需的代码更改已突出显示。
训练¶
Float32¶
import torch
import torchvision
import intel_extension_for_pytorch as ipex
LR = 0.001
DOWNLOAD = True
DATA = 'datasets/cifar10/'
transform = torchvision.transforms.Compose([
torchvision.transforms.Resize((224, 224)),
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
train_dataset = torchvision.datasets.CIFAR10(
root=DATA,
train=True,
transform=transform,
download=DOWNLOAD,
)
train_loader = torch.utils.data.DataLoader(
dataset=train_dataset,
batch_size=128
)
model = torchvision.models.resnet50()
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr = LR, momentum=0.9)
model.train()
model, optimizer = ipex.optimize(model, optimizer=optimizer)
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
output = model(data)
loss = criterion(output, target)
loss.backward()
optimizer.step()
print(batch_idx)
torch.save({
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
}, 'checkpoint.pth')
BFloat16¶
import torch
import torchvision
import intel_extension_for_pytorch as ipex
LR = 0.001
DOWNLOAD = True
DATA = 'datasets/cifar10/'
transform = torchvision.transforms.Compose([
torchvision.transforms.Resize((224, 224)),
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
train_dataset = torchvision.datasets.CIFAR10(
root=DATA,
train=True,
transform=transform,
download=DOWNLOAD,
)
train_loader = torch.utils.data.DataLoader(
dataset=train_dataset,
batch_size=128
)
model = torchvision.models.resnet50()
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr = LR, momentum=0.9)
model.train()
model, optimizer = ipex.optimize(model, optimizer=optimizer, dtype=torch.bfloat16)
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
with torch.cpu.amp.autocast():
output = model(data)
loss = criterion(output, target)
loss.backward()
optimizer.step()
print(batch_idx)
torch.save({
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
}, 'checkpoint.pth')
推理 - 命令式模式¶
Float32¶
import torch
import torchvision.models as models
model = models.resnet50(pretrained=True)
model.eval()
data = torch.rand(1, 3, 224, 224)
#################### code changes ####################
import intel_extension_for_pytorch as ipex
model = ipex.optimize(model)
######################################################
with torch.no_grad():
model(data)
BFloat16¶
import torch
from transformers import BertModel
model = BertModel.from_pretrained(args.model_name)
model.eval()
vocab_size = model.config.vocab_size
batch_size = 1
seq_length = 512
data = torch.randint(vocab_size, size=[batch_size, seq_length])
#################### code changes ####################
import intel_extension_for_pytorch as ipex
model = ipex.optimize(model, dtype=torch.bfloat16)
######################################################
with torch.no_grad():
with torch.cpu.amp.autocast():
model(data)
推理 - TorchScript 模式¶
TorchScript 模式使图优化成为可能,因此可以提高某些拓扑结构的性能。英特尔® 扩展 for PyTorch* 启用了最常用的算子模式融合,用户无需进行任何额外的代码更改即可获得性能提升。
Float32¶
import torch
import torchvision.models as models
model = models.resnet50(pretrained=True)
model.eval()
data = torch.rand(1, 3, 224, 224)
#################### code changes ####################
import intel_extension_for_pytorch as ipex
model = ipex.optimize(model)
######################################################
with torch.no_grad():
d = torch.rand(1, 3, 224, 224)
model = torch.jit.trace(model, d)
model = torch.jit.freeze(model)
model(data)
BFloat16¶
import torch
from transformers import BertModel
model = BertModel.from_pretrained(args.model_name)
model.eval()
vocab_size = model.config.vocab_size
batch_size = 1
seq_length = 512
data = torch.randint(vocab_size, size=[batch_size, seq_length])
#################### code changes ####################
import intel_extension_for_pytorch as ipex
model = ipex.optimize(model, dtype=torch.bfloat16)
######################################################
with torch.no_grad():
with torch.cpu.amp.autocast():
d = torch.randint(vocab_size, size=[batch_size, seq_length])
model = torch.jit.trace(model, (d,), check_trace=False, strict=False)
model = torch.jit.freeze(model)
model(data)
示例 – GPU¶
本节显示了在 GPU 上使用英特尔® 扩展 for PyTorch* 进行训练和推理的示例。
英特尔® 扩展 for PyTorch* 所需的代码更改已在代码行上方的注释中突出显示。
训练¶
Float32¶
import torch
import torchvision
############# code changes ###############
import intel_extension_for_pytorch as ipex
############# code changes ###############
LR = 0.001
DOWNLOAD = True
DATA = 'datasets/cifar10/'
transform = torchvision.transforms.Compose([
torchvision.transforms.Resize((224, 224)),
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
train_dataset = torchvision.datasets.CIFAR10(
root=DATA,
train=True,
transform=transform,
download=DOWNLOAD,
)
train_loader = torch.utils.data.DataLoader(
dataset=train_dataset,
batch_size=128
)
model = torchvision.models.resnet50()
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr = LR, momentum=0.9)
model.train()
#################################### code changes ################################
model = model.to("xpu")
model, optimizer = ipex.optimize(model, optimizer=optimizer, dtype=torch.float32)
#################################### code changes ################################
for batch_idx, (data, target) in enumerate(train_loader):
########## code changes ##########
data = data.to("xpu")
target = target.to("xpu")
########## code changes ##########
optimizer.zero_grad()
output = model(data)
loss = criterion(output, target)
loss.backward()
optimizer.step()
print(batch_idx)
torch.save({
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
}, 'checkpoint.pth')
BFloat16¶
import torch
import torchvision
############# code changes ###############
import intel_extension_for_pytorch as ipex
############# code changes ###############
LR = 0.001
DOWNLOAD = True
DATA = 'datasets/cifar10/'
transform = torchvision.transforms.Compose([
torchvision.transforms.Resize((224, 224)),
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
train_dataset = torchvision.datasets.CIFAR10(
root=DATA,
train=True,
transform=transform,
download=DOWNLOAD,
)
train_loader = torch.utils.data.DataLoader(
dataset=train_dataset,
batch_size=128
)
model = torchvision.models.resnet50()
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr = LR, momentum=0.9)
model.train()
##################################### code changes ################################
model = model.to("xpu")
model, optimizer = ipex.optimize(model, optimizer=optimizer, dtype=torch.bfloat16)
##################################### code changes ################################
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
######################### code changes #########################
data = data.to("xpu")
target = target.to("xpu")
with torch.xpu.amp.autocast(enabled=True, dtype=torch.bfloat16):
######################### code changes #########################
output = model(data)
loss = criterion(output, target)
loss.backward()
optimizer.step()
print(batch_idx)
torch.save({
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
}, 'checkpoint.pth')
推理 - 命令式模式¶
Float32¶
import torch
import torchvision.models as models
############# code changes ###############
import intel_extension_for_pytorch as ipex
############# code changes ###############
model = models.resnet50(pretrained=True)
model.eval()
data = torch.rand(1, 3, 224, 224)
model = model.to(memory_format=torch.channels_last)
data = data.to(memory_format=torch.channels_last)
#################### code changes ################
model = model.to("xpu")
data = data.to("xpu")
model = ipex.optimize(model, dtype=torch.float32)
#################### code changes ################
with torch.no_grad():
model(data)
BFloat16¶
import torch
import torchvision.models as models
############# code changes ###############
import intel_extension_for_pytorch as ipex
############# code changes ###############
model = models.resnet50(pretrained=True)
model.eval()
data = torch.rand(1, 3, 224, 224)
model = model.to(memory_format=torch.channels_last)
data = data.to(memory_format=torch.channels_last)
#################### code changes #################
model = model.to("xpu")
data = data.to("xpu")
model = ipex.optimize(model, dtype=torch.bfloat16)
#################### code changes #################
with torch.no_grad():
################################# code changes ######################################
with torch.xpu.amp.autocast(enabled=True, dtype=torch.bfloat16, cache_enabled=False):
################################# code changes ######################################
model(data)
Float16¶
import torch
import torchvision.models as models
############# code changes ###############
import intel_extension_for_pytorch as ipex
############# code changes ###############
model = models.resnet50(pretrained=True)
model.eval()
data = torch.rand(1, 3, 224, 224)
model = model.to(memory_format=torch.channels_last)
data = data.to(memory_format=torch.channels_last)
#################### code changes ################
model = model.to("xpu")
data = data.to("xpu")
model = ipex.optimize(model, dtype=torch.float16)
#################### code changes ################
with torch.no_grad():
################################# code changes ######################################
with torch.xpu.amp.autocast(enabled=True, dtype=torch.float16, cache_enabled=False):
################################# code changes ######################################
model(data)
推理 - TorchScript 模式¶
TorchScript 模式使图优化成为可能,因此可以提高某些拓扑结构的性能。英特尔® 扩展 for PyTorch* 启用了最常用的算子模式融合,用户无需进行任何额外的代码更改即可获得性能提升。
Float32¶
import torch
from transformers import BertModel
############# code changes ###############
import intel_extension_for_pytorch as ipex
############# code changes ###############
model = BertModel.from_pretrained(args.model_name)
model.eval()
vocab_size = model.config.vocab_size
batch_size = 1
seq_length = 512
data = torch.randint(vocab_size, size=[batch_size, seq_length])
#################### code changes ################
model = model.to("xpu")
data = data.to("xpu")
model = ipex.optimize(model, dtype=torch.float32)
#################### code changes ################
with torch.no_grad():
d = torch.randint(vocab_size, size=[batch_size, seq_length])
##### code changes #####
d = d.to("xpu")
##### code changes #####
model = torch.jit.trace(model, (d,), check_trace=False, strict=False)
model = torch.jit.freeze(model)
model(data)
BFloat16¶
import torch
from transformers import BertModel
############# code changes ###############
import intel_extension_for_pytorch as ipex
############# code changes ###############
model = BertModel.from_pretrained(args.model_name)
model.eval()
vocab_size = model.config.vocab_size
batch_size = 1
seq_length = 512
data = torch.randint(vocab_size, size=[batch_size, seq_length])
#################### code changes #################
model = model.to("xpu")
data = data.to("xpu")
model = ipex.optimize(model, dtype=torch.bfloat16)
#################### code changes #################
with torch.no_grad():
d = torch.randint(vocab_size, size=[batch_size, seq_length])
################################# code changes ######################################
d = d.to("xpu")
with torch.xpu.amp.autocast(enabled=True, dtype=torch.bfloat16, cache_enabled=False):
################################# code changes ######################################
model = torch.jit.trace(model, (d,), check_trace=False, strict=False)
model = torch.jit.freeze(model)
model(data)
Float16¶
import torch
from transformers import BertModel
############# code changes ###############
import intel_extension_for_pytorch as ipex
############# code changes ###############
model = BertModel.from_pretrained(args.model_name)
model.eval()
vocab_size = model.config.vocab_size
batch_size = 1
seq_length = 512
data = torch.randint(vocab_size, size=[batch_size, seq_length])
#################### code changes ################
model = model.to("xpu")
data = data.to("xpu")
model = ipex.optimize(model, dtype=torch.float16)
#################### code changes ################
with torch.no_grad():
d = torch.randint(vocab_size, size=[batch_size, seq_length])
################################# code changes ######################################
d = d.to("xpu")
with torch.xpu.amp.autocast(enabled=True, dtype=torch.float16, cache_enabled=False):
################################# code changes ######################################
model = torch.jit.trace(model, (d,), check_trace=False, strict=False)
model = torch.jit.freeze(model)
model(data)
C++(仅限 CPU)¶
为了与 PyTorch 的 C++ 库 libtorch 协同工作,英特尔® 扩展 for PyTorch* 也提供了其 C++ 动态库。C++ 库应该只处理推理工作负载,例如服务部署。对于常规开发,请使用 Python 接口。与使用 libtorch 相比,除了将输入数据转换为通道优先数据格式外,不需要进行任何特定的代码更改。编译遵循使用 CMake 的推荐方法。详细说明可以在 PyTorch 教程 中找到。在编译过程中,一旦链接了英特尔® 扩展 for PyTorch* 的 C++ 动态库,英特尔优化将自动激活。
example-app.cpp
#include <torch/script.h>
#include <iostream>
#include <memory>
int main(int argc, const char* argv[]) {
torch::jit::script::Module module;
try {
module = torch::jit::load(argv[1]);
}
catch (const c10::Error& e) {
std::cerr << "error loading the model\n";
return -1;
}
std::vector<torch::jit::IValue> inputs;
// make sure input data are converted to channels last format
inputs.push_back(torch::ones({1, 3, 224, 224}).to(c10::MemoryFormat::ChannelsLast));
at::Tensor output = module.forward(inputs).toTensor();
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(example-app)
find_package(intel_ext_pt_cpu REQUIRED)
add_executable(example-app example-app.cpp)
target_link_libraries(example-app "${TORCH_LIBRARIES}")
set_property(TARGET example-app PROPERTY CXX_STANDARD 14)
编译命令
$ cmake -DCMAKE_PREFIX_PATH=<LIBPYTORCH_PATH> ..
$ make
如果 Found INTEL_EXT_PT_CPU 显示为 TRUE,则表示扩展已链接到二进制文件中。这可以使用 Linux 命令 ldd 进行验证。
$ cmake -DCMAKE_PREFIX_PATH=/workspace/libtorch ..
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE
-- Found Torch: /workspace/libtorch/lib/libtorch.so
-- Found INTEL_EXT_PT_CPU: TRUE
-- Configuring done
-- Generating done
-- Build files have been written to: /workspace/build
$ ldd example-app
...
libtorch.so => /workspace/libtorch/lib/libtorch.so (0x00007f3cf98e0000)
libc10.so => /workspace/libtorch/lib/libc10.so (0x00007f3cf985a000)
libintel-ext-pt-cpu.so => /workspace/libtorch/lib/libintel-ext-pt-cpu.so (0x00007f3cf70fc000)
libtorch_cpu.so => /workspace/libtorch/lib/libtorch_cpu.so (0x00007f3ce16ac000)
...
libdnnl_graph.so.0 => /workspace/libtorch/lib/libdnnl_graph.so.0 (0x00007f3cde954000)
...
模型库(仅限 CPU)¶
英特尔工程师已经优化的用例可以在 英特尔® 架构模型库(分支名称格式为 pytorch-r<version>-models)中找到。GitHub 页面上还提供了许多用于基准测试的 PyTorch 用例。只需运行模型库中的脚本,即可立即获得性能提升。