目次
こんにちは.高山です.
本連載記事では実験で,KaggleのGoogle Isolated Sign Language Recognition (以下,GISLR) で用いられたデータセットをHDF5に加工して使っています.
本当に今更で恐縮なのですが,GISLRデータセットをHDF5形式にまとめる方法を全く説明していなかったことに気づきました(^^;).
そこで今回は,GISLRデータセットをHDF5形式に変換する方法を紹介したいと思います.
今回解説するスクリプトはGitHub上に公開しています.
Colab上で使用しているデータセットは,説明用に大部分の追跡点を削除したデータセットです.
ご自分の環境で試す場合は,オリジナルのデータセットをローカル環境で (Google Driveに入り切らないため) 使用するようにしてください.
1. GISLRデータセットのダウンロード
オリジナルのデータセットの入手方法については,こちらの記事で解説しています (第2.1項をご参照ください).
ダウンロードが完了すると,asl-signs.zip
というZIPファイルが入手でき,中身は下記のようになっています.
$ unzip asl-signs.zip
$ ls asl-signs
sign_to_prediction_index_map.json train.csv train_landmark_files
今回は,これらのファイルがローカル環境または Colab からアクセス可能な場所に配置してある,という前提のもと説明していきます.
2. 前準備
2.1 データセットのダウンロード
ここからはColab上のスクリプトの内容を説明していきます.
まずは,前準備として Google Colab にテスト用のデータセットをアップロードします.
まず最初に,データセットの格納先からデータをダウンロードし,ご自分のGoogle driveへアップロードしてください.
次のコードでGoogle driveをColabへマウントします.
Google Driveのマウント方法については,補足記事にも記載してあります.
1 2 3 |
|
ドライブ内のファイルをColabへコピーします.
パスはアップロード先を設定する必要があります.
# Copy to local.
!cp drive/MyDrive/Datasets/gislr_dataset_orig.zip gislr_orig.zip
データセットはZIP形式になっているので unzip
コマンドで解凍します.
!unzip -o gislr_orig.zip
Archive: gislr_orig.zip
creating: inputs/google_islr/
inflating: inputs/google_islr/sign_to_prediction_index_map.json
...
inflating: inputs/google_islr/train_landmark_files/62590/1000240708.parquet
成功すると inputs/google_islr
以下にデータが解凍されます.
!ls inputs/google_islr
sign_to_prediction_index_map.json train.csv train_landmark_files
2.2 データセットの内容
辞書ファイル
単語辞書には単語名と数値の関係が250単語分定義されています.
!cat inputs/google_islr/sign_to_prediction_index_map.json
{"TV": 0, "after": 1, ..., "zipper": 249}
サンプル情報
train.csv
は各サンプルの情報を表形式でまとめたデータです.
!cat inputs/google_islr/train.csv | head
path,participant_id,sequence_id,sign
train_landmark_files/26734/1000035562.parquet,26734,1000035562,blow
train_landmark_files/28656/1000106739.parquet,28656,1000106739,wait
train_landmark_files/16069/100015657.parquet,16069,100015657,cloud
train_landmark_files/25571/1000210073.parquet,25571,1000210073,bird
train_landmark_files/62590/1000240708.parquet,62590,1000240708,owie
train_landmark_files/26734/1000241583.parquet,26734,1000241583,duck
train_landmark_files/26734/1000255522.parquet,26734,1000255522,minemy
train_landmark_files/32319/1000278229.parquet,32319,1000278229,lips
train_landmark_files/37055/100035691.parquet,37055,100035691,flower
各カラムの内容は次のとおりです.
path
: 骨格追跡点データへのパスparticipant_id
: 手話話者IDsequence_id
: データ番号sign
: 何の手話単語を表出しているか
追跡点データ
train_landmarks
は追跡点データが格納されているディレクトリです.
中身は話者ID毎のサブディレクトリで構造化されています.
!ls inputs/google_islr/train_landmark_files
16069 2044 25571 27610 29302 32319 36257 37779 49445 55372 62590
18796 22343 26734 28656 30680 34503 37055 4718 53618 61333
テスト用データセットには,各ディレクトリに1ファイルだけ追跡点データが含まれています.
!ls inputs/google_islr/train_landmark_files/16069
100015657.parquet
今回はこのテスト用データセットを用いてHDF5形式への変換処理を組んでいきます.
本番ではオリジナルのデータセットに差し替えてご利用いただければと思います.
3. HDF5形式への変換処理
3.1 モジュールのロード
主要な処理の実装に先立って,下記のコードでモジュールをロードします.
1 2 3 4 5 6 7 8 |
|
【コード解説】
- 標準モジュール
- json: JSONファイル制御ライブラリ.辞書ファイルのロードに使用します.
- os: システム処理ライブラリ
- 3rdパーティモジュール
- numpy: 行列演算ライブラリ
- h5py: HDF5ファイル処理ライブラリ
- pandas: データ解析支援ライブラリ.
今回は parquet 形式のファイルをロードするために用います.
3.2 追跡点の読み込み処理
まずは追跡点の読み込み処理を実装します.
追跡点のデータフォーマットは下記のようになっています.
(こちらの記事でも解説しています (第2.2項-追跡点データをご参照ください).)
frame row_id type landmark_index x y z
0 20 20-face-0 face 0 0.494400 0.380470 -0.030626
1 20 20-face-1 face 1 0.496017 0.350735 -0.057565
2 20 20-face-2 face 2 0.500818 0.359343 -0.030283
3 20 20-face-3 face 3 0.489788 0.321780 -0.040622
4 20 20-face-4 face 4 0.495304 0.341821 -0.061152
... ... ... ... ... ... ... ...
12484 42 42-right_hand-16 right_hand 16 0.001660 0.549574 -0.145409
12485 42 42-right_hand-17 right_hand 17 0.042694 0.693116 -0.085307
12486 42 42-right_hand-18 right_hand 18 0.006723 0.665044 -0.114017
12487 42 42-right_hand-19 right_hand 19 -0.014755 0.643799 -0.123488
12488 42 42-right_hand-20 right_hand 20 -0.031811 0.627077 -0.129067
[12489 rows x 7 columns]
データは表形式で格納されており,各カラムの内容は次のとおりです.
frame
: 追跡点系列のフレーム番号.上の例で示されるとおり,0始まりではありません.
また,途中抜けの番号もありますが評価で用いられるコードを見る限りでは,そのようなフレームは単純に無視されるようです.row_id
: 各行のユニークID.[frame][type][landmark_index] の形式になっています.type
: 身体部位名.face
,left_hand
,pose
,right_hand
のどれかになります.landmark_index
: 各部位の追跡点番号x
,y
,z
: 追跡点の座標値
この並び方は全データに共通しているため,各カラムを細かく追いかける必要はなく,下記に示す処理で追跡点を統一的にロードすることができます.
1 2 3 4 5 6 7 8 |
|
【コード解説】
- 1行目: 追跡点の個数を事前定義
- 4-5行目: `x`, `y`, `z` のカラムだけロード
- 6-7行目: `[T, J, C]` の形状に変形して返す
- T: フレーム数
- J: 追跡点数.ここでは543
- C: 特徴量数.ここでは3
3.3 変換処理
ここから先は変換処理本体を実装していきます.
まず次のコードで,サンプル情報を読み込みます.
1 2 3 4 |
|
# Load data definition.
root_dir = "inputs/google_islr"
track_info = pd.read_csv(os.path.join(root_dir, "train.csv"))
print(track_info)
path participant_id sequence_id sign
0 train_landmark_files/26734/1000035562.parquet 26734 1000035562 blow
1 train_landmark_files/28656/1000106739.parquet 28656 1000106739 wait
2 train_landmark_files/16069/100015657.parquet 16069 100015657 cloud
3 train_landmark_files/25571/1000210073.parquet 25571 1000210073 bird
4 train_landmark_files/62590/1000240708.parquet 62590 1000240708 owie
... ... ... ... ...
94472 train_landmark_files/53618/999786174.parquet 53618 999786174 white
94473 train_landmark_files/26734/999799849.parquet 26734 999799849 have
94474 train_landmark_files/25571/999833418.parquet 25571 999833418 flower
94475 train_landmark_files/29302/999895257.parquet 29302 999895257 room
94476 train_landmark_files/36257/999962374.parquet 36257 999962374 happy
[94477 rows x 4 columns]
次に,下記のコードで手話者IDを読み込みます.
1 2 3 4 |
|
[ 2044 4718 16069 18796 22343 25571 26734 27610 28656 29302 30680 32319
34503 36257 37055 37779 49445 53618 55372 61333 62590]
下記のコードで辞書データを読み込みます.
1 2 3 4 5 |
|
{'TV': 0, 'after': 1, ..., 'zipper': 249}
変換の準備ができましたので,下記のコードで変換処理を実装します.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
【コード解説】
- 2行目: `[C, T, J]` 形式で保存するように指定
- 3-4行目: 出力ディレクトリを作成
- 6-27行目: 変換処理ループ.
手話者毎にHDF5ファイルを作成して,データを格納します.
- 7行目: サンプル情報を手話者IDでフィルタリング
- 8行目: 出力ファイル名を定義
- 9行目: HDF5ファイルオープン
- 10-27行目: 変換処理
`itertuples()` を用いてサンプル情報を 1 行ずつ取り出しています.
- 11-15行目: サンプル情報を取り出して,変数に格納
- 16-19行目: 追跡点データ読み込み
- 21-22行目: `[T, J, C] -> [C, T, J]` に変換
- 25-27行目: サンプルID毎にグループを作成して,データを格納.
追跡点データは `feature`,単語ID は `token` というキー値で格納しています.
4. 出力ファイルの確認
では,データが正しく保存されているかを確認していきます.
!ls dataset
16069.hdf5 22343.hdf5 27610.hdf5 30680.hdf5 36257.hdf5 4718.hdf5 55372.hdf5
18796.hdf5 25571.hdf5 28656.hdf5 32319.hdf5 37055.hdf5 49445.hdf5 61333.hdf5
2044.hdf5 26734.hdf5 29302.hdf5 34503.hdf5 37779.hdf5 53618.hdf5 62590.hdf5
[話者ID].hdf5
という形式で保存されていることが分かります.
次のコードでHDF5ファイルの中身を確認します.
1 2 3 4 5 6 7 8 9 10 11 |
|
Groups: <KeysViewHDF5 ['100015657']>
Data in a group: <KeysViewHDF5 ['feature', 'token']>
(3, 105, 543)
[48]
HDF5ファイルは辞書データのように,キーバリュー形式でデータを取り出せます.
下記のような階層関係でデータが保存されていることが分かると思います.
- 100015657: サンプルID
|- feature: 追跡点データ
|- token: 単語ID
今回は,GISLRデータセットをHDF5形式に変換してまとめる方法を紹介しましたが,如何でしたでしょうか?
機械学習用データセットは個別のフォーマットを採用しており,毎回専用の IO 処理を実装するのは少し面倒です.
(可能な場合は) 慣れているフォーマットに変換すると後段の処理変更が少なく済むことがあるため,本連載ではHDF5形式に変換したデータセットを使用しています.
今回紹介した話が,これから手話認識を勉強してみようとお考えの方に何か参考になれば幸いです.