アプリとサービスのすすめ

アプリやIT系のサービスを中心に書いていきます。たまに副業やビジネス関係の情報なども気ままにつづります

Vitis,Petalinuxのインストールから、Vivadoの起動まで【FPGA, avnet】-VitisPlatform作りpart2

今回はVitisPlatfrom構築に必要な「Vitis、Petalinux、その他関連ツール」のインストール。
Ultra96の開発環境(Vitis2019.2版)」をメインに参考にした。


Vitisプラットフォーム(vitis IDE)はVivado起動後に、「Ultra96用Vitisプラットフォームの作り方(BASE編)」を参考に次記事でやる予定。


前回作った仮想環境用ネットワークを少し改良して、外付けHDDの中にVirtualBoxをいれて仮想環境を作った。


そこにUbuntu Linux 18.04.2 LTS (64 ビット)を入れて、vitisとPetaLinuxとかをインストールして、Vivadoを起動するまで。

VirtualBoxで作ったubuntuの仮想環境のストレージ容量は、VitisとPetaLinuxを入れるために500GBくらいのを作った。



改良ネットワーク図f:id:trafalbad:20200319090235j:plain



目次
1.ゲストOS側でライブラリの準備
2.Vitisのインストール
3.その他必要なツールのインストール
4.ゲストOS側からVivadoの起動


1.ゲストOS側で必要なライブラリの準備

Vitisプラットフォーム構築に必要なライブラリをゲストOS側でインストール。

$ sudo dpkg --add-architecture i386 && sudo apt update && sudo apt install apt-utils libc6:i386 libncurses5:i386 libstdc++6:i386 g++-multilib libgtk2.0-0:i386 dpkg-dev:i386 libxtst6:i386 default-jre unzip net-tools libtext-csv-perl libcanberra-gtk-module libcanberra-gtk3-module lsb-core opencl-headers ocl-icd-opencl-dev ocl-icd-libopencl1 wget -y && sudo ln -s /usr/bin/make /usr/bin/gmake

$ sudo apt install tofrodos iproute2 gawk make net-tools locales cpio libncurses5-dev libssl-dev flex bison libselinux1 gnupg wget diffstat chrpath socat xterm autoconf libtool tar unzip texinfo zlib1g-dev gcc-multilib build-essential libsdl1.2-dev libglib2.0-dev screen pax gzip xvfb tftpd tftp libtool-bin default-jre -y lsb-release zlib1g:i386 git python-dev 

$ sudo apt-get install -y binutils ncurses-dev u-boot-tools file iproute2 tftpd-hpa diffstat x11-apps less etckeeper jed
$ sudo locale-gen en_US.UTF-8

# 有効なインストール可能なパッケージの一覧を更新(update) & 有効なパッケージ一覧を元にインストール済みパッケージの更新 (upgrade)
$ sudo apt-get update && sudo apt-get upgrade
$ sudo apt autoremove

参考記事xilinx2017.2_dep.sh(github)  




2.Vitisのインストール


1.Vitisのダウンロード


Vitisはこのページからダウンロード。

ダウンロードするものは、

ザイリンクス統合インストーラ アップデート 1 - 2019.2 (TAR/GZIP - 9.03 GB)

ザイリンクス統合インストーラー 2019.2: Linux 用自己解凍型ウェブインストーラー(BIN - 115.4MB)




2.ウェブインストーラーの実行




ホストOS側でダウンロード後、ゲストOS側(ubuntu側)に移動して、ウェブインストーラーを実行。

# ゲストOS側で実行
$ sudo chmod 777 Xilinx_Unified_2019.2_1106_2127_Lin64.bin
$ ./Xilinx_Unified_2019.2_1106_2127_Lin64.bin

注意事項を聞かれるのでOKした後に、インストール開始画面になる。
f:id:trafalbad:20200311235452j:plain



途中でXlinxのアカウント入力が必要。
f:id:trafalbad:20200311235536j:plain

インストール対象に「Vitis」を選択をした後、保存先を聞かれる。

ホストOS内のVivadoフォルダのパス「/media/[host-name]/Vivado」を指定。500GBもあるので十分足りる。
f:id:trafalbad:20200319020816p:plain



インストール開始画面
f:id:trafalbad:20200319020843p:plain




インストール中
f:id:trafalbad:20200311235714j:plain


インストール完了
f:id:trafalbad:20200311235735p:plain

インストール完了までは気長に待つだけ。


licenseの取得


次にvivadoで必要になるxilinxのlicenseの取得。


ページからvivado HLSのライセンスを取得。(これをしないと高位合成のときSynthesis errorになる)。
Obtain Licenseを選び、ラジオボックスを上から2番目(Get Vivado or IP〜)に合わせ、Connect Nowを起動。
f:id:trafalbad:20200805125246p:plain


Xilinxのサインインを済ませ、Product Licensingのページに移動し、したの画面の基本licenseに全部チェックして取得。
f:id:trafalbad:20200805125605p:plain


するとXilinxからメールが届いて、「Xilinx.lic」が添えつけられているので、適当な場所に配置

# Xilinx.licをVivadoファルダに移動
$ mv /media/[マウントフォルダ]/Xilinx.lic Vivado/
$ sudo chmod 777 Xilinx.lic

あとはLicence ManagerのLoad Licenseを起動し、Copy Licenseをクリック。
f:id:trafalbad:20200805125658p:plain

Xilinx.licを選べば完了。
f:id:trafalbad:20200805125738p:plain

f:id:trafalbad:20200805125745p:plain





3.その他必要なツールのインストール

・Petalinux



1.Petalinuxのインストール


このサイトから下のをdownload。


PetaLinux 2019.2 インストーラ(TAR/GZIP - 7.92GB)


ちなみにrootユーザーではインストーラの実行ができない。
ホストOS側でダウンロードしたものを、マウント共有フォルダでゲストOS内移動して、実行した。

# check user name
$ whoami   # user
$ export USER=user
$ sudo mkdir -p /opt/petalinux/
$ sudo chmod -R 777 /opt/petalinux/
$ sudo chown $USER:$USER /opt/petalinux
# /home/userのところでinstallの実行
$ sudo chmod 777 petalinux-v2019.2-final-installer.run 
$ ./petalinux-v2019.2-final-installer.run /opt/petalinux

>>>>>
INFO: Checking installation environment requirements...
INFO: Checking free disk space
INFO: Checking installed tools
INFO: Checking installed development libraries
INFO: Checking network and other services
INFO: Checking installer checksum...
INFO: Extracting PetaLinux installer...

LICENSE AGREEMENTS
〜
INFO: Installing PetaLinux...
*********************************************
WARNING: PetaLinux installation directory: /opt/petalinux/. is not empty!
*********************************************
Please input "y" to continue to install PetaLinux in that directory?[n]y
INFO: Checking PetaLinux installer integrity...
INFO: Installing PetaLinux SDK to "/opt/petalinux/."
INFO: Installing aarch64 Yocto SDK to "/opt/petalinux/./components/yocto/source/aarch64"...
INFO: Installing arm Yocto SDK to "/opt/petalinux/./components/yocto/source/arm"...
INFO: Installing microblaze_full Yocto SDK to "/opt/petalinux/./components/yocto/source/microblaze_full"...
INFO: Installing microblaze_lite Yocto SDK to "/opt/petalinux/./components/yocto/source/microblaze_lite"...
INFO: PetaLinux SDK has been installed to /opt/petalinux/.


インストール後、PetaLinuxツール(components, doc, etc, tools, settings.csh, settings.sh)の確認。

$ ls
components  doc  etc  settings.csh  settings.sh  tools


・XRTライブラリ(ザイリンクスランタイム)


XRTはライブラリなので、実行してもフォルダは出現しない。

# xilinxツール用ディレクトリ作成(sshでログインして実行)
$ mkdir xilinx_drivers && cd xilinx_drivers
$ wget https://www.xilinx.com/bin/public/openDownload?filename=xrt_201920.2.3.1301_18.04-xrt.deb -O xrt_201920.2.3.1301_18.04-xrt.deb
# 実行
$ sudo apt install ./xrt_201920.2.3.1301_18.04-xrt.deb -y

>>>>
DKMS: install completed.
Finished DKMS common.postinst
Loading new XRT Linux kernel modules
Installing MSD / MPD daemons
〜
Collecting pyopencl
  Downloading https://files.pythonhosted.org/packages/a1/b5/c32aaa78e76fefcb294f4ad6aba7ec592d59b72356ca95bcc4abfb98af3e/pyopencl-2020.2.tar.gz (351kB)
    100% |████████████████████████████████| 358kB 2.6MB/s 
    Complete output from command python setup.py egg_info:
〜
 create mode 100644 OpenCL/vendors/xilinx.icd
 create mode 100644 bash_completion.d/dkms
〜
 create mode 100644 systemd/system/mpd.service
 create mode 100644 systemd/system/msd.service
 create mode 100644 udev/rules.d/10-xclmgmt.rules
 create mode 100644 udev/rules.d/10-xocl.rules





・ボードファイル



# sshでログインして実行
$ cd xilinx_drivers
# wget https://github.com/Avnet/bdf/archive/master.zip && unzip master.zip

# new board copy
$ unzip -o vivado-boards-master.zip
$ sudo cp -rf vivado-boards-master/new/board_files/* /home/user/Vivado/2019.2/data/boards/board_files/
$ sudo rm -rf vivado-boards-master

# copy usual board 
$ unzip -o bdf-master.zip
$ sudo cp -rf bdf-master/* /home/user/Vivado/2019.2/data/boards/board_files/
$ sudo rm -rf bdf-master




・ケーブルドライバー



$ cd Vivado/2019.2/data/xicom/cable_drivers/lin64/install_script/install_drivers
$ sudo ./install_drivers

>>>>>
INFO: Installing cable drivers.
INFO: Script name = ./install_drivers
INFO: HostName = hagi-VirtualBox
INFO: Current working dir = /home/[host-name]/Vivado/Vivado/2019.2/data/xicom/cable_drivers/lin64/install_script/install_drivers
INFO: Kernel version = 5.3.0-42-generic.
INFO: Arch = x86_64.
Successfully installed Digilent Cable Drivers
--File /etc/udev/rules.d/52-xilinx-ftdi-usb.rules does not exist.
--File version of /etc/udev/rules.d/52-xilinx-ftdi-usb.rules = 0000.
--Updating rules file.
--File /etc/udev/rules.d/52-xilinx-pcusb.rules does not exist.
--File version of /etc/udev/rules.d/52-xilinx-pcusb.rules = 0000.
--Updating rules file.

INFO: Digilent Return code = 0
INFO: Xilinx Return code = 0
INFO: Xilinx FTDI Return code = 0
INFO: Return code = 0
INFO: Driver installation successful.
CRITICAL WARNING: Cable(s) on the system must be unplugged then plugged back in order for the driver scripts to update the cables.




環境変数の設定



# LD_LIBRARY_PATH の設定
$ export GID=`id -g`
$ sudo chown ${UID}:${GID} /home/$USER/.bashrc

# ゲストOSの環境変数の設定
$ sudo echo "source /home/〜/Vivado/2019.2/settings64.sh" >> ~/.bashrc
$ sudo echo "source /home/〜/Vitis/2019.2/settings64.sh" >> ~/.bashrc
$ sudo echo "source /opt/xilinx/xrt/setup.sh  " >> ~/.bashrc
$ sudo echo "source /opt/petalinux/settings.sh " >> ~/.bashrc

あとは念のためGUIで再起動(CUI:$sudo reboot)




4.ゲストOS側からVivadoの起動

# Vivadoコマンドを起動
$ /home/〜/Vivado/2019.2/bin/vivado


起動できた。
f:id:trafalbad:20200311235852p:plain





後は以下の図の流れでVitisPlatformを構築していく。

f:id:trafalbad:20200311235916p:plain



参考サイト



・[https://qiita.com/georgioush/items/1e19ecd9a9ef8be886d7:title=Vivado License Error [17-345]]

Vitis 2019.2 をインストールした(FPGAの部屋)

PetaLinux Tools Documentation

PetaLinux 2017.3 をインストールする(FPGAの部屋)

ultra96v2の環境の構築。仮想環境のubuntuとMacの外付けHDDをマウントするまで -VitisPlatform作りpart1【fpga, avnet】

・1.ultra96-v2動作に必要なもの
はじめてのUltra96 必要なもの」によると、Ultra96-v2に必要なものは、買った付属品以外に、
「Vitisプラットフォーム(vitis IDE)」という開発環境の構築

環境構築用OS ubuntu

が必要らしい。



・2.まず自分がやること
Ultra96-v2でAIを動かすことための「GPUが必要、仮想環境はダメっぽい」など面倒な課題はあとでなんとかするとして、

・大容量の外付けHDD

ubuntu環境

を用意して、とにかく「vitisプラットフォーム」を外付けHDDの中に構築することにした




・3.この記事でやること
そのために、自分がこの記事でやることは下の通り(仮想環境と外付けHDDをマウントするまでの流れ)。

mac上でVirtualBoxの仮想環境を構築

仮想環境にubuntuをインストール

mac側の大容量の外付けHDDとubuntuをマウント

(次記事で外付けHDDの中に「vitisプラットフォーム」を構築する)

この作業の備忘録をまとめてく。




作成するネットワーク全体像f:id:trafalbad:20200308114134j:plain



*注:Macを以下「ホストOS」、ubuntuの仮想環境を「ゲストOS」と表記。




目次
1.VirtualBoxの仮想環境にubuntuをインストールする

2.ホストOSからsshでログインするため、ゲストOS内でネットワーク設定

3.ホストOS側の外付けHDDをゲストOS側とマウント





1.VirtualBoxの仮想環境にubuntuをインストールする

ほぼ「MacにVirtualBoxでUbuntuを立てる方法【画像での解説つき】」の通りにやった。




1.VirtualBoxのインストール & ubuntuをダウンロード


VirtualBoxMac用のubuntu for desktopは以下からdownload。

ubuntuのバージョンは「Ubuntu Linux 16.04.5 LTS, 16.04.6 LTS, 18.04.1 LTS, 18.04.2 LTS (64 ビット)」のどれか。
ここでは18.04.2 LTS (64 ビット)を選択。

VirtualBox
VirtualBox

ubuntuの18.04.2 LTS (64 ビット)





2.VirtualBoxのネットワーク(ホストオンリーネットワーク)の作成


サイトを参考に、virtualboxでネットワーク設定(ホストオンリーネットワークで「vboxnet0」を作成)。

VirtualBox起動=>「ファイル」=>「ホストネットワークマネージャー」=>「vboxnet0」の作成と有効化。


f:id:trafalbad:20200308114212p:plain



次にVirtualBoxからネットワークの設定。「ネットワーク」のアダプター1と2を以下の図のように設定。

f:id:trafalbad:20200504230849p:plain


f:id:trafalbad:20200504230907p:plain


3.VirtualBox起動してubuntuのインストール



ubuntuのインストール画面では、容量を節約するため「最小のインストール」を選択した。

・「通常のインストール」:オフィスソフトウェアやミュージックプレイヤーなどが合わせてインストールされる

・「最小のインストール」:ソフトウェアのみがインストール


後はサイト通りにインストールすればOK。



ubuntuをインストール中
f:id:trafalbad:20200308114251p:plain

# 例:ubuntuアカウント
Your name: Ls
PC name: Ls-VirtualBox
User name: Ls
Pasward: Ls11


2.ホストOSからsshでログインするため、ゲストOS内でネットワーク設定


1.ubuntu内のターミナルでネットワーク設定


# vimとopenssh-serverのインストール
$ sudo apt-get install vim openssh-server

# ubuntuでadressの確認
$ ip address show


# /etc/network/interfacesの編集
$ sudo vi /etc/network/interfaces

# 下のように書き込んで、「esc+:wq」
auto enp0s3
iface enp0s3 inet static
address 192.168.56.104
netmask 255.255.255.0


その後、GUIで再起動

参考サイト:Ubuntu18.04だとifconfigコマンドが標準で使えない?






2.ホストOS側ターミナルからゲストOSにsshでログイン


さっきのubuntuアカウントのYour nameと、/etc/network/interfacesの編集で使ったaddressでログイン。

# ssh [アカウント名]@[address]
$ ssh Ls@192.168.56.104

>>>
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 5.3.0-28-generic x86_64)

* Documentation:  https://help.ubuntu.com
* Management:     https://landscape.canonical.com
* Support:        https://ubuntu.com/advantage

* Canonical Livepatch is available for installation.
  - Reduce system reboots and improve kernel security. Activate at:
    https://ubuntu.com/livepatch

70 個のパッケージがアップデート可能です。
57 個のアップデートはセキュリティアップデートです。

Your Hardware Enablement Stack (HWE) is supported until April 2023.

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.


ログインできた。


ここまでのネットワーク全体像f:id:trafalbad:20200308124910j:plain







3.ホストOS側の外付けHDDをゲストOS側とマウント


ホストOS側で大容量の外付けHDDを差し込んで、vitisをインストールする場所にした。

vitisのインストールには110GBくらい必要なので、大容量の外付けHDDを選択。



自分が選んだのは1TBある、BUFFALOの外付けHDD
f:id:trafalbad:20200308114408j:plain




最終的に「vitisプラットフォーム」構築は、

・ホストOS側とゲストOSをマウントする共有フォルダに外付けHDDを指定

・ゲストOS側(ubuntu環境)から外付けHDDの中に「vitisプラットフォーム」を作成する

という流れ。





1.ホストOS上でマウント用フォルダの作成


ホストOS上で、外付けHDDを差込み、中にマウント用ファルダ「ubuntu_mount」を作成。



外付けHDDの中身
f:id:trafalbad:20200308114441p:plain






2.VirtualBoxで外付けHDDの「ubuntu_mount」を「共有フォルダー」に設定




ubuntu_mount」のパスを確認。(外付けHDDのパスはディスクユーティリティから確認)

$ cd /Volumes/BuFFALO && ls

Xlinx        other        ubuntu_mount

$ cd ubuntu_mount && pwd
/Volumes/BuFFALO/ubuntu_mount


VirtualBox仮想マシンを選択=>「設定」=>「共有フォルダー」
=>右のフォルダマークをクリック=>下のようにパスとかを入れる


f:id:trafalbad:20200308114518p:plain

=>「"読み込み専用"のチェックを外す」=>「OK」クリック


f:id:trafalbad:20200308131749p:plain






3.「Guest addtions」をubuntuにインストール


ubuntuでマウントを完了するには「Guest addtions」のインストールが必要。


VirtualBoxからubuntuを起動して、上の「Decices」=>「Insert Guest Addition CD Image~」をクリック。


次に、ubuntu上の画面に表示された「Guest addtions」のソフトウェアを実行。

f:id:trafalbad:20200308114621j:plain


Returnをクリックしてインストール完了。
その後、GUIで再起動。


再起動した後に、ubuntuの「/media」に移動したところ、マウント用に作成されたフォルダ(sf_[マウントするフォルダ名])があって、ちゃんとマウントされてる。

$ cd /media && ls
sf_ubuntu_mount

***「Guest addtions」が入らない場合
ターミナルでこのコマンドを実行すれば、同じのが入る

sudo apt-get install virtualbox-guest-utils

参考:Unable to Install Guest Additions CD Image on Virtual Box



これで、ホストOS側の外付けHDDをゲストOS側とマウントするネットワークができた




完成図f:id:trafalbad:20200308124802j:plain




次記事でこの外付けHDDの「ubuntu_mount」の中に、ゲストOS側から「vitisプラットフォーム」を作ってく予定。





メイン参考サイト


VirtualboxのUbuntu ServerにOSXホストのフォルダをマウントする 

MacにVirtualBoxでUbuntuを立てる方法【画像での解説つき】

FPGAのultra96v2で「unboxingからLチカまで」の操作手順【avnet, hardware】

AIをカメラとかのハードウェア上で動かすために、ラズパイと同じFPGAField Programmable Gate Array)のUltra96-v2を購入した。

目的はハードでAIを使いたいから(≒ヒロアカのハイエンド脳無に惚れたから)。



FPGAでAIを動かすために必要な作業は下の図のようになり、今回は「SDカード作りの部分」をまとめた。


FPGAでAIを動かすために必要な作業f:id:trafalbad:20200229150230p:plain



SDカード作りは「unboxing(開封)してから、一通りUltra96-v2を動作させる(Lチカ)まで」で、その手順には


・ライセンス取得
・Micro SD cardイメージをSDカードに書き込む
wifiを通し、Lチカで動作確認


などが必要で、とりあえず作業で手順をまとめてく。

ultra96v2の構造



目次
1,ライセンス取得
2. Micro SD cardイメージをSDカードに書き込む
3.wifiを通し、Lチカで動作確認
4.linux上での一通りの操作


1,ライセンス取得

Ultra96-v2を買うと、XILINXのライセンス取得用の紙があるので用意。



XILINXのページにアクセスして、ユーザー名とパスワードを作成して、ログイン。


「Create New license」からvoucher code(ライセンス取得用紙の下のコード)を入力

f:id:trafalbad:20200229144631p:plain


そして、「OEM Zynq Ultra96 Vivado Design~Voucher pack」のライセンスを取得。

取得する際に、HostnameHost value idが必要。


・Hostname


linux上で

$ hostname

で確認



・Host value id


環境設定→「ネットワーク環境」で「内蔵Ethernet」を作成。

その後下の「詳細」→ハードウェア→で「MACアドレス」の12桁の英数字がhost value id

f:id:trafalbad:20200229144706j:plain

参考:MACアドレスの確認・IPアドレスの設定

またはこのコマンドを打てば、host IDがわかる。

$ /usr/sbin/netstat -I en0

ライセンスを取得するとライセンス確認用メールが届く。


再度ログイン後に、さっきのページで「Manege Licenseでlicense」から取得したライセンスを確認できてる。

f:id:trafalbad:20200229144740p:plain







2. Micro SD cardイメージをSDカードに書き込む


まず、MicroSDカードにイメージを書き込むために「etcher」をdownload。


次にMicro SD cardイメージのdownload

$ wget http://www.fpga.co.jp/AI-EDGE/ultra96v2_oob.img.zip 

etcherを起動後にinstall &解凍した「ultra96v2_oob.img」を開く。
MicroSD カードへのイメージの書き込みstart

f:id:trafalbad:20200229144838p:plain



書き込み完了

f:id:trafalbad:20200229144859j:plain







3. wifiを通し、Lチカで動作確認

Ultra96-v2の構成は以下のようになってる。


f:id:trafalbad:20200229144918p:plain




まず、microSDカードを取り出しultra96-v2に差し込む。
そしてSW4のスイッチを押す。

f:id:trafalbad:20200229144950j:plain



wifi名「ultra96-v2_ ~」が出てることを確認。


f:id:trafalbad:20200229145009j:plain

アクセスして、ブラウザから「http://192.168.2.1」にアクセス。



ultra96-v2の接続画面に入れた。

f:id:trafalbad:20200229145032j:plain


ここからのLチカの動作はこちらのyoutube動画を参照。

youtu.be






4.linux上での一通りの操作

とりあえず、例としてscpで必要なファイル転送が可能にしてみる。
パスワードは「root」を入力

$ ssh -l root 192.168.2.1
>>>
root@192.168.2.1's password: 
mount: /mnt: /dev/mmcblk0p1 already mounted on /run/media/mmcblk0p1.
mount: /mnt: /dev/mmcblk0 already mounted or mount point busy.
attempting to run /mnt/init.sh
/mnt
root@ultra96v2-oob-2019_2:~# 

これでUltra96-v2を購入してからLチカまでできるようになる。



次の記事ではコードを書いたり、FPGAを操作するIDEの「vitisプラットフォーム」を構築でき次第、記事にまとめようと思う。

f:id:trafalbad:20200229145519j:plain

Efficient-Unetで天気画像の予測(パターン認識)リベンジ【機械学習】

今回はこの前の記事で書いた「signateの天気コンペ」の優勝者(天気の専門家ガチ勢)が実装したモデルを、既存のデータでも予測できる構成で個人的に作ってみた。


convLSTMを使わずにUnetにしたのは「予測」タスクではなく、「パターン認識」タスクにしたかったから。


特定の気象条件なら、次の24時間はこういう画像になる」というパターン認識の形で次の24枚の天気画像を生成(予測)する。


目次
1.ネットワーク構成
2.ネットワークに使った技術
3.予測した画像
4.他の上位入賞者のテクの備忘録




1. ネットワーク構成


優勝者の使ったモデル



・自分で天気の特徴量を350こ作った

・ハイスペックマシンで計算可能な環境を持っていた

efficient-Netという最高精度の画像分類ネットワークを使ったencoderを2つ使ったUnet

hypercolumnの使用

Feature Pyramid Attention(FPA)の使用


という点が特徴で下のネットワーク構成
f:id:trafalbad:20200223012634j:plain




自分が作ったモデル




自分が目をつぶったポイント

・特別な特徴量を作成しない(面倒くさい、ガチ勢ちゃうから)

gooogle colabで計算できる計算量(金かけたくない)



上のポイントでケチったため、自分なりにかなり近い形の、下図のネットワークを作成した(encoderのinputは予測する一時間前の画像(直前の画像))

f:id:trafalbad:20200223012544j:plain

encoder input予測直前の画像(前日の23時の画像)
met input前日の3時間ごとの風の特徴量8こ
sat input前日の3時間ごとの天気画像8枚







2. ネットワークに使った技術

1.最後の出力層のoutput channelを24にして、セグメントタスクと同じ形式にした



out_channels = 24
o = Conv2D(out_channels, (1, 1), padding='same', kernel_initializer=conv_kernel_initializer)(o)




2. sigmoidを入れて、生成画像のブレをなくす


met-inputとsat-inputをdecoderに注入してるので、sigmoidで単位を合わせてあげなければ、画像がチャけた白黒テレビのようにブレブレになる。


f:id:trafalbad:20200223013111j:plain


sigmoidとhypercolumnの組み合わせで、ぶれを解消





3. PSP moduleの使用


PSP moduleはセグメントで有名なPSPNetで使われているモジュール。


PSPNetはEncoderにResNet101を使い、EncoderとDecoderの間にPyramid Pooling Module(PSP module)を追加している。

f:id:trafalbad:20200223012742p:plain


PSP moduleはhypercolmunと、注入したデータ(met-input, sat-Input)に適用したら、全てのケースで精度があがった。





4. 天気の特徴量(met-input, sat-input)をdecoderに挿入


met-input(風の特徴量), sat-input(天気画像)を全DecoderのConvtranspose層に挿入

# LambdaでreshapeしないとNonetypeエラーが出る
def psp_layer(inputs, skip_h, skip_w):
    inputs = PyramidPoolingModule()(inputs)
    output = Lambda(lambda x:tf.image.resize_images(x, size=(skip_h, skip_w), method=tf.image.ResizeMethod.BILINEAR))(inputs)
    return output



# encoderで挿入するより、直接Decoderに挿入の方がいい(やりやすい、早い、便利)。
def Conv2DTranspose_block(filters, kernel_size=(3, 3), transpose_kernel_size=(2, 2), upsample_rate=(2, 2),
                          initializer='glorot_uniform', skip=None, met_input=None, sat_input=None):
    def layer(input_tensor):
        x = Conv2DTranspose(filters, transpose_kernel_size, strides=upsample_rate, padding='same')(input_tensor)
        
        if skip is not None and met_input is not None:
            h, w = skip.get_shape().as_list()[1:3]
            met_output = psp_layer(met_input, h, w)
            sat_output = psp_layer(sat_input, h, w)
            x = Concatenate()([x, skip, met_output, sat_output])
        elif skip is not None and met_input is None:
            x = Concatenate()([x, skip])

        x = channel_spatial_squeeze_excite(x)
        return x

    return layer






5. FPA(Feature Pyramid Attention)


FPAはCNNで抽出した汎用特徴量の細かい部分まで補ってくれる。

セグメンテーションタスクだと細かい部分のピクセルまで再現できるので、セグメンテーションタスクでも使ってる例は多い。

f:id:trafalbad:20200223093005j:plain




FPAを使うときは以下の点に注意

・FPAを使うときは 画像サイズは shape=(256, 256)かそれ以上のshapeの必要がある

計算量が多くなる

今回は計算量の関係で使わなかったが、試しに使ってみると精度はかなり良くなった。




FPAのセグメンテーション使用例
f:id:trafalbad:20200223012840p:plain






6. SCSE(Concurrent Spatial and Channel Squeeze & Excitation)



SCSEはすでに出回ってる既存モデル(resnet50とかその他多数)に計算量をそこまで増やさず & 簡単に組み込むことができる。

f:id:trafalbad:20200223012859p:plain

特にセグメンテーション系などのタスクで性能を向上させることができる。


実際、DecoderのConvolution層の代わりに、SCSEを使ったら、計算量が減り、精度が上がった。






7. hypercolumn


hypercolumn」はConvolution層の出力を組み合わせて精度を上げる手法。

f:id:trafalbad:20200223012923p:plain


ベターな組み合わせは「Convolutional hypercolumns in Python」に詳しく載ってる。


今回のベストプラクティスは「decoder1とdecoder5」だった。

なるべく対照的な位置のlayerを組み合わせると良いらしい。

def interpolation(inputs, interpolation_shape):
    patch_size = np.multiply(inputs.get_shape().as_list()[1:3], interpolation_shape)
    inputs = PyramidPoolingModule()(inputs)
    output = Lambda(lambda x: tf.image.resize_images(x, size=patch_size, method=tf.image.ResizeMethod.BILINEAR))(inputs)
    return output

# decoder のhypercolumnの部分
if hypercolumn:
        o = Lambda(lambda x: tf.concat([x, d5], axis=3))(o)



8.精度指標


精度指標はなるべく多く使い(MSE, PSNR, SSIM)、多角的にモデルの性能を判断した。

from sklearn.metrics import mean_absolute_error
from skimage.measure import compare_ssim, compare_psnr
def measurement(func, **kwargs):
    val = func(kwargs["img1"], kwargs["img2"])
    return val

maes= 0
psnrs = 0
ssims = 0
for idx, (pr, im) in enumerate(zip(y_pred, test)):
  maes += mean_absolute_error(pr, im)
  psnrs += measurement(compare_psnr, img1=im, img2=pr)
  ssims += measurement(compare_ssim, img1=im, img2=pr)

print('total mae', maes/24)
print('total psnr', psnrs/24)
print('total ssim', ssims/24)


参考:MSE/PSNR vs SSIM の比較画像紹介






予測した画像

前回のと比べるとかなり良くなった

【GroundTruth】
f:id:trafalbad:20200223013020g:plain




【自分が予測した画像】
f:id:trafalbad:20200223013037g:plain

total mae 0.04931812573362152
total psnr 22.823581818309222
total ssim 0.7469266660346182



4. 他の上位入賞者のテクの備忘録


・好奇心でやってる人がほぼ全員、義務感でやってる奴はほぼ下位

画像サイズを変更して、同じネットワークでアンサンブル学習する。

efficient-Netのb4とかb5とかでうまくネットワーク変えながら、アンサンブルしてた。

metaデータからうまく天気と関連した特徴量を作成(マイナスの値を0に置換して、風の向きをうまくプラスのベクトルのみで表現してた)

論文から実装が多く、特にネットワークに変更は加えてない(PredRNN++とか)

・セグメントタスクみたいにチャンネルを24にして予測する手法はみんなしてた。

データ量は少なくして(1 batchとか)、爆速でPDCA回す。

精度指標は多めにして多角的視点から精度評価してた




参考サイト


hypercolumn参考GitHub

FPAを使用したUnetの参考GitHub

エイリアスを設定してlinuxのショートカットコマンドを作成する(linuxカスタマイズ)

エイリアスを設定して、長ったらしいlinuxコマンドのショートカットコマンドを、自分なりにカスタマイズして作成したのでその備忘録。

これで面倒なコマンドはいちいちググらずに済む。


f:id:trafalbad:20200210103255j:plain


目次
1. .bashrcと.zshenv にエイリアスを記述する
2. .bash_profileで.bashrc(と.zshenv)を読み込む設定をする
3. 実験
4. まとめ



1. .bashrcと.zshenvにエイリアスを記述する

自分のPCの場合、anaconaをインストールしてたためか、エラー

zsh: command not found


が出るので「.zshenv」ファイルにも同じことを書く必要があった。

まず試しにファイル数をカウントするコマンドで

alias count='ls -1 | wc -l'

を書いてみる。

# .bashrc(と.zshenv)ファイルをvimで開く
$ vi ~/.bashrc  (vi ~/.zshenv)


# 「i」で入力モードになるので入力モードで
$ alias count='ls -1 | wc -l'

と入力後「esc+:wq」で入力モードを終了。





2. .bash_profileで.bashrc(と.zshenv)を読み込む設定をする

エイリアスは.bash_profileに.bashrc(と.zshenv)を読んでもらう必要がある。


.bash_profileはターミナルが起動すると読み込まれる仕組みなので、ターミナルを起動するたびに読み込んでもらう。つまりショートカットコマンドを永久に保存できる。

$ vi ~/.bash_profile
# 以下を入力
source ~/.bashrc
source ~/.zshenv


と記述。この変更自体も反映させなければいけないので、ターミナルから以下を実行

$ source ~/.bash_profile


自分のPCはanacondaの変なコマンドが書いてあるので、消去してまっさらな状態で上のコマンドだけ書いて実行。







3.実験

実験1



# desktopに移動コマンドのショートカット作成
$ vi ~/.bashrc (vi ~/.zshenv)
alias desk='cd && cd desktop'

# 反映
$ source ~/.bash_profile

# 実行
$ desk
$ pwd 
>>>> /Users/~/desktop

移動できた





実験2



# ファイル数カウントコマンドのショートカット作成
$ vi ~/.bashrc (vi ~/.zshenv)
$ alias count='ls -1 | wc -l’

# 反映
$ source ~/.bash_profile

# 実行
$ count
>>>> 6


できた。





4.まとめ

エイリアス設定の利点はたくさんあるけど、下の2つがでかい。

・いちいち調べてたlinuxコマンドを調べる手間が減った
・長いlinuxコマンドを入力せずに簡単に実行できた。

これが生産性向上かと思う瞬間だった気がした。


# vi ~/.bashrcと~/.zshenvの中身
alias count='ls -1 | wc -l'
alias desk='cd && cd desktop'
alias down='cd && cd downloads'
# vi ~/.bash_profileの中身
source ~/.bashrc
source ~/.zshenv




参考サイト



ターミナルをいじってるとzshが「command not found」と叫ぶので、叫ばないようにした

conda activate の CommandNotFoundError への対処方法

【初心者向け】エイリアスの設定方法

学習済みのYOLOv3でオリジナルデータに転移学習(finetune)【物体検出】

オリジナルのデータセットにYOLOv3を使って物体検出した。
一から学習せずに、COCOデータセットの学習済みYOLOv3で転移学習してみたのでその備忘録


目次
1.オリジナルデータセットのclasses.txtと学習済みモデルの作成
2.訓練
3.学習結果


1.オリジナルデータセットのclasses.txtと学習済みモデルの作成

オリジナルデータセットはとあるコンペの公開画像を使用。

データセットformat(classes.txt)


[image_path, x1, y1, x2, y2, clas_id] で入力

anno_path = 'dataset_path'
fname = [path for path in os.listdir(anno_path)]
sorted_file =[path for path in natsorted(fname)]

df=[]
for idx, f in enumerate(sorted_file):
    fname, save,  b, cls_id = convert_annotation(anno_path, f)
    img = cv2.imread(fname)
    df.append([save, b[0], b[1], b[2], b[3], cls_id])

with open('classes.txt', 'w+') as f:
    for d in df:
        f.write(','.join(map(str, d)) + '\n')


classes.txt

Car
Pedestrian
Truck
Signal
Signs
Bicycle




学習済みモデル作成手順



kerasのYOLOv3を参考にdarknet53のweightの代わりに、COCO datasetの学習済みのYOLOv3のweightを使用

# Keras versionのYOLOv3をgit clone

$ git clone https://github.com/tanakataiki/keras-yolo3

# 学習済みmodelをdownloads
$ wget https://pjreddie.com/media/files/yolov3.weights

# 変換
$ python convert.py yolov3.cfg yolov3.weights yolo.h5

サイトに書いてあるとおり。






train.pyで使用

DARKNET_PATH = 'yolov3.h5'

def create_tiny_model(input_shape, anchors, num_classes, load_pretrained=True, freeze_body=2,
            weights_path=DARKNET_PATH):
    '''create the training model, for Tiny YOLOv3'''
    K.clear_session() # get a new session
    image_input = Input(shape=(None, None, 3))
    h, w = input_shape
    num_anchors = len(anchors)

    y_true = [Input(shape=(h//{0:32, 1:16}[l], w//{0:32, 1:16}[l], \
        num_anchors//2, num_classes+5)) for l in range(2)]

    model_body = tiny_yolo_body(image_input, num_anchors//2, num_classes)
    print('Create Tiny YOLOv3 model with {} anchors and {} classes.'.format(num_anchors, num_classes))

    if load_pretrained:
        model_body.load_weights(weights_path, by_name=True, skip_mismatch=True)
        print('Load weights {}.'.format(weights_path))
        if freeze_body in [1, 2]:
            # Freeze the darknet body or freeze all but 2 output layers.
            num = (20, len(model_body.layers)-2)[freeze_body-1]
            for i in range(num): model_body.layers[i].trainable = False
            print('Freeze the first {} layers of total {} layers.'.format(num, len(model_body.layers)))

    model_loss = Lambda(yolo_loss, output_shape=(1,), name='yolo_loss',
        arguments={'anchors': anchors, 'num_classes': num_classes, 'ignore_thresh': 0.7})(
        [*model_body.output, *y_true])
    model = Model([model_body.input, *y_true], model_loss)

    return model




2.訓練

optimizerとcallbackメソッド

Adam(lr=1e-3)

ReduceLROnPlateau

ModelCheckpoint

model.compile(optimizer=Adam(lr=1e-3), loss={'yolo_loss': lambda y_true, y_pred: y_pred})

reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, verbose=1)
checkpoint = ModelCheckpoint('drive/My Drive/ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',
        monitor='val_loss', save_weights_only=True, save_best_only=True, period=1)


学習曲線は怖いくらい順調に下がり、ログをとってないけどほぼ下の図のように降下。汎化性能も抜群


学習曲線図

f:id:trafalbad:20200118163451j:plain


YOLOv3はネットワークの構造上、大きい物体を学習しておけば、推論時には小さい物体も検知できるので、学習時には大きい物体のみくっきり写ってる「良質かつ大量」のデータセットで学習


yolov3は構造上小さい物体も検知できる

f:id:trafalbad:20200118163430p:plain




3.学習結果

予測した画像は下の感じ。かなりいい感じに検出できてる


明るい画像



f:id:trafalbad:20200118163531j:plain



f:id:trafalbad:20200118163528j:plain


夜の暗い画像


f:id:trafalbad:20200118163550j:plain


f:id:trafalbad:20200118163554j:plain


学習時に気をつけたことは

大きい物体がくっきり写ってる良質かつ大量のデータセットで学習(小さい物体は学習させてない)


optimizerはSGDではなくAdamに変更

callbackメソッドでval_lossの調整が意外に効いた

公開されてる学習済みモデルで転移学習はコスパ的にかなり秀逸


今回はdarknet53の重みで一から学習せずにYOLOv3で転移学習してみた。faster-RCNNより小さい物体の検出対策がやりやすいので好きになった。



一から学習するより公開済みの学習ずみモデルで転移学習すれば、ほとんどのモデルで予想以上の成果でそう。


参考サイト


A Closer Look at YOLOv3

Kaggle 2018 Google AI Open Images - Object Detection Track

HOG+Adaboostで物体検出(object detection)【機械学習】

HOGとの組み合わせはSVMが有名だけど、今回はSVMじゃなく「HOG+AdaBoost」を使った。

どっちも精度は同じくらいだけど、AdaBoostの方が2回目以降精度が増すし、汎用性が高いのが特徴。


目次
・訓練データ・テストデータの収集
・前処理
HOG+AdaBoostで物体検出


訓練データ・テストデータの収集

あらかじめバウンディングボックスの座標がアノテーションされた画像から、車とそれ以外のものをクロップして

・Positiveサンプル(車):1500枚 
・negativeサンプル(車以外): 1500枚

を集めた。

車がちょうどよく入る大きさのにresize(300px)。Sliding windowサイズはリサイズしたサイズより大きめ(400~600px)にとった。

サンプルが多く、綺麗に物体が写ってるほど精度も良かった。

# trainと精度
print("HOG classifier AdaBoosting...")
ada = AdaBoostClassifier(n_estimators=100, random_state=0)
ada.fit(trainData, trainLabels)

print("HOG classifier Evaluating on test data ...")
predictions = ada.predict(testData)
print(classification_report(testLabels, predictions))

>>>>>>
"""
 Evaluating classifier on test data ...
              precision    recall  f1-score   support

           0       0.91      0.92      0.91       375
           1       0.90      0.88      0.89       301

    accuracy                           0.90       676
   macro avg       0.90      0.90      0.90       676
weighted avg       0.90      0.90      0.90       676
"""



前処理

基本的に前処理は以下の流れ

1. trainの時にHOG特徴量が検出しやすいように画像を明るくする

2. testや本番で使う画像には前処理かけない(明るくしない)



明るくする方法はいくるかあるけどgammaを使ったコントラストは上手くいかない、しかも精度を下げる結果に。

def ganmma(img, gamma = 3.0):
    lookUpTable = np.zeros((256, 1), dtype = 'uint8')
    for i in range(256):
        lookUpTable[i][0] = 255 * pow(float(i) / 255, 1.0 / gamma)

    img_gamma = cv2.LUT(img, lookUpTable)
    return img_gamma

なので明るくするために、単純にRGBごとに明るくして、不純物を極力含めないようにした。

def equalize(img):
    for j in range(3):
        img[:, :, j] = cv2.equalizeHist(img[:, :, j])
    return img






HOG+AdaBoostで物体検出

HOG特徴量を使った物体検出の仕組みは、sliding windowを順番に画像内を走らせて、検出できた領域をバウンディングボックスで囲む。



f:id:trafalbad:20200112185716p:plain

def sliding_window(image, stepSize, windowSize):
    # slide a window across the image
    for y in range(0, image.shape[0], stepSize):
        for x in range(0, image.shape[1], stepSize):
            # yield the current window
            yield (x, y, image[y: y + windowSize[1], x:x + windowSize[0]])



検出結果



Sliding windowサイズを大きめ(400〜600px)にして、検出後にHOG特徴量用の300pxにリサイズした方が検出結果がよかった。

ベストパフォーマンスはWindow size = (500, 500) にResize size = (300, 300)




Window size = (500, 500) Resize size = (300, 300)のとき(ベストパフォーマンス)
f:id:trafalbad:20200112185839j:plain





Window size = (400, 400) Resize size = (300, 300)のとき
f:id:trafalbad:20200112185902j:plain




Window size = (600, 600) Resize size = (300, 300)のとき
f:id:trafalbad:20200112185918j:plain







物体検出以外の使い方



HOGでの物体検出は検出領域をバウンディングボックスで囲む以外にも、「エッジ検出」したり、「輪郭抽出」したりといろんな使い方ができる。

HOGでのsliding windowでの用途は多様なので、yolov3とかfaster-RCNNの物体検出ニューラルネットワークの「補助的な役割」として使うくらいがお利口な使い方かと思った。


バウンディングボックスで囲む部分のエッジ検出

def rgb_to_gray(src):
    b, g, r = src[:,:,0], src[:,:,1], src[:,:,2]
    return np.array(0.2989 * r + 0.5870 * g + 0.1140 * b, dtype='uint8')

def edge_detection(img):
    img_hist_eq = img.copy()
    for i in range(3):
        img_hist_eq[:, :, i] = cv2.equalizeHist(img_hist_eq[:, :, i])
    # img_gray = cv2.cvtColor(img_hist_eq, cv2.COLOR_BGR2GRAY) 
    img_gray = rgb_to_gray(img_hist_eq)
    canny_img = cv2.Canny(img_gray, 50, 110)
    backtorgb = cv2.cvtColor(canny_img,cv2.COLOR_GRAY2RGB)
    return backtorgb


f:id:trafalbad:20200112185949j:plain






バウンディングボックスで囲む部分の輪郭抽出

def extract_contours(img):
    imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,thresh = cv2.threshold(imgray,127,255,0)
    image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

    contour_img = cv2.drawContours(img, contours, -1, (0,255,0), 3)
    return contour_img

f:id:trafalbad:20200112190007j:plain






発展系 joint-HOG


単なるHOG特徴量だけを使うのではなく、ピクセルごとのHOG特徴量(の勾配)の組み合わせを使った「joint-HOG」もある。



joint-HOGの検出例
f:id:trafalbad:20200112190051p:plain


下のように、仕組みを真似して自分なりに組んでみたけど特に精度が良くなるわけではなかった。

from skimage.feature import hog
from skimage import data, exposure

# 輝度勾配を計算
def hog_gradient_img(image):
    fd, hog_image = hog(image, orientations=8, pixels_per_cell=(16, 16),
                        cells_per_block=(1, 1), visualize=True)

    hog_image_rescaled = exposure.rescale_intensity(hog_image, in_range=(0, 10))
    return hog_image_rescaled


# 勾配画像からjoint HOGを作成
def joint_hog(hog_img, threshold = 0.1):
    joint_fd = []
    fd = hog_img.flatten()
    for y in fd:
        for x in fd:
            if y-x > threshold:
                bit = 0
            else:
                bit = 1
            joint_fd.append(bit)
    return np.array(joint_fd)

組み方がよくないのは確かなので、正規のやり方でやればいい結果が出ることは間違いない。


HOGは決まったサイズの画像にしか適用できない上に、sliding windowを使うと計算コストもバカ高いので、物体検出はやっぱニューラルネットワーク一択だなと実感した。

ただニューラルネットワークのための画像前処理としては十分使えるのは間違いない。
joint-HOGは時間がなくてガチなのは組めなかったけど、qiitaとかで注目されてきたらやってみたい




参考サイト



【joint-HOG
第20回LSIデザインコンテスト・イン沖縄 設計仕様書 - 3-1
python-hog(github)

Joint HOG 特徴を用いた 2 段階 AdaBoost による車両検出

局所特徴量と統計学習法による物体検出



HOG物体検出参考サイト】
Opencvチュートリアル

python-bow-hog-object-detection