アノテーション済みデータをABEJA Platformにアップロードする


# はじめに

ABEJA Platformは強力なアノテーションツールを持っており、アノテーションから学習までのフローをスムーズに実施できます。一方、公開されているベンチマークデータセットや、過去にアノテーションしたデータをアップロードする場合、Platformのフォーマットでアップロードする必要があります。本記事では、その手順について説明します。

ABEJA Platformは生データを保持するDatalakeと、アノテーションデータを保存するDatasetという機構を持ちます。まずは、手元の画像データをDatalakeにアップロードしましょう。なお、この手順はPlatformのGUIからでも可能です。その後、Datasetを作成します。

### Datalakeチャンネルの作成

チャンネルの作成は以下のようになります。なお、CLIとSDKは[過去の記事](https://qiita.com/peisuke/items/1e25a2d474467188cb11)を参考にインストールしてください。

```python
from abeja.datalake import Client as DatalakeClient
from abeja.datalake.storage_type import StorageType
from abejacli.config import (
    ABEJA_PLATFORM_USER_ID, ABEJA_PLATFORM_TOKEN
)

organization_id = 'XXXXXXXXXXXXXX'
credential = {
    'user_id': ABEJA_PLATFORM_USER_ID,
    'personal_access_token': ABEJA_PLATFORM_TOKEN
}

datalake_client = DatalakeClient(organization_id=organization_id, credential=credential)

name = 'XXXXXXXXXXXXXXXXXXX'
description = 'XXXXXXXXXXXXXXXXXXXXXXX'

channel = datalake_client.channels.create(name, description, StorageType.DATALAKE.value)
```

続いてデータをアップロードします。

```python
channel = datalake_client.get_channel(channel.channel_id)
file = channel.upload_file('cat.jpg')
```

### Datasetの作成（Classification編）

Datasetの箱は以下のように作成します。最初にスキーマ（クラスの情報）を定義します。ここでは、dog/catの２クラスの分類問題とします。マルチクラス分類の場合は、`categories`のリストに複数のカテゴリを追加します。

```python
from abeja.datasets import Client as DatasetClient
datasets_client = DatasetClient(organization_id=organization_id, credential=credential)

labels = [{"label_id": 0, "label": "dog"}, {"label_id": 1, "label": "cat"}]
category = {'labels': labels, 'category_id': 0, 'name': 'cats_dogs'}
props = {"categories": [category]}

dataset = datasets_client.datasets.create(name='XXXXXXXXXXXXX', type='classification', props=props)
```

アノテーションデータは以下のようにアップロードします。

```python
source_data = [
    {
        'data_type': 'image/jpeg',
        'data_uri': 'datalake://{}/{}'.format(channel.channel_id, file.file_id),
    }
]

data = {
    'category_id': 0,
    'label_id': 1
}
attributes = {'classification': [data]}

dataset_item = dataset.dataset_items.create(source_data=source_data, attributes=attributes)
```

### Datasetの作成（Detection編）

Detectionの場合は、以下のようになります。スキーマとしては先ほどと同様に犬と猫の２値分類とします。`type`を`detection`に変更します。

```python
from abeja.datasets import Client as DatasetClient
datasets_client = DatasetClient(organization_id=organization_id, credential=credential)

labels = [{"label_id": 0, "label": "dog"}, {"label_id": 1, "label": "cat"}]
category = {'labels': labels, 'category_id': 0, 'name': 'cats_dogs'}
props = {"categories": [category]}

dataset = datasets_client.datasets.create(name='XXXXXXXXXXXXX', type='detection', props=props)
```

アノテーションデータは以下のようにアップロードします。

```python
source_data = [
    {
        'data_type': 'image/jpeg',
        'data_uri': 'datalake://{}/{}'.format(channel.channel_id, file.file_id),
    }
]

rect = {'xmin': 200, 'ymin': 0, 'xmax': 1000, 'ymax': 900}
det1 = {
    'category_id': 0,
    'label_id': 1,
    'rect': rect
}
attributes = {'detection': [det1]}

dataset_item = dataset.dataset_items.create(source_data=source_data, attributes=attributes)
```

### Datasetの作成（Custom編）

Classification/Detectionだけではなく、自由な形式のアノテーションを利用できます。この場合、`type`を`custom`にします。

```python
from abeja.datasets import Client as DatasetClient
datasets_client = DatasetClient(organization_id=organization_id, credential=credential)

labels = [{"label_id": 0, "label": "dog"}, {"label_id": 1, "label": "cat"}]
category = {'labels': labels, 'category_id': 0, 'name': 'cats_dogs'}
props = {"categories": [category]}

dataset = datasets_client.datasets.create(name='XXXXXXXXXXXXX', type='custom', props=props)
```

アノテーションデータは以下のようにアップロードします。

```python
source_data = [
    {
        'data_type': 'image/jpeg',
        'data_uri': 'datalake://{}/{}'.format(channel.channel_id, file.file_id),
    }
]
d = {
    'category_id': 0,
    'label_id': 1,
    'text': 'nyaan'
}
attributes = {'detection': [d]}
dataset_item = dataset.dataset_items.create(source_data=source_data, attributes=attributes)
```

### データの読み込み

作成したDatasetを学習時に読み込みバッチにする必要があります。ここではフレームワークに依存しないようDatasetにアップロードしたアノテーションデータを表示する方法を説明します。学習に利用する際は、このアノテーションデータを利用し、各フレームワークの作法に従ってバッチにしましょう。`dataset.dataset_items.list`はイテレータを返しますが、`prefetch=True`にすると全データを一括でダウンロード、`prefetch=False`にするとデータを逐次ダウンロードしてキャッシュされます。今回はデータが１つなので前者を利用しますが、大量のデータがある場合は後者を使います。


```python
from abeja.datasets import Client as DatasetClient

client = DatasetClient(organization_id=organization_id, credential=credential)

dataset = client.get_dataset(XXXXXXXXXXXX)

dataset_list = list(dataset.dataset_items.list(prefetch=True))

d = dataset_list[0]
file_content = d.source_data[0].get_content()
file_like_object = io.BytesIO(file_content)

img = Image.open(file_like_object)
annotation = d.attributes
```