FiftyOneでリモートマシンにデータをダウンロードして閲覧するまでのメモ

普段の作業環境（ロカールのWindowsマシンからリモートのLinuxに接続して機械学習などを行っている）で、FiftyOneを使ってみた際の覚書です。

## FiftyOneについて
FiftyOneはVoxel51社が提供するオープンソースのツールで、データセットのダウンロードや可視化など、様々な用途をサポートしているツールです。
[Open Images Dataset](https://storage.googleapis.com/openimages/web/download_v7.html#download-fiftyone)や[COCO](https://cocodataset.org/#download)など、データセット公式のダウンロード方法の一つとしてFiftyOneが紹介されている例もあります。

https://github.com/voxel51/fiftyone

今回は、リモートマシン上にデータをダウンロードして、別マシンからFiftyOneのアプリで閲覧してみます。

- 試した環境
  - リモート：　学習用デスクトップ、Ubuntu20.04
  - ローカル：　ノートPC、Windows10

## インストール
データをダウンロードしたいマシン（今回はsshで入ったリモートマシン）で以下を実行。かんたん。
```console
$ pip install fiftyone
```

## データセットのダウンロード
FiftyOneのDataset Zooにはたくさんの公開データセットが登録されているので、有名どころのデータであればAPIを使って簡単にダウンロードすることができます。

以下、ダウンロードを行うpythonスクリプトのサンプルです。

```python:サンプルデータ (quickstartデータ) のダウンロード
import fiftyone as fo
import fiftyone.zoo as foz

# quickstartデータをダウンロード
foz.download_zoo_dataset(name="quickstart") 
```
```download_zoo_dataset()```のname引数で"caltech101"、"coco-2017"、"open-images-v6"といった各種データセットが指定できます。
利用可能なデータセットの一覧は[こちら](https://voxel51.com/docs/fiftyone/user_guide/dataset_zoo/datasets.html)。

ダウンロード先ディレクトリの指定なども可能です。
```python
foz.download_zoo_dataset(
    name="quickstart", 
    dataset_dir="./MyDataset"  # デフォルトは ~/fiftyone
)
```

## リモートマシン上でデータをダウンロード＆ロードしてFiftyOneアプリを起動

以下では```download_zoo_dataset()```の代わりに```load_zoo_daataset()```を使います。
```load_zoo_dataset()```は（すでにダウンロード済みでなければ）データのダウンロードとFiftyOneが扱うデータ形式としてのロードを一緒に行います。
この方法でロードされたデータセットをFiftyOneのアプリ上で閲覧することができます。

```name```の指定などは```download_zoo_dataset()```同様です。
また、ロードする画像の枚数や、データセット特有の項目などをさらに指定できます。

以下、Open Imagesの例（[参考ページ](https://voxel51.com/docs/fiftyone/user_guide/dataset_zoo/datasets.html#open-images-v6)）
```python
dataset = foz.load_zoo_dataset(
    name="open-images-v6", 
    split="validation", # "train","validation","test"、分類が存在しないデータセットなら全部ダウンロード
    label_types=["segmentations"],  # ラベル種類を指定、"detections","segmentations"など
    classes=["Person"],  # 画像に含まれるクラスを指定
    max_samples=30,  # 枚数の指定（この場合ランダムに30枚を上限としてvalidation splitからデータを取得）
    only_matching=True  # Trueなら条件に一致したラベルのみ取得（Person指定ならPerson以外のラベルは取得しない）
) 
```

データセットの準備と、アプリの起動を合わせたスクリプト（sample_launch_app.py）が以下
```python:sample_launch_app.py
import fiftyone as fo
import fiftyone.zoo as foz

dataset = foz.load_zoo_dataset(
    name="open-iamges-v6", 
    split="train",
    label_types=["detections"],
    classes=["Person"],
    max_samples=30,
    only_matching=True
) 

# remoteオプションを有効にして、Appを起動
session = fo.launch_app(dataset, remote=True)  

# プロセスが勝手に終わらないようにこの記述を入れる
session.wait()  
```
リモートマシンでの実行時は```launch_app()```のオプションで```remote=True```を入れるのがポイント

以下で実行
```console
$ python sample_launch_app.py
```
ダウンロードやロードに時間が掛かるので少し待ちます。
これでリモートマシン上でアプリの準備ができました。

## ローカルからのアクセス
ローカルマシン側では以下コマンドでポートフォワーディングをしておく
```powershell:powershell
ssh -N -L 5151:127.0.0.1:XXXX <username>@<hostname>
```
FiftyOneはデフォルトでポート番号5151を使うので、変更してなければXXXXの部分は5151でOK
上記ではローカル側のポートも5151を利用
usernameとhostnameはリモートマシンのもの

上記が済んだ状態で、ローカルマシンのブラウザから[http://localhost:5151](http://localhost:5151)にアクセスすると、アプリ画面を見ることができるはず。
※表示がない場合は、左上の「Select dataset」からデータを選択する
![fiftyone_app_openimages.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3070559/0e62cd08-8be4-f38b-c83a-42cc307b62a8.jpeg)
detectionタスクのPersonクラスを含むものを指定したので、アプリ上で表示される画像もそのようになっています。

## おわりに
まだちょっとしか使えてませんが、自前のデータセットの可視化なども時間ができたら試したいと思います。

## 参考
https://voxel51.com/docs/fiftyone/index.html
https://qiita.com/RyoWakabayashi/items/ffcf21558855f6d5a9be