源码编译不需要眼泪! MacOS 成功编译 TensorFlow 源码!

源码编译不需要眼泪! MacOS 成功编译 TensorFlow 源码!

最近打算开始研究下 TensorFlow, 想着以后可能要写一些 Ops, 因此有必要从源码开始编译 TF. 预想到可能会遇到很多问题, 而事实上 TF 果然诚不我欺, 给我留下了一大堆让人摸不着头脑的编译 Errors, 好在凭着自己的智慧、勇气和坚持 😋, 花了数个小时终于编译成功 ✌️✌️✌️. 此文用来纪念那些为编译 TF 而逝去的的美好时光以及凋零的脑细胞 🤣.

广而告之

可以在微信中搜索 “珍妮的算法之路” 或者 “world4458” 关注我的微信公众号;另外可以看看知乎专栏 PoorMemory-机器学习, 以后文章也会发在知乎专栏中;

重要的事提前说

编译完成, 总结避免重复采坑的经验如下, 可以进行参考:

  • 我编译的 TensorFlow 版本为 v1.10.0;
  • Bazel 版本很重要, 目前用的是 1.2.1;
  • 不建议用 Anaconda 进行编译, 可以先创建一个 virtualenv, 如: conda create -n tf1.10 python=3.5, 默认安装了 3.5.6 的 Python. (不要采用 3.7 的 Python, 会有各种问题).
  • 可以先用 pip install tensorflow==v1.10.0 对 TensorFlow 进行安装, 这样 pip 会自动下载所需要的 Python 库, 而且还是正确的版本, 避免自己手动安装. (如果需要手动安装, 可以在文件 tensorflow/tools/pip_package/setup.py 中查看 REQUIRED_PACKAGES. )

完整过程

TF 源码下载

https://github.com/tensorflow/tensorflow 下载最新的 TF 源码:

git clone --recursive https://github.com/tensorflow/tensorflow

我目前下载的源码, 其 master 分支的 commit id 为: 3fa68e2d8835f4dd231b9c767517a9dcec26c6a9. 由于我想编译的是 v1.10.0 版本的 TF, 故使用:

git checkout v1.10.0

命令切换到 v1.10.0 分支.

Bazel 安装

TensorFlow 项目采用 Bazel 进行编译, 需要先安装 Bazel. 注意 Bazel 的版本要和 TensorFlow 版本匹配, 我证明了 Bazel 1.2.1 版本是可以没有问题的. MacOS 一般采用 HomeBrew 来安装软件, 参考 https://docs.bazel.build/versions/master/install-os-x.html 可以获得用 HomeBrew 安装 Bazel 的方法. 但该方法默认安装最新版的 Bazel. 为了安装特定版本的 Bazel, 这里提一个我发现的 Trick.

  1. 卸载 bazel 的方法是: brew uninstall bazel.
  2. 首先到 https://github.com/bazelbuild/homebrew-tap/blob/master/Formula/bazel.rb, 下载该 bazel.rb 文件到本地:
# bazel.rb
class Bazel < Formula
  desc "Fast, scalable, multi-language and extensible build system"
  homepage "https://bazel.build/"
  url "https://releases.bazel.build/2.0.0/release/bazel-2.0.0-installer-darwin-x86_64.sh", :using => :nounzip
  version "2.0.0"
  sha256 "c675fa27d99a3114d681db10eb03ded547c40f702b2048c99b8f4ea8e89b9356"

  bottle :unneeded

  def install
    chmod 0555, "bazel-#{version}-installer-darwin-x86_64.sh"
    system "./bazel-#{version}-installer-darwin-x86_64.sh", "--prefix=#{buildpath}"
    bin.install "lib/bazel/bin/bazel" => "bazel"
    bin.install "lib/bazel/bin/bazel-real" => "bazel-real"
    bash_completion.install "lib/bazel/bin/bazel-complete.bash"
    zsh_completion.install "lib/bazel/bin/_bazel"
  end

  test do
    touch testpath/"WORKSPACE"
    (testpath/"Main.java").write <<~EOS
      public class Main {
        public static void main(String... args) {
          System.out.println("Hello world!");
        }
      }
    EOS
    (testpath/"BUILD").write <<~EOS
      java_binary(
        name = "main",
        srcs = ["Main.java"],
        main_class = "Main",
      )
    EOS
    system bin/"bazel", "build", "//:main"
    system "bazel-bin/main"
  end
end

观察该脚本可以发现, 它其实是下载 bazel-<version>-installer-darwin-x86_64.sh 这个脚本来实现对 Bazel 的安装, 但需要我们额外提供 sha256. 我们可以将 url 这个字段中的 2.0.0 全部改为 1.2.1, 同时将 version 中的 2.0.0 也改成 1.2.1, 注释 bash_completion.install 以及 zsh_completion.install 两行 (用 # 可以进行注释),

然后运行:

brew install bazel.rb

命令报错, 提示信息如下:
brew install bazel.rb 的结果

替换 bazel.rb 中的 sha256 值, 得到文本如下:

class Bazel < Formula
  desc "Fast, scalable, multi-language and extensible build system"
  homepage "https://bazel.build/"
  url "https://releases.bazel.build/1.2.1/release/bazel-1.2.1-installer-darwin-x86_64.sh", :using => :nounzip
  version "1.2.1"
  #sha256 "c675fa27d99a3114d681db10eb03ded547c40f702b2048c99b8f4ea8e89b9356"
  sha256 "59e469bf1d8d1615b67856ea17e761be05e9c92b462e55c0354cd78145b480d5"

  bottle :unneeded

  def install
    chmod 0555, "bazel-#{version}-installer-darwin-x86_64.sh"
    system "./bazel-#{version}-installer-darwin-x86_64.sh", "--prefix=#{buildpath}"
    bin.install "lib/bazel/bin/bazel" => "bazel"
    bin.install "lib/bazel/bin/bazel-real" => "bazel-real"
    #bash_completion.install "lib/bazel/bin/bazel-complete.bash"
    #zsh_completion.install "lib/bazel/bin/_bazel"
  end

  test do
    touch testpath/"WORKSPACE"
    (testpath/"Main.java").write <<~EOS
      public class Main {
        public static void main(String... args) {
          System.out.println("Hello world!");
        }
      }
    EOS
    (testpath/"BUILD").write <<~EOS
      java_binary(
        name = "main",
        srcs = ["Main.java"],
        main_class = "Main",
      )
    EOS
    system bin/"bazel", "build", "//:main"
    system "bazel-bin/main"
  end
end

再次运行: brew install bazel.rb, 成功安装 Bazel.

另外, Bazel 的 Github 库也 Release 了 1.2.1 版本, 如: https://github.com/bazelbuild/bazel/releases/tag/1.2.1, 然而按照我上面的方式做, 可以用 HomeBrew 来管理 Bazel, 方便卸载或安装其他的版本.

Python 虚拟环境

如果安装了 Anconda 发行版的话, 建议创建一个 Python 虚拟环境来编译 TF. 暂时无法断言 Anaconda 对 TF 的编译有不良影响, 但采坑经验告诉我最好还是额外创建一个虚拟环境. 另外, Python 的版本也至关重要, 选择 Python 3.5.

# 进入 tf 源码目录
cd tensorflow/
# 创建虚拟环境, Python 版本最后为 3.5.6
conda create -n tf1.10 python=3.5
# 激活虚拟环境
conda activate tf1.10

编译 TF 还需要一些 Python 包, 可以通过:

pip install tensorflow==v1.10.0

进行安装, 避免了手动安装的麻烦~.

TensorFlow 的编译

先做一些准备工作:

## 虽然上面已经说过了, 再说一遍, 先进入 TensorFlow 源码目录
cd tensorflow/
git checkout v1.10.0

然后参照 Building and Installing TensorFlow from Source on Your Mac , 下载 build_tf.sh 脚本到当前目录中, 增加执行权限并运行该文件, 即可正常编译 TensorFlow.

chmod +x build_tf.sh

为了避免该脚本的链接失效, 将内容拷贝至此处:

# Check whether script is executing in a VirtualEnv or Conda environment
if [ -z "$VIRTUAL_ENV" ] && [ -z "$CONDA_PREFIX" ] ; then
	echo "VirtualEnv or Conda env is not activated"
	exit -1
fi

# Set the virtual environment path
if ! [ -z "$VIRTUAL_ENV" ] ; then
  VENV_PATH=$VIRTUAL_ENV
elif ! [ -z "$CONDA_PREFIX" ] ; then
  VENV_PATH=$CONDA_PREFIX
fi

# Set the bin and lib directories
VENV_BIN=$VENV_PATH/bin
VENV_LIB=$VENV_PATH/lib

# bazel tf needs these env vars
export PYTHON_BIN_PATH=$VENV_BIN/python
export PYTHON_LIB_PATH=`ls -d $VENV_LIB/*/ | grep python`

# Set the native architecture optimization flag, which is a default
COPT="--copt=-march=native"

# Determine the available features of your CPU
raw_cpu_flags=`sysctl -a | grep machdep.cpu.features | cut -d ":" -f 2 | tr '[:upper:]' '[:lower:]'`

# Append each of your CPU's features to the list of optimization flags
for cpu_feature in $raw_cpu_flags
do
	case "$cpu_feature" in
		"sse4.1" | "sse4.2" | "ssse3" | "fma" | "cx16" | "popcnt" | "maes")
		    COPT+=" --copt=-m$cpu_feature"
		;;
		"avx1.0")
		    COPT+=" --copt=-mavx"
		;;
		*)
			# noop
		;;
	esac
done

# First ensure a clear working directory in case you've run bazel previously
bazel clean

# Run TensorFlow configuration (accept defaults unless you have a need)
./configure

# Build the TensorFlow pip package
bazel build -c opt $COPT -k //tensorflow/tools/pip_package:build_pip_package
bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg

我的小 MBP 花了好一段时间才将 TensorFlow 编译好, 编译成 .whl 文件保存到 /tmp/tensorflow_pkg 目录中.

至此, MacOS 上编译 TensorFlow 这一旅程终于结束了. 今早运行脚本之后和朋友逛了国家博物馆, 回来后发现编译成功了! 我无法想象拖着疲惫的身躯回到家后看到电脑屏幕显示的是 Build Failed 字样的结果.

Issues

编译过程中遇到了大量的问题, 编译成功之后就选择性地忘了曾经的伤痛, 而下面的网页则帮我记录了这些伤痕, 它们是否能称为其他人的良药呢… 🤣

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!要编译 Qt 模块的源码,你可以按照以下步骤进行操作: 1. 下载 Qt 源码:你可以在 Qt 的官方网站(https://www.qt.io/download)上找到最新的 Qt 源码包。选择适合你系统的版本,并将其下载到本地。 2. 安装依赖项:在编译 Qt 源码之前,你需要安装一些依赖项。这些依赖项可能因操作系统而异,你可以参考 Qt 官方文档(https://doc.qt.io/qt-5/linux-requirements.html)或相关的 Qt 文档来了解需要安装的依赖项。 3. 解压源码包:将下载的源码包解压到一个目录中。 4. 配置编译选项:在解压后的源码目录下,打开一个终端或命令行窗口,执行以下命令来配置编译选项: ``` ./configure ``` 这将开始配置编译环境,并检查你系统上的依赖项是否满足需求。根据你的需求,你可以添加一些额外的参数来进行更详细的配置。可以执行 `./configure --help` 命令来查看所有可用的选项。 5. 开始编译:配置完成后,执行以下命令来开始编译: ``` make ``` 这将开始编译 Qt 源码编译过程可能需要一些时间,取决于你的系统性能和源码的大小。 6. 安装编译结果:编译完成后,执行以下命令来安装编译结果: ``` make install ``` 这将安装编译好的 Qt 模块到默认的安装目录中。 注意:上述步骤仅适用于 Linux 和 macOS 系统。如果你使用的是 Windows 系统,你可以参考 Qt 官方文档或相关的 Qt 文档来了解如何在 Windows 上编译 Qt 源码。 希望这些步骤能帮助到你成功编译 Qt 模块的源码!如果还有其他问题,请随时向我提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值