あるサイトのエンジニア募集ページに記載されていた情報から、NILM(Nonintrusive Load Monitoring:非侵入型負荷監視)という技術が存在することを知りました。
en.wikipedia.org電源ラインの一次配電盤に取り付けたセンサーによって電圧や電流の変化データを取得し、そのデータから電源ライン上の装置や機器の消費電力や稼働状況をモニタリングする技術らしいです。
こういう技術が在ることは聞いたことがありましたが、これには機械学習が使われていることは知りませんでした。NILMの一つの実装例としてseq2point-nilmというものが在ることも上述のページで知りました。
コロナ拡大の社会情勢下で電力消費が増大しており、エネルギー・エコ化も永続的な社会トレンドとなっている中で、さらに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の学習処理とテスト処理もやってみるつもりです。その結果は、また別の記事として投稿する予定です。
参照リンク