• このエントリーをはてなブックマークに追加

今なら、継続入会で月額会員費が1ヶ月分無料!

記事 8件
  • 【機械学習】Chainerで作ったニューラルネットをC++に移植してベンチマークしてみる

    2016-08-29 20:40  
    100pt
     マシン語 それは男のロマンである。 異論は認めん。 CPUの能力を限界まで引き出すコード。 そう、マシンたちの歓喜の声が聞こえてくる。 もっとオレを回してくれ! マイクロコードの1クロックまで! レジスタの限界まで オレを、オレをもっと愛してくれ! コアのひとつひとつ、パイプラインの全てのステージをコードで満たしてくれ! オレはもっと回りたい。 もっと回したいんだ・・・ ・・・そうだ、いい子だ。 それがマシン語である。 マシン語に比べると最近はPythonだのRubyだの適当な擬似言語で満足する輩が多すぎる。 軟弱者め!!! とまあ意気込んでは見たものの・・・いきなりマシン語はつらたんなのでとりあえずネイティブコードで動かしてみることを今回の記事では目標にする。 題材はいつものアレ 9-8-8-6の中間層二層のニューラル・ネットワーク。 こいつをC++に移植してみる。 ウヒョー、ワクワクするぜっ! まず、C++の文法を思い出すところからはじめなければならない。 いやー、忘れたよ。 最初はJSONで出力してJSONで扱おうかと思ったのだが、ネットワークが充分小さいのでヘッダファイルにコンバートすればいいか、ということでL1とL2のW(重み)とb(バイアス)をlayers.hに出力してみる。
    double  l1_W [8] [9] ={
    { 0.367395937443 ,
    0.620269238949 ,
    -0.0110975131392 ,
    0.0458976365626 ,
    -2.03605866432 ,

     こんな感じ。 まず、C++の多次元配列の作り方からして忘れてたからね。 ずっとエラーが出てて「なんで?」と思ったら、配列の初期化を[]でやってたからだった。 どんだけ離れてたんだよ。 まあ慣れてくれば昔とった杵付。 なんとかなりまさあ とりあえずデータをC言語で扱おうと思ったのだが・・・Cはつらすぎる。 だめだ、おれのオブジェクトが思考を始めてしまった。 オーバーヘッドは爆増するが、ここはひとつクラスを作らせてつかぁさい!
    class Vector{
    public:
    double *v;
    int size;
    Vector(double *_v,int _size){
    v = _v;
    size = _size;
    v = new double[_size];
    for(int i=0;i<_size;i++){
    v[i]=_v[i];
    }
    };
    Vector(int _size){
    size = _size;
    v = new double[_size];
    };
    Vector *add(Vector *_v){
    for(int i=0;i<size;i++){
    v[i]+=_v->v[i];
    }
    return this;
    };
    Vector *sigmoid(){
    for(int i=0;i<size;i++){
    v[i]=_sigmoid(v[i]);
    }
    return this;
    };
    void dump(){
    printf("dim:%d\n",size);
    for(int i=0;i<size;i++){
    printf("%f,",v[i]);
    }
    puts("");
    }
    };

     テンソルのクラスを作るのはつらそうだったので軟弱なオレはもうベクトルのクラスと行列のクラスだけでなんとかすることにする。いんだよ細けぇことは。畳込みNNだってテンソルっつうても画像がたくさんあるだけだからな。学習しないでインファレンス側で使うだけならこれでいんだよ別に。 しかしクラスの定義とか参照とかポインタとか盛大に忘れていて焦った。 やはりプログラミング言語が進化するというのは大きな理由と意義がある。 「.」と「->」の使い分けとか、本当に無駄すぎる。まあしかし、マシン語を意識する場合はこれがわかんないと話しになんないわけだけどな。 思い出しながら作ったのでnewとかが盛大に無駄こいてる。 本来はパフォーマンスを再優先するならばせめてオブジェクトプールを使うべきだ。 まあSTLとか使うという手もあるだろう。 しかし、コンストラクタのオーバーロードとか作ったの何年ぶりだろう。 だがしかし、STLまで思い出すのは辛すぎるので今回はいいや。まあこれでパフォーマンスがうまく上がんなかったら別の手を考えるベエ。
    class Matrix{
    public:
    double *m;
    int w,h;
    Matrix(double *_m,int _h,int _w){
    int i,j;
    h=_h;
    w=_w;
    m = new double[w*h];
    for(j=0;j<h;j++){
    for(i=0;i<w;i++){
    m[j*w+i] = _m[j*w+i];
    }
    }
    };
    Vector *apply(Vector *v){
    Vector *r = new Vector(h); 
    for(int j=0;j<h;j++){
    double acc=0.0;
    for(int i=0;i<w;i++){
    acc += m[j*w+i] * (v->v[i]);
    }
    r->v[j]=acc;
    }
    return r;
    }
    };

     男の行列クラス! もう男らしい。行列に対してベクトルを乗算する機能しかない! 乗算する度にnewしてるとか昔の自分なら絶対許さないコードだが、いんだよ細けぇことは後で考えれば。 これでとりあえず下準備完了。 次にフォワード(順伝播)を作る。 シグモイド使うやつと使わない奴
    Vector *forward(Vector *x,Matrix *W,Vector *b){
    Vector *a = W->apply(x); 
    a->add(b);
    return a;
    }
    Vector *forwardSigmoid(Vector *x,Matrix *W,Vector *b){
    Vector *a = W->apply(x); 
    a->add(b);
    a->sigmoid();
    return a;
    }

     ちなみにC++の場合、シグモイドを自前で実装するとこうなる。
    double _sigmoid(double x) {
        return 1.0 / (1.0 + exp(-1.0 * x));
    }


     さあこれで準備完了。 いくぜ男のメイン関数
    int main(){
    /*テスト用データ*/
    double in[] = {0.1083984375,0.213452398777,0.774722874165,0.110441893339,0.212938994169,0.780655622482,
    0.112617187202,0.212380990386,0.785996675491};
    Vector *inV = new Vector(in,9);
    Matrix *l1W = new Matrix((double*)l1_W,8,9);
    Vector *l1b = new Vector(l1_b,8);
    Matrix *l2W = new Matrix((double*)l2_W,6,8);
    Vector *l2b = new Vector(l2_b,6);
    Vector *h;
    clock_t start=clock();
    double dummy=0.0;
    for(int i=0;i<1000;i++){
    h=forwardSigmoid(inV,l1W,l1b);
    h=forward(h,l2W,l2b);
    dummy+=h->v[0];
    }
    clock_t end=clock();
    double t=(end-start)/(double)CLOCKS_PER_SEC;
    printf("%f sec\n",t);
    printf("%f \n",dummy);
    h->dump();

     テストデータは前回Pythonの整数版の精度検証に使ったのと同じものを使用。 これが同じになればちゃんと動いてると推定できる。 1000回ループ回してるところでなぞの変数dummyを足している理由は、計算結果を利用しないとコンパイラが万が一炎の最適化をかけてしまったらベンチマークにならないからだ(表示してるのも同様の理由)。 さあ、実行してみよう。ちなみにPython版では最も高速だったFloat64で1000回ループに22ミリ秒掛かったんだよねー。 レッツゴー! ・・・? 1.6ミリ秒・・・だ・・・と・・・!!!!!?!??!?!?!?!?!?! 念のためもう一回実行してみる。  1ミリ秒 おいおい。 ということは、Python版の1/200の実行時間で終わってしまうということか?どういうことだってばよ。 今回の速度比較はこうなった。 これはなんの冗談なんだろう。本当に計算してんのかな?と思って、試しに浮動小数点の足し算だけのループをまわしてみると確かに高速化しているのでまあ何らかの計算はしているのだろう。試しにPythonのfloat64版と同じくらいの実行時間になるにはループがどのくらいあればいいのか調べてみた。これでもPython/float64よりはだいぶ高速だが、まあこの結果になるのにどのくらいのループをしたかというと
    for(int i=0;i<200000;i++){
    h=forwardSigmoid(inV,l1W,l1b);
    h=forward(h,l2W,l2b);
    dummy+=h->v[0];
    }


    20万回でした。つまり、どうやらC++で書き直すだけでCPUでの実行時間において、全く同じニューラル・ネットワークでPython版の200倍高速に、Chainerの500倍高速に計算できることがわかりました。まあ畳込み絡んできたりGPU絡んできたりすれば状況は違うんだろうけど。やはりChainerは便利で簡単に書ける分、代償も少なくないんだろうなあ。 
  • 【shi3zの華麗とはいえない日常】 最近ガチすぎるのでぼやぼや飯の話でも書く

    2016-08-25 10:31  
    1pt
    とりあえず、C++で実装した五層オートエンコーダをRaspberryPi3で実行したところ、0.3秒くらいかかることがわかった。0.3秒っつうのは、要するにMacBookAirでChainerを使った時と同じくらいというわけだ。けっこう遅いな、0.3秒って。まあこれは64ビット浮動小数点でやっているので、もしかしたら32ビット浮動小数点とか整数でやったらまた違った結果になるかも。まあこのへんは気が向いたらもうちょっと突っ込んでやろうと思う。まあしかし、ぼやぼやするのも大事だよな。ぼやぼやしたい。毎度毎度、ちょっと悩むのが朝飯である。朝起きてブログでも書いてしばらくすると腹が減ってくる。ところが腹が減る時間というのが、8時から10時のあいだだ。すると、開いてる店が限られる。吉野家か、ゆで太郎か。でもでも11時までガマンすれば選択肢は一気に広がる。そこまで待つか、待たないか。いつも心は揺れ動く
  • 【機械学習】Chainerで作った全結合ニューラル・ネットワークを整数化してみる

    2016-08-22 07:22  
    100pt
     整数化 それは男のロマンである。 異論は認めん。 Chainerは使いやすいがいかんせん動作が遅いという問題がある。 これはMacなどで使う場合にはそれほど気にならないし、究極的にはGPU搭載マシンで使うわけだからそこが速ければ問題ないのだが、まあ実際問題GPU搭載マシンでも残念ながら他のフレームワークの方が速かったりすることはままある。 とはいえとはいえ、Chainerに任せっきりの全結合ネットワークを自分で実装しなおしてみることはそう悪いことではない。 それに、Chainerで学習させた全結合ネットワークを他のプラットフォーム、たとえば組込み機器用の非力なプロセッサとかまあその手のものに実装したり、最終的にはC言語にしたりするときに、内部構造を知っておくのは悪くないアイデアだろう。 そしてGoogleのTPU、つまりTensor Processing Unitがなぜ高速なのかということも、整数化を通して知ることができるかもしれない。 そこで前回作ったChainerの全結合ネットワークをひとまずPython上で整数化してみることにする。 前回作ったChainerの全結合ネットワークとは具体的には下図のような構造である。 これは筆跡の予測をするためのニューラル・ネットワークである。 入出力あわせて四層しかないのでディープニューラル・ネットワークではないが、積層オートエンコーダも原理的には全く同じ仕組で動くはずである。 単純なネットワークのほうが扱いやすいのでこういう形にした。 ただし、回帰問題を解くネットワークなので精度に関しては畳込みニューラル・ネットワークが扱う分類問題よりはかなりシビアだ。 Chainerでの定義はこんな感じになる。
    n_units=8
    class Model(Chain):
        def __init__(self):
            super(Model, self).__init__(
                l1=L.Linear(9, n_units),
                l2=L.Linear(n_units, 6),
                )
        def __call__(self, x,layer=0):
            h = self.l1(x)
            h = F.sigmoid(h)
            return self.l2(h)
        def dump(self):
            pickle.dump(self.l1,open('l1.pkl', 'w'))
            pickle.dump(self.l2,open('l2.pkl', 'w'))
        def load(self):
            self.l1=pickle.load(open('l1.pkl', 'r'))
            self.l2=pickle.load(open('l2.pkl', 'r'))

     ご覧のように、l1とl2という2つの全結合層(Linear)がある。 予め学習させたデータを見てみよう
    >>> model = Model()
    >>> model.load()
    >>> model.l1.W.data.shape
    (8, 9)
    >>> model.l1.b.data.shape
    (8,)
    >>> model.l2.W.data.shape
    (6, 8)
    >>> model.l2.b.data.shape
    (6,) 
     実のところニューラル・ネットワークの正体というのは単なる配列である。 全結合層の場合は、W(重み)とb(バイアス)の2つが必要になる。 Wが8x9の2次元配列になっているのは、まずL1(第一層)が8次元のためだ。 9次元の入力に対して、それぞれの入力にW(重み)を乗じて積分していく。 最後にバイアスであるbを足して、それから活性化関数(この場合はsigmoid)を通して出力する。 それを8つのニューロンに対して繰り返す。 バイアスは8つのニューロンに対してそれぞれひとつずつ。だからL1.b.data.shapeは(8,)になる。 そういう処理をChainerを使わずに書いてみると下記のようになる。
    def forward(layer,x,activation):
        r=[]
        for W,b in zip(layer.W.data,layer.b.data):
            accum=0.0
            for w,h in zip(W,x):
                accum += w*h
            if activation:
                r.append(sigmoid(accum+b))
            else:
                r.append(accum+b)
        return r
     h = forward(model.l1,x,True)
     y = forward(model.l2,h,False)

     活性化関数を使う場合と使わない場合があるので、やや泥臭いコードになっているが、実際に実行してみるとこれで上手くいってることが分かる。 比較のためChainerでも同じ計算をして表示すると
    Chainer:[ 0.1148746   0.21153805  0.78971589  0.11715603  0.21138623  0.79293698]Float64:[0.11487447682804452, 0.21153808168055044, 0.78971603399232249, 0.11715607325794686, 0.211386418677598, 0.79293766352923889]


     という感じになり、ちゃんと倍精度(64ビット浮動小数点精度)で同じ結果が出てることが分かる。 ちなみに今のMacやWindowsのCPUは、そもそもが64ビットCPUのため、実はChainerの32ビット浮動小数点演算よりも64ビット浮動小数点演算の方が高速である。あとでベンチマークを見せるが、だいたい2倍くらい64ビットの方が速い。 これを整数化するわけである。 整数は計算負荷が低いので一般的に組込み機などでは有利なはずである。 今回は手軽な整数化として固定小数点化を行った。 浮動小数点演算が難しいのは小数点が文字通り浮動するからであり、小数点が固定されていれば、それは整数と同じに見做せるというおなじみの手法で、筆者が小学生の頃から多用した古典的な高速化テクニックのひとつである。というか当時のコンピュータでは浮動小数点演算は非常にコストが高く、どんな計算でも高速に処理したければ固定小数点化する必要があった。 また、初代プレイステーションの積和演算ハードウェアも、実体は固定小数点の整数演算専用のDSPだった。 さきほどの処理を整数化(固定小数点化)するとこうなる。
    base=2**16 #固定小数点をどこに置くか
    for i in range(len(y)):
        y[i] = int(_y[i]*base)
    print "goal",y
    for i in range(len(_x)):
        x[i] = int(_x[i]*base)
    def sigmoidInt64(z):
        z = float(z)/base
        return int(1/(1+math.e**(-z))*base)
    def forwardInt64(layer,x,activation):
        r=[]
        for W,b in zip(layer.W.data,layer.b.data):
            b = int(b*base)
            accum=0
            for w,h in zip(W,x):
                w = int(w*base)
                accum += int(w*h)/base
            if activation:
                r.append(sigmoidInt64(accum+b))
            else:
                r.append(accum+b)
        return r
    h = forwardInt64(model.l1,x,True)
    y = forwardInt64(model.l2,h,False)
    print "result",y

     固定小数点というからには小数点をどこかに置かなければならない。 今回の場合、64ビットコンピュータでやるのでまずは64ビット整数で固定小数点を置くことにする。固定小数点はひとまず16ビットとした。ややオーバーキル気味の精度ではある。 実行結果を比較するために、浮動小数点演算の結果得られた数値を参考までに同じ精度で整数化して表示する。
    goal [7528, 13863, 51754, 7677, 13853, 51965]
    result [7518, 13856, 51747, 7675, 13839, 51959]

     goalが、浮動小数点演算の結果を整数化したもので、resultが16ビット固定小数点精度で64ビット演算を行った結果である。 これを見るとだいたいあってるけど下二桁が違うということがわかる。 念のため、32ビット固定小数点精度でやってみる
    goal [493382121, 908549142, 3391804539, 503181503, 907897755, 3405641332]
    result [493382110L, 908549140L, 3391804532L, 503181497L, 907897749L, 3405641328L]

     こうするとかなりの精度が出ることがわかる。 ただIntelの64ビットCPUで整数演算するメリットはあまりない。計算速度は浮動小数点演算の1.5倍くらい遅いのだ。 RaspberryPi3は64ビットCPUだが、浮動小数点演算とどっちが速いか実際にベンチマークしないとわからないので、試しにRaspberryPi2やRaspberryPiZeroで動かすことを想定して32ビット固定小数点演算をやってみる。
    base=2**16
    for i in range(len(y)):
        y[i] = np.int32(_y[i]*base)
    print "goal",y
    for i in range(len(_x)):
        x[i] = np.int32(_x[i]*base)
    def sigmoidInt(z):
        z = float(z)/base
        return np.int32(1/(1+math.e**(-z))*base)
    def forwardInt(layer,x,activation):
        r=[]
        for W,b in zip(layer.W.data,layer.b.data):
            b = np.int32(b*base)
            accum=0
            for w,h in zip(W,x):
                w = np.int64(w*base)
                accum += np.int64(w*h)/base
            if activation:
                r.append(sigmoidInt(accum+b))
            else:
                r.append(accum+b)
        return r
    h = forwardInt(model.l1,x,True)
    y = forwardInt(model.l2,h,False)
    print "result",y

    今回は精度の確認が目的なので、遅いことを承知でnumpy.int32を使う。ただし、そのままではWと入力を乗じる時に精度が足りなくなるのでそこだけ64ビット整数で計算している。16ビット固定小数点で演算結果は以下のとおり。
    goal [7528, 13863, 51754, 7677, 13853, 51965]
    result [7518, 13856, 51747, 7675, 13839, 51959]

     やはり回帰問題としては厳しい。 ただ、回帰でこれだけいけるなら、分類問題なら充分な精度が出せると思う
    goal [117, 216, 808, 119, 216, 811]
    result [102, 212, 802, 110, 209, 803]

     念のため、初代プレイステーションと同じく10ビット固定小数点演算でやってみた。 この精度を許容できるかどうかは利用目的によるだろう。 これは軌跡の予測なのでドット数と考えれば、常に10ドットくらいズレる予測を許容できるかという問題になる。 全体を実行したベンチマーク結果を以下に示す。

    $ python getdata.py 
    [ 0.1148746   0.21153805  0.78971589  0.11715603  0.21138623  0.79293698]
    Chainer:0.532674sec
    [0.11487447682804452, 0.21153808168055044, 0.78971603399232249, 0.11715607325794686, 0.211386418677598, 0.79293766352923889]
    Float64:0.253355sec
    goal [493382121, 908549142, 3391804539, 503181503, 907897755, 3405641332]
    input [465567744, 916771071, 3327409408, 474344319, 914566015, 3352890367, 483687136, 912169407, 3375830015]
    result [493382110L, 908549140L, 3391804532L, 503181497L, 907897749L, 3405641328L]
    Int64:0.4142sec
    goal [117, 216, 808, 119, 216, 811]
    input [111, 218, 793, 113, 218, 799, 115, 217, 804]
    result [102, 212, 802, 110, 209, 803]
    Int32:0.522224sec

    計測はtime.clock()を用いて1000回ループで行った。とりあえず手元のMacBookAir(1.7 GHz Intel Core i7)では、64ビット浮動小数点演算はChainer(32ビット浮動小数点演算)の2倍くらい速く、64ビット整数演算は浮動小数点演算より遅く32ビット固定小数点演算より速いことがわかった。まあイマドキのCPUらしい結果である。 同じベンチマークをRaspberryPiで実行したらどうなるのか、興味の湧くところである。 
  • 【機械学習】 Chainerによる筆跡の予測

    2016-08-19 07:45  
    100pt
     さて、手書きとは何かというのを追求するのが僕のライフワークである。 そこで以前、樋口真嗣監督がenchantMOONの発表会で描いていたラクガキが発見されたので載せてみる。 懐かしい写真。 監督が暇つぶしに何を書いているのか覗いてみると・・・ すげえ上手い。 しかも怪獣を書いています。おもえばこの時は2013年。 まさにシン・ゴジラの構想を練っていた時でしょう。 このときは単に「樋口さんは本当に怪獣が好きなんだなあ」としか思わなかったのですが、まさかゴジラの構想を練っていたとはなあ。 とまあこのように、書く人によって全然違うのが手書きの面白いところです。 enchantMOONでは筆跡の予測が重要で、この予測によって見かけ上、反応速度が上がっているように見えます。ちなみにこの筆跡の予測は東芝のREGZA tabletのTruNoteにも入っていて、細かい字を書こうとする時に違いが出ます。絵を描こうとするときはむしろ予測は邪魔かも。 今回はこの筆跡データを機械学習させたらどうなるの? という話です。 幸い、手元には自分の過去三年にも及ぶ手書きメモが残っているので、筆跡データは唸るほどあります。 まずニューラル・ネットワークを設計します。 オートエンコーダを使えば深層化できるんだけど今回はそこまでいらないかなと思って非常に単純な三層パーセプトロンを作りました。だからタグも「深層学習」ではなくて「機械学習」 過去3フレームのペンの筆跡座標と筆圧の情報から将来2フレームの座標と筆圧を予測させるというニューラル・ネットワークです。 深層学習でなくても、機械学習でどのようにアルゴリズムを組むか参考になると思います。 実際のニューラル・ネットワークのモデルはこんな感じになります。 まあ説明する必要がないほど簡単ですけど。 中間層が2つの単純なニューラル・ネットワークです。 今回は分類ではなくて回帰として解くのでこのようになっています。 隠れユニット数(n_units)は8にしていますが、ここは複雑すぎなければなんでもいいかと。 これを学習させるわけですが、ここからがちょい厄介です。 まず、enchantMOONのストロークデータはstroke1.jsonなどのように格納され、しかもディスク内にバラバラに入っています。 そこでまず UNIXコマンドを実行します。sudo find / -name 'stroke*.json' > jsonlist.txt
     こうすると、ディスク内にある全てのstroke*.jsonへのパスが手にはいります。 このjsonlist.txtを舐めればいいわけです。 これで得られた座標と圧力をいきなりつっこんでみると・・・
    2773785 #学習データセット総数277万
    ('epoch:', 0, 'loss:', array(25634.8125, dtype=float32)) ('epoch:', 1, 'loss:', array(26884.3515625, dtype=float32)) ('epoch:', 2, 'loss:', array(26972.904296875, dtype=float32)) ('epoch:', 3, 'loss:', array(25882.63671875, dtype=float32)) ('epoch:', 4, 'loss:', array(26219.3046875, dtype=float32)) ('epoch:', 5, 'loss:', array(26219.53515625, dtype=float32)) ('epoch:', 6, 'loss:', array(26157.064453125, dtype=float32)) ('epoch:', 7, 'loss:', array(26268.296875, dtype=float32)) ('epoch:', 8, 'loss:', array(26588.7109375, dtype=float32)) ('epoch:', 9, 'loss:', array(26797.19921875, dtype=float32)) ('epoch:', 10, 'loss:', array(26485.3671875, dtype=float32))
    ('epoch:', 11, 'loss:', array(26378.431640625, dtype=float32))

     壮絶に失敗しました。いくらなんでもlossが2万を超えていたら収束する気がしません。 なんでこういうことが起きるかというと、まあ簡単にいえば正則化してないからです。 enchantMOONの座標は600x800で格納されています。圧力は0〜1です。 これではうまくいくものもいきません。 ニューラル・ネットワークに入力するデータとしては数値が違いすぎるのです。相関関係を測ろうにも無理です。 あるときは、オーバーフローを起こしてしまいました。 そこで入力する座標データを圧力のサイズにあわせて0〜1に縮小します。filelist = open('jsonlist.txt').readlines()
    for file in filelist:
        print file.rstrip('\n')
        data = json.loads(open(file.rstrip('\n')).read())
        for stroke in data['strokes']:
            line = []
            cnt=0
            for i in stroke['data']:
                if cnt==0:
                    line.append(i/800)
                elif cnt==1:
                    line.append(i/600)
                else:
                    line.append(i)
                    cnt=0 
     次に、予測する線分の学習データセットを作ります  
                x_set =[]
                y_set =[]
                for i in range(0,len(line)-15,3):
                    x_set=[]
                    for j in range(9):
                        x_set.append(line[i+j])
                    y_set=[]
                    for j in range(6):
                        y_set.append(line[i+9+j])
                    x_train.append(x_set)
                    y_train.append(y_set)

     これで過去3フレームから未来2フレームを予測するx_trainとy_trainができました。 ちょい泥臭いところは目をつむってください。 学習そのものは非常にシンプルにできます。
    batchsize = 10000
    x_train = np.array(x_train,dtype=np.float32)
    y_train = np.array(y_train,dtype=np.float32)
    datasize = len(x_train)
    for j in range(0,400000):
        indexes = np.random.permutation(datasize)
        for i in range(0, datasize, batchsize):
            x = Variable(x_train[indexes[i : i + batchsize]])
            t = Variable(y_train[indexes[i : i + batchsize]])
            optimizer.zero_grads()
            y = model(x,layer=0) 
            loss = F.mean_squared_error(y, t)
            loss.backward()
            optimizer.update() 
     これで学習ができます。 学習した結果はこんな感じになりました。
    ('epoch:', 0, 'loss:', array(0.03901803493499756, dtype=float32)) ('epoch:', 1, 'loss:', array(0.03184596449136734, dtype=float32)) ('epoch:', 2, 'loss:', array(0.028442196547985077, dtype=float32)) ('epoch:', 3, 'loss:', array(0.02407853491604328, dtype=float32)) ('epoch:', 4, 'loss:', array(0.02016972377896309, dtype=float32)) ('epoch:', 5, 'loss:', array(0.016892623156309128, dtype=float32)) ('epoch:', 6, 'loss:', array(0.013871355913579464, dtype=float32))

     学習させたばっかりだとこんな感じの予測 1,2,3までの入力に対して4,5の予測を出しています。 おおう。暴れすぎだ。何があった? さすがにこれでは使い物になりません。
     が、4万回くらい学習させるとlossが0.0001くらいまで下がります。 これで予測させるとこんな感じに これはわりとちゃんと予測できているのではないかと思います。 
  • 【shi3zの華麗とはいえない日常】 休んでないのに夏休みが終わる

    2016-08-18 07:20  
    1pt
     どうも。 ティアー・ワン・シン・ゴジラ・ジャーナリストです。 お盆だというのに気が付けば10連勤。 一体全体どうなっているのでしょうか。 この国は、経営者といえどブラック労働から逃れられないのでしょうか。 というか中小企業の経営者に人権ないよなほんと。 つらい。つらたん。 そんな休むヒマもなく日々労働に勤しんでいるワタクシですが、まあ一日だけ休みがあって、その日はいつものように南治さんのご自宅でBBQと洒落こみました。そう、久しぶりに肉を焼いた話ですよ。 南治さんといえば、カウボーイズファミリーでお馴染み、トロトロのチチことトロチチ先生です。 もうサラダとかツマミとかお手の物なんですよねー。毎回、悪いなあ。 そして火起こし。 ファイアースターターは男のロマン。 こうやって炭に火を入れていくわけですよ。 すげー火事みたいになっていますが大丈夫です。 今回はなんとトロチチ先生がダッチオーブンを用意してくれたので料理が捗ること。 まず最初に作るのはローストビーフにしました。 ローストビーフは、上質な塊肉にまんべんなく塩コショウして、それを弱火でじっくり焼いていきます。 ローストビーフを上手く焼くコツは、まずトングで表面を全てまんべんなく炙って表面をコーティングし、あとは対流で日が通るようにするわけですが、ダッチオーブンの場合、一定期間火にくべたらしばらく火からおろして放置するくらいがちょうどいいです。 しばらくしたら、オーブンから取り出し、アルミホイルで包んで20分くらい寝かせます。 余熱で火が奥まで浸透していくと美味しく焼きあがるというワケ。 そしてローストビーフの味を決定するのは、なんといっても、ソースです。 今回は帰ってきたアメリカ人、エリック・アンドリュー・マキーバーが地元オクラホマのソウルフードである特製BBQソースを持ってきました。 ローストビーフにたっぷり掛けます。 このローストビーフ、我ながら久々に上手く焼けたと思う。 そしてなによりこのバーベキューソースがね、フルーティで、すんごく美味い!!! なんていうメーカーなのか知りたい。 
  • 月と鼈 〜僕の人類補完計画 #40 ファイナルファンタジー7をプログラミングした男

    2016-08-15 07:00  
    100pt
    ■伝説を作った男 「よう、飯食った?」 北野さんとの出会いから2年が経過した頃、橋本和幸からそういうメッセージが来ることが頻繁になってきた。
     橋本和幸は、伝説的なプログラマーの一人だ。 もとはLISP使いで、人工知能の研究者。 しかし、橋本が学生の頃は人工知能の研究が再び冬の時代に入っていた頃だ。 人工知能の研究者たちがよく使っていた言語のひとつ、LISP使いだった橋本は、世界で最も理想的な就職先を見つけた。LISPマシンを製造販売していたSymbolics社だ。 ところがSybmolics社に就職すると、実は人工知能そのものを扱う仕事はないのだという現実を知る。 「コンピュータグラフィックスとかやってみて」 そう言われて、橋本は仕方なくコンピュータグラフィックスを扱うことにしたのだという。 その彼が、後に初代PlayStationの恐竜のデモンストレーションを作り、ついにはゲーム業界最
  • 【shi3zの華麗とはいえない日常】 ダメだ、殺人的に忙しい

    2016-08-07 06:31  
    1pt
     なーんざんしょうね。 やっと出張ラッシュが終わって一息つけるかと思ったら、セミナーセミナーまたセミナーで、怒涛のセミナーラッシュ。水曜日にNHK文化センターでしょ、木金がDEEPstationスタンダードセミナーでしょ、土曜日が某経営大学院生向け人工知能セミナーでしょ、そして今日、日曜日はCANVASでenchantMOONをつかったワークショップでしょ、んで、明日は10代のための人工知能プログラミング講座。 だめだ。 だめだっていうか。 なんでこんなに忙しいんだ。 いや、自業自得なのは100も承知ではあるが。 それにしても・・・いや・・・しかし・・・ほんと・・・なんなんだこの忙しさは いや、ロスは楽しかったよ。忙しかったけど、それなりに。 でもさあ、仕事が全然進んでないんだよ。何でかしらないけど。グリフィス天文台でロマンチックな夜景を見たよ。男三人で。 
  • 月と鼈 〜僕の人類補完計画 #39 深層ニューラルネットワーク

    2016-08-01 07:00  
    100pt
    ■深層ニューラルネットワーク 「なに・・・これ」
     その日、僕は画面の前で固まっていた。 今でも目の前で起きていることが信じられない。 それくらい衝撃的だった。 「おい、ちょっとこれ見ろ」 後藤を呼び出して、画面を見せる。 「なんですかこれは」 後藤は迷惑そうに顔をしかめた。 「いいから。これな、これ何に見える?」 僕は画像ファイルをダブルクリックしてつけ麺の画像を表示した。 「えーっ、つけ麺でしょ。つけ麺じゃないんですか?」 「いや、つけ麺だ」 「????」 続いて僕は、コマンドラインでプログラムを実行した。 「これはカリフォルニア大学バークレー校で訓練された人工知能だ。こいつにつけ麺の画像を見せると・・・」 「どうなるんですか?」 「そもそもアメリカ人はつけ麺なんか知らないだろ?」 「たしかに」 「じゃあどうなると思う?」 後藤はクビを傾げる。 「エラーとかになるんですかね」 「そう思