[InfoGAN] 日本語手書き文字データを自動生成する [AIOCR]

2021年12月23日木曜日

Artificial Intelligence

本記事では、InfoGANと呼ばれる機械学習手法を使って、日本語の手書き文字データを生成する方法を紹介します。

アイキャッチ

概要

本記事の実施内容の概要説明をはじめに記載します。
本記事では、学習データとして確保が難しい、日本語手書き文字データを自動生成を目指します。

下図は出力のイメージです。

生成する画像データのイメージ図

上図のような画像を生成し、AIOCRにおける文字認識の学習データとして活用することを目指します。

技術概要

InfoGAN

InfoGANそのものは、既に素晴らしい日本語の解説記事が存在するためこちらでは説明を割愛します。
【論文メモ:InfoGAN】InfoGAN: Interpretable Representation Learning by Information Maximizing Generative Adversarial Netsの記事などが参考になるためInfoGANのネットワークの詳細に興味がある方はこちらをご参考下さい。
本記事としては、いくつかの日本語手書き文字データを入力として、様々な日本語手書き文字データを出力するために利用する技術であると理解頂いていれば十分です。

下図は行ごとに変数(continuous latent variable)を変化させた結果です。行ごとに文字の形状が変化していますね。

MNISTを入力としたInfoGANの出力結果
出典: https://github.com/eriklindernoren/PyTorch-GAN#infogan

ETL文字データベース

ETL文字データベースは、独立行政法人産業技術総合研究所によって収集された、手書きまたは印刷の英数字、記号、ひらがな、カタカナ、教育漢字、JIS第1水準漢字など、 約120万の文字画像データです。
本記事では、これらの内手書きデータを利用させて頂きます。

このデータセットをInfoGANに学習させ、様々な形状の手書き文字を出力するモデルを生成していきます。

InfoGANの導入手順

セットアップ: conda環境構築

それでは早速、開発環境にInfoGANをセットアップしていきます。
動作確認は下記の環境で行っています。

OS: Ubuntu 18.04.3 LTS
GPU: GeForce GTX 1080

なお、このデモはPythonで実装しています。
Pythonの実装に不安がある方、Pythonを使った機械学習について詳しく勉強したい方は、以下の書籍やオンライン講座などがおすすめです。

それでは、InfoGANをインストールしていきます。他の機械学習環境に影響を与えないためにMinicondaの仮想環境上に構築していきます。Minicondaのインストール手順は公式ドキュメントをご参照ください。

# python version 3.7のconda環境を作成
$ conda create -n pytorch_gan python=3.7 -y

# 作成した環境をアクティベート
$ conda activate pytorch_gan
$ cd pytorch_gan

# Proxy配下の場合は事前に下記を設定
$ export http_proxy="http://"username":"password"@proxy:port"
$ export https_proxy="http://"username":"password"@proxy:port"

# githubからcode clone
$ git clone https://github.com/eriklindernoren/PyTorch-GAN
$ cd PyTorch-GAN/
$ pip3 install -r requirements.txt

# torchの動作確認
$ python -c "import torch; print(torch.__version__); print(torch.cuda.is_available()); print(torch.cuda.device_count());"
1.10.1+cu102
True
2

以上で環境のセットアップは完了です。

手書き数字画像の生成

まず、あらかじめ用意されているinfogan.pyを動かしてみます。
こちらは手書き数字のデータセットであるMNISTを入力とし、様々な形状の手書き数字を出力するモデルをトレーニングします。

$ cd implementations/infogan
$ python3 infogan.py
MNIST出力結果
出典: https://github.com/eriklindernoren/PyTorch-GAN#infogan

上図GIFはepochごとの出力結果を表しています。学習が進むにつれて、徐々に手書き数字のような形状の文字を持つ画像を生成していますね。

日本語の文字画像の生成手順

DataLoaderの定義

これからご紹介するコードは全てこちらのGithubに掲載しています。
本題のETL文字データベースを入力に日本語の手書き文字データの生成を行います。
ETL文字データベースの取得方法は以下の記事はご参照ください。

まずは、このETL文字データベースをinfoGANに学習させるためDataLoaderを定義します

class EtlCdbDataLoader(Dataset):
    IMG_EXTENSIONS = [".jpg", ".jpeg", ".png", ".bmp"]

    def __init__(self, img_dir, transform=None):
        # 画像ファイルのパス一覧を取得する。
        self.etl_paths, self.np_labels = self._get_etl_paths(img_dir)
        self.transform = transform

    def __getitem__(self, index):
        # # [img_path, [x, y, w, h], label]
        etl_path = self.etl_paths[index]

        # load image
        img = Image.open(etl_path[0])
        # load label(index)
        label = np.where(self.np_labels == etl_path[2])[0][0]

        if self.transform is not None:
            # 前処理がある場合は行う。
            img = self.transform(img)

        return img, label

    def _get_etl_paths(self, img_dir):
        img_dir = Path(img_dir)

        pickle_paths = glob.glob(os.path.join(img_dir, '*.pickle'), recursive=True)
        
        # pickleに格納したETLCDBデータをロード
        # [img_path, [x, y, w, h], label]
        etl_paths = []
        temp_labels = []
        for pickle_path in pickle_paths:
            with open(pickle_path, 'rb') as pickle_file:
                contents = pickle.load(pickle_file)
                for content in contents:
                    # infoGAN作業ディレクトリからの相対パスに修正
                    # 出力先親ディレクトリ取得
                    root_dir = Path(content[0]).parents[3]
                    # 親ディレクトリ以下のディレクトリ取得
                    child_dir = content[0].split(str(root_dir))[1]
                    dir = os.path.join(str(img_dir) + str(child_dir))

                    # etl全て
                    #etl_paths.append( [dir, content[1], ord( content[2] )] )
                    #temp_labels.append(ord( content[2] ))

                    # CHAR_LISTのみ
                    result = False
                    for target in CHAR_LIST_HIRAGANA:
                        if target in dir:
                            result = True

                    if result == True:
                        # label(Unicode)
                        etl_paths.append( [dir, content[1], ord( content[2] )] )
                        temp_labels.append(ord( content[2] ))

        # IMG_EXTENSIONSに該当するファイルのみ取得
        etl_paths = [
            p for p in etl_paths
            # 拡張子取得
            if '.' + os.path.splitext( os.path.basename(p[0]) )[1][1:]
            in EtlCdbDataLoader.IMG_EXTENSIONS
        ]

        logger.debug('data: %s', etl_paths[0])
        # labelsのcategory数を計算
        np_labels = np.sort( np.unique(np.array( temp_labels )) )
        logger.debug('please set --n_classes: %d', np_labels.size)

        return etl_paths, np_labels

    def __len__(self):
        """ディレクトリ内の画像ファイルの数を返す。
        """
        return len(self.etl_paths)

上記コードの__getitem__を見ていただくとわかりますが、学習時にETLデータベースの画像とその画像のラベルを提供します。

ラベルは従来のinfoGANの実装に合わせて、0~から採番しています。
例えば、"あ"、"い"、"う"、"え"、"お"の画像が存在する場合、
それぞれ"0"、"1"、"2"、"3"、"4"とラベル付けされます。

DataLoaderさえ定義できてしまえば、あとはデータを入力してトレーニングさせるのみです。

ひらがな(10種)画像の生成

まず、MNISTの同じカテゴリ数となるようにあ行と、か行のひらがな10種を学習させてみます。

$ python3 infogan_jp.py --n_classes 10
あ~この学習結果

またlossの推移は以下の通りです。

あ~このloss推移

ひらがな(20種)画像の生成

つづいて、MNISTの同じカテゴリ数となるようにさ行からは行のひらがな20種を学習させてみます。

$ python3 infogan_jp.py --n_classes 20
さ~ほの学習結果

lossの推移は以下です。

さ~ほのloss推移

ひらがな(46種)画像の生成

ひらがな全て46種を学習してみます。

$ python3 infogan_jp.py --n_classes 46
ひらがな全部の学習結果
ひらがな全部のloss推移

カテゴリ数の増加に伴い、正確な形状の画像が生成されにくくなっています。
またinfo lossも高止まりしています。

漢字(10種)画像の生成

さきほどはひらがな全てを一度に学習した場合、カテゴリ数が多くなり学習が上手く収束しない結果となりました。

次に漢字(10種)の学習を行ってみます。

今回用意したデータにおいては、漢字は一文字あたり161枚ひらがなは一文字あたり700枚と一文字あたりのデータ数に大きな差があります。

同一カテゴリ数のにおける一文字あたりの学習データ数の差による結果の違いを見てみます。

$ python3 infogan_jp.py --n_classes 10
漢字10種の学習結果
漢字10種のloss推移

学習データが少ないためか、やや漢字の形状が崩れたままとなりました。

まとめ

本記事では、InfoGANを使って日本語の手書き文字データを自動生成する方法を紹介しました。 学習結果からみると、カテゴリ数は20前後、1文字あたりのデータは700以上は用意しておいた方が良好な出力結果が得られるようです。

現実問題として、モデルの精度確保において、学習データの確保はコストの問題から十分に確保できない場合があります。
今回のように人手をかけずに自動生成する方法があればこれらの課題解決の一つになり得ますね。

また本記事では、機械学習を動かすことにフォーカスしてご紹介しました。
もう少し学術的に体系立てて学びたいという方には以下の書籍などがお勧めです。ぜひご一読下さい。


また動かせるだけから理解して応用できるエンジニアの足掛かりに下記のUdemyなどもお勧めです。

参考文献

1. 論文 - InfoGAN: Interpretable Representation Learning by Information Maximizing Generative Adversarial Nets

2. GitHub - eriklindernoren/PyTorch-GAN

AIで副業ならココから!

まずは無料会員登録

プロフィール

メーカーで研究開発を行う現役エンジニア
組み込み機器開発や機会学習モデル開発に従事しています

本ブログでは最新AI技術を中心にソースコード付きでご紹介します


Twitter

カテゴリ

このブログを検索

ブログ アーカイブ

TeDokology