データセット作成を爆速にするツールで、3コマンドでデータを解析可能にする

どうも、AdansonsのPdMの樋口です。
機械学習のデータセットの作成を効率化したり、データセットの質を改善することでAIの性能を向上するためのツール開発をしています。

[前回の記事](https://qiita.com/KenichiHiguchi/items/a6d4174572e19e6842cf)ではデータをコード上で解析に使うために手間がかかるということを紹介しました。
そこでこの記事では、もう少し具体的に、私たちが開発している`Base`というツールがどういうものか、また実際にどうデータセットを作成するかを解説します。

テストユーザーを募集しているので、ぜひフィードバックしてください！

**Get Invitation Form**
↓↓↓

https://share.hsforms.com/1IiKZRnYrQz27zq05Ys_QKQ8moen

https://github.com/adansons/base

## つまるところBaseは何をするツールなのか
![base_flow_ja.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615011/d495be57-cbbe-05b4-c6e0-544d041a0531.png)

簡単にいえば、ファイルやフォルダ構造に記録されたメタデータを抽出し、整理されたデータベースを作るツールです。

データセット作成において最も手間がかかるのは、メタデータに表記揺れがあったり、フォルダ構造が一致していないときなので、Baseではデータファイル本体のHash値を使用することで、フォルダ構造やファイル名が一致しない場合でもメタデータとデータファイルを紐付けられるようにしています。
また、Excelやcsvといったメタデータファイルから自動で表を抽出・機械で読み込めるように整形し、データベースと結合する際に紐付けるカラムを自動で推定することで、表記揺れがあるメタデータファイルの統合を1コマンドで実行できるようにしています。

ここから、実際にデータセットを読み込むまでの作業内容がこれまでとどのように変わるのか見ていきましょう！

## これまでのデータセット作成でやらなければいけない工程
データをコード上で解析に使えるようにするということは、すなわちアノテーションなどのメタデータとデータファイルを紐付けた上で読み込むデータローダー関数を実装するということです。

そのためには、アノテーションなどのメタデータを記述する際の外部ファイルの仕様や、フォルダ構造やファイル名の命名規則といったメタデータの仕様を統一しなければいけません。

### 1. メタデータを、機械で読み込める仕様に整理する
非構造化データのメタデータの記述方法で最もよくあるのは、フォルダ構造やファイル名に含ませる方法です。
例えば分類タスクにおいて、説明変数に使いたい正解ラベル毎にフォルダを作り、各データファイルを振り分ける作業を実施します。

また説明変数以外にもメタデータを使用する時は、別途Excelファイルやcsvファイルを用意して、そこにデータファイルを指し示すIDと紐付けて記述することがよくあります。
外部ファイルとしてもメタデータが記述されている場合は、そのメタデータの仕様を統一する作業も必要になります。
例えば、Excelの1つのシートに複数の表がある場合は1つの表に整理し、カラム名などの値がメタデータファイル毎に揃っていない場合は統一させなければいけません。

![fix_excel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615011/b0b46903-e4ca-67ca-7852-230e071241a5.png)

### 2. メタデータと紐付けてデータファイルを読み込めるデータローダー関数を実装する
メタデータの整理が終わったら、データファイルと紐付けてコード上で読み込むためのデータローダー関数を実装していくことになります。

![carbon (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615011/cadba84f-959e-07fe-4b18-94f37f849c3a.png)

https://www.kaggle.com/code/javiersj2000/tfg-v6?scriptVersionId=95182497&cellId=6

上の画像は、Kaggleに投稿されたデータローダー関数の1例です。
この例のように参照する外部ファイルが少なく、メタデータが整理されている場合はシンプルで綺麗なコードになりますが、新しくデータが追加されると、メタデータの仕様が変わったり、新しく参照しなければならない外部ファイルが増えて、データローダー関数がどんどん複雑に肥大化していきます。

## それ、Baseなら3コマンドで簡単にできます
特に、メタデータファイルが複数あったり、それぞれの仕様が統一されていない時に手作業で修正して統合していた作業を自動化します。
ここでは、特に重要なBaseのコマンドを紹介します。
詳細は[Githubのチュートリアル](https://github.com/adansons/base/blob/main/example/01_mnist_tutorial.ipynb)を確認してください！

### 1. データファイルをimportしてメタデータDBを初期化する（CLI）
```
base import --directory **** --extension png --parse "{dataType}/{label}/{id}.png"
```

Baseにおいて、データファイルのHash値はメタデータの紐付けの中心になる重要な情報です。
`base import`コマンドでは、引数にデータファイルが入っている最下層のフォルダ（データフォルダ）を指定することで、自動でHash値を計算します。
また、フォルダ構造やファイル名から抜き出したいメタデータがある場合は、データフォルダ以下の階層から抜き出したい情報を`{}`で括り、その中にメタデータDBの検索に使うKey名として、それぞれのメタデータが何を意味するか名付けることで自動で抽出してくれます。

![Screen Shot 2022-05-16 at 0.44.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615011/df56435f-e56f-a191-a1ca-788d6e09ca61.png)

> "john/2022-5_hello.wav"というファイルパスを"{name}/{year}-{month}_{phrase}.wav"のように複雑に抽出することもできます

### 2. メタデータファイルの中身を整理してデータファイルと紐付ける（CLI）
```
base import --external-file --path *****
```

`base import`コマンドの`--external-file`オプションでは、Excelやcsvといったメタデータファイルから表を自動で抽出し、機械で読み込めるように変換します。
先ほど例に出した、1シートに2つの表があるようなExcelであっても、自動で整形して1つの表に整理できます。

![fix_excel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615011/b0b46903-e4ca-67ca-7852-230e071241a5.png)

また、既にimportされているメタデータDBに統合する際に紐付けに使用するカラム（Key）を自動で推定することができます。

```
2 tables found!
now estimating the rule for table joining...

1 table joining rule was estimated!
Below table joining rule will be applied...


Rule no.1

	key 'index'	->	connected to 'id' key on exist table
	key 'originalLabel'	->	connected to 'label' key on exist table
	key 'correction'	->	newly added
	key 'dataType'	->	connected to 'dataType' key on exist table

2 tables will be applied
Table 1 sample record:
	{'index': 8, 'originalLabel': 5, 'correction': -1, 'dataType': 'test'}
Table 2 sample record:
	{'index': 1061, 'originalLabel': 0, 'correction': '0or6', 'dataType': 'test'}
Success!
```

例えば、以下の写真の例では、上段左の、データファイルをimportしたあとのメタデータDBにpathの他に`dataType`, `label`, `id`の3つのkeyがあるのに対して、右の新しく追加したいメタデータファイルには`index`, `originalLable`, `correction`のkeyがあります。
各keyの中身の類似度に基づいて、Baseがテーブル結合時の紐付けkeyを推定し、この例では`label`と`originalLabel`、`id`と`index`が自動で紐付けられ、`correction`は新しいメタデータとして追加されます。

![Screen Shot 2022-05-16 at 1.18.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615011/1b860f53-a1e8-9c04-d385-c59eb475d8a2.png)

### 3. データセットを作成するクエリを書く（Python SDK）
```python
from base import Project

project = Project(project_name="mnist")
correct_label_data = project.files(query=["correction != -1"])

print(len(correct_label_data))
# -> 9963

print(correct_label_data[0])
# -> /home/****/dataset/mnist/train/3/302.png

print(correct_label_data[0].label)
# -> 3
# 各要素はbase.File classのインスタンスになっていて、
# importしたメタデータにkeyでアクセスすることができる
```

ここまで来たら、もう複雑なデータローダー関数を実装する必要はありません。
Python上で解析する場合は、データファイルをimportする前に登録する自分のプロジェクト名で`base.Project`クラスを初期化し、importしたあらゆるメタデータでクエリを記述してデータセットを作成することができます。

データファイルやメタデータファイルが新たに追加された場合でも、`base import`もしくは`base import --external-file`コマンドを使用することで、すぐ対応できるようになります。
プロジェクトメンバーとフォルダ構造やファイル名が一致していない場合であっても、メンバーをBase上のプロジェクトに招待するコマンドを別途使用することで、解析コードを共有できるようになります。

## このツールを使ってあなたのプロジェクトのデータを整理するには

現在実装している機能は無料で公開しています。
プロダクトへのアクセスキーと最新情報を入手するために、ぜひユーザーコミュニティ（Slack）に参加ください！

**Get Invitation Form**
↓↓↓

https://share.hsforms.com/1IiKZRnYrQz27zq05Ys_QKQ8moen

https://github.com/adansons/base