飞桨框架(PaddlePaddle)现在可以支持Graphcore的IPU处理器了!在过去的几个月里, 通过飞桨研发团队与Graphcore China CE团队的不懈努力,已经初步完成了IPU与飞桨框架的适配工作。目前,用户可以在飞桨框架选择IPU硬件作为后端做深度学习的训练或推理任务。
本篇文章中,我们会详细演示基于Graphcore IPU的安装、训练和推理流程;本期的第二篇文章『飞桨 x Graphcore IPU适配方案深度解读与硬件介绍 』中,我们还会进一步介绍飞桨与Graphcore的适配初衷、适配的方案设计,以及关于Graphcore IPU的详细解读。
关于GraphCore
与飞桨的合作
Graphcore在2016年成立于英国,其智能处理器(IPU)硬件和Poplar软件帮助创新者在机器智能方面实现了新突破。IPU是第一个专为机器智能设计的处理器,与通常用于人工智能的其他计算硬件相比,具有显著的性能优势。
飞桨框架通过与Graphcore的适配合作,可以让广大开发者以极低的学习成本即可使用Graphcore出众的软硬件产品,真正做到以灵活的硬件后端和完善的功能助力开发者快速实现AI想法,上线AI业务,帮助越来越多的行业完成AI赋能,实现产业智能化升级。
在本期的第二篇文章中,会有更多关于本次适配架构的说明,以及关于Graphcore IPU的详细解读。
如何开始
(How to get started)
环境准备
Graphcore的Poplar SDK对硬件、操作系统以及软件环境均有一定的要求,具体参见:https://docs.graphcore.ai/projects/sdk-overview/en/latest/overview.html#requirements
通过源码编译安装
(1)下载源码
git clone -b paddle_bert_release https://github.com/graphcore/Paddle.git
(2)构建 Docker 镜像
docker build -t paddlepaddle/paddle:dev-ipu-2.3.0 \
-f tools/dockerfile/Dockerfile.ipu .
(3)创建并运行 Docker container
IPU依赖于ipu.conf配置文件进行分区,需要有可用的ipu.conf才能获取IPU设备。如果没有ipu.conf,可参考如下命令生成。
# 例:生成POD16(16个IPU)配置文件:
vipu create partition ipu --size 16
ipu.conf将会生成在以下路径:
ls ~/.ipuof.conf.d/
(4)启动Docker并编译环境
请将以下命令的${HOST_IPUOF_PATH}替换成host中ipu.conf的绝对路径。
docker run --ulimit memlock=-1:-1 --net=host --cap-add=IPC_LOCK \
--device=/dev/infiniband/ --ipc=host --name paddle-ipu-dev \
-v ${HOST_IPUOF_PATH}:/ipuof \
-e IPUOF_CONFIG_PATH=/ipuof/ipu.conf \
-it paddlepaddle/paddle:dev-ipu-2.3.0 bash
【注意:之后的操作均在container内执行。】
(5)(可选)验证IPU设备
通过以下命令可以查看当前全部IPU设备,以及正在使用的IPU设备ID
gc-monitor
出现以下图片说明正常获取IPU设备。如果没办法获取IPU设备,请检查是否提供正确的ipu.conf。
(6)编译飞桨框架
git clone -b paddle_bert_release https://github.com/graphcore/Paddle.git
cd Paddle
cmake -DPYTHON_EXECUTABLE=/usr/bin/python \
-DWITH_PYTHON=ON -DWITH_IPU=ON -DPOPLAR_DIR=/opt/poplar \
-DPOPART_DIR=/opt/popart -G "Unix Makefiles" -H`pwd` -B`pwd`/build
cmake --build \`pwd`/build --config Release --target paddle_python -j$(nproc)
(7)安装wheel包
pip install -U build/python/dist/paddlepaddle-0.0.0-cp37-cp37m-linux_x86_64.whl
(8)验证安装
python -c "import paddle; print(paddle.fluid.is_compiled_with_ipu())"
预期得到以下结果:
> True
目前Graphcore的IPU支持通过飞桨框架做大规模的模型训练任务,也支持通过Paddle Inference库执行高性能的推理任务。
BERT-Base 训练体验
Demo示例获取:
https://github.com/graphcore/portfolio-examples/tree/master/paddlepaddle/bert-base
Bert-Base Training 包含以下任务:
- phase1: sequence_length=128预训练
- phase2: sequence_length=384预训练
- SQuAD fine-tune
- SQuAD validation
数据准备
(1)预训练数据生成
git clone https://github.com/NVIDIA/DeepLearningExamples.git
cd DeepLearningExamples/TensorFlow/LanguageModeling/BERT
bash scripts/docker/build.sh
打开脚本并修改生成数据的配置
cd data/
vim create_datasets_from_start.sh
修改line 40 --max_seq_length 512 成--max_seq_length 384修改line 41 -- max_predictions_per_seq 80 成--max_predictions_per_se 56
cd ../
bash scripts/data_download.sh wiki_only
运行后将生成sequence_length=128 和 384的输入数据。
(2)准备SQuAD数据集
Stanford Question Answering Dataset (SQuAD) 是一个包含了特定范围内的维基百科内容,规模大且质量高的阅读理解数据集。SQuAD的答案是text span,即以文章原文中的某小一段文字来作为问题的答案,这种形式是首次在同类数据集中提出。
Fine-tune dataset:
curl --create-dirs -L https://rajpurkar.github.io/SQuAD-explorer/dataset/train-v1.1.json -o data/squad/train-v1.1.json
Validation dataset:
curl --create-dirs -L https://rajpurkar.github.io/SQuAD-explorer/dataset/dev-v1.1.json -o data/squad/dev-v1.1.json
PaddleNLP环境准备
本例除了依赖飞桨框架(已在上文中安装),还依赖PaddleNLP做模型构建和数据处理。请按照如下操作安装PaddleNLP:
(1)安装依赖:
pip3.7 install jieba h5py colorlog colorama seqeval multiprocess numpy==1.19.2 paddlefsl==1.0.0 six==1.13.0 wandb
pip3.7 install torch==1.7.0+cpu -f https://download.pytorch.org/whl/cpu/torch_stable.html
pip3.7 install torch-xla@https://storage.googleapis.com/tpu-pytorch/wheels/torch_xla-1.7-cp37-cp37m-linux_x86_64.whl
(2)安装PaddleNLP
pip3.7 install git+https://github.com/graphcore/PaddleNLP.git@paddle_bert_release
开始训练
修改run_stage.sh中的--input_dir为对应的输入数据路径:
Phase1: tfrecord(sequence_length=128)文件的存放路径;
Phase2: tfrecord(sequence_length=384)文件的存放路径;
Fine-tune: train-v1.1.json的存放路径;
Validation: dev-v1.1.json的存放路径。
run_stage.sh有4个参数:
device: ipu 或 cpu;
stage: phase1, phase2, SQuAD或validation;
input_pdparams: 导入的pdparams的路径+前缀;
output_pdparams: 导出的pdparams的路径+前缀。
【注意:程序中有使用wandb记录运行数据,运行时会弹出如下提示,需要选择对应的模式运行。如果没有wandb账号请输入3。】
Run Phase1:
Phase1不需要导入params,随机初始化权重
./run_stage.sh ipu phase1 _ pretrained_128_model
Run Phase2:
Phase2需要导入phase1训练好的params
./run_stage.sh ipu phase2 pretrained_128_model pretrained_384_model
Run SQuAD fine-tune:
fine-tune需要导入phase2训练好的params
./run_stage.sh ipu SQuAD pretrained_384_model finetune_model
Run validation:
./run_stage.sh ipu validation finetune_model _
BERT-Base
精度与性能
目前Graphcore的IPU支持通过飞桨框架做大规模的模型训练任务,也支持通过Paddle Inference库执行高性能的推理任务。
BERT训练 (BERT trainning)
Pretrain Phase1 (sequence_length=128):
Pretrain Phase2 (sequence_length=384):
SQuAD:
Paddle Inference 推理 (FP16)
word2vec推理演示
生成Paddle Inference原生推理库
基于之前的飞桨编译命令增加-DON_INFER=ON,编译完成后将在build目录下生成 paddle_inference_install_dir目录。该目录为Paddle Inference库目录。
cmake -DPYTHON_EXECUTABLE=/usr/bin/python \
-DWITH_PYTHON=ON –DON_INFER=ON -DWITH_IPU=ON -DPOPLAR_DIR=/opt/poplar \
-DPOPART_DIR=/opt/popart -G "Unix Makefiles" -H`pwd` -B`pwd`/build
cmake --build \`pwd`/build --config Release --target paddle_python -j$(nproc)
#目录如下:
可参考以下ipu_word2vec_sample.cc使用Paddle Inference库进行推理:
下载模型:
wget -q http://paddle-inference-dist.bj.bcebos.com/word2vec.Inference.model.tar.gz
编写Paddle Inference推理代码
#include <iostream>
#include <vector>
#include <numeric>
#include <string>
#include "paddle/fluid/inference/api/paddle_inference_api.h"
#include "gflags/gflags.h"
#include "glog/logging.h"
DEFINE_string(infer_model, "", "Directory of the inference model.");
using paddle_infer::Config;
using paddle_infer::Predictor;
using paddle_infer::CreatePredictor;
void inference(std::string model_path, bool use_ipu, std::vector<float> *out_data) {
//# 1. Create Predictor with a config.
Config config;
config.SetModel(FLAGS_infer_model);
if (use_ipu) {
// ipu_device_num, ipu_micro_batch_size
config.EnableIpu(1, 4);
}
auto predictor = CreatePredictor(config);
//# 2. Prepare input/output tensor.
auto input_names = predictor->GetInputNames();
std::vector<int64_t> data{1, 2, 3, 4};
// For simplicity, we set all the slots with the same data.
for (auto input_name : input_names) {
auto input_tensor = predictor->GetInputHandle(input_name);
input_tensor->Reshape({4, 1});
input_tensor->CopyFromCpu(data.data());
}
//# 3. Run
predictor->Run();
//# 4. Get output.
auto output_names = predictor->GetOutputNames();
auto output_tensor = predictor->GetOutputHandle(output_names[0]);
std::vector<int> output_shape = output_tensor->shape();
int out_num = std::accumulate(output_shape.begin(), output_shape.end(), 1,
std::multiplies<int>());
out_data->resize(out_num);
output_tensor->CopyToCpu(out_data->data());
}
int main(int argc, char *argv[]) {
::GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);
std::vector<float> ipu_result;
std::vector<float> cpu_result;
inference(FLAGS_infer_model, true, &ipu_result);
inference(FLAGS_infer_model, false, &cpu_result);
for (size_t i = 0; i < ipu_result.size(); i++) {
CHECK_NEAR(ipu_result[i], cpu_result[i], 1e-6);
}
LOG(INFO) << "Finished";
}
编译生成推理Demo程序
编译方法:
CMakeList.txt:
cmake_minimum_required(VERSION 3.0)
project(cpp_inference_demo CXX C)
include_directories("${PADDLE_LIB}/")
set(PADDLE_LIB_THIRD_PARTY_PATH "${PADDLE_LIB}/third_party/install/")
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}protobuf/include")
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}glog/include")
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}gflags/include")
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}xxhash/include")
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}cryptopp/include")
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}mkldnn/include")
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}mklml/include")
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}protobuf/lib")
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}glog/lib")
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}gflags/lib")
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}xxhash/lib")
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}cryptopp/lib")
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}ipu")
link_directories("/opt/poplar/lib")
link_directories("/opt/popart/lib")
link_directories("${PADDLE_LIB}/paddle/lib")
set(EXTERNAL_LIB "-lrt -ldl -lpthread")
set(DEPS ${DEPS}
${PADDLE_LIB_THIRD_PARTY_PATH}mkldnn/lib/libdnnl.so.2
${PADDLE_LIB_THIRD_PARTY_PATH}mklml/lib/libiomp5.so
paddle_inference paddle_ipu flags
glog gflags protobuf xxhash cryptopp
${EXTERNAL_LIB})
set(CMAKE_CXX_FLAGS "-std=c++11")
add_executable(${DEMO_NAME} ${DEMO_NAME}.cc)
target_link_libraries(${DEMO_NAME} ${DEPS})
编译脚本compile.sh:
【注意:请将${PADDLE_INFERENCE_INSTALL_DIR}替换为对应的Paddle Inference库路径】
#!/bin/bash
mkdir -p build
cd build
rm -rf *
DEMO_NAME=ipu_word2vec_sample
LIB_DIR=${PADDLE_INFERENCE_INSTALL_DIR}
cmake .. -DPADDLE_LIB=${LIB_DIR} -DDEMO_NAME=${DEMO_NAME}
make –j
编译:
./compile.sh
本测例将会分别完成IPU和CPU的推理,并对比两者结果
./ipu_word2vec_sample –-infer_model=word2vec.inference.model
其他Demo体验
MNIST demo
https://github.com/graphcore/Paddle_internal/issues/312
相关资料 (links)
https://www.paddlepaddle.org.cn/
https://github.com/PaddlePaddle/Paddle
关注公众号,获取更多技术内容~