前言

在开篇的时候我谈到,这个系列的内容来自于我在使用GPU实践中的一点心得。但是围绕GPU相关的技术话题实在是太过于广泛,如果洋洋洒洒的写下去我很担心会错过许多新鲜的话题。于是就让这一篇成为这个系列的终结篇,并且分享一下使用GPU的最重要的领域-深度学习上的框架与工具这个内容吧。

这里我所指的工具是指那些在深度学习应用中发挥了重大作用的几个工具,包括了历久弥新的OpenCV以及利用Intel CPU加速数学运算的MKL库(Intel Math Kernel Library )。而深度学习的框架则是那些已经众所周知的深度学习框架,包括了TensorFlowPyTorch 以及Apache MxNet等。

事实上,关于这几个工具与框架的内容可以说是汗牛充栋了。而我想分享的不是如何使用这些工具,而是如何编译、优化这几个工具与框架。针对GPU实例(例如EC2 P3 实例),针对性的优化可以最大限度的发挥出来这个实例的能力,对于模型的训练或者推理的性能会起到显著的提升,如果你有兴趣,就让我们挽起袖子一起来尝试一下。

计算机视觉领域的瑞士军刀 – OpenCV

OpenCV(Open Source Computer Vision Library) 是一个开源的计算机视觉和机器学习软件库。OpenCV项目的目标是为了为计算机视觉应用提供一个通用的基础设施。OpenCV采用了BSD许可,这使得开发人员与企业很容易地在自己的产品中使用它。

OpenCV提供了超过2500个优化的算法,其中包括一套全面的经典和最先进的计算机视觉和机器学习算法。这些算法可以用来检测和识别人脸、识别对象,对人的行动的视频分类、跟踪相机移动、跟踪移动物体、提取对象的三维模型,从立体相机产生三维点云图像合成到一起产生一个高分辨率图像的整个场景、从一个图像数据库发现类似的图像、从使用闪光灯拍摄的图像中删除红眼、追踪眼球运动、识别风景并建立标记,将其与增强现实叠加等等。目前OpenCV有超过47,000个用户社区,估计下载量超过1800万。OpenCV是用C++编写的,并且有一个与STL容器无缝配合的模板化接口。怎对开发者OpenCV提供了C++、Python、Java和MATLAB等的接口,并且支持Windows、Linux、Android和Mac OS等平台。

在过去的几年,随着机器学习、深度学习尤其是计算机视觉技术的快速发展,OpenCV的也不断推出了新的特性和版本。其中延续原有接口的3.X系列发展到了3.4.10且表现出来更加的成熟与稳定;而4.X系列则引入了许多新的技术, 例如在版本4.2中增加了引入了对cuDNN的支持使得其DNN模块的性能得到显著提升;对于OpenVINO™ 的支持又使得OpenCV 可以有更好的适应性,例如在RaspBerry Pi 上通过使用Intel® Neural Compute Stick 2计算棒来提升性能。在今年4月份发布的4.3.0 这个版本中,更是一口气增加了对于ONNX、Darknet、MobileNet-SSD 等令人心动的技术的支持。

Intel® Neural Compute Stick 2 (NCS2) 计算棒

不过,在我们使用的Ubuntu 10.04中内置的OpenCV的版本仅仅是3.2。而上述的那许多新的特性难道只能望洋兴叹了吗?那就让我们自己动手编译出来一个吧。我现在使用的OpenCV 就是通过这个脚本编译出来的。脚本的内容如下-

#!/bin/bash
set -e
project_name="opencv/opencv"
VERSION=$(curl --silent "https://github.com/${project_name}/releases/latest" | sed 's#.*tag/\(.*\)\".*#\1#')

sudo apt-get -y install build-essential unzip pkg-config libomp5 libomp-dev
python3.7 -m pip install numpy setuptools wheel -U --user -q
if [ ! -d $HOME/Projects ]; then
  mkdir $HOME/Projects
fi
if [ ! -d $HOME/Downloads ]; then
  mkdir $HOME/Downloads
fi
#Download and unpack opencv source code
cd $HOME/Downloads
if [ ! -f opencv-${VERSION}.zip ]; then
  wget -O opencv-${VERSION}.zip https://github.com/opencv/opencv/archive/${VERSION}.zip -q -o /dev/null
fi
if [ ! -f opencv_contrib-${VERSION}.zip ]; then
  wget -O opencv_contrib-${VERSION}.zip https://github.com/opencv/opencv_contrib/archive/${VERSION}.zip -q -o /dev/null
fi
if [ -d opencv-${VERSION} ]; then
  /bin/rm -rf opencv-${VERSION}
fi
unzip ~/Downloads/opencv-${VERSION}.zip
if [ -d opencv_contrib-${VERSION} ]; then
  /bin/rm -rf opencv_contrib-${VERSION}
fi
unzip ~/Downloads/opencv_contrib-${VERSION}.zip
#install necessary library
sudo apt-get -y install libjpeg-dev libpng-dev libtiff-dev
sudo apt-get -y install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
sudo apt-get -y install libxvidcore-dev libx264-dev
sudo apt-get -y install libavcodec-dev libavformat-dev libswscale-dev libdc1394-22-dev
sudo apt-get -y install libxine2-dev libv4l-dev
sudo apt-get -y install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
sudo apt-get -y install libtbb-dev
#sudo apt-get -y install libgtk-3-dev libgtk2.0-dev qt5-default
sudo apt-get -y install libatlas-base-dev
sudo apt-get -y install software-properties-common
sudo add-apt-repository "deb http://security.ubuntu.com/ubuntu xenial-security main"
sudo apt-get -y update
sudo apt-get -y install libjasper1
Optional dependencies
#sudo apt-get -y install libprotobuf-dev protobuf-compiler
sudo apt-get -y install libgoogle-glog-dev libgflags-dev
sudo apt-get -y install libgphoto2-dev libeigen3-dev libhdf5-dev doxygen
#build source code
cd opencv-${VERSION}
mkdir build
cd build
cmake -G "Unix Makefiles"   -D CMAKE_BUILD_TYPE=RELEASE   -D CMAKE_INSTALL_PREFIX=/usr/local   -D INSTALL_PYTHON_EXAMPLES=OFF   -D BUILD_NEW_PYTHON_SUPPORT=ON   -D INSTALL_C_EXAMPLES=OFF   -D BUILD_TESTS=OFF   -D BUILD_PERF_TESTS=OF   -D WITH_OPENMP=ON   -D WITH_CUDA=ON   -D ENABLE_FAST_MATH=ON   -D CUDA_FAST_MATH=ON   -D WITH_CUDNN=ON   -D OPENCV_DNN_CUDA=ON   -D WITH_CUBLAS=ON   -D WITH_TBB=ON   -D WITH_V4L=ON   -D WITH_OPENGL=ON   -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${VERSION}/modules   -D PYTHON_DEFAULT_EXECUTABLE=/usr/bin/python3.7         -D PYTHON3_EXECUTABLE=/usr/bin/python3.7         -D PYTHON_INCLUDE_DIR=/usr/include/python3.7m         -D PYTHON_INCLUDE_DIR2=/home/ubuntu/.local/include/python3.7m         -D PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.7m.so -D BUILD_OPENCV_PYTHON3=ON   -D BUILD_OPENCV_PYTHON2=OFF   -D BUILD_OPENCV_JAVA=OFF   -D BUILD_EXAMPLES=OFF   -D OPENCV_ENABLE_NONFREE=ON   -D ENABLE_CXX11=ON   -D CUDA_ARCH_BIN="7.0"   -D CUDA_ARCH_PTX=""   -D WITH_NVCUVID=OFF   -D BUILD_OPENCV_CUDACODEC=OFF ..

make -j$(nproc) sudo make install sudo ldconfig

这个脚本看起来很长,内容却不复杂。我来给大家解释一下我的思路

VERSION=$(curl --silent "https://github.com/${project_name}/releases/latest" | sed 's#.*tag/\(.*\)\".*#\1#')

这一句使用来取得OpenCV 最新的版本号。这样可以确保我们每一次构建都能够获得最新的版本。

#install necessary library
sudo apt-get -y install libjpeg-dev libpng-dev libtiff-dev
sudo apt-get -y install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
sudo apt-get -y install libxvidcore-dev libx264-dev
sudo apt-get -y install libavcodec-dev libavformat-dev libswscale-dev libdc1394-22-dev
sudo apt-get -y install libxine2-dev libv4l-dev
sudo apt-get -y install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
sudo apt-get -y install libtbb-dev
#sudo apt-get -y install libgtk-3-dev libgtk2.0-dev qt5-default
sudo apt-get -y install libatlas-base-dev
sudo apt-get -y install software-properties-common
sudo add-apt-repository "deb http://security.ubuntu.com/ubuntu xenial-security main"
sudo apt-get -y update
sudo apt-get -y install libjasper1

这一段安装的是OpenCV所依赖的库。我们可以针对具体的需要酌情删减。

cmake -G "Unix Makefiles" \
  -D CMAKE_BUILD_TYPE=RELEASE \
  -D CMAKE_INSTALL_PREFIX=/usr/local \
  -D INSTALL_PYTHON_EXAMPLES=OFF \
  -D BUILD_NEW_PYTHON_SUPPORT=ON \
  -D INSTALL_C_EXAMPLES=OFF \
  -D BUILD_TESTS=OFF \
  -D BUILD_PERF_TESTS=OF \
  -D WITH_OPENMP=ON \
  -D WITH_CUDA=ON \
  -D ENABLE_FAST_MATH=ON \
  -D CUDA_FAST_MATH=ON \
  -D WITH_CUDNN=ON \
  -D OPENCV_DNN_CUDA=ON \
  -D WITH_CUBLAS=ON \
  -D WITH_TBB=ON \
  -D WITH_V4L=ON \
  -D WITH_OPENGL=ON \
  -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${VERSION}/modules \
  -D PYTHON_DEFAULT_EXECUTABLE=/usr/bin/python3.7 \
        -D PYTHON3_EXECUTABLE=/usr/bin/python3.7 \
        -D PYTHON_INCLUDE_DIR=/usr/include/python3.7m \
        -D PYTHON_INCLUDE_DIR2=/home/ubuntu/.local/include/python3.7m \
        -D PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.7m.so \
-D BUILD_OPENCV_PYTHON3=ON \
  -D BUILD_OPENCV_PYTHON2=OFF \
  -D BUILD_OPENCV_JAVA=OFF \
  -D BUILD_EXAMPLES=OFF \
  -D OPENCV_ENABLE_NONFREE=ON \
  -D ENABLE_CXX11=ON \
  -D CUDA_ARCH_BIN="7.0" \
  -D CUDA_ARCH_PTX="" \
  -D WITH_NVCUVID=OFF \
  -D BUILD_OPENCV_CUDACODEC=OFF ..

这是编译OpenCV 最重要的步骤,通过cmake 生成编译需要的Makefile。需要注意的是,在这个配置中我启用了对CUDA以及cuDNN 支持。如果我们仅仅需要一个支持CPU的版本可以关闭掉这几个选项。此外,由于重要用于Python3的环境之下,于是在编译中关闭了Python2 与Java的支持。

在一台P3 实例的机器上编译所需的时间不长,我们就得到了在Python 3中使用OpenCV的库- /home/ubuntu/.local/lib/python3.7/site-packages/cv2/python-3.7/cv2.cpython-37m-x86_64-linux-gnu.so 。测试一下,就看到了这个结果

好了,OpenvCV 已经大功告成。

CPU 运算的加速器- Intel Math Kernel Library (MKL)

Intel 的MKL是一个为科学、工程和金融应用程序以及机器学习优化数学例程的库。核心数学函数包括BLAS、LAPACK、ScaLAPACK、稀疏求解器、快速傅里叶变换和向量运算等。这个库自2003年出现以来,被广泛的用于利用Intel CPU 指令集中 AVX2、AVX512 等特性来提升运算处理性能。其性能表现可以参考MKL vs OpenBLAS 的一个性能对比。

需要强调一点,Intel 向开发者免费提供了MKL,在软件分发方面需要遵守Intel Simplified Software License,而要获得商业支持则需要付费购买。相比较起来,我们可能更熟悉MK-LDNN,这个项目是Intel 的一个开源产品,我们在许多框架当中例如Tensorflow、MXNet中都能看到它。与商业化的Intel MKL 不同,MKL-DNN采用的的是Apache 许可。不过Intel 现在有了一个名为oneAPI 的策略,于是MKL-DNN 被改称oneAPI Deep Neural Network Library (oneDNN)。而Intel MKL 也成为了oneAPI 下的一个重要的组件。与以往的注册、下载、安装不同,MKL 现在提供了一个简单的方法完成在Ubuntu 下的安装。

第一步:添加Intel 的oneAPI repo

#!/bin/bash
set -e

wget -q https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB -O /tmp/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB
if [ -f /tmp/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB ]; then
  sudo apt-key add /tmp/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB
  rm /tmp/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB
fi
#echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list
sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main"
sudo apt-get update

echo "Done."

第二步、安装Intel MKL

#!/bin/bash
sudo apt update
sudo apt-get install -y intel-mkl-2020.0-088
echo "Done."

第三步、安装其它Intel 的产品。

例如Intel 优化的Python 3 解释器以及TBB 。这里说的TBB指的是Intel 提供的一个C++模板库,用于多核处理器上的并行编程。使用TBB,计算被分解为可以并行运行的任务。该库管理并调度执行这些任务的线程。

#!/bin/bash
sudo apt update
sudo apt-get -y install intelpython3
sudo apt-get -y install intel-tbb-64bit-2020.0-088
echo "Done.

好了,Intel MKL 安装完毕。

深度学习框架- TensorFlow、PyTorch 以及MXNet

可以说,TensorFlow、Pytorch 以及Apache MXNet 是最为流行的深度学习框架了。无论是通过官网下载、PIP安装或者Anaconda 等等我们都可以非常容易的完成这几个框架的安装。但是,我们能够想到为了兼顾更为广泛的使用环境的匹配,我们能够得到这几个框架的安装包都只能进行有限度的优化。无非是区分一下使用GPU优化(CUDA、cuDNN)或者CPU优化(MKL-DNN)等等。至于完全匹配我们具体的运行环境的安装包就只能依靠我们自己动手了。

从我的体会来看,动手编译这几个框架固然比较麻烦。但是一来这样可以帮助我们更好的理解框架本身,二来性能提升的效果也是非常令人满意的。

动手编译TensorFlow

动手之前,我们先要解决的一件事就是Bazel 这个构建工具。完全是因为TensorFlow 才让我熟悉了这个工具。考虑到这是Google 的出品,就能够理解TensorFlow放弃Ninja、cmake等成熟工具而选用Bazel 的原因了。Bazel 的运行需要JVM的支持,因此我们需要首先完成JDK 的安装- sudo apt install openjdk-11-jdk。其次,Bazel 的安装有两种方法,第一种是使用Bazel’s apt repository 来进行安装。这种方法最为简单,但却不是我所推荐的方法。原因在于TensorFlow 需要依赖特定的Bazel 版本,于是Binary 安装包就成为了不二的选择。安装脚本如下 –

!/bin/bash
set -e

if ! [ -x "$(command -v curl)" ]; then
  sudo apt install curl -y
fi
#version for tensoflow
#VERSION=$(curl --silent "https://raw.githubusercontent.com/tensorflow/tensorflow/master/configure.py" | awk '/_TF_MAX_BAZEL_VERSION =/{print}' | sed 's/[^0-9|.]*//g')
#version for tensorflow 2.0
TF_VER="r2.2"
VERSION=$(curl --silent "https://raw.githubusercontent.com/tensorflow/tensorflow/${TF_VER}/configure.py" | awk '/_TF_MAX_BAZEL_VERSION =/{print}' | sed 's/[^0-9|.]*//g')
#TF_VER="r1.15"
#VERSION=$(curl --silent "https://raw.githubusercontent.com/tensorflow/tensorflow/${TF_VER}/configure.py" | awk '/_TF_MAX_BAZEL_VERSION =/{print}'| sed 's/[^0-9|.]*//g')
if [ -z $VERSION ]; then
  echo "Can not find the version of bazel."
  exit 1
fi
Install required packages
sudo apt-get -y install pkg-config zip   zlib1g-dev unzip curl
if [ -d "~/.bazel" ]; then
  /bin/rm  -fr $HOME/.bazel $HOME/.bazelrc $HOME/bin/bazel
fi
Download bazel
if [ ! -d "$HOME/Downloads" ]; then
  mkdir -p $HOME/Downloads
fi
cd $HOME/Downloads
if [[ ! -f "bazel-$VERSION-installer-linux-x86_64.sh" ]]; then
  curl -fSsL -O https://github.com/bazelbuild/bazel/releases/download/$VERSION/bazel-$VERSION-installer-linux-x86_64.sh
fi
Run the installer
chmod +x bazel-$VERSION-installer-linux-x86_64.sh
./bazel-$VERSION-installer-linux-x86_64.sh --user
Add $HOME/bin directory to your default paths

echo '#bazel' >> ~/.bashrc echo 'export PATH=$PATH:$HOME/bin' >> ~/.bashrc source $HOME/.bashrc $HOME/bin/bazel version echo "Done."

需要解释的一点,TensorFlow 1.X 与2.X 所使用的Bazel 版本不同,需要我们在脚本中通过注释的方法来选择版本。

TensorFlow 1.5.2

#!/bin/bash
set -e

project_name="tensorflow/tensorflow"
VERSION="1.15.2"
check wget
if ! [ -x "$(command -v wget)" ]; then
  echo 'Error: wget is not installed.' >&2¬
  sudo apt-get -y install wget
fi
#check directory
if [ ! -d $HOME/Downloads ]; then
  mkdir $HOME/Downloads
fi
cd $HOME/Downloads
if [ ! -f "v${VERSION}.tar.gz" ];then
  wget https://github.com/tensorflow/tensorflow/archive/v${VERSION}.tar.gz -O tensorflow-${VERSION}.tar.gz -q -o /dev/null
fi
if [ ! -d "$HOME/Projects" ]; then
  mkdir -p $HOME/Projects
fi
cd $HOME/Projects
if [ -d tensorflow-${VERSION} ]; then
  /bin/rm -rf tensorflow-${VERSION}
fi
tar xzvf $HOME/Downloads/tensorflow-${VERSION}.tar.gz
if [ ! -d $HOME/.venvs/tensorflow-1_env ]; then
  python3.7 -m venv $HOME/.venvs/tensorflow-1_env
fi
source $HOME/.venvs/tensorflow-1_env/bin/activate
pip install -U pip six numpy wheel setuptools mock future -q
pip install -U keras_applications --no-deps -q
pip install -U keras_preprocessing --no-deps -q
if [ -d tensorflow-${VERSION} ]; then
  cd tensorflow-${VERSION}
else
  echo "Can not find dir of tensorflow-${VERSION}."
  exit 1
fi
if [ -f "tf_config.sh" ]; then
  /bin/rm tf_config.sh
fi
cat <<EOT >> tf_config.sh
#!/bin/bash
source $HOME/.venvs/tensorflow-1_env/bin/activate
export PYTHONPATH=/home/ubuntu/.venvs/tensorflow-1_env/bin/python3
export PYTHON_BIN_PATH=/home/ubuntu/.venvs/tensorflow-1_env/bin/python3
export PYTHON_LIB_PATH=/home/ubuntu/.venvs/tensorflow-1_env/lib/python3.7/site-packages/
export TF_ENABLE_XLA=1
export TF_NEED_COMPUTECPP=1
export TF_NEED_OPENCL_SYCL=0
export TF_NEED_ROCM=0
export TF_CUDA_COMPUTE_CAPABILITIES="7.0,7.0,7.0,7.0"
export TF_NEED_CUDA=1
export TF_CUDA_VERSION="10.2"
export TF_CUDNN_VERSION="7"
export TF_NCCL_VERSION="2"
export CUDA_TOOLKIT_PATH=/usr/local/cuda
export CUDNN_INSTALL_PATH=/usr
export NCCL_INSTALL_PATH=/usr
export LD_LIBRARY_PATH="/usr/local/cuda-10.2/lib64:/usr/local/cuda-10.2/extras/CUPTI/lib64:"
export GCC_HOST_COMPILER_PATH="/usr/bin/gcc"
export TF_NEED_TENSORRT=0
export TF_NEED_MPI=1
export MPI_INSTALL_PATH=/usr
export MPI_HOME=/usr/local
export CC_OPT_FLAGS='-march=native -Wno-sign-compare'
export TF_CUDA_CLANG=0
export TF_CONFIGURE_IOS=False
export TF_SET_ANDROID_WORKSPACE=False
./configure
EOT
chmod +x tf_config.sh
if [ -f "build_tensorflow.sh" ]; then
  /bin/rm build_tensorflow.sh
fi
cat <<EOT >> build_tensorflow.sh
#!/bin/bash
VERSION="${VERSION}"
prefix=$(python3 -c "import sys;print(sys.prefix)")
if [[ ${prefix} == "tensorflow" ]];then
  echo "You are the venv of tensorflow..."
else
  source $HOME/.venvs/tensorflow-1_env/bin/activate
fi
export TMP=/tmp
bazel clean --expunge_async
bazel build --copt=-march=native --cxxopt=-march=native \
        -c opt --copt=-O3 \
        --config=cuda  \
        --config=v1 \
        --config=mkl \
        --config=nohdfs --config=noignite --config=nokafka \
        --verbose_failures \
        //tensorflow/tools/pip_package:build_pip_package
EOT
chmod +x build_tensorflow.sh
if [ -f "build_whl.sh" ]; then
  /bin/rm build_whl.sh
fi
cat <<EOT >> build_whl.sh
#!/bin/bash
VERSION="${VERSION}"
prefix=$(python3 -c "import sys;print(sys.prefix)")
if [[ ${prefix} == "tensorflow" ]];then
  echo "You are the venv of tensorflow..."
else
  source $HOME/.venvs/tensorflow-1_env/bin/activate
fi
export TMP=/tmp
bazel clean --expunge_async
bazel build --copt=-march=native --cxxopt=-march=native \
        -c opt --copt=-O3 \
        --config=cuda  \
        --config=v1 \
        --config=mkl \
        --config=nohdfs --config=noignite --config=nokafka \
        --verbose_failures \
        //tensorflow/tools/pip_package:build_pip_package
EOT
chmod +x build_tensorflow.sh
if [ -f "build_whl.sh" ]; then
  /bin/rm build_whl.sh
fi
cat <<EOT >> build_whl.sh
#!/bin/bash
if [ -d /tmp/tensorflow_pkg ]; then
  /bin/rm /tmp/tensorflow_pkg/*
fi
prefix=$(python3 -c "import sys;print(sys.prefix)")
if [[ ${prefix} == "tensorflow" ]];then
        echo "You are the venv of tensorflow..."
else
        source $HOME/.venvs/tensorflow-1_env/bin/activate
fi
./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
pip3 install /tmp/tensorflow_pkg/.whl -U
cp /tmp/tensorflow_pkg/.whl ~/Downloads
cd ..
python3 -c "import tensorflow as tf;print(tf.version)"
EOT
chmod +x build_whl.sh

deactivate echo "Done."

在上面的这个脚本中,我们在~/Project 下克隆了Tensorflow 1.52 的源代码,并且创建了 build_tesnsorflow.sh 与buuild_whel.sh 两个脚本文件。前一个脚本用来编译TensorFlow,后一个脚本用来生成python安装的whl 文件。

编译完成以后我们就得到了Python 包的安装文件tensorflow-1.15.2-cp37-cp37m-linux_x86_64.whl。检查一下可以看到这个结果 –

TensorFlow 2.2

TensorFlow 2.2 的安装与上述的过程比较类似,脚本也大体相同。

#!/bin/bash
set -e

BRANCH="r2.2"
CUDA_VER="10.2"
#check dir
if [ ! -d "$HOME/Projects" ]; then
  mkdir -p $HOME/Projects
fi
cd $HOME/Projects
if [ ! -d $HOME/.venvs/tensorflow-2_env ]; then
  python3.7 -m venv ~/.venvs/tensorflow-2_env
fi
source $HOME/.venvs/tensorflow-2_env/bin/activate
pip install -U pip six numpy wheel setuptools mock future -q
pip install -U keras_applications --no-deps -q
pip install -U keras_preprocessing --no-deps -q
check git
if ! [ -x "$(command -v git)" ]; then
  echo 'Error: git is not installed.' >&2
  sudo apt -y install git
fi
if [ -d tensorflow-2.x ]; then
  cd tensorflow-2.x
else
  git clone https://github.com/tensorflow/tensorflow.git tensorflow-2.x
  cd tensorflow-2.x
fi
git clean -f
git checkout ${BRANCH}
git pull
if [ -f "tf_config.sh" ]; then
  /bin/rm tf_config.sh
fi
cat <<EOT >> tf_config.sh
#!/bin/bash
source $HOME/.venvs/tensorflow-2_env/bin/activate
export PYTHONPATH=/home/ubuntu/.venvs/tensorflow-2_env/bin/python3
export PYTHON_BIN_PATH=/home/ubuntu/.venvs/tensorflow-2_env/bin/python3
export PYTHON_LIB_PATH=/home/ubuntu/.venvs/tensorflow-2_env/lib/python3.7/site-packages/
export TF_ENABLE_XLA=1
export TF_NEED_COMPUTECPP=1
export TF_NEED_OPENCL_SYCL=0
export TF_NEED_ROCM=0
export TF_CUDA_COMPUTE_CAPABILITIES="7.0,7.0,7.0,7.0"
export TF_NEED_CUDA=1
export TF_CUDA_VERSION="${CUDA_VER}"
export TF_CUDNN_VERSION="7"
export TF_NCCL_VERSION="2"
export CUDA_TOOLKIT_PATH=/usr/local/cuda
export CUDNN_INSTALL_PATH=/usr
export NCCL_INSTALL_PATH=/usr
export LD_LIBRARY_PATH="/usr/local/cuda-10.1/lib64:/usr/local/cuda-${CUDA_VER}/extras/CUPTI/lib64:"
export GCC_HOST_COMPILER_PATH="/usr/bin/gcc"
export TF_NEED_TENSORRT=1
export TensorRT=0
export TF_NEED_MPI=1
export MPI_INSTALL_PATH=/usr
export MPI_HOME=/usr/local
export CC_OPT_FLAGS='-march=native -Wno-sign-compare'
export TF_CUDA_CLANG=0
export TF_CONFIGURE_IOS=False
export TF_SET_ANDROID_WORKSPACE=False
./configure
deactivate
EOT
chmod +x tf_config.sh
cat <<EOT >> build_tensorflow.sh
#!/bin/bash
prefix=$(python3 -c "import sys;print(sys.prefix)")
if [[ ${prefix} == "tensorflow-2" ]];then
  echo "You are the venv of tensorflow..."
else
  source $HOME/.venvs/tensorflow-2_env/bin/activate
fi
export TMP=/tmp
bazel clean --expunge_async
bazel build --copt=-march=native --cxxopt=-march=native \
        -c opt --copt=-O3 \
        --config=cuda \
        --config=nohdfs \
        --verbose_failures \
        --config=v2 //tensorflow/tools/pip_package:build_pip_package
EOT
chmod +x build_tensorflow.sh
if [ -f "build_whl.sh" ]; then
  /bin/rm build_whl.sh
fi
cat <<EOT >> build_whl.sh
#!/bin/bash
if [ -d /tmp/tensorflow_pkg ];then
  /bin/rm /tmp/tensorflow_pkga/*
fi
prefix=$(python3 -c "import sys;print(sys.prefix)")
if [[ ${prefix} == "tensorflow-2" ]];then
        echo "You are the venv of tensorflow..."
else
        source $HOME/.venvs/tensorflow-2_env/bin/activate
fi
./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
pip3 install /tmp/tensorflow_pkg/.whl -U -q
cp /tmp/tensorflow_pkg/.whl ~/Downloads
cd ..
python3 -c "import tensorflow as tf;print(tf.version)"
EOT
chmod +x build_whl.sh

deactivate git status echo "Done."

在这台EC2 P3 8xlarge 的实例上,编译的过程需要大约4100s,也就是一个多小时的时间。提醒一下,不要忘记使用screen 确保网络断线的情况下编译的过程不会中断。

作为编译的结果,我们得到了这个文件tensorflow-2.2.0-cp37-cp37m-linux_x86_64.whl。检查一下版本

动手编译  PyTorch

相比较起来,PyTorch 的编译脚本要简单一些,编译的时间开销也要少一些。编译的脚本如下 –

#!/bin/bash
set -e

#check dir
if [ ! -d "$HOME/Projects" ]; then
  mkdir -p $HOME/Projects
fi
cd $HOME/Projects
check git
if ! [ -x "$(command -v git)" ]; then
  echo 'Error: git is not installed.' >&2
  sudo apt -y install git
fi
if [ -d $HOME/.venvs/pytorch_env ];then
  source $HOME/.venvs/pytorch_env/bin/activate
else
  echo "Please setup your pytorch env."
  exit 1
fi
sudo apt install -y libomp-dev libmpfr-dev libgmp-dev libfftw3-dev
pip3 install ninja setuptools wheel numpy pytest -U -q
pip3 install mypy mypy-extensions -U -q
if [ -d pytorch ]; then
  cd pytorch
  git clean -f
else
git pull repo
  git clone --recursive https://github.com/pytorch/pytorch
  cd pytorch
fi
if you are updating an existing checkout
git checkout master
git pull
git submodule sync
git submodule update --init --recursive
pip3 install -r requirements.txt -q
if [ -f  build_pytorch.sh ]; then
  /bin/rm build_pytorch.sh
Fi
cat <<EOT >> build_pytorch.sh
#!/bin/bash
/bin/rm -rf build/*
/bin/rm -rf dist/*
prefix=i$(python3 -c "import sys;print(sys.prefix)")
if [[ $prefix == "pytorch" ]];then
        echo "You are the venv of pytorch..."
else
        source $HOME/.venvs/pytorch_env/bin/activate
fi
python3 setup.py clean
USE_CUDA=1 \
USE_CUDNN=1 \
CUDNN_LIB_DIR=/usr/lib/x86_64-linux-gnu \
CUDNN_INCLUDE_DIR=/usr/include \
BUILD_TEST=0 \
USE_MKLDNN=1 \
USE_NNPACK=1 \
USE_DISTRIBUTED=1 \
USE_SYSTEM_NCCL=1 \
USE_NCCL=1 \
USE_OPENCV=1 \
NCCL_ROOT=/usr \
NCCL_INCLUDE_DIR=/usr/include \
NCCL_LIB_DIR=/usr/lib/x86_64-linux-gnu \
USE_TENSORRT=0 \
BUILD_BINARY=1 \
BUILD_TORCH=ON \
python3 setup.py bdist_wheel
#install torch
if [ -f dist/.whl ]; then
  pip3 install -U dist/.whl -q
  cp dist/*.whl ~/Downloads
fi
EOT

chmod +x build_pytorch.sh deactivate echo "Done."

编译成功以后我们就得到了一个Python 安装包- torch-1.6.0a0+30e7055-cp37-cp37m-linux_x86_64.whl。验证一下结果,

此外,我还可以从其它的几个方面针对PyTorch 进行优化,例如torchversion 以及pillow。具体说来就是针对这两个工具在编译中引入SIMD 以及AVX指令的优化,使之性能更加出色。这里说的SIMD指的是单指令流多数据流(Single Instruction Multiple Data)是一种采用一个控制器来控制多个处理器,同时对一组数据(又称“数据向量”)中的每一个分别执行相同的操作从而实现空间上的并行性的技术。

pillow-simd 的安装脚本如下 –

#!/bin/bash

sudo apt-get install -y     libjpeg-turbo8-dev     zlib1g-dev     libtiff5-dev     liblcms2-dev     libfreetype6-dev     libwebp-dev     libharfbuzz-dev     libfribidi-dev     libopenjp2-7-dev     libraqm0
prefix=$(python3 -c "import sys;print(sys.prefix)")
if [[ $prefix == "pytorch" ]];then
        echo "You are the venv of pytorch..."
else
        source $HOME/.venvs/pytorch_env/bin/activate
fi
pip3 uninstall -y pillow-simd || true
CC="cc -mavx2 -msse4" pip3 install --no-cache-dir -U -I --force-reinstall pillow-simd     --global-option="build_ext"     --global-option="--enable-zlib"     --global-option="--enable-jpeg"     --global-option="--enable-tiff"     --global-option="--enable-freetype"     --global-option="--enable-lcms"     --global-option="--enable-webp"     --global-option="--enable-webpmux"     --global-option="--enable-jpeg2000"
deactivate
prefix=$(python3 -c "import sys;print(sys.prefix)")
if [[ $prefix == "tensorflow" ]];then
        echo "You are the venv of tensorflow..."
else
        source $HOME/.venvs/tensorflow-2_env/bin/activate
fi
pip3 uninstall -y pillow-simd || true
CC="cc -mavx2 -msse4" pip3 install --no-cache-dir -U -I --force-reinstall pillow-simd     --global-option="build_ext"     --global-option="--enable-zlib"     --global-option="--enable-jpeg"     --global-option="--enable-tiff"     --global-option="--enable-freetype"     --global-option="--enable-lcms"     --global-option="--enable-webp"     --global-option="--enable-webpmux"     --global-option="--enable-jpeg2000"
deactivate
source $HOME/.venvs/tensorflow-1_env/bin/activate
pip3 uninstall -y pillow-simd || true
CC="cc -mavx2 -msse4" pip3 install --no-cache-dir -U -I --force-reinstall pillow-simd     --global-option="build_ext"     --global-option="--enable-zlib"     --global-option="--enable-jpeg"     --global-option="--enable-tiff"     --global-option="--enable-freetype"     --global-option="--enable-lcms"     --global-option="--enable-webp"     --global-option="--enable-webpmux"     --global-option="--enable-jpeg2000"
deactivate

echo "Done."

 

而torchversion 这个PyTorch 的最佳拍档,其安装脚本如下-

#!/bin/bash
set -e

#check dir
if [ ! -d "$HOME/Projects" ]; then
  mkdir -p $HOME/Projects
fi
cd $HOME/Projects
check git
if ! [ -x "$(command -v git)" ]; then
  echo 'Error: git is not installed.' >&2
  sudo apt-get -y install git
fi
sudo apt-get -y install libavcodec-dev libavformat-dev libswscale-dev
prefix=$(python3 -c "import sys;print(sys.prefix)")
if [[ $prefix == "pytorch" ]];then
  echo "You are the venv of pytorch..."
else
  source $HOME/.venvs/pytorch_env/bin/activate
fi
#uninstall torchvision
pip3 uninstall -y vision || true
git pull repo
if [ ! -d vision ];then
  git clone https://github.com/pytorch/vision.git
fi
cd vision
git checkout master
git pull
#if [ -d build ];then
/bin/rm -rf build/*
/bin/rm -rf dist/*
#fi
python3 setup.py clean
FORCE_CUDA=1 python3 setup.py bdist_wheel
if [ -f dist/.whl ]; then
  pip3 install -U dist/.whl -q
  cp dist/*.whl ~/Downloads
fi
deactivate

echo "Done."

这里一个主要的优化手段就是使得torchvision 使用GPU 来进行加速。

动手编译 Apache MXNet

MXNet 这个项目虽非声名显赫,但其巨大的进步也是有目共睹,最新版本已经发展到了1.6.0。对我来说,我更期待其2.0的版本。在MXNet 2.0 Roadmap 中我们看到了许多令人激动的特性,希望这个版本正式发布的日子早点到了。

编译MXNet 不是件麻烦的事情,在官方文档中有详尽的描述。我的编译脚本是这样的-

#!/bin/bash
set -e

project_name="apache/incubator-mxnet"
VERSION=$(curl --silent "https://github.com/${project_name}/releases/latest" | sed 's#.*tag/v(.)".#\1#')
sudo apt-get update
sudo apt-get install -y ninja-build ccache libopenblas-base libopenblas-dev libjemalloc-dev liblapack-dev graphviz
if ! [ -x "$(command -v cmake)" ]; then
  echo "Please install cmake."
  exit 1
fi
#check dir
if [ ! -d "$HOME/Projects" ]; then
  mkdir -p $HOME/Projects
fi
cd $HOME/Projects
if [ ! -d $HOME/.venvs/mxnet_env ]; then
  python3.7 -m venv ~/.venvs/mxnet_env
fi
source $HOME/.venvs/mxnet_env/bin/activate
pip3 install -U pip numpy wheel setuptools graphviz -q
check git
if ! [ -x "$(command -v git)" ]; then
  echo 'Error: git is not installed.' >&2
  sudo apt -y install git
fi
if [ -d mxnet ]; then
  cd mxnet
  git pull
  git submodule sync
  git submodule update --init --recursive
else
  git clone --recursive https://github.com/apache/incubator-mxnet.git mxnet
  cd mxnet
fi
git clean -f
#git checkout tags/${VERSION}
/bin/rm -rf build
fi
cd build
cmake -GNinja     -DUSE_CUDA=ON     -DUSE_CUDNN=ON     -DUSE_NCCL=ON     -DUSE_LAPACK=1     -DUSE_OPENMP=1     -DUSE_OPENCV=1     -DUSE_DIST_KVSTORE=0     -DUSE_MKL_IF_AVAILABLE=ON     -DCMAKE_BUILD_TYPE=Release ..
ninja -v
if [ -f libmxnet.so ];then
  cp libmxnet.so $HOME/.venvs/mxnet_env/lib/python3.7/site-packages/mxnet/
else
  echo "Build libmxnet failed."
  exit 1
fi
install python package
cd ../python
python3 setup.py bdist_wheel
if [ -f dist/.whl ]; then
  pip3 install -U dist/.whl -q
  cp dist/*.whl ~/Downloads
  sudo ldconfig
fi

echo "Done."

好了,到这里这个系列终于可以告一段落了。其实,在我的构思中其实还有一些内容来不及加入进来,例如Horovod、JupyterLab、TensorFlow Lite 以及TVM 等等。如果有机会,我还是希望能够与各位分享这些内容。随着时间的推移,更多有意思的内容也会不断的涌现,就像是我现在正在玩 的YOLOv4 一样。希望这些内容能够对各位有所稗益,也预祝各位在技术的海洋中自得其乐。