LSTM+トピック
全国的にはそろそろ春なんでしょうか。札幌は段々と暖かくなってきましたが今日の夜は氷点下6度だそうです。北海道の冬は長い。早く自転車に乗りたいです。
LSTMでの文生成の限界
狭い分野に限られたコーパスだとそれなりの文を生成できますが、ニュースやwikipediaなど幅広い分野の単語が登場するコーパスだとほとんど文になりません。wikipediaコーパスだとこういうやつを平気で出力してきやがります。
情報化社会における織田信長のコンスタンティノープルの陥落については諸説ある。
文法は正しいけど意味がめちゃくちゃ。
ようするに名詞が駄目。accが0.35ぐらいの言語モデルを品詞ごとに調べてみると助動詞は0.5、助詞0.4、動詞0.35に対して名詞は0.05でした。登場頻度は名詞が最も高いのにaccが低すぎるために意味が通らない文になってしまう。
トピックを入れる
そこで、文生成時に今生成しようとしている文の「トピック」を入れてやれば名詞の精度が高まるんじゃないかと以前から考えていました。上のめちゃくちゃな例文の「情報化社会」「織田信長」「コンスタンティノープル」は意味的に非常に遠い単語なので一緒の文に出てくる可能性は低いはずなのに、シンプルなLSTMだとあまりその辺りを消化してくれていない。なのでトピックを入れてやれば「織田信長」についての文ならそれに関連する名詞を優先的に使ってくれるのではないか、という感じです。
[1602.06291] Contextual LSTM (CLSTM) models for Large scale NLP tasks
この論文は次の文字予測(LM)、次の文を選択などのタスクでContextual/Topicという概念を付与することで性能が上がった、ということみたいです。
(上記論文PDFより引用)
前の単語だけではなく前の文やパラグラフのトピックを入れることで性能が2~3%上がっています(perplexityは低い方が性能が上)。次の文の選択タスクでは20%程度の性能向上らしいです。
LMについては期待したほどperplexityが下がっていないようですが、名詞出力専用のネットワークを別に作って組み合わせるとか、あるいは無理してニューラルネットワークで全部やらないなど工夫次第でもう少し性能は高められそうな気がします。
可変長データのミニバッチをchainerのwhereでやる
以前にもちょこっと書いたのだけど、自然言語はたいてい次元(単語数、文字数など)が合わない。
データA 1 2
データB 1 2 3
こんな感じで次元が合っていないデータをミニバッチで学習したい。
末尾をEOSで埋めてミニバッチ
可変長のミニバッチの時に末尾をEOSで埋めてそのまま学習するとまずいのでwhereを使うといいらしい。以前から挑戦していたのだけれどもなかなかうまくいかず、先日ようやく中の人にtwitterで教えてもらって出来ました。
まず末尾を0や-1など特殊なもので埋めて次元を固定する。仮に0をEOSに該当するIDだとしたらこのように埋められる。これでAもBも4次元で揃った。
データA 1 2 0 0
データB 1 2 3 0
転置(numpyの.T)したらそのまま入力に使える形式になってくれる。
A B
1 1
2 2
0 3
0 0
実際のコードだとこう。
a = numpy.asarray( [[1,2,0,0],[1,2,3,0]] ) a #array([[1, 2, 0, 0], [1, 2, 3, 0]]) a.T #array([[1, 1], [2, 2], [0, 3], [0, 0]])
ここから学習を開始する
step1
1 1 ←最初はここが入力(x)
2 2 ←最初はここが正解データ(t)
0 3
0 0
step2
次は一つずれる
データAのtに0が来る。この場合、正解がEOSになってもいいならば問題ない。
1 1
2 2 ← x
0 3 ← t
0 0
step3
ここでxに0が入ってしまう。
1 1
2 2
0 3 ← x
0 0 ← t
EOSを入力して正解にEOSを出すように学習することになる。これがマズいかどうかはタスク次第かもしれない。次の文字を予測するだけのタスクに使うならEOSを出力した時点で打ち切ると思うのでさほど問題は無いかもしれない。
でも文の終わりの時点での状態(シグナル?chainerのlstmだとhに入ってるやつ)を正確に取り出したいなら、
1→2→0
1→2→0→0
この両者は違うベクトルを出力するので困る。きちんと1→2→0で終わらせたい。
前置きが長くなったけど、そういう時にwhereを使うといいらしい。教えて頂いたコードをそのまま引用すると、
c, h = lstm(c_prev, lstm_in) #ここでlstm enable = (x != 0) #where用のcondition 実際はこれをVariableにする c_next = where(enable, c , c_prev) #x!=0ならcを、x=0ならc_prevをc_nextに入れる h_next = where(enable, h , h_prev) #hも同じ
自分はLinkのlstmを使いたいので__call__を上のように少し書き換えて使ってます。
本当は下のように書ければベストだけどwhereの入力はVariableに限られているしlstm自体もc,hのタプルを返してきて直接whereに使えないので上のように一度lstmしてから戻り値をwhereで振り分けている。
c_next , h_next = where( conditon , lstm(c_prev, lstm_in) , ( c , h ) )
さらに末尾埋めに-1を使う場合(自分がやってる方法)
-1で埋めるやり方もある。1.4よりsoftmax_cross_entropyが正解t=-1の場合はlossに0を返してくれるようになったので出来れば末尾は-1で埋めたい。もし末尾0埋めだとlossやacc周りが少し面倒な気がする。EOSは0にして、末尾-1で埋める場合、
データA 1 2 0 -1 -1 -1
データB 1 2 3 4 0 -1
これを転置して学習開始するのだけど、以下のstepになると問題発生する。xに-1が来ちゃう。
A B
1 1
2 2
0 3
-1 4 ←x
-1 0 ←t
-1 0
ただし、ここでも書いたようにEmbedIDに-1を投げると危険。
#これはマズい nanが返ってきたりしていつかlossが破綻する h0 = self.embed(x) #自分はこうやってx=-1のときはZEROベクトルを返すようにしてる h0 = F.where( x != -1 , self.embed(x) , ZERO )
そのうちEmbedIDにもignore flag=-1が出来ると思います。
Ignore labels for EmbedID · Issue #832 · pfnet/chainer · GitHub
2016/4/30追記 バージョン1.8でignore_flagが実装されました
デフォルトでは無効になっているので手動で設定します。-1じゃなくても0などintであればおk。若干パフォーマンス落ちるようです。
super(RNNLM, self).__init__( embed=L.EmbedID(n_vocab, n_units,ignore_label=-1), #ここで設定 l1 = L.LSTM(n_units, n_units), l2 = L.LSTM(n_units, n_units), )
追記終わり
次元が同じもの同士だけでミニバッチする
以下の例のように末尾埋めしちゃうと一番長い文に次元を合わせないといけないので、そのぶん無駄もできる。
1 2 -1 -1 ................................-1 ←短文
1 2 3 -1...................................-1 ←短文
1 2 3 4 5 6 7.......100 101 102 -1 ←長文 こいつのせいで無駄な処理が発生
長さが同じ文だけを集めてミニバッチすれば上の末尾埋めで発生する色々な煩わしさが無くなるし、何より速い。
ただ常に次元が同じものだけで学習するとコーパスが偏って学習に影響が出そうなのでできればシャッフル性を高めたい。
両者いいとこ取り
1.完全ランダム(一番遅い)
2.次元一致したのだけで学習(超高速)
3.なるべく末尾埋めが少なくなるようにうまいことシャッフル(20~30だけ、30~40だけ、みたいなグループにわける)
これをローテーションすれば学習に悪影響を与えずに速度も速くできるのかなと思いました。
以上です。
こんなやり方でシンプルなRNNだと簡単にミニバッチできるようになった。
でも木構造のrecursiveとかattentionなどの場合はどうするんだろう…。
chainerのwhereでbroadcastingやりたいけどtype_checkに弾かれる
numpyのbroadcastingは自分には難しくてあまり理解していなかったのだけど最近ようやく少しだけわかってきた。
Pythonによるデータ分析入門のP410からの説明、英語版だと嬉しい事にPython for Data Analysis - Free Download eBook - pdfより無料で読める。P362より。シンプルな動作なら英語版Figure 12-4の図だけを見ればだいたいわかると思います。この本は大半がpandasの使い方で占められているのだけどnumpyのところだけ切り取って加筆してもっと薄く安くして売って欲しかった。
以下はxpにcuda.cupyを入れているけどnumpyでも同じ動作。
where( condition , Trueだったら代入する行列 , Falseだったら代入する行列 )
xp = cuda.cupy #numpyでも同じ動作 A = xp.asarray([[1,1,1] , [2,2,2]] , dtype=np.float32) #=> shape(2,3) Zero = xp.zeros((2,3) , dtype=np.float32) #Aと同じ形で中身が0の行列を作る #Aの2行目(indexは1、つまり[2,2,2]のところ)を0にしたい cond = xp.asarray( [[True , True , True],[False ,False , False]] ) B = xp.where( cond , A , Zero ) #=>[[ 1. 1. 1.] [ 0. 0. 0.]]になる
ここでcondを以下のようにしても同じ動作になる。
cond = xp.asarray( [ [True] , [False] ] ) #shapeが(2,1) B = xp.where( cond , A , Zero ) #=>[[ 1. 1. 1.] [ 0. 0. 0.]] 上と同じ結果になる
上は全部(2,3)の行列だけど、下は(2,1)と(2,3)の行列が混じってる。
これでうまくいくのはnumpyのbroadcastingのおかげらしい。
本題:chainerのwhereの場合
同じような動作をするchainerのfunctionもある。入出力はもちろんVariableになる。
import chainer.functions as F def to_variable(asarray): return Variable(asarray) #AとZeroは上と同じ条件なので省略 cond = xp.asarray( [[True , True , True],[False ,False , False]] ) #全部Variableに変換 A = to_variable(A) ; Zero = to_variable(Zero) ;cond = to_variable(cond) B = F.where(valid , A , Zero ) #=>B.dataが[[ 1. 1. 1.] [ 0. 0. 0.]]になる
ところがcondを(2,1)にしてbroadcastingを試みるとこうなってしまう。
cond = xp.asarray( [ [True] , [False] ] ) #shapeが(2,1) B = xp.where( cond , A , Zero ) #以下のエラー #chainer.utils.type_check.InvalidType: #Invalid operation is performed in: Where (Forward) #Expect: in_types[1].shape == in_types[0].shape #Actual: (2, 3) != (2, 1)
type_checkさんがwhereの前に仕事をしてしまい、shape不一致で弾かれてしまう。ただ中のコードを読むとtype_checkさえスルーできればいけそうなので、
import os os.environ["CHAINER_TYPE_CHECK"] = "0" #type_checkしない ~省略~ cond = xp.asarray( [ [True] , [False] ] ) B = F.where(valid , A , Zero ) #=>B.dataが[[ 1. 1. 1.] [ 0. 0. 0.]]になる
としたらうまくいった。
ちなみにos.environ["CHAINER_TYPE_CHECK"] = "0" はtype_checkしないぶん学習も速くなります。自分はいつもオフにしてます。
F.whereはメモリをそこそこ食う
隠れ層同士の結合(例 512 * 512とか)にwhere使ってもそこまでサイズは大きくならないけれど、最終出力層がクラス分類で単語ボキャブラリー数なんかだと(512 * 60000)みたいになって前者より100倍サイズが大きいのでかなりメモリを食ってしまう。where使いだして異常にメモリを食うようになったら注意です。
おしまい。
低火力ディープラーニングのための環境(自作ハード編)
昨日こんなプレスリリースが話題になっていました。
www.sakura.ad.jp
高火力ですって。強そう。
ちょっと前にはこんなのも話題に。
ディープラーニング専用GPUサーバファーム「紅莉栖(くりす)」を構築|ニュース|広報情報|株式会社ドワンゴ
現時点で世界最高性能となるMaxwell世代のCUDAコアを搭載したGPUサーバー100台程度で構成
凄い。強そう。
こういう記事を読んだ後に自分の足下で動いている機械をまじまじと眺めてみると、あまりの低火力に恥ずかしさすら覚えます。ワットチェッカーで測ってみると500Wにも満たないそうで、安物電子レンジレベル。まさに低火力。
低火力ディープラーニングのための自作ハード
企業や研究室にTitan4枚指し環境が整っているような人にとってはおもちゃみたいな環境かもしれませんが、私が使っている環境を晒しつつ、個人の趣味レベルで(プチ)ディープラーニングやるにはどういう環境を揃えればいいのか、どのくらいお金を出せば遊べるのかの目安になればと思って書いてます。誰の役にたつのかわかりませんが…。
重要度は1~5でつけてます。
NvidiaのGPU(ビデオカード) 重要度:5
GPUはディープラーニングに必要なモノの中でも花形中の花形、ハード面では最重要パーツです。いかにこいつにお金をつぎ込めるかが勝負みたいなところがあります。
使っているパソコンのGPUがNvidiaならそれをそのまま使えるのですが、インテルCPU内蔵グラフィックスだったりAMDのGPUの場合はNvidiaのを買う必要があります。私が普段使っているiMacはNvidiaじゃなかったので新しくGPUを買ってきてUbuntuが動いているマザーボードに取り付けてディープラーニング入門しました(当時は750ti)。
「GPUが無いと駄目なのか?CPUはかなりいいの積んでるぞ」と思った方、やる処理にもよりますが、現在最高価格のCPUをもってしても1万円程度のGPUの足下にも及ばないです。そのくらいGPUは速いです。大雑把に言ってこのFLOPSの値が高ければ高いほど速い。
FLOPS - Wikipedia
CPUの代表格Core i7 5960X(13万円)は0.4TFLOPS、それに対して1万円程度のGPU(750ti)は4倍近くの1.3TFLOPSです。もしCore i7 5960Xと同じ金額をGPUに出すならTitanXの6TFLOPSになりますから、CPUに対して価格性能比は15倍にものぼります。
GPUの選び方
とにかく計算の大部分はGPUがやるので、ここに一番重点的にお金投資するべきです。
選ぶ時に大事なパラメータとしては
- TFLOPS…計算速度
- メモリ量…どれだけデータをのせられるか
の2つ。
FLOPSは先ほど説明したように高ければ高いほど計算が速く終わります。CUDAコア数 * クロック周波数 = FLOPSみたいな感じ。
TitanX(6TFLOPS)が1日で終わる処理なら、750ti(1.3TFLOPS)は4~5日かかるイメージ。
何気に大事なのがメモリです。これはマザーボードに指すメモリとは別のGPU専用のメモリです。↓これではありません。
GPU買ったら内蔵されてるものと思ってください。
FLOPSが低い、つまり計算速度が遅いのはぶっちゃげた話ひたすら計算が終わるのを待てばいいんですが、メモリが少なすぎるとそもそも計算を始められません。例えるならFLOPSは足の速さ、メモリは手で運べる重さの限界、みたいなもの。
幼稚園児の足は遅いけど、時間さえかければゴールにたどり着けます。
でも20kgの米袋を幼稚園児が運ぶのは無理ですよね。そもそもスタートできません。
FLOPSとメモリはこんな感じのイメージ。
お財布が許す範囲でTFLOPSとメモリのバランスが取れたものを選びたいところです。
現行品の代表的なGPUを以下にあげておきます。価格はうろ覚え。
GPU名 | TFLOPS | メモリ | 価格 |
---|---|---|---|
750ti | 1.3 | 2GB | 12,000円 |
960 | 2.3 | 2GB | 24,000円 |
970 | 3.5 | 4GB(3.5GB) | 45,000円 |
980ti | 5.6 | 6GB | 90,000円 |
TitanX | 6.1 | 12GB | 130,000円 |
入門用にお勧めなのは安価な750tiです。私もこれで始めました。上位クラスと比べると遅いしメモリも少ないですが、それでもCPUに比べれば十分高速ですし、消費電力も少なく手軽に遊ぶのには十分です。
現在一番売れているのは970。メモリ4GBのはずが色々ありまして実質的には3.5GBしか無かったという騒動を発売直後に引き起こしつつも価格と性能バランスが取れた名機としてかなり売れているようです。一番人気のMSI GAMINGは長らく40,000円台だったんですが最近5000円ほど値上がりしてしまいました。残念。
980tiは今私が使ってるものです。TFLOPSは上位のTitanXに迫るものがあります。
TitanXは現在最高峰のGPUの一つ。12GBという破格のメモリを積んでます。13万程度。高い。リッチな研究室や企業にはこれが4枚刺さってる計算機がたくさんあるそうです。なかなかの火力。
さらにこの上にTeslaというGPUもあるのですが、一般人には手が出るレベルでは無いのでここでは割愛します。普通のPCパーツ屋さんには売ってないです。
同じ型番なのに色んなメーカーが違うパッケージで販売してるけど、何が違うの?
使ってるGPU自体はNvidiaが作ったものでどこのメーカーから出てるものも同じ物です。それを各社が工夫してさらに性能(クロック)を上げたり、冷やすためのファンを取り付けたりしてパッケージングしたものが、私たちが手に取る「ビデオカード」です。
GPU…Nvidiaが作った各社共通のもの これだけ買う事はできない 売ってない
ビデオカード…GPU + ファン + メモリ これを買う MSIやASUSやGigabyteというメーカーが販売している
よくわからなかったら970~980tiでは今のところMSIのGAMINGシリーズが優秀で人気なのでお勧め。
次期Pascalは凄いらしい
今年の半ば以降に発売される予定の次期Pascalはかなりの性能アップが見込まれていて、ディープラーニングに特化した処理では10倍速くなるとかいう話も。当面はCPUで遊んでPascalが出たら一番良いのを買うという手もあります。多分最初は15万ぐらいしますけど。
CPU 重要度:3
ディープラーニグの大半の計算はGPUが処理しますが、GPUに渡すデータの準備などはこのCPUが処理しますので、あまり足を引っ張らない程度のものを積んでおきたいです。いわゆるメインストリーム向けの4コア8スレッドCPUで十分で、6コア〜8コアクラスを積むぐらいならそのお金をGPUに回した方がいいです。私は3770Kという2012年当時の4コア最高クラスのを使ってます。4コア8スレッドですが、計算中は1スレッドしか使わないのであまり4コアの意味が無い。もっと下位のCPUでも処理時間には影響無さそう。
ただMecabやCabochaなど自然言語の前処理をする時に並列8スレッド全部使って時間短縮などはできるので、4コア8スレッドに越した事はありません。
マザーボード 重要度:2
(wikipediaより)
マザーボードによってはGPUを1枚だけではなくて複数枚刺せるものがあります。もし将来的にガチでやろうという方はPCI-Express 16Xという端子が複数あるものを選んでください。私のマザーは1枚しか刺せないのでちょっと後悔してます。
メモリ 重要度:2
(wikipediaより)
↑今度はこれです。こっちのメモリです。
マザーボードの限界32GB積んでますが使い切る事はまず無いです。
ストレージ(HDD or SSD) 重要度:2
もしストレージに保存しているデータを逐次読み込んで処理するような場合はSSDに越した事はありません。ランダムアクセス(細かいデータを読む能力)に長けてます。ただ基本的には最初に全部メモリに乗っけてから処理を開始すると思うのでHDDだからといって必ずしも足を引っ張るわけではありません。
電源 重要度:1
上位クラスのGPUは消費電力が250Wなどかなり電力を必要とします。よくわからない人はショップ店員さんに構成を伝えてアドバイスをウケてください。よく初心者がやりがちなのは「システム全体で380Wに収まるはずだから400Wでいこう」みたいにギリギリのを買ってしまったり、逆に1200Wなど過剰なのを揃えてしまうパターン。システム全体で350Wぐらいだったら550~700Wが無難です。店員さんによっては電源効率のいいもの(高い)を進めてきますがBlonzeで十分だと個人的には思ってます。
電気代に注意
仮に500Wのハードを24時間30日動かし続けるとそれだけでだいたい月8000円の電気代がかかります。夜寝ている間にもずっと計算し続けていると翌月の電気代に驚きます。
私は単身で通常5~6000円程度に収まっていた電気代ですが、低火力とはいえディープラーニングで遊びだしてからは2万円に迫る勢い。ご利用は計画的に…。
まとめ
以上自宅で低火力ディープラーニングをやるために必要なハードについて書いてみました。とにかく大事なのはGPUの性能と、GPUの計算の足を引っ張らない程度の他構成という感じでしょうか。いくらGPUが凄くてもCPUやストレージ側で足を引っ張ってしまい、GPUが待機している時間が長くなってしまっては宝の持ち腐れになってしまいます。
今時は自作する人も少なくなっているようですが自分で組んだ方がお金の節約になりますし、徐々に各構成をパワーアップしていく感覚はドラクエみたいなRPGに通じるものがあって楽しいです。また、まずはAmazonのGPUインスタンスで遊んでみて、もっと本格的にやりたいと思ったら自作するという手もありますね。g2.2xlargeインスタンスなら1日1500円~で性能的には970クラスです。
本当はOSとかライブラリの事も書く予定だったんですがハードの話だけで力尽きました。いつかソフト編も書きたいところ。おしまい。
CaboCha(python)で辞書指定
mecabの辞書はほぼneologdに切り替えて使っているのだけど、久しぶりにCaboChaをpythonから使おうとしたら辞書の指定の仕方がわからなかったのでメモ。
#デフォルト辞書を使う時 cabocha = CaboCha.Parser("") #辞書指定する場合はこう(ディレクトリは各々の環境に変えてください) cabocha = CaboCha.Parser("-d /usr/lib/mecab/dic/mecab-ipadic-neologd") #解析 tree = cabocha.parse("北海道札幌市中央区")
デフォルト辞書だと
北海道 / 札幌 / 市 / 中央 / 区
neologdだと
北海道 / 札幌市中央区
と辞書を切り替えられていたことを確認。
タイトルと関係はないけれど結果treeのパースはこちらを参考。
shogo82148.github.io
おわり。
chainer1.6.0リリース
一日前倒しでリリースされたようです。
Release v1.6.0 · pfnet/chainer · GitHub
1.5からの機能追加バージョンなので1.5のコードが動かなくなったりすることは無いようです。
- インストール時にHDF5が必須じゃなくなった。1.5のインストールで躓いた人が多かったからかな。
- NumPy 1.10のサポート
- cuDNNのv4をサポート?、ただしv3/v4ともに全ての機能をカバーしているわけではない。
個人的に気になるの
- GRUを1.5で導入されたLSTMと同様にシンプルに書けるようになった?StatefulGRUというやつ。
- 高性能な活性化関数Maxout/ELU
Maxout networks
[1511.07289] Fast and Accurate Deep Network Learning by Exponential Linear Units (ELUs)
- sigmoid_cross_entropyに無視フラグ(-1)。softmax_cross_entropyと同様に、正解に-1を付与すると損失を0に。
延期?
木構造のLSTMを扱えるSLSTMが無くなってしまったようです。既に使ってるんですがまだ未完成だったのでしょうか。
chainerのバージョンごとの違い(2016年1月19日現在)
あと数日で1.6がやってくるchainer。
1.0~1.6までのバージョンごとの差について簡単にまとめてみます。
大きく分けると3つのグループ
1.0 1.1 1.2 黎明期バージョン
1.3 1.4 CuPy導入
1.5 1.6 色々とパワーアップした現世代
特にこれからchainer始める人はこのグループ分けを覚えておいた方がいいです。グループが違うと中身がかなり違うので他の人が書いたサンプルを参考にしたりフォーラムで質問する時は注意が必要です。
同じグループ同士のアップグレードはそこそこ楽ですが、1.2→1.3や、1.4→1.5はそれなりに大変。
バージョンの見分け方
良さげなサンプルコードを見つけて使ってみたいけど対応しているバージョンがわからない、という方向けに簡単な見分け方を。
1.5、1.6
chainer.links
chainer.Chain
serializers.save_hdf5
これらが一つでもあれば1.5以上が確定。
1.3、1.4
cupy
xp
これらがあれば1.3以上がほぼ確定(ただしcupy/xpいずれもGPUのためコードなので、CPUだけのために書かれたコードの場合は引っかからないかも)。
いずれも見つからなければ1.2以下の可能性が高いです。
各バージョンに対する主観
1.0
CaffeやPyBrainなどはちょこちょこ触っていたけれど設定ファイルがyamlだったりで面倒だなあとモヤモヤしていたところに国産フレームワークの登場。
右も左もわからなくてもニューラルネットワークが書けてしまう衝撃の登場でした。
そのぶんまだまだ産まれたてといった感じで、GPU環境のインストールは皆さん苦労されたかと思います。私もchainerで使いたくてGPUを買って帰宅してから10時間近くCUDA/PyCUDAの設定に明け暮れてました。この頃はGPUで動かしてエラーが出ても「what(): explicit_context_dependent failed: invalid device context - no currently active context?」というどれも共通?のエラーが出て何が原因なのかわからなかったり。そういえばpython3にもまだ対応していませんでした。
1.1
バグ修正やint32やfloat32などの型チェックが厳格になったバージョン。python3やCaffeモデルの読み込みに対応。
1.2
あまり印象が無いバージョン。
1.1→1.2に上げる注意点としてはFunctionSetあたりのディレクトリの構造が変わった?のかFunctionSetごとpickleしたモデルは互換性が無くなってしまいました。
1.3
CuPy導入でGPU対応コードがめちゃくちゃ簡単に書けるようになった記念すべきバージョン。まだ1.2以前でchainer入門されてる人が結構いるみたいですが、GPUを使うなら最低限この1.3に上げてからにした方がいいです。1.2以前のインストールを難しくさせていた原因であるPyCUDAが完全に必要なくなったのでpipでさくっと入るようになってます。xpにnumpyかcuda.cupyのどちらかを入れておくというテクニックでCPU/GPU分岐コードもほぼいらず。
1.4
本来はここで現在の1.5相当の大幅な変更が行われる予定でしたが開発に時間がかってしまったので1.4は1.3のマイナーアップデート的な位置づけでリリース。CuPy周りでたくさんの機能が追加されてnumpy互換性が高まりました。
1.5
1.4以前とコード・モデルの互換性を大幅に切り捨て、より速くより洗練された現在の1.5さん。今まで書き溜めてきたコードのアップグレードは大変でしたが上げてしまうと快適です。
- CuPyのCython化で1.3で落ちてしまったGPUの速度が1.2以前のPyCUDA版よりも速く
- モデルの公式保存/読み込みサポート
- LSTMをシンプルに書けるように
- Chainをどんどん繋いでいけるようになって名実共にchainerに(まだ使いこなせてないけど便利そう)
など改善点が多め。そのぶんインストールが少し大変になったようですが1.6で改善されるそう。
1.6(未リリース)
ぱっと見た感じですが機能の追加がメインなのでコードの書き換えは全く必要無さそうです。
メモリ解放、ELUやMaxoutなどの高性能活性化関数、cudnn v3のsoftmaxLog対応、cudnn v4対応?、木構造のLSTM、GRU修正などなど。
以上です。
今から始めるんだけど、どのバージョンがいい?
1.2以前はお勧めできません。GPU環境のインストールは大変ですし、今のバージョンとはGPUまわりの書き方がかなり違うので、もし最新バージョンに上げたくてもすんなり移行できないかもしれません。コツコツ書いたコードが無駄になるかも。chainerの日本語フォーラムで1.2以前のバージョンで質問されている方がいますけど、回答もつきにくいイメージ。悪いところばかりではなくて、chainerが世に出た当初にたくさん書かれてたチュートリアル的な記事を利用しやすいというメリットもあります。
できれば1.5。1/20に1.6が出るのでそれでも。
どうしてもインストールにつまずくようなら1.4。
といった感じでしょうか。ちなみにpipでバージョンを指定してインストールするには、
pip install chainer=="1.5.1"
のようにします(環境によってsudoつけてください)。