LoginSignup
13
5

More than 3 years have passed since last update.

QEMU4.0.0 のハードウェアエミュレーションモードで Debian Buster armhf のOSイメージをゼロから作成する方法 (Kernel 4.19.0-5-armmp-lpae, Tensorflow armhfビルド用)

Last updated at Posted at 2019-07-25

Tensorflow-bin GitHub stars

Bazel_bin GitHub stars

1.Introduction

私はいつも、RaspberryPi3 で Tensorflow をビルドしています。 ただ、Tensorflow はビルドをするために大量のリソースを消費するため、RaspberryPi3 の RAM 1GB では SWAP が大量に発生して micorSDカード を破壊してしまいます。 そこで、Raspbian Buster とほぼ同じ環境を QEMU 4.0.0 の仮想環境上に構築し、さらに、 RAM 4GB + CPU 4core を実現したうえで、 Tensorflow をビルドしようとしました。 OSをイチからインストールする手順ですのでとても時間が掛かりますが、確実に起動に成功する手順をココに残します。 Tensorflow を自力でビルドする理由は、公式のパッケージがバグっているということと、Tensorflow Lite がデフォルトで無効になっているのを自力で解消しているということだけです。

なお、巷には QEMU の STATICモード による環境構築手順の記事があちこちにありますが、 対象OSが Jessie/Stretch であったり、RAM が 256MB かつ CPU が シングルコア だったり、QEMU のI/O周りにバグがあってまともに動作しなかったり、ネットワークが使えなかったりと、どれもとても使用に耐える環境ではありませんでした。 また、STATICモードは爆速なのですが、規模の大きめなパッケージをビルドしようとすると、途端に QEMU STATICモジュール のバグに遭遇してうまくビルドできません。 ちなみに、Dockerベースのクロスコンパイルを提案している多くの記事は、Dockerのバックグラウンドで QEMU の STATICモジュール を使用していますので、ビルド対象によっては失敗します。 私はビルドスピードを向上することを目的としているわけではなく、ビルドを完走させることが本質と考えていますので、あえて低速なハードウェアエミュレーションモードを採用しています。

今回も、必要なリソース一式を全て公式サイトからダンロードすると遅すぎて日が暮れてしまいますので、私の Google Drive に必要なものをアップロードしました。 QEMUを除く大容量のリソースは私の Google Drive から高速にダウンロードできるようにしてあります。

今回の手順を実施済みのイメージはこの記事の こちらのリンク からダウンロード可能です。

2.Environment

  • Ubuntu 16.04 x86_64 (Host PC)
  • QEMU 4.0.0
  • Debian Buster armhf/armv7l (Python 3.7.3)

3.Procedure

3−1.Build and install QEMU 4.0.0.

Setting_of_QEMU_4.0.0
$ sudo apt-get update

$ cd ~
$ wget https://download.qemu.org/qemu-4.0.0.tar.xz
$ tar xvJf qemu-4.0.0.tar.xz
$ cd qemu-4.0.0
$ ./configure
$ make -j8
$ sudo make install
$ qemu-system-arm --version

QEMU emulator version 4.0.0
Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers

3−2.Installing Debian Buster armhf

Run_the_Debian_Buster_armhf_installer
$ cd ~
$ mkdir qemu-system-debian-armhf;cd qemu-system-debian-armhf/

# vmlinuz download 
$ curl -sc /tmp/cookie "https://drive.google.com/uc?export=download&id=15cwDe68vMRoPmz2z789C0_LDElDVHDIx" > /dev/null
$ CODE="$(awk '/_warning_/ {print $NF}' /tmp/cookie)"
$ curl -Lb /tmp/cookie "https://drive.google.com/uc?export=download&confirm=${CODE}&id=15cwDe68vMRoPmz2z789C0_LDElDVHDIx" -o installer-vmlinuz

# initrd.gz download
$ curl -sc /tmp/cookie "https://drive.google.com/uc?export=download&id=1bTMiZ9Nmi1pjguf4wHRkaYaNb_Jb9Pe7" > /dev/null
$ CODE="$(awk '/_warning_/ {print $NF}' /tmp/cookie)"
$ curl -Lb /tmp/cookie "https://drive.google.com/uc?export=download&confirm=${CODE}&id=1bTMiZ9Nmi1pjguf4wHRkaYaNb_Jb9Pe7" -o installer-initrd.gz

# Create disk image
$ qemu-img create -f qcow2 hda.qcow2 20G

# Launch Installer
$ qemu-system-arm -M virt -m 1024 \
  -kernel installer-vmlinuz \
  -initrd installer-initrd.gz \
  -drive if=none,file=hda.qcow2,format=qcow2,id=hd \
  -device virtio-blk-device,drive=hd \
  -netdev user,id=mynet \
  -device virtio-net-device,netdev=mynet \
  -nographic -no-reboot

Screenshot 2019-07-06 00:28:57.png
Screenshot 2019-07-06 00:29:52.png
Screenshot 2019-07-06 00:30:26.png
Screenshot 2019-07-06 00:32:54.png
Screenshot 2019-07-06 00:33:19.png
Screenshot 2019-07-06 00:34:52.png
Screenshot 2019-07-06 00:35:50.png
Screenshot 2019-07-06 00:36:17.png
Screenshot 2019-07-06 00:36:47.png
Screenshot 2019-07-06 00:37:09.png
Screenshot 2019-07-06 00:37:53.png
Screenshot 2019-07-06 00:42:33.png
Screenshot 2019-07-06 00:43:38.png
Screenshot 2019-07-06 00:44:45.png
Screenshot 2019-07-06 00:45:37.png
Screenshot 2019-07-06 00:46:09.png
Screenshot 2019-07-06 00:46:34.png
Screenshot 2019-07-06 00:47:46.png
Screenshot 2019-07-06 00:48:24.png
Screenshot 2019-07-06 00:50:09.png
Screenshot 2019-07-06 00:50:38.png
Screenshot 2019-07-06 01:02:53.png
Screenshot 2019-07-06 01:03:32.png
Screenshot 2019-07-06 14:23:53.png
Screenshot 2019-07-06 01:04:44.png
Screenshot 2019-07-06 01:06:15.png
Screenshot 2019-07-06 01:43:38.png
Screenshot 2019-07-06 01:44:27.png
Screenshot 2019-07-06 01:46:24.png
Screenshot 2019-07-06 01:47:57.png
Screenshot 2019-07-21 22:11:11.png
Screenshot 2019-07-21 22:11:18.png
Screenshot 2019-07-21 22:11:32.png
Screenshot 2019-07-21 22:12:02.png
Screenshot 2019-07-21 22:12:29.png
Screenshot 2019-07-21 22:13:24.png
Screenshot 2019-07-21 22:14:15.png

3−3.Extract kernel for running Debian Buster armhf

Kernel_extraction
$ sudo apt-get install -y libguestfs-tools

$ cd ~/qemu-system-debian-armhf
$ sudo virt-ls -a hda.qcow2 /boot/

System.map-4.19.0-5-armmp-lpae
config-4.19.0-5-armmp-lpae
initrd.img
initrd.img-4.19.0-5-armmp-lpae
initrd.img.old
lost+found
vmlinuz
vmlinuz-4.19.0-5-armmp-lpae
vmlinuz.old

$ sudo virt-copy-out -a hda.qcow2 /boot/vmlinuz-4.19.0-5-armmp-lpae /boot/initrd.img-4.19.0-5-armmp-lpae .

Screenshot 2019-07-21 22:27:11.png

3−4.Start Debian Buster armhf (CPU 4core, RAM 4GB)

Start_Debian_Buster_armhf_with_4GB_RAM_and_CPU_4core_configuration
$ qemu-system-arm -M virt -m 4096 -smp 4 \
  -kernel vmlinuz-4.19.0-5-armmp-lpae \
  -initrd initrd.img-4.19.0-5-armmp-lpae \
  -append 'root=/dev/vda2' \
  -drive if=none,file=hda.qcow2,format=qcow2,id=hd \
  -device virtio-blk-device,drive=hd \
  -netdev user,id=mynet \
  -device virtio-net-device,netdev=mynet \
  -nographic

Screenshot 2019-07-25 22:56:09.png

3−5.Install sudo command

Enable_sudo_command
$ su -
# apt-get update
# apt-get install sudo
# visudo

====================================
# User privilege specification
root    ALL=(ALL:ALL) ALL
debian  ALL=(ALL) ALL
====================================

# exit

4.Finally

CPU 4core かつ RAM 4GB の環境、最高!!
RaspberryPi4、早く技適通して日本で販売して欲しい。。。

5.Resources

Installation kernel
https://drive.google.com/open?id=15cwDe68vMRoPmz2z789C0_LDElDVHDIx
https://drive.google.com/open?id=1bTMiZ9Nmi1pjguf4wHRkaYaNb_Jb9Pe7

Boot kernel
https://drive.google.com/open?id=1VYQLbATeLxBM30mfGllqvC5tldjAaAxr
https://drive.google.com/open?id=1-i6-bsv8ZNIc4a3wtM1pVnz8B9nVXCn4

Debian Buster installed qcow2 file
【caution】 Change your password to something strong.
debian / p[ssw0rd
英語キーボード設定になっていますので [ は、日本語キーボードの @ に読み替える必要があります。
https://drive.google.com/open?id=1Q6TQ0sDGjucdiUfvmn6ZqXHoSQoMWL6E

6.Appendix (Build Tensorflow for RaspberryPi3/4)

Tensorflow build procedure.

6−1.Expansion of SWAP area (100MB -> 3GB)

Install_dphys-swapfile
$ sudo apt-get install dphys-swapfile
$ free -m
              total        used        free      shared  buff/cache   available
Mem:           4042          53        3780           5         208        3822
Swap:          3021           0        3021

6−2.pip command installation

Install_pip_command
$ sudo apt-get install -y python3-pip
$ sudo pip3 install pip --upgrade

6−3.Installation of various tools

Install_tools
$ sudo apt-get install -y cmake make zip unzip git wget curl

6−4.Tensorflow build

Build_Tensorflow
$ sudo apt-get install -y libhdf5-dev libc-ares-dev libeigen3-dev openjdk-11-jdk
$ sudo pip3 install keras_applications==1.0.7 --no-deps
$ sudo pip3 install keras_preprocessing==1.0.9 --no-deps
$ wget https://github.com/PINTO0309/Tensorflow-bin/raw/master/packages/numpy-1.16.4-cp37-cp37m-linux_armv7l.whl
$ wget https://github.com/PINTO0309/Tensorflow-bin/raw/master/packages/h5py-2.9.0-cp37-cp37m-linux_armv7l.whl
$ sudo pip3 install numpy-1.16.4-cp37-cp37m-linux_armv7l.whl
$ sudo pip3 install h5py-2.9.0-cp37-cp37m-linux_armv7l.whl
$ sudo apt-get install -y openmpi-bin libopenmpi-dev
$ sudo -H pip3 install -U --user six numpy wheel mock
$ sudo apt update;sudo apt upgrade

$ cd ~
$ git clone https://github.com/PINTO0309/Bazel_bin.git
$ Bazel_bin/0.24.1/Raspbian_Buster_armhf/install.sh

$ cd ~
$ git clone -b v1.14.0 https://github.com/tensorflow/tensorflow.git
$ cd tensorflow
$ git checkout -b v1.14.0

The following problem was solved.
#15062, #21574, #21855, #23082, #25120, #25748, #29617, #30359

tensorflow/lite/python/interpreter.py
# Add the following two lines to the last line
  def set_num_threads(self, i):
    return self._interpreter.SetNumThreads(i)
tensorflow/lite/python/interpreter_wrapper/interpreter_wrapper.cc
// Corrected the vicinity of the last line as follows
PyObject* InterpreterWrapper::ResetVariableTensors() {
  TFLITE_PY_ENSURE_VALID_INTERPRETER();
  TFLITE_PY_CHECK(interpreter_->ResetVariableTensors());
  Py_RETURN_NONE;
}

PyObject* InterpreterWrapper::SetNumThreads(int i) {
  interpreter_->SetNumThreads(i);
  Py_RETURN_NONE;
}

}  // namespace interpreter_wrapper
}  // namespace tflite
tensorflow/lite/python/interpreter_wrapper/interpreter_wrapper.h
  // should be the interpreter object providing the memory.
  PyObject* tensor(PyObject* base_object, int i);

  PyObject* SetNumThreads(int i);

 private:
  // Helper function to construct an `InterpreterWrapper` object.
  // It only returns InterpreterWrapper if it can construct an `Interpreter`.
tensorflow/lite/tools/make/Makefile
BUILD_WITH_NNAPI=false
tensorflow/contrib/__init__.py
from tensorflow.contrib import checkpoint
#if os.name != "nt" and platform.machine() != "s390x":
#  from tensorflow.contrib import cloud
from tensorflow.contrib import cluster_resolver
tensorflow/contrib/__init__.py
from tensorflow.contrib.summary import summary

if os.name != "nt" and platform.machine() != "s390x":
  try:
    from tensorflow.contrib import cloud
  except ImportError:
    pass

from tensorflow.python.util.lazy_loader import LazyLoader
ffmpeg = LazyLoader("ffmpeg", globals(),
                    "tensorflow.contrib.ffmpeg")
configure
$ ./configure 
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.google.protobuf.UnsafeUtil (file:/home/debian/.cache/bazel/_bazel_debian/install/f61ff4d38c27bd5cacd410a0fc62f7e0/_embedded_binaries/A-server.jar) to field java.nio.Buffer.address
WARNING: Please consider reporting this to the maintainers of com.google.protobuf.UnsafeUtil
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
WARNING: --batch mode is deprecated. Please instead explicitly shut down your Bazel server using the command "bazel shutdown".
You have bazel 0.24.1- (@non-git) installed.


Please specify the location of python. [Default is /usr/bin/python]: /usr/bin/python3

Found possible Python library paths:
  /usr/local/lib/python3.7/dist-packages
  /usr/lib/python3/dist-packages
Please input the desired Python library path to use.  Default is [/usr/local/lib/python3.7/dist-packages]

Do you wish to build TensorFlow with XLA JIT support? [Y/n]: n
No XLA JIT support will be enabled for TensorFlow.

Do you wish to build TensorFlow with OpenCL SYCL support? [y/N]: n
No OpenCL SYCL support will be enabled for TensorFlow.

Do you wish to build TensorFlow with ROCm support? [y/N]: n
No ROCm support will be enabled for TensorFlow.

Do you wish to build TensorFlow with CUDA support? [y/N]: n
No CUDA support will be enabled for TensorFlow.

Do you wish to download a fresh release of clang? (Experimental) [y/N]: n
Clang will not be downloaded.

Do you wish to build TensorFlow with MPI support? [y/N]: n
No MPI support will be enabled for TensorFlow.

Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -march=native -Wno-sign-compare]: 


Would you like to interactively configure ./WORKSPACE for Android builds? [y/N]: n
Not configuring the WORKSPACE for Android builds.

Preconfigured Bazel build configs. You can use any of the below by adding "--config=<>" to your build command. See .bazelrc for more details.
    --config=mkl            # Build with MKL support.
    --config=monolithic     # Config for mostly static monolithic build.
    --config=gdr            # Build with GDR support.
    --config=verbs          # Build with libverbs support.
    --config=ngraph         # Build with Intel nGraph support.
    --config=numa           # Build with NUMA support.
    --config=dynamic_kernels    # (Experimental) Build kernels into separate shared objects.
Preconfigured Bazel build configs to DISABLE default on features:
    --config=noaws          # Disable AWS S3 filesystem support.
    --config=nogcp          # Disable GCP support.
    --config=nohdfs         # Disable HDFS support.
    --config=noignite       # Disable Apache Ignite support.
    --config=nokafka        # Disable Apache Kafka support.
    --config=nonccl         # Disable NVIDIA NCCL support.
Configuration finished

High speed build with 4GB of RAM and 2core CPU.

Build_Tensorflow
$ sudo bazel build \
--config=opt \
--config=noaws \
--config=nogcp \
--config=nohdfs \
--config=noignite \
--config=nokafka \
--config=nonccl \
--local_resources=4096.0,2.0,1.0 \
--copt=-mfpu=neon-vfpv4 \
--copt=-ftree-vectorize \
--copt=-funsafe-math-optimizations \
--copt=-ftree-loop-vectorize \
--copt=-fomit-frame-pointer \
--copt=-DRASPBERRY_PI \
--host_copt=-DRASPBERRY_PI \
//tensorflow/tools/pip_package:build_pip_package

Screenshot 2019-07-26 20:37:35.png
Screenshot 2019-07-28 17:41:36.png

6−5.Generation of Wheel and Installation of Tensorflow

Build_pip_package_and_Install_Tensorflow
$ su --preserve-environment
# ./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
# exit
$ sudo cp /tmp/tensorflow_pkg/tensorflow-1.14.0-cp37-cp37m-linux_arm7l.whl ~
$ cd ~
$ sudo pip3 uninstall tensorflow
$ sudo -H pip3 install tensorflow-1.14.0-cp37-cp37m-linux_armv7l.whl

$ sudo poweroff

6−6.Extract Tensorflow Wheel File from QEMU Virtual Environment

Extract_Tensorflow_Wheel_File_from_QEMU_Virtual_Environment
$ sudo virt-ls -a hda.qcow2 /home/debian
.bash_history
.bash_logout
.bashrc
.cache
.gnupg
.local
.profile
Bazel_bin
h5py-2.9.0-cp37-cp37m-linux_armv7l.whl
numpy-1.16.4-cp37-cp37m-linux_armv7l.whl
tensorflow
tensorflow-1.14.0-cp37-cp37m-linux_armv7l.whl

$ sudo virt-copy-out -a hda.qcow2 /home/debian/tensorflow-1.14.0-cp37-cp37m-linux_armv7l.whl .

6−7.Tensorflow Wheel file for RaspberryPi built with QEMU 4.0.0 + Debian Buster armhf

Tensorflow v1.14.0 Wheel file built with QEMU 4.0.0 + Debian Buster armhf
https://drive.google.com/open?id=1mUP6t4o7xBXhXDTTkS91uluZstqcnQj5

7.Appendix (QEMU4.0.0 STATIC module build procedure)

QEMU4.0.0_STATIC_module_build_procedure
$ wget https://download.qemu.org/qemu-4.0.0.tar.xz
$ tar xvJf qemu-4.0.0.tar.xz
$ rm qemu-4.0.0.tar.xz
$ cd qemu-4.0.0
$ mkdir build;cd build
$ ../configure \
  --prefix=$(cd ..; pwd)/qemu-user-static \
  --disable-bsd-user \
  --disable-guest-agent \
  --disable-strip \
  --disable-werror \
  --disable-gcrypt \
  --disable-debug-info \
  --disable-debug-tcg \
  --disable-docs \
  --disable-tcg-interpreter \
  --enable-attr \
  --disable-brlapi \
  --disable-linux-aio \
  --disable-bzip2 \
  --disable-bluez \
  --disable-cap-ng \
  --disable-curl \
  --disable-fdt \
  --disable-glusterfs \
  --disable-gnutls \
  --disable-nettle \
  --disable-gtk \
  --disable-rdma \
  --disable-libiscsi \
  --disable-vnc-jpeg \
  --disable-kvm \
  --disable-lzo \
  --disable-curses \
  --disable-libnfs \
  --disable-numa \
  --disable-opengl \
  --disable-vnc-png \
  --disable-rbd \
  --disable-vnc-sasl \
  --disable-sdl \
  --disable-seccomp \
  --disable-smartcard \
  --disable-snappy \
  --disable-spice \
  --disable-libssh2 \
  --disable-libusb \
  --disable-usb-redir \
  --disable-vde \
  --disable-vhost-net \
  --disable-virglrenderer \
  --disable-virtfs \
  --disable-vnc \
  --disable-vte \
  --disable-xen \
  --disable-xen-pci-passthrough \
  --disable-xfsctl \
  --enable-linux-user \
  --disable-system \
  --disable-blobs \
  --disable-tools \
  --static \
  --disable-pie
$ make -j8
$ sudo make install
$ cd ../qemu-user-static/bin
$ for i in *; do mv $i $i-static; done
13
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
5