ヴェズルフェルニルの研究ノート

座右の銘「ただ一人犀の角のように歩め」的な研究活動ノート

〔Homebrew〕macOS High Sierraでの最新版LLVMのインストール

macOSのパッケージマネージャーとしてHomebrewを利用しています。GitHubなどから入手したプログラムソースをビルドしてMacで利用するには、Homebrewは必須のツールです。Homebrewがなければ、Macでのオープンソースを利用したソフトウェア開発はできないとも言えます。

ところが、現行のHomebrew(本記事執筆時点はバージョン3.6.1)ではmacOS 10.13 High Sierra はサポート対象外となっており、何かパッケージをインストールする度に次のような警告が表示されます。

Warning: You are using macOS 10.13.  
We (and Apple) do not provide support for this old version.  
You will encounter build failures with some formulae.  
Please create pull requests instead of asking for help on Homebrew's GitHub,  
Twitter or any other official channels. You are responsible for resolving  
any issues you experience while you are running this  
old version. 

Homebrewの多くフォーミュラはすでにBig Sur以降用に更新されているようで、一部のフォーミュラはそのままではHigh Sierraにインストールできなくなってしまっています。

事情があって、High Sierraを使い続けている人は結構多いのではないでしょうか。そういう私も2台のMacでまだHigh Sierraを使っています(マルチパーティションでBig Surと共存させたりしていますが)。一つの大きな理由として、NVIDIA GPUボードがHigh Sierraまでしか利用できないことがあります。NVIDIA GPUボード用ドライバがHigh Sierra対応版までしかリリースされておらず、macOS 10.14 Mojave以降ではCUDAや機械学習ディープラーニングのソフトウェア開発ができません。

HomebrewでHigh Sierraにインストールできないフォーミュラの一つとしてLLVMがというものがあります。Command Line Toolsにも入っているclangコンパイラを含んでいるLLVMの最新版ですが、この最新版LLVMにはclangも最新版バージョンが収納されています。この最新版LLVMをインストールできないことはHomebrewを利用したソフトウェア開発にとって大きな障害となります。多くのフォーミュアがこの最新バージョンのclangでビルドすることを前提として更新されており、それらは先に最新版LLVMがインストールされるからです。OpenCVやQtなどのメジャーなフォーミュラが最新版LLVMに依存しているため、High Sierraでは現行のHomebrewを使ってこれらをインストールすることができません。

GitHubから入手したいくつかのプログラムをビルドしようとして、この障害に何度か遭遇しましたが、試行錯誤しながら解決することができました。同じ問題によって困っている人は多いと思うので、その解決方法を本記事に書いておきます。

LLVMインストール時のエラー障害

High Sierra上でHomebrewを使って最新版LLVM(本記事執筆時点はバージョン14.0.6)をインストールしようとすると、以下のようなエラーが起きます。

$ brew install llvm
... ...
==> Downloading https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.6/llvm-project-14.0.6.src.tar.xz
/usr/local/Homebrew/Library/Homebrew/shims/shared/curl --disable --cookie /dev/null --globoff --show-error --user-agent Homebrew/3.6.1\ \(Macintosh\;\ Intel\ Mac\ OS\ X\ 10.13.6\)\ curl/7.54.0 --header Accept-Language:\ en --retry 3 --location --silent --head --request GET https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.6/llvm-project-14.0.6.src.tar.xz
Already downloaded: /Users/yuhri/Library/Caches/Homebrew/downloads/ca2953276467b5dcc28485aa2b1afc3bcf32bbf84d5e0236f6284234afca2d8d--llvm-project-14.0.6.src.tar.xz
... ...
tar --extract --no-same-owner --file /Users/yuhri/Library/Caches/Homebrew/downloads/ca2953276467b5dcc28485aa2b1afc3bcf32bbf84d5e0236f6284234afca2d8d--llvm-project-14.0.6.src.tar.xz --directory /private/tmp/d20220915-7100-llrho7
cp -pR /private/tmp/d20220915-7100-llrho7/llvm-project-14.0.6.src/. /private/tmp/llvm-20220915-7100-9zovwz/llvm-project-14.0.6.src
==> cmake -G Unix Makefiles .. -DLLVM_ENABLE_PROJECTS=clang;clang-tools-extra;lld;lldb;mlir;polly -DLLVM_ENABLE_RUNTIMES=compiler-rt;libcxx;libcxxabi;libunwind;
==> cmake --build .
... ...
[ 80%] Built target lldELF
make: *** [all] Error 2

HomebrewはLLVMをソースからビルドしてインストールしようと試みますが、このエラーによってビルド処理が停止するため、LLVMのインストールは失敗してしまいます。

High Sierraに最新版LLVMをインスールする手順

上記のエラー障害を解決して、High Sierra上でHomebrewを使ってLLVMをインスールする手順を以降に説明します。

Xcode 10.1をインストールする

まずXcodeをHigh Sierraへインストールしておく必要があります。Xcode 10.1がHigh Sierraで利用可能な最終バージョンですが、これをApple Developerサイトからダウンロードした上で解凍し、Applicationsフォルダへコピーしてください。

Homebrewをインストール済みならCommand Line Toolsは単独でインストールされているはずで、フォーミュラのビルドは通常こちらを使って行われます。しかし、LLVMのインストールではXcodeに含まれる一部のツールがビルド処理で使われます。

すでにXcode 10.1をインストール済みなら、この操作を行う必要はありません。

なお、HombrewがXcodeの存在を認識しているかどうかは、以下のコマンドによって確認できます。

$ brew config
HOMEBREW_VERSION: 3.6.1
ORIGIN: https://github.com/Homebrew/brew
HEAD: 6e2b162c4786e075323f038d46bfb566d91889e7
Last commit: 5 days ago
Core tap ORIGIN: https://github.com/Homebrew/homebrew-core
Core tap HEAD: 4d6529affa1851ffb992a33fe5641b0cd739c895
Core tap last commit: 2 hours ago
Core tap branch: master
HOMEBREW_PREFIX: /Users/yuhri/homebrew
HOMEBREW_REPOSITORY: /Users/yuhri/homebrew
HOMEBREW_CELLAR: /Users/yuhri/homebrew/Cellar
HOMEBREW_CASK_OPTS: []
HOMEBREW_DISPLAY: /private/tmp/com.apple.launchd.gBCDRKkzIz/org.xquartz:0
HOMEBREW_MAKE_JOBS: 24
Homebrew Ruby: 2.6.8 => /Users/yuhri/homebrew/Library/Homebrew/vendor/portable-ruby/2.6.8_1/bin/ruby
CPU: 24-core 64-bit westmere
Clang: 10.0.0 build 1000
Git: 2.17.2 => /Library/Developer/CommandLineTools/usr/bin/git
Curl: 7.54.0 => /usr/bin/curl
macOS: 10.13.6-x86_64
CLT: 10.1.0.0.1.1539992718
Xcode: 10.1

Xcodeがインストールされていないと、 "Xcode: N/A" と表示されます。

Command Line ToolsをXcode側へ切り替える

xcode-select コマンドを使って、Xcode側のCommand Line Toolsが使われるように変更します。

$ xcode-select -p
/Library/Developer/CommandLineTools
$ sudo xcode-select -s /Applications/Xcode.app
Password:
$ xcode-select -p
/Applications/Xcode.app/Contents/Developer

LLVMのインストールを”--debug”オプション付きで開始する

brew コマンドには --debug というオプションがありますが、このオプションを指定してLLVMのインストールを開始します。

$ brew install --debug llvm

--debug オプションをつけると、エラーが起きた時点で、以下のようなメッセージが表示されてHomebrewのインストール処理が停止します。

... ...
[ 80%] Built target lldELF
make: *** [all] Error 2
/usr/local/Homebrew/Library/Homebrew/shims/shared/git --version
/usr/local/Homebrew/Library/Homebrew/shims/shared/curl --version
/usr/local/Homebrew/Library/Homebrew/ignorable.rb:29:in `block in raise'
BuildError: Failed executing: cmake --build .
1. raise
2. ignore
3. backtrace
4. irb
5. shell
Choose an action: 5
When you exit this shell, you will return to the menu.
$ 

この”Choose an action:” プロンプトに対して ”5”  を選ぶと、シェルプロンプトに復帰します。

LLVMのビルド・エラーの原因を解決する

シェルプロンプトになったら、以下のように作業ディレクトリを移動します。

$ pwd
/private/tmp/llvm-20220915-7100-9zovwz/llvm-project-14.0.6.src
$ cd llvm/build

そして、 HostInfoMacOSX.mm というファイルを以下のように編集します。

$ vi ../../lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
--- ../../lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm.orig  2022-06-22 16:46:24.000000000 +0000
+++ ../../lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm    2022-09-15 13:18:17.000000000 +0000
@@ -228,7 +228,7 @@
     len = sizeof(is_64_bit_capable);
     ::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0);

-    if (cputype == CPU_TYPE_ARM64 && cpusubtype == CPU_SUBTYPE_ARM64E) {
+    if (cputype == CPU_TYPE_ARM64) {
       // The arm64e architecture is a preview. Pretend the host architecture
       // is arm64.
       cpusubtype = CPU_SUBTYPE_ARM64_ALL;

手動でLLVMのビルド処理を継続する

HostInfoMacOSX.mm の修正が終わったら、以下の一連のコマンドを順次実行していきます。

$ cmake . -DLLVM_CREATE_XCODE_TOOLCHAIN=On
...   ...
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/llvm-20220915-7100-9zovwz/llvm-project-14.0.6.src/llvm/build
$ cmake --build .
...   ...
[100%] Built target lldb-vscodex
/usr/local/Cellar/cmake/3.24.1/bin/cmake -E cmake_progress_start /tmp/llvm-20220915-7100-9zovwz/llvm-project-14.0.6.src/llvm/build/CMakeFiles 0
$ cmake --build . --target install
...   ...
-- Installing: /usr/local/Cellar/llvm/14.0.6_1/lib/cmake/llvm/./FindSphinx.cmake
-- Installing: /usr/local/Cellar/llvm/14.0.6_1/lib/cmake/llvm/./FindGRPC.cmake
-- Installing: /usr/local/Cellar/llvm/14.0.6_1/lib/cmake/llvm/./TableGen.cmake
$ cmake --build . --target install-xcode-toolchain

上記の最後のコマンドによるビルド処理が終わると、以下のようなメッセージが表示されます。

ここでの"Choose an action:"プロンプトでは、すべて "2" を選択します。

...   ...
-- Installing: /usr/local/Cellar/llvm/14.0.6_1/Toolchains/LLVM14.0.6.xctoolchain//usr/lib/cmake/llvm/./FindSphinx.cmake
-- Installing: /usr/local/Cellar/llvm/14.0.6_1/Toolchains/LLVM14.0.6.xctoolchain//usr/lib/cmake/llvm/./FindGRPC.cmake
-- Installing: /usr/local/Cellar/llvm/14.0.6_1/Toolchains/LLVM14.0.6.xctoolchain//usr/lib/cmake/llvm/./TableGen.cmake
Built target install-xcode-toolchain
/usr/local/Cellar/cmake/3.24.1/bin/cmake -E cmake_progress_start /tmp/llvm-20220915-7100-9zovwz/llvm-project-14.0.6.src/llvm/build/CMakeFiles 0
$ 
1. raise
2. ignore
3. backtrace
4. irb
5. shell
Choose an action: 2
==> cmake --build . --target install
Last 15 lines from /Users/yuhri/Library/Logs/Homebrew/llvm/03.cmake:
2022-09-15 07:06:11 +0000

cmake
--build
.
--target
install

Error: could not load cache
/usr/local/Homebrew/Library/Homebrew/shims/shared/curl --version
/usr/local/Homebrew/Library/Homebrew/ignorable.rb:29:in `block in raise'
BuildError: Failed executing: cmake --build . --target install
1. raise
2. ignore
3. backtrace
4. irb
5. shell
Choose an action: 2

2回 "2" を選択すると、LLVMのビルド処理が終了し、以降はHomebrewによってインストール処理が継続実行されます。

...   ...
==> Fixing /usr/local/Cellar/llvm/14.0.6_1/lib/python3.9/site-packages/clang/cindex.py permissions from 644 to 444
==> Fixing /usr/local/Cellar/llvm/14.0.6_1/lib/python3.9/site-packages/clang/enumerations.py permissions from 644 to 444
...   ...
==> Changing dylib ID of /Users/yuhri/homebrew/Cellar/llvm/14.0.6_1/lib/libomp.dylib
  from @rpath/libomp.dylib
    to /Users/yuhri/homebrew/opt/llvm/lib/libomp.dylib
==> Changing dylib ID of /Users/yuhri/homebrew/Cellar/llvm/14.0.6_1/lib/libunwind.1.0.dylib
  from @rpath/libunwind.1.dylib
    to /Users/yuhri/homebrew/opt/llvm/lib/libunwind.1.dylib
/Users/yuhri/homebrew/Library/Homebrew/brew.rb (Formulary::FromPathLoader): loading /Users/yuhri/homebrew/opt/llvm/.brew/llvm.rb
==> Caveats
To use the bundled libc++ please add the following LDFLAGS:
  LDFLAGS="-L/Users/yuhri/homebrew/opt/llvm/lib -Wl,-rpath,/Users/yuhri/homebrew/opt/llvm/lib"

llvm is keg-only, which means it was not symlinked into /Users/yuhri/homebrew,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

If you need to have llvm first in your PATH, run:
  echo 'export PATH="/Users/yuhri/homebrew/opt/llvm/bin:$PATH"' >> ~/.zshrc

For compilers to find llvm you may need to set:
  export LDFLAGS="-L/Users/yuhri/homebrew/opt/llvm/lib"
  export CPPFLAGS="-I/Users/yuhri/homebrew/opt/llvm/include"

==> Summary
🍺  /Users/yuhri/homebrew/Cellar/llvm/14.0.6_1: 11,663 files, 1.8GB, built in 76 minutes 6 seconds
...   ...

そして、最後はLLVMのインストールが成功して終わります。

インストールされたLLVMを確認する

インストールされたLLVMが利用可能かどうかは 、以下のコマンドによって確認できます。

$ /usr/bin/clang --version
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
$ /Library/Developer/CommandLineTools/usr/bin/clang --version
Apple LLVM version 10.0.0 (clang-1000.10.44.4)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
$ /usr/local/opt/llvm/bin/clang --version
Homebrew clang version 14.0.6
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm/bin

/usr/bin/clangXcode 10.1のclangコンパイラ/Library/Developer/CommandLineTools/usr/bin/clang がCommand Line Toolsのclang、/usr/local/opt/llvm/bin/clang がインストールしたLLVMのclangです。

Command Line Toolsの選択を元に戻す

上記までの手順でLLVMのインストールは完了ですが、"brew install --debug llvm " コマンドを実行する前に変更したCommand Line Toolsの選択を元に戻しておきます。

$ xcode-select -p
/Applications/Xcode.app/Contents/Developer
$ sudo xcode-select -s /Library/Developer/CommandLineTools
Password:
$ xcode-select -p
/Library/Developer/CommandLineTools

seq2point-nilmのDockerfileを作る

あるサイトのエンジニア募集ページに記載されていた情報から、NILM(Nonintrusive Load Monitoring:非侵入型負荷監視)という技術が存在することを知りました。

en.wikipedia.org電源ラインの一次配電盤に取り付けたセンサーによって電圧や電流の変化データを取得し、そのデータから電源ライン上の装置や機器の消費電力や稼働状況をモニタリングする技術らしいです。

こういう技術が在ることは聞いたことがありましたが、これには機械学習が使われていることは知りませんでした。NILMの一つの実装例としてseq2point-nilmというものが在ることも上述のページで知りました。

github.com

コロナ拡大の社会情勢下で電力消費が増大しており、エネルギー・エコ化も永続的な社会トレンドとなっている中で、さらにIoTにも繋がる技術としてNILMへの注目度が急上昇しているらしいです。

 

NILMがどういう技術で、その動作原理や使われているアルゴリズムがどんなものかを知りたくなったので、手始めに、このseq2point-nilmを動かしてみることにしました。ちなみに、seq2point-nilmの機械学習処理はTensorFlowとKerasを使って実現されているようです。

 

このような機械学習プログラムを手っ取り早く動かすにはDockerを利用するのが一番楽な方法です。そこで、Dockerfileを作りながらseq2point-nilmの動作確認を試みました。

以下が、私が自作したseq2point-nilmのDockerfileです。

FROM continuumio/anaconda3:2021.05

# install prerequistites
ENV DEBCONF_NOWARNINGS yes
RUN apt-get update && \
    apt-get install -y wget git unzip p7zip-full && \
    apt-get autoremove -y

# copy the seq2point-nilm
COPY ./seq2point-nilm /seq2point-nilm

# create a Python environment for seq2point-nilm installing python prerequistites
WORKDIR /seq2point-nilm
RUN conda env create -f environment.yml

ENV NVIDIA_VISIBLE_DEVICES all
ENV NVIDIA_DRIVER_CAPABILITIES utility,compute

# download the REFIT dataset file
WORKDIR /seq2point-nilm/dataset_management/refit
RUN wget https://pureportal.strath.ac.uk/files/62090184/CLEAN_REFIT_081116.7z && \
    7z x -oCLEAN_REFIT_081116 CLEAN_REFIT_081116.7z && \
    rm -f CLEAN_REFIT_081116.7z

# download the UK-DALE datasets file
WORKDIR /seq2point-nilm/dataset_management/ukdale
RUN wget http://data.ukedc.rl.ac.uk/simplebrowse/edc/efficiency/residential/EnergyConsumption/Domestic/UK-DALE-2017/UK-DALE-FULL-disaggregated/ukdale.zip && \
    unzip ukdale.zip -d ukdale && \
    rm -f ukdale.zip

# download the REDD datasets file
WORKDIR /seq2point-nilm/dataset_management/redd
RUN wget --http-user="redd" --http-password="disaggregatetheenergy" http://redd.csail.mit.edu/data/low_freq.tar.bz2 && \
    tar -jxvf low_freq.tar.bz2 && \
    rm -f low_freq.tar.bz2

ARG AGGREGATE_MEAN=522
ARG AGGREGATE_STD=814

# create a REFIT dataset
WORKDIR /seq2point-nilm/dataset_management/refit
RUN mkdir dataset && \
    cd dataset && \
    python ../create_dataset.py --data_dir '../CLEAN_REFIT_081116/' --appliance_name 'kettle' --save_path './' && \
    python ../create_dataset.py --data_dir '../CLEAN_REFIT_081116/' --appliance_name 'microwave' --save_path './' && \
    python ../create_dataset.py --data_dir '../CLEAN_REFIT_081116/' --appliance_name 'fridge' --save_path './' && \
    python ../create_dataset.py --data_dir '../CLEAN_REFIT_081116/' --appliance_name 'dishwasher' --save_path './' && \
    python ../create_dataset.py --data_dir '../CLEAN_REFIT_081116/' --appliance_name 'washingmachine' --save_path './'
    #python ../create_dataset.py --data_dir '../CLEAN_REFIT_081116/' --appliance_name 'kettle' --aggregate_mean AGGREGATE_MEAN --aggregate_std AGGREGATE_STD --save_path './' && \
    #python ../create_dataset.py --data_dir '../CLEAN_REFIT_081116/' --appliance_name 'microwave' --aggregate_mean AGGREGATE_MEAN --aggregate_std AGGREGATE_STD --save_path './' && \
    #python ../create_dataset.py --data_dir '../CLEAN_REFIT_081116/' --appliance_name 'fridge' --aggregate_mean AGGREGATE_MEAN --aggregate_std AGGREGATE_STD --save_path './' && \
    #python ../create_dataset.py --data_dir '../CLEAN_REFIT_081116/' --appliance_name 'dishwasher' --aggregate_mean AGGREGATE_MEAN --aggregate_std AGGREGATE_STD --save_path './' && \
    #python ../create_dataset.py --data_dir '../CLEAN_REFIT_081116/' --appliance_name 'washingmachine' --aggregate_mean AGGREGATE_MEAN --aggregate_std AGGREGATE_STD --save_path './'

# create a UK-DALE dataset
WORKDIR /seq2point-nilm/dataset_management/ukdale
RUN mkdir dataset && \
    mkdir dataset/kettle dataset/microwave dataset/fridge dataset/dishwasher dataset/washingmachine &&& \
    PYTHONPATH="${PYTHONPATH}:../" python create_trainset_ukdale.py --data_dir './ukdale/' --appliance_name 'kettle' --save_path './dataset/kettle/' && \
    PYTHONPATH="${PYTHONPATH}:../" python create_trainset_ukdale.py --data_dir './ukdale/' --appliance_name 'microwave' --save_path './dataset/microwave/' && \
    PYTHONPATH="${PYTHONPATH}:../" python create_trainset_ukdale.py --data_dir './ukdale/' --appliance_name 'fridge' --save_path './dataset/fridge/' && \
    PYTHONPATH="${PYTHONPATH}:../" python create_trainset_ukdale.py --data_dir './ukdale/' --appliance_name 'dishwasher' --save_path './dataset/dishwasher/' && \
    PYTHONPATH="${PYTHONPATH}:../" python create_trainset_ukdale.py --data_dir './ukdale/' --appliance_name 'washingmachine' --save_path './dataset/washingmachine/'
    #PYTHONPATH="${PYTHONPATH}:../" python create_trainset_ukdale.py --data_dir './ukdale/' --appliance_name 'kettle' --aggregate_mean AGGREGATE_MEAN --aggregate_std AGGREGATE_STD --save_path './dataset/kettle/' && \
    #PYTHONPATH="${PYTHONPATH}:../" python create_trainset_ukdale.py --data_dir './ukdale/' --appliance_name 'microwave' --aggregate_mean AGGREGATE_MEAN --aggregate_std AGGREGATE_STD --save_path './dataset/microwave/' && \
    #PYTHONPATH="${PYTHONPATH}:../" python create_trainset_ukdale.py --data_dir './ukdale/' --appliance_name 'fridge' --aggregate_mean AGGREGATE_MEAN --aggregate_std AGGREGATE_STD --save_path './dataset/fridge/' && \
    #PYTHONPATH="${PYTHONPATH}:../" python create_trainset_ukdale.py --data_dir './ukdale/' --appliance_name 'dishwasher' --aggregate_mean AGGREGATE_MEAN --aggregate_std AGGREGATE_STD --save_path './dataset/dishwasher/' && \
    #PYTHONPATH="${PYTHONPATH}:../" python create_trainset_ukdale.py --data_dir './ukdale/' --appliance_name 'washingmachine' --aggregate_mean AGGREGATE_MEAN --aggregate_std AGGREGATE_STD --save_path './dataset/washingmachine/'

# create a REDD dataset
WORKDIR /seq2point-nilm/dataset_management/redd
RUN mkdir dataset && \
    mkdir dataset/microwave dataset/fridge dataset/dishwasher dataset/washingmachine && \
    python create_trainset_redd.py --data_dir './low_freq/' --appliance_name 'microwave' --save_path './dataset/microwave/' && \
    python create_trainset_redd.py --data_dir './low_freq/' --appliance_name 'fridge' --save_path './dataset/fridge/' && \
    python create_trainset_redd.py --data_dir './low_freq/' --appliance_name 'dishwasher' --save_path './dataset/dishwasher/' && \
    python create_trainset_redd.py --data_dir './low_freq/' --appliance_name 'washingmachine' --save_path './dataset/washingmachine/'
    #python create_trainset_redd.py --data_dir './low_freq/' --appliance_name 'microwave' --aggregate_mean AGGREGATE_MEAN --aggregate_std AGGREGATE_STD --save_path './dataset/microwave/'
    #python create_trainset_redd.py --data_dir './low_freq/' --appliance_name 'fridge' --aggregate_mean AGGREGATE_MEAN --aggregate_std AGGREGATE_STD --save_path './dataset/fridge/'
    #python create_trainset_redd.py --data_dir './low_freq/' --appliance_name 'dishwasher' --aggregate_mean AGGREGATE_MEAN --aggregate_std AGGREGATE_STD --save_path './dataset/dishwasher/'
    #python create_trainset_redd.py --data_dir './low_freq/' --appliance_name 'washingmachine' --aggregate_mean AGGREGATE_MEAN --aggregate_std AGGREGATE_STD --save_path './dataset/washingmachine/'

WORKDIR /seq2point-nilm
ENTRYPOINT ["/bin/bash"]

Dockerfileは何度か作っていますが、これの難易度は中程度位でした。

このDockerfileは私のGitHubリポジトリに置いてあります。

github.comこのDockerfileの使い方は簡単で、まず以下の手順によって上のDockerfileが格納されたリポジトリ取得します。

$ git clone https://github.com/ketus-ix/seq2point-nilm_docker.git
$ cd seq2point-nilm_docker
$ git submodule update --init --recursive

その後、以下のコマンドを実行すると、seq2point-nilmのDockerイメージを作成できます。

$ cp docker/Dockerfile.conda .
$ docker build . -t seq2point-nilm_conda -f Dockerfile.conda

このDockerコンテナの中で、REFIT(514.3MB)、UK-DALE(3.59GB)、REDD(169.4MB)という3つのデータセットのダウンロードを行っています。そのため、Dockerイメージが生成されるのにかなり時間がかかります。これらのデータセットはseq2point-nilmによって利用されます。

 

このDockerfileによって作成したDockerコンテナは、すべてのデータセットがseq2point-nilmが使用する形式に変換・作成されるところまで確認してあります。

以下のディレクトリにseq2point-nilmが使用する形式の各データセットが格納されます。

 

 /seq2point-nilm/dataset_management/refit/dataset

 /seq2point-nilm/dataset_management/ukdale/dataset

 /seq2point-nilm/dataset_management/redd/dataset

 

seq2point-nilmの学習処理とテスト処理はこの作成済みのデータセットを用いて実行することができます。機械学習の肝であるこれらの処理も確認してみたかったのですが、残念ながらそれはできませんでした。いま手元にNVIDIA GPUボードを持っていないからです。

 

過去の仕事で利用していた機械学習環境が整ったPCを使っているので、GPUボードさえ有ればすぐに動作確認を行えるのですが、いまはGPUボードを手放してしまっています。

 

ここまでだと中途半端なので、上のDockerfileから作成したイメージを使って、seq2point-nilmの動作確認を行う手順を一応書いておきます。

 

まず、seq2point-nilmのDockerコンテナをGPUアクセスを有効にした状態で起動します。

$ docker run -it --rm --gpus all seq2point-nilm_conda

ただし、このコマンドを実行したときに、以下のようなエラーに遭遇してDockerコンテナを起動できないことがあります。

$ docker: Error response from daemon: could not select device driver "" with capabilities: gpu

nvidia-driverがインストールされておりnvidia-smiコマンドも使える状態なのに、このようなエラーが起きる場合は、システムにNVIDIA Container Runtimeが入っていないからです。

このようなケースでは、以下の手順を実行して、NVIDIA Container Runtimeをインストールしてください。

$ vi nvidia-container-runtime-script.sh
curl -s -L https://nvidia.github.io/nvidia-container-runtime/gpgkey | \
  sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-container-runtime/$distribution/nvidia-container-runtime.list | \
  sudo tee /etc/apt/sources.list.d/nvidia-container-runtime.list
sudo apt-get update
$ sh nvidia-container-runtime-script.sh
$ sudo apt-get install nvidia-container-runtime
$ sudo systemctl restart docker.service

seq2point-nilmのDockerコンテナを起動できたら、その中で作業ディレクトリが /seq2point-nilm になっていることを確認してください。

(base) root@9d1c222ac40e:/seq2point-nilm# ls
README.md    appliance_data.py	dataset_management  images     model_structure.py		   remove_space.py    seq2point_train.py  train_main.py
__pycache__  data_feeder.py	environment.yml     model.png  nvidia-container-runtime-script.sh  seq2point_test.py  test_main.py

この状態で以下のコマンドを実行すると、REFITデータセットから抽出した ケトルの観測電気データに対するseq2point-nilmの学習処理を開始することがきます。

# python train_main.py --appliance_name 'kettle' --training_directory './dataset_management/refit/dataset/kettle/kettle_training_.csv' --validation_directory './dataset_management/refit/dataset/kettle/kettle_validation_H5.csv' --crop 10000

さらに以下のコマンドによって、REFITデータセットのケトルの観測電気データに対するテスト処理も実行できます。

# python test_main.py --appliance_name 'kettle' --test_directory './dataset_management/refit/dataset/kettle/kettle_test_H2.csv' --crop 10000

このテスト処理では、先に実行した学習処理によって生成された学習モデルが使われます。

上の2つの操作は実際には試していませんが、多分動くんじゃないかと思います。

 

近いうちにGPUボードを入手する予定なので、そのときにseq2point-nilmの学習処理とテスト処理もやってみるつもりです。その結果は、また別の記事として投稿する予定です。

 

参照リンク

arxiv.org

OpenVSLAM(stella_vslam)のUbuntu 18.04でのビルド

ある人から教えてもらった情報が元なんですが、画像認識の一分野としてSLAM(Simultaneous Localization and Mapping:自己位置推定)という技術が在ることを知りました。現存の物だと、お掃除ロボット、未来の物だと、自動運転車などに利用される技術らしいです。

ja.wikipedia.org画像認識はいまの自分の主たる研究テーマの一つなのに、こんな興味深い技術をいままで知らないでいたとは不覚です。慌てて、SLAMについて調べ始めています。

入力データの形式によってSLAMにも複数の種類があるようですが、その中でもVisual SLAMに注目しています。

オープンソースとして公開されているVisual SLAMの代表的な実装例として、OpenVSLAMというものがあります。これは国立研究開発法人産業技術総合研究所が開発したものだそうです。

本記事執筆時点でOpenVSLAMのソースは非公開になっているのですが、OpenVSLAMのコミュニティ・フォーク版がGithHub上にいくつか存在しているので、ソースを入手することはできます。

これらの中からstella_vslamを選んで、Ubuntu 18.04上でのビルドと動作確認までやってみました。

github.com

stella_vslamのビルドに必要なパッケージの導入

$ sudo apt install -y build-essential pkg-config cmake git wget curl unzip
$ sudo apt install -y libatlas-base-dev libsuitesparse-dev
$ sudo apt install -y libgtk-3-dev
$ sudo apt install -y ffmpeg
$ sudo apt install -y libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev
$ sudo apt install -y gfortran
$ sudo apt install -y binutils-dev
$ sudo apt install -y libyaml-cpp-dev libgflags-dev
$ sudo apt install -y libglew-dev
$ sudo apt install -y libsqlite3-dev

stella_vslamとリンクされるライブラリのビルドとインストール

Eigenのビルドとインストール

$ git clone -b 3.3 https://gitlab.com/libeigen/eigen.git
$ cd eigen
$ mkdir build && cd build
$ cmake \
      -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_INSTALL_PREFIX=/usr/local \
      ..
$ make -j4
$ sudo make install

OpenCVのビルドとインストール

$ wget -q https://github.com/opencv/opencv/archive/3.4.0.zip
$ unzip -q 3.4.0.zip
$ cd opencv-3.4.0
$ mkdir build && cd build
$ cmake \
      -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_INSTALL_PREFIX=/usr/local \
      -DENABLE_CXX11=ON \
      -DBUILD_DOCS=OFF \
      -DBUILD_EXAMPLES=OFF \
      -DBUILD_JASPER=OFF \
      -DBUILD_OPENEXR=OFF \
      -DBUILD_PERF_TESTS=OFF \
      -DBUILD_TESTS=OFF \
      -DWITH_EIGEN=ON \
      -DWITH_FFMPEG=ON \
      -DWITH_OPENMP=ON \
      -DWITH_CUDA=OFF \
      -DWITH_NVCUVID=OFF \
      ..
$ make -j4
$ sudo make install

FBoWのビルドとインストール

$ git clone https://github.com/stella-cv/FBoW.git
$ cd FBoW
$ mkdir build && cd build
$ cmake \
      -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_INSTALL_PREFIX=/usr/local \
      ..
$ make -j4
$ sudo make install

g2oのビルドとインストール

$ git clone https://github.com/RainerKuemmerle/g2o.git
$ cd g2o
$ git checkout 9b41a4ea5ade8e1250b9c1b279f3a9c098811b5a
$ mkdir build && cd build
$ cmake \
      -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_INSTALL_PREFIX=/usr/local \
      -DCMAKE_CXX_FLAGS=-std=c++11 \
      -DBUILD_SHARED_LIBS=ON \
      -DBUILD_UNITTESTS=OFF \
      -DG2O_USE_CHOLMOD=OFF \
      -DG2O_USE_CSPARSE=ON \
      -DG2O_USE_OPENGL=OFF \
      -DG2O_USE_OPENMP=OFF \
      ..
$ make -j4
$ sudo make install

PangolinViewerのビルドとインストール

$ git clone https://github.com/stevenlovegrove/Pangolin.git
$ cd Pangolin
$ git checkout ad8b5f83222291c51b4800d5a5873b0e90a0cf81
$ mkdir build && cd build
$ cmake \
      -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_INSTALL_PREFIX=/usr/local \
      ..
$ make -j4
$ sudo make install

stella_vslamのビルドとインストール

$ git clone https://github.com/stella-cv/stella_vslam.git
$ cd stella_vslam
$ git submodule update -i --recursive
$ mkdir build && cd build
$ cmake \
      -DUSE_PANGOLIN_VIEWER=ON \
      -DINSTALL_PANGOLIN_VIEWER=ON \
      -DUSE_SOCKET_PUBLISHER=OFF \
      -DBUILD_TESTS=ON \
      -DBUILD_EXAMPLES=ON \
      ..
$ make -j4
$ sudo make install

stella_vslamの動作確認

$ ./run_kitti_slam -h
Allowed options:
  -h, --help               produce help message
  -v, --vocab arg          vocabulary file path
  -d, --data-dir arg       directory path which contains dataset
  -c, --config arg         config file path
  --frame-skip arg (=1)    interval of frame skip
  --no-sleep               not wait for next frame in real time
  --wait-loop-ba           wait until the loop BA is finished
  --auto-term              automatically terminate the viewer
  --log-level arg (=info)  log level
  --eval-log               store trajectory and tracking times for evaluation
  -p, --map-db arg         store a map database at this path after SLAM

上のような結果になれば、stella_vslamのビルドとインストールは成功しているはず。

 

上記のビルド手順は、stella_vslamのドキュメントサイトに掲載されている情報とほぼ同じですが、一点だけ相違があり、ビルドに必要なパッケージとしてlibsqlite3-devを追加インストールしています。これを入れないと、stella_vslamの "cmake ..." 過程で以下のようなエラーに遭遇します。

CMake Error at /usr/share/cmake-3.10/Modules/FindPackageHandleStandardArgs.cmake:137 (message):
  Could NOT find SQLite3 (missing: SQLite3_INCLUDE_DIR SQLite3_LIBRARY)
Call Stack (most recent call first):
  /usr/share/cmake-3.10/Modules/FindPackageHandleStandardArgs.cmake:378 (_FPHSA_FAILURE_MESSAGE)
  cmake/FindSQLite3.cmake:57 (find_package_handle_standard_args)
  src/stella_vslam/CMakeLists.txt:10 (find_package)


-- Configuring incomplete, errors occurred!

ビルドできたんなら当然動かしてみたい。プログラムを動かしてみるのが、その中で使われている技術を理解する早道だし。

公式サイトで推薦されているKITTI Visual Odometryという車載画像データセットを利用してstella_vslamの動作確認をやってみました。

下のような手順によって、このデータセットを使ってstella_vslamの動作確認ができます。

# at the stella_vsalm/build directory 
$ mkdir ../vocab
$ mkdir ../dataset
$ cd ../vocab
$ curl -sL "https://github.com/stella-cv/FBoW_orb_vocab/raw/main/orb_vocab.fbow" -o orb_vocab.fbow
$ cd ../dataset
# Download KITTI Odometry dataset (grayscale, 22 GB)
$ wget -q HTTPS_URLPATH_TO_KITTI_DATASET/data_odometry_gray.zip
$ unzip -q data_odometry_gray.zip $ cd ../build $ ./run_kitti_slam -v ../vocab/orb_vocab.fbow -d ../dataset/dataset/sequences/00/ -c ../example/kitti/KITTI_mono_00-02.yaml --frame-skip 1 --no-sleep --map-db map-KITTI_mono_00-02.msg

上の手順中のdata_odometry_gray.zipというのが対象のデータセットが格納された圧縮ファイルですが、これはKITTI(The KITTI Vision Benchmark Suite)のサイトでアカウント登録をしないとダウンロードできません。

このデータセットでstella_vslamを作動させると、下の動画のように、Visual SLAMの動きが良く解ります。 

www.youtube.com

 

参照リンク

arxiv.org

OpenVSLAMのビルドと360度カメラサンプル実行まで - Qiita

Installation — stella_vslam documentation