[ トップページ ]

« Caltech 歩行者データセットの Python へのとりこみ | メイン | Caltech dataset からの MPEG ビデオ・ファイル生成 »

コンピュータ・ビジョン , 並列処理 , 機械学習

Theano で GPU メモリに int8 配列をつめこむ方法

GPU のメモリは貴重だ. 12 GB のメモリをもつ NVIDIA TITAN X は高価だが,12 GB ではまだたりないことがある. 下位機種ではなおさらだ. 本来 1 バイトですむ値なら 8 bit 整数のかたちで GPU メモリにつめこめばそれを有効につかうことができるので,そのための方法を記述する.

機械学習とくに深層学習 (deep learning) のプログラムを実行するのに GPU がよくつかわれる. GPU のプログラミングはやっかいだが,ニューラルネットなどのプログラムを記述するには Theano というシステムをつかうのがひとつの方法だ.

学習データとして画像などをつかうとき,1 ピクセルを 32 bit 浮動小数で表現すると 4 バイトつかうので,貴重な GPU メモリを多量につかってしまう. それをふせぐために NVIDIA のライブラリ cuDNN ver. 2 などでは 16 bit 浮動小数をサポートしているが,それでも 2 バイトつかってしまうし,Theano などではまだ 16 bit 浮動小数のサポートがない. 画像が 256 階調なら 8 bit 整数であらわすることができるので,そのまま GPU メモリにつめこむことができれば,よりおおくのデータをつめこむことができる.

Theano による深層学習のプログラムは Deep learning tutorial などに記述されている. その一部である logistic regression のプログラムのなかにデータセットを GPU メモリによみこむ load_data() という関数があるが,この関数も 32 bit 浮動小数の配列を生成する. しかし,それをすこしかえることで,8 bit 整数の配列にすることができる. load_data() にふくまれる,配列を生成するもとのプログラムはつぎのとおりだ.

def shared_dataset(data_xy, borrow=True):
    data_x, data_y = data_xy
    shared_x = theano.shared(numpy.asarray(data_x, dtype=theano.config.floatX),
                             borrow=borrow)
    shared_y = theano.shared(numpy.asarray(data_y, dtype=theano.config.floatX),
                             borrow=borrow)
    return shared_x, T.cast(shared_y, 'int32')  # “T” means Theano

これをつぎのようにかきかえれば,shared_x は 8 bit 整数の配列になる. 使用する直前にそれが 32 bit 浮動小数に変換される (変換せずにつかおうとすると,Theano がエラー・メッセージをだす). もちろん,その要素の値があらかじめ −128 から 127 のあいだになるようにしておく必要がある (もとの値が uint8 ならば 128 をひいておく必要がある).

def shared_dataset(data_xy, borrow=True):
    data_x, data_y = data_xy
    shared_x = theano.shared(numpy.asarray(data_x, dtype='int8'),
                             borrow=borrow)
    shared_y = theano.shared(numpy.asarray(data_y, dtype='int32'),
                             borrow=borrow)
    return T.cast(shared_x, 'float32'), shared_y

shared_x を上記のように式にかきかえると,それに対して get_value がつかえなくなる. そのため,つぎのようなかきかえが必要になる.

    train_set_x, train_set_y = datasets[0]
        # datasets[0] は load_data() がかえした値 (shared_x)
    ...
    # compute number of minibatches for training, validation and testing
    n_train_batches = train_set_x.get_value(borrow=True).shape[0] / batch_size
    ...

これをつぎのようにかきかえる.

    train_set_x, train_set_y = datasets[0]
    ...
    # compute number of minibatches for training, validation and testing
    n_train_batches = train_set_y.eval().shape[0] / batch_size
    ...

get_value(borrow=True) を eval() にかきかえるだけでなく train_set_x を train_set_y にかきかえたのは,そのほうがオーバヘッドがすくないだろうとかんがえたからである.

浮動小数の場合は平均値が 0 になるように正規化しておくことができるが,整数だとそれは困難なので,使用する直前に平均値をひいておくのがよいだろう. また,値の範囲もたとえば −1 から 1 のあいだにそろえておくのがよいだろう. このチュートリアルのプログラムでは入力変数に x というなまえがついているから, x((x − T.mean(x)) / 128.0) によって置換すればよい. たとえば,logistic regression のプログラムではつぎの行をおきかえる.

classifier = LogisticRegression(input=x, n_in=28 * 28, n_out=10)

これをつぎのようにする.

classifier = LogisticRegression(input=((x − T.mean(x)) / 128.0), n_in=28 * 28, n_out=10)

配列から内容をとりだすたびに計算が必要になるが,たたみこみニューラルネットなどの大規模な計算ならオーバヘッドは 10% 以下ですむ.

Keywords:

トラックバック

このエントリーのトラックバックURL:
http://www.kanadas.com/mt/mt-tb.cgi/7085

コメントを投稿

このページについて

2015-11-19 21:54 に投稿されたエントリーのページです。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Creative Commons License
このブログは、次のライセンスで保護されています。 クリエイティブ・コモンズ・ライセンス.
Powered by
Movable Type 3.36