空飛ぶロボットのつくりかた

ロボットをつくるために必要な技術をまとめます。ロボットの未来についても考えたりします。

GPD pocketにUbuntu18.04 & ROS Dashing Install

[セット品]GPD Pocket 本体,Three One®オリジナル収納バッグ,Lenovo純正ロープロファイルトラックポイント セット

ロボットの開発に便利な小型PC

やりたいこと

GPDにUbuntu18.04をインストール。そのあとROS2 Dashingのインストールと動作チェック。

ざっくりまとめ。いま手元にあるPCを全部Ubuntu18.04に移行中。。。

Ubuntuインストールのための準備

  1. BIOSの変更(してない場合)
  2. ISOファイルのダウンロード

ISOイメージの作り方

  1. Etcherをダウンロード(iso書き込み用)
  2. ブート用USBをさす

  3. Etcherを立ち上げ先程ダウンロードしたISOファイルを書き込み

Ubuntuのインストール

  1. ブータブルUSBをさして、再起動し、Fn + F7を複数回打ち込む。

  2. 起動の選択にブータブルUSBを選択。

  3. Ubuntu install。

  4. ここで多分grubのエラーがでる。その際はそのまま進み。boot-repairを使って以下の手順で修復。

    1. Terminalを開く。

    2. sudo add-apt-repository ppa:yannubuntu/boot-repair && sudo apt-get update

    3. sudo apt-get install -y boot-repair && (boot-repair &)

    4. Recommended repairを実行

ROS2 Dashingのインストール

以下の手順のInstall development tools and ROS toolsまで実施。

そのあと

  1. sudo apt install ros-dashing-desktop

  2. source /opt/ros/dashing/setup.bash

  3. ros2 run demo_nodes_cpp talker

これで以下の写真のようなHello World画面が出ればOK。

f:id:robonchu:20190819123244j:plain
ros2 demo check in GPD pocket

GPD pocketにUbuntu18.04とROS2 Dashingのインストールされたことが確認できる。

コメント

GPD pocketはこんな感じでRoombaなど小さいロボットに載せるのに便利。

f:id:robonchu:20190819123807p:plain

構成はRoomba620 x RPLIDAR A1 x GPD pocket です。

robonchu.hatenablog.com

Roomba Hackの詳細はからあげ先生の記事をご覧ください。

karaage.hatenadiary.jp

MyEnigmaさんのソフトウェア編がとても楽しみ♪

myenigma.hatenablog.com

はじめてのROSでOpenVINO - インストール〜サンプル実行まで

f:id:robonchu:20190624060141p:plain

やりたいこと

  • CPUリソースで認識機能(顔検出や姿勢推定など)をそこそこの検出速度(10~30FPSくらい)で使いたい

  • ROS x OpenVINOを動かしてみる

環境

  • OS: Ubuntu18.04

  • Middleware: ROS1 melodic

  • CPU: Intel® Core™ i7-8650U CPU @ 1.90GHz × 8

使用するパッケージは⤵

GitHub - intel/ros_openvino_toolkit

ROS x OpenVINOのデザインアーキ

f:id:robonchu:20190624064728p:plain
https://github.com/intel/ros_openvino_toolkit

実装されている認識機能

  1. Face Detection
  2. Emotion Recognition
  3. Age & Gender Recognition
  4. Head Pose Estimation
  5. Object Detection
  6. Vehicle Detection
  7. Object Segmentation
  8. Person Reidentification

インストール&各種設定

環境設定

手順は以下に沿って行う

流れを順に説明⤵

  1. ros_openvino_toolkitのインストール

    git clone https://github.com/intel/ros_openvino_toolkit.git

  2. セットアップスクリプトの実行

    • cd ~/ros_openvino_toolkit/script

    • ./environment_setup.sh

    • 内容の変更は同フォルダのmodules.conf(以下参照)をいじる。0すると無効。

      clean=1

      ros_debian=0

      opencv=1

      opencl=1

      dldt=1

      model_zoo=1

      openvino=1

      librealsense=0

      other_dependency=0

  3. 環境変数の設定(set ENV InferenceEngine_DIR, CPU_EXTENSION_LIB and GFLAGS_LIB)

    • export InferenceEngine_DIR=/opt/openvino_toolkit/dldt/inference-engine/build/

    • export CPU_EXTENSION_LIB=/opt/openvino_toolkit/dldt/inference-engine/bin/intel64/Release/lib/libcpu_extension.so

    • export GFLAGS_LIB=/opt/openvino_toolkit/dldt/inference-engine/bin/intel64/Release/lib/libgflags_nothreads.a

    • 毎回設定したくない人は、以下を.bashrcなどに追記すると良い。  

  4. catkin_make用のworkspace作成

    • mkdir -p ~/catkin_ws/src

    • cd ~/catkin_ws/src

    • git clone https://github.com/intel/ros_openvino_toolkit

    • git clone https://github.com/intel/object_msgs

    • git clone https://github.com/ros-perception/vision_opencv

    • git clone https://github.com/intel-ros/realsense

    • cd realsense

    • git checkout 2.1.3

  5. パッケージのビルドとリンク

    • source /opt/ros/melodic/setup.bash
    • cd ~/catkin_ws
    • catkin_make
    • source devel/setup.bash
    • sudo mkdir -p /opt/openvino_toolkit
    • sudo ln -s ~/catkin_ws/src/ros_openvino_toolkit /opt/openvino_toolkit/ros_openvino_toolkit

ここまで来たらあともう少し

事前準備

GitHub - intel/ros_openvino_toolkitの手順に沿って行う。

訓練済みモデルの変換

Segmentation(Mask-RCNN)を使うための準備。

 cd /opt/openvino_toolkit/dldt/model-optimizer/install_prerequisites
 sudo ./install_prerequisites.sh
 mkdir -p ~/Downloads/models
 cd ~/Downloads/models
 wget http://download.tensorflow.org/models/object_detection/mask_rcnn_inception_v2_coco_2018_01_28.tar.gz
 tar -zxvf mask_rcnn_inception_v2_coco_2018_01_28.tar.gz
 cd mask_rcnn_inception_v2_coco_2018_01_28
 python3 /opt/openvino_toolkit/dldt/model-optimizer/mo_tf.py --input_model frozen_inference_graph.pb --tensorflow_use_custom_operations_config /opt/openvino_toolkit/dldt/model-optimizer/extensions/front/tf/mask_rcnn_support.json --tensorflow_object_detection_api_pipeline_config pipeline.config --reverse_input_channels --output_dir ./output/
 sudo mkdir -p /opt/models
 sudo ln -s ~/Downloads/models/mask_rcnn_inception_v2_coco_2018_01_28 /opt/models/

Detection(MobileNet-SSD)を使うための準備。

  • sudo apt-get install python3-networkx
 cd /opt/openvino_toolkit/open_model_zoo/model_downloader
 python3 ./downloader.py --name mobilenet-ssd
 #FP32 precision model
 sudo python3 /opt/openvino_toolkit/dldt/model-optimizer/mo.py --input_model /opt/openvino_toolkit/open_model_zoo/model_downloader/object_detection/common/mobilenet-ssd/caffe/mobilenet-ssd.caffemodel --output_dir /opt/openvino_toolkit/open_model_zoo/model_downloader/object_detection/common/mobilenet-ssd/caffe/output/FP32 --mean_values [127.5,127.5,127.5] --scale_values [127.5]
 #FP16 precision model
 sudo python3 /opt/openvino_toolkit/dldt/model-optimizer/mo.py --input_model /opt/openvino_toolkit/open_model_zoo/model_downloader/object_detection/common/mobilenet-ssd/caffe/mobilenet-ssd.caffemodel --output_dir /opt/openvino_toolkit/open_model_zoo/model_downloader/object_detection/common/mobilenet-ssd/caffe/output/FP16 --data_type=FP16 --mean_values [127.5,127.5,127.5] --scale_values [127.5]
最適化されたモデルの中間表現をダウンロード
 cd /opt/openvino_toolkit/open_model_zoo/model_downloader
 python3 downloader.py --name face-detection-adas-0001
 python3 downloader.py --name age-gender-recognition-retail-0013
 python3 downloader.py --name emotions-recognition-retail-0003
 python3 downloader.py --name head-pose-estimation-adas-0001
 python3 downloader.py --name person-detection-retail-0013
 python3 downloader.py --name person-reidentification-retail-0076
ラベルファイルのコピー

Segmentation用

 sudo cp /opt/openvino_toolkit/ros_openvino_toolkit/data/labels/object_segmentation/frozen_inference_graph.labels /opt/models/mask_rcnn_inception_v2_coco_2018_01_28/output

Detection用

 sudo cp /opt/openvino_toolkit/ros_openvino_toolkit/data/labels/emotions-recognition/FP32/emotions-recognition-retail-0003.labels /opt/openvino_toolkit/open_model_zoo/model_downloader/Retail/object_attributes/emotions_recognition/0003/dldt
 sudo cp /opt/openvino_toolkit/ros_openvino_toolkit/data/labels/face_detection/face-detection-adas-0001.labels /opt/openvino_toolkit/open_model_zoo/model_downloader/Transportation/object_detection/face/pruned_mobilenet_reduced_ssd_shared_weights/dldt
 sudo cp /opt/openvino_toolkit/ros_openvino_toolkit/data/labels/object_detection/mobilenet-ssd.labels /opt/openvino_toolkit/open_model_zoo/model_downloader/object_detection/common/mobilenet-ssd/caffe/output/FP32
 sudo cp /opt/openvino_toolkit/ros_openvino_toolkit/data/labels/object_detection/mobilenet-ssd.labels /opt/openvino_toolkit/open_model_zoo/model_downloader/object_detection/common/mobilenet-ssd/caffe/output/FP16
環境変数の設定
  • export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/openvino_toolkit/dldt/inference-engine/bin/intel64/Release/lib

  • 毎回設定したくない人は、以下を.bashrcなどに追記すると良い。

サンプル実行

パソコンに既存のカメラもしくは指しているUSBカメラ情報を用いた顔認識周りのサンプル

  1. cd ~/catkin_ws/

  2. source devel/setup.bash

  3. roslaunch vino_launch pipeline_people_oss.launch

すると、rvizとImageWindowが立ち上がり結果が表示される。

全力で笑顔を作るとちゃんとHappyに☺

f:id:robonchu:20190624071058p:plain

加工雑すぎ問題...

中身の簡単な解説とFPS

このlaunchは、

  1. 顔検出

  2. 年齢&性別判定

  3. 感情推定

  4. 頭の向き推定

が立ち上がるようになっていて、検出速度は10FPSくらいでてる。

顔検出だけにするとだいだい30FPSまで上がる。

launchファイルはparamディレクトリのyamlファイルを読み込むようになっていて、このyamlにどの認識機能を使うかや何を入力としてどこに出力するか等の設定が書かれている。

所感

CPUリソースだけで処理速度はそこそこ速いので、ラピッドプロトで何かを作る際には便利だと思う。

OpenVINOのROS2パッケージもあるし、OpenVINOは今後も要チェック。

個人の活動はもうそろそろROS2に切り替えていこう。

アルゴリズムのお勉強(3)- 動的計画法(DP) : ボトムアップ形式

f:id:robonchu:20190610003125p:plain
http://theoryofprogramming.com/2015/03/02/dynamic-programming-introduction-and-fibonacci-numbers/

やりたいこと

動的計画法とは

以下動的計画法 - Wikipediaから抜粋。

  • 細かくアルゴリズムが定義されているわけではなく、下記2条件を満たすアルゴリズムの総称である。

    1. 帰納的な関係の利用:より小さな問題例の解や計算結果を帰納的な関係を利用してより大きな問題例を解くのに使用する。

    2. 計算結果の記録:小さな問題例、計算結果から記録し、同じ計算を何度も行うことを避ける。

今回着目するのは1番の方。漸化式で解ける。

ボトムアップ形式のDPを使ってとく例題

atcoder.jp

  • AtCoder Beginner Contest 129のC問題より抜粋

問題: C - Typical Stairs

f:id:robonchu:20190610005349p:plain

入力

f:id:robonchu:20190610005526p:plain

出力

f:id:robonchu:20190610005700p:plain

制約

f:id:robonchu:20190610005639p:plain

入力/出力例

入力
6 1
3
出力
4

移動方法は以下の 4通りです。

  • 0→1→2→4→5→6
  • 0→1→2→4→6
  • 0→2→4→5→6
  • 0→2→4→6

解き方

以下の漸化式を用いて壊れた床の場合はスキップすることで解ける。

f:id:robonchu:20190610010827p:plain

  • x段目にたどり着く方法はx-1から一歩で上がるか、x-2から二歩であがるかの二通りだから。

ボトムアップ形式のDPを使った実装例(C++)

f:id:robonchu:20190610010157p:plain

#include <iostream>
#include <vector>

using namespace std;
const long long mod=1e9+7;
 
int main(){
  int N, M;
  cin >> N >> M;
 
  //  0段目があるので、N+1の配列を用意し、
  //  壊れていない階段をtrue=1、壊れている階段をfalse=0で初期化。
  //  これを使ってスキップの処理を行う。
  vector<int> oks(N + 1, true);
  for(int i = 0; i < M; ++i) {
    int a;
    cin >> a;
    oks[a] = false;
  }

  //  0~N段目までの"通り数"を入れる配列
  vector<long long int> dp(N + 1);

  //  0段目を1で初期化
  dp[0] = 1;
 
  for(int now = 0; now < N; ++now){
    //  ここがポイント。
    //  階段が壊れていなければ、ここのfor loopはi = N - 1 を除いて二回、i = N - 1のときは一回実行される。
    //  この二回の実行の繰り返しによって上記の漸化式が実装でされることになる。
    //  以下に簡単なイメージ図を添付。  
    for(int next = now + 1; next <= min(N, now + 2); ++next){
      //  最初に作ったoks配列を用いることで壊れている床をスキップする。
      if (oks[next]) {
        //  漸化式。
        dp[next] += dp[now];

        //  期待される出力のためにmodで割る。
        dp[next] %= mod;
      }
     }
   }

   // 求めたいN番目の通り数を出力。
   cout << dp[N] << endl;
   return 0;
}

f:id:robonchu:20190610015946p:plain

内容まとめ

  • 漸化式を使って解く。

  • 漸化式の実装にコツがいるが、基本的には問題に対して正しく漸化式が作れれば解ける。

  • 実装する前に上のように紙に書くなどして頭を整理すると良い。

感想

DPが使いこなせるようになれば、解ける問題が一気に増えるイメージ。

次はトップダウンも扱いたい。簡潔ないい問題ないかな。

アルゴリズムのお勉強(2)- 深さ優先探索(DFS)

f:id:robonchu:20190520021125p:plain
Wikipedia - 深さ優先探索

やりたいこと

深さ優先探索とは

上図のように繋がっているノードを上から下へ順々に探索。再帰関数かスタックで解ける。

詳細は以下参照。

深さ優先探索を用いて解く例題

問題: D - Even Relation

f:id:robonchu:20190520021705p:plain

入力

f:id:robonchu:20190520021747p:plain

出力

f:id:robonchu:20190520022010p:plain

制約

f:id:robonchu:20190520021905p:plain

入力/出力例

入力
3
1 2 2
2 3 1
出力
0
0
1
深さ優先探索を用いた実装例(C++)
再帰関数を用いた実装
#include <iostream>
#include <vector>
 
using namespace std;
const int MAX_N = 100001;

// 対象のノード番号の要素にそれに隣接するノード名とその距離のペアが入る
vector<std::pair<int, int>> vm[MAX_N];
int ans[MAX_N];

// 第1引数に対象ノード番号を入れる
// 第2引数はすでにチェックした番号を示す
void DFS(int target, int checked){
  for(int i=0; i < vm[target].size(); ++i){
    int nn = vm[target][i].first;  // 隣接ノード番号を格納
    if(nn == checked) continue;  //チェックしたものの場合は飛ばす
    
    if(vm[target][i].second % 2) {
      // 2で割り切れない場合、白黒を入れ替える
      if(ans[target]) ans[nn] = 0;
      else ans[nn] = 1;
    }else{
      ans[nn] = ans[target];
    }
    DFS(nn, target);
  }
}

 
int main(){
  int n;
  cin >> n;

  int u, v, w;
  for(int i=0; i<n-1; ++i){
    cin >> u >> v >> w;
    // u,vの同じノード番号の要素に値を追加。
    vm[u].push_back(std::make_pair(v,w));
    vm[v].push_back(std::make_pair(u,w));
  }
 
  // 1から順に探索を始める。1は最初に探索するので、第2引数にもセット。
  DFS(1, 1);

  for(int i=1; i<=n; ++i){
    cout << ans[i] << endl;
  }
  return 0;
}

内容まとめ

  • 深さ優先探索は上記例のように繋がっているノードを上から下へ順に調べていく手法。

  • 実装時には再帰関数かスタックを用いる。

感想

アルゴリズムは実装ポイントを知っていると、実装時間がだいぶ短縮できる。

それぞれのアルゴリズムの内容理解に加えて実装ポイントを抑えていこう。

実機を使ってマニピュレーション技術を学ぼう(1)- 環境セットアップ編

f:id:robonchu:20190512104005p:plain

やりたいこと

  • ロボットのコア技術であるマニピュレーション技術(主に認識とプランニング)を安価な実機を動かしながら学んでいく。

  • タスクとしては、様々な対象物を認識して、物を把持したり、置いたりする。

仕様実機

想定OS/ミドルウェア

  • Ubuntu16.04

  • ROS Kinetic

    • ROS2も触り始めたい...

今回のテーマ

  • ロボットアームBraccioの環境設定

今回必要なもの

Arduinoのセッティング

以下を参照。とてもわかり易いです。ありがとうございます!

Braccioのセッティング

ソフト

  1. GitHub - arduino-org/arduino-library-braccio: Arduino Braccio LibraryからGit clone

  2. cloneした内容を~/arduino-1.8.9/libraries/にコピー

  3. arduinoを起動

  4. 左上のFile->Examples->Braccio->testBraccio90を選択し書き込み

ハード

  1. 説明書を見ながら頑張って組み立てる笑。以下動画がおすすめ。とても簡単。

アライメント

  1. BraccioのシールドをUnoに挿して電源接続。

  2. Unoのリセットボタンを押すと先程のtestBraccio90が走る。理想状態は以下の写真。

    f:id:robonchu:20190512104641p:plain

  3. ズレていたら以下のように最終行を書き換えて修正し、初期値のズレを計測(メモ)しておく。

 /*
  testBraccio90.ino

 testBraccio90 is a setup sketch to check the alignment of all the servo motors
 This is the first sketch you need to run on Braccio
 When you start this sketch Braccio will be positioned perpendicular to the base
 If you can't see the Braccio in this exact position you need to reallign the servo motors position

 Created on 18 Nov 2015
 by Andrea Martino

 This example is in the public domain.
 */

#include <Braccio.h>
#include <Servo.h>


Servo base;
Servo shoulder;
Servo elbow;
Servo wrist_rot;
Servo wrist_ver;
Servo gripper;

void setup() {  
  //Initialization functions and set up the initial position for Braccio
  //All the servo motors will be positioned in the "safety" position:
  //Base (M1):90 degrees
  //Shoulder (M2): 45 degrees
  //Elbow (M3): 180 degrees
  //Wrist vertical (M4): 180 degrees
  //Wrist rotation (M5): 90 degrees
  //gripper (M6): 10 degrees
  Braccio.begin();
}

void loop() {
  /*
   Step Delay: a milliseconds delay between the movement of each servo.  Allowed values from 10 to 30 msec.
   M1=base degrees. Allowed values from 0 to 180 degrees
   M2=shoulder degrees. Allowed values from 15 to 165 degrees
   M3=elbow degrees. Allowed values from 0 to 180 degrees
   M4=wrist vertical degrees. Allowed values from 0 to 180 degrees
   M5=wrist rotation degrees. Allowed values from 0 to 180 degrees
   M6=gripper degrees. Allowed values from 10 to 73 degrees. 10: the toungue is open, 73: the gripper is closed.
  */
  
  // the arm is aligned upwards  and the gripper is closed
                     //(step delay, M1, M2, M3, M4, M5, M6);
  // Braccio.ServoMovement(20,         95, 90, 90, 90, 90,  73);  // ここを以下のように書き換え
  Braccio.ServoMovement(20,         95, 95, 98, 95, 86,  73);  
  
     
}

以上で簡単なBraccioのセットアップは完了。

テスト動作

  1. exampleプログラムのtakethespongeを書き込み

    • arduino editorを開いて左上のFile->Examples->Braccio->takethespongeを選択
  2. 実行すると、こんな感じ↓

  • 色はスプレーで塗装してます

次回

  • ROS x MoveIt! でモーションプランをする予定。

f:id:robonchu:20190512110151p:plain

所感

$200+αで家でいろんな実験ができるのはいい感じ。きれいに色塗るの難かしい...

最終的に机の上を自律で片付けるくらいまでまとめれたらいいな。

アルゴリズムのお勉強(1)- 幅優先探索(BFS)

f:id:robonchu:20190505092638p:plain
幅優先探索-Wikipedia

やりたいこと

幅優先探索とは

幅優先探索実装時に用いるキューの使い方(C++)

幅優先探索を用いて解く例題

問題: A - Darker and Darker

f:id:robonchu:20190505095511p:plain

入力

f:id:robonchu:20190505095607p:plain

制約

1≦H,W≦1000

入力/出力例

入力
3 3
...
.#.
...
出力
2
幅優先探索を用いた実装例(C++)
#include <iostream>
#include <queue>

#define P pair<int,int>
using namespace std;

// マスの縦横
int H,W;
// #,.を格納するマス
char A[1000][1000];

// 幅優先探索の深さを格納するマス
int am[1000][1000];
// 隣り合う辺への移動量
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
// 答え
int ans = 0;
 
void BFS(){
  // 入力を受取り、キューに位置x,yを格納
  cin >> H >> W;
  queue<P> que;
  for (int i=0;i<H;i++){
    for (int j=0;j<W;j++){
      cin >> A[i][j];
      if (A[i][j]=='#'){
        am[i][j] = 0;
        que.push(P(i,j));
      }
    }
  }
  // キューを前から取り出し、隣り合う辺が.か#か調べ.なら#に更新し、深さを1足す
  while (!que.empty()){
    P p = que.front();
    que.pop();
    for (int i=0;i<4;i++){
      int nx = p.first + dx[i];
      int ny = p.second + dy[i];
      if (nx>=0 && nx<H && ny>=0 && ny<W && A[nx][ny]!='#'){
        A[nx][ny] = '#';
        am[nx][ny] = am[p.first][p.second]+1;
        que.push(P(nx,ny));
      }
    }
  }
}
 
int main(){
  BFS();
  // 答えとなる最も深いものを取り出す
  for (int i=0;i<H;i++){
    for (int j=0;j<W;j++){
      ans = max(ans, am[i][j]);
    }
  }
  cout << ans << endl;
  return 0;
}

内容まとめ

  • 幅優先探索は上記例のように始点から近い順に網羅的に調べていく手法。

  • 実装時にはqueueを使う。

感想

アルゴリズムの勉強楽しい。問題も解き方が多数あるから頭の体操になって良い。

AtcoderのC,D問題が解けるくらいのアルゴリズムを少しずつまとめていきたいな : )

Sim2Real論文まとめ(2) - PixelDomainAdaptation

f:id:robonchu:20190303135127p:plain

やりたいこと

実データを取得するのが大変なので、限られたデータからDomain Adaptationがしたい。

そのために有用そうなUnsupervised Pixel-Level Domain Adaptation with GANを理解する。

論文について

arxiv.org

  • presented at CVPR 2017

  • Google Brainの論文

評価

☆☆☆☆(4/5)

ロス関数の作り方やGANを安定させるための工夫が参考になる。

内容まとめ

Abstract

  • 品質のいいアノテーション付きのデータセットを作るのはとても大変

  • 解決策として、人工的なデータによる自動アノテーションすることが考えられるが、生成モデルが現実世界に適合できないことも多い。

  • 本論文では、画像空間においてあるドメインから対象とするドメインに適応させる教師なしのGANのアプローチを提案する。

Introduction

  • ImageNetなどのアノテーション付き大規模データセットは認識技術の向上に大きく貢献した。

  • 一方でデータの作成がとても大変だという課題がある。

  • ここで、人口的に作成した画像で代替できればよいが、それだけで訓練したモデルでは実画像に対して適用できないことが多い。

  • ひとつの解決策として、教師なしのDomain Adaptationがある。

  • つまり、ラベル付けされたあるDomainからラベル付けされていない対象Domainへ学んだ知識を転移させたい。

  • 本論文では元の特徴量を保持しつつ、あるDomainの画像をまるで対象のDomainであるように見映を変化させるようなモデルを提案する。

  • Pixelレベルでの教師なしのDomain Adaptationであり、PixelDAと呼ぶ。既存技術に対し様々な利点がある。

f:id:robonchu:20190302232505p:plain

上図からわかるように対象Domainに近い見映の画像が生成されている。

以下に簡単に提案手法の特徴を述べる。

Decoupling from the Task-Specific Architecture
  • 一般的なDomain AdaptationではDomain Adaptationのプロセスとタスク(Classification or Detection etc ..)特有の構造が絡み合っている。

  • これに対してPixelDAではDomain Adaptationの構成を再学習することなしに、タスク特有の構造を変えることができる。

Generalization Across Label Spaces
  • PixelDAはタスク固有部分とdomain adaptation部を非干渉化できているので、訓練時とテスト時で異なるlabel spaceを扱うことができる
Training Stability
  • GANを利用したDomain Adaptationは初期状態に影響を受けやすい。

  • この対策として、ソース画像と生成画像を用いた損失関数による訓練とピクセル類似度による正則化によって安定性を向上させる。(詳細後述)

Data Augumentation
  • これまでの一般的なDomain Adaptationdeは有限のソースとターゲットデータからの学習に限られる。

  • 提案モデルはソースデータと確率ノイズベクターによる条件付けによって、制限なく仮想的にターゲットDomainから似た画像を生成することができる。

Model

  • PixelDAは汎用的に使用可能だが、説明のため画像の classificationを例に説明を行う。

  • この論文のゴールは、ソースDomainからターゲットDomainに対して汎化的なclassifierを訓練することである。

  • 提案モデルはタスク固有のclassificationからdomain adaptationのプロセスが分離されているので、1度adaptするとdomain adaptationすることなしに他のclassificationタスクへ適用(訓練)することができる。

  • 私たちはDomain間の差異はhigh-level(対象物のタイプや幾何的な変化etc...)というよりlow-level(ノイズや色、彩度etc...)な情報による影響が大きいと考えていることを強調したい。

  • 定式化すると

    f:id:robonchu:20190303135234p:plain

    はソースのデータセットを表現し、 xsはソース画像、ysはソースラベル。

    f:id:robonchu:20190303135259p:plain

    はGenerator functionを表し、θがパラメータでソース画像とnoise vectorであるzからfake imageであるxfを出力する。

    Generator function Gが求まると、以下のようにadaptされた新しいデータセットをつくることができる。

    f:id:robonchu:20190303135334p:plain

Learning
  • GをターゲットDomainに近い画像を生成できるようGANを用いる。

  • ソース画像xsとnoise vector zからadaptされた画像xfを生成するGを訓練する。

  • モデルは、ターゲットDomainからサンプルされた画像かどうかの尤度dを出力するdiscriminator func Dによって補強される。

  • Discriminatorはgeneratorから作られたfake画像かターゲットDomainからとってきたreal画像かを見分けようとする関数である。

  • ここで大事なことが、一般的なGANはnoise vectorのみに制限付けられているのに対して、提案モデルはnoise vectorとソースDomainからの画像の両方に制限付けられている、ということである。

  • なので、ゴールは以下のmin-max gameを最適化することである。

    f:id:robonchu:20190303135357p:plain

    αとβは重みで、LdはターゲットDomainに近づけるためにloss funcでLtはタスクをこなすためのloss funcである。

  • Ldは以下のようにかける。DとGのmin-max game。

    f:id:robonchu:20190303135413p:plain

  • Ltは以下のようにかける。classificationの場合の典型的なsoftmax cross-entropy lossを用いている。

    f:id:robonchu:20190303135437p:plain

    ここで、Gで生成した画像とソース画像の両方を用いてTを訓練しているのは訓練を安定させるため。これによって、初期値依存性が減り安定性が大きく向上した

    f:id:robonchu:20190303123809p:plain

    実装したモデルは上図参照。min-max gameでの最適化時は2つのステップに分かれている。

    1. generatorのθGを固定した状態で、discriminator とタスク特徴のパラメータθDとθTを更新する。

    2. パラメータθDとθTを固定した状態で、θGを更新する。

Content-similarity loss
  • low-levelの画像のadaptationについて、前景と後景に対して処理をするのが良いという知見がある。

  • そこでラベル付けされた情報の類似性を保つために前景と後景を切り分けるz-buffer maskを用いて工夫を行う。

  • その工夫とは前景のpixelのみソース画像とgenerate画像の間の大きな差異にペナルティを与えるlossを新たに追加するというものである。

  • これによって、min-max gameの最適化がより安定する。

  • まとめると以下のようにloss関数を表現できる。

    f:id:robonchu:20190303135508p:plain

    αとβとγは重みで、Lcは類似度を一定に保つようなcontent-similarity lossである。

  • このloss func Lcinputとoutputの全体の差ではなく、pixelごとの差に対してpenaltyを与えるmasked pairwise mean squared error(masked-PMSE)を用いる。以下のように表現でき、generateされた前景画像とソース前景画像に対して、計算される。

    f:id:robonchu:20190303135532p:plain

    mはbinary maskでkはkはinput xのpixle数でL2ノルㇺをとっている。

  • これによって対象物の全体の形状など再現するための情報を保つことができる。

Evaluation

ここからは画像ベースでPixelDAを使った例を貼り付けます。

MNISTの例

f:id:robonchu:20190303135554p:plain

Linemodeの例

f:id:robonchu:20190303135619p:plain

ラベリング情報は保ちつつlow-levelな情報が様々変化している画像が生成されていることがわかる。

所感

loss関数をうまく設計することで変化させたい情報とさせたくない情報を切り分けれるのは面白い。

Domain Adaptationにおいてlow-levelの情報に着目しているのは納得。

GANを安定化させるための共有要素/普遍的な方法を検討していきたい。