AOK FEの復旧

昔作った AOKシナリオMODのFEを復旧させることが出来た。

ダウンロードここちらから
http://rtilabs.rti-giken.jp/files/2017_02_13/aok_fe.7z
http://steamcommunity.com/sharedfiles/filedetails/?id=909693388

ファイアーエムブレムをAOEで強引に再現するMOD
MOD which forcibly reproduces Fire Emblem at AOE

ファイアーエムブレム 暗黒龍と光の剣を AOEで強引に再現しました。
Fire Emblem The dark dragon and the sword of light were forcibly reproduced with AOE.

このMODは、二次創作作品です。
This MOD is a Fan Fiction.

公式とは一切関係ありません。
It has nothing to do with official.

現在は日本語のみです。
Currently it is only Japanese.

全12ステージあります。
There are 12 stages in all.

ファイアーエムブレムのサントラを流しながらやると楽しいですよ。
It's fun to do it while sending Fire Emblem's soundtrack.

I made it in 2014, but it was destroyed by utf correspondence of patch update, I made a tool and restored it...
http://d.hatena.ne.jp/rti7743/20140812/1407829818

AOK年貢の復旧

昔作った AOKシナリオMODの年貢を復旧させることが出来た。
ついでに、機械翻訳で英語版も作ってみた。

downloadはここか、steamのワークショップからどうぞ。
http://rtilabs.rti-giken.jp/files/2017_02_13/aok_nengu.7z
http://steamcommunity.com/sharedfiles/filedetails/?id=863251050

しかし、aokの新しいシナリオファイルって容量が10倍以上にでかくなるんたけど、開発陣はどういうプログラムかいているんだ?

年貢の解説記事はこっち。
http://d.hatena.ne.jp/rti7743/20140725/1406275415

年貢(nengu)
nengu is mean tax in medieval japan.

シングルプレイ用のシナリオです。
It is a scenario for single play.

ひたすら内政をやりたい人に向いています。
It is suitable for those who just want to do internal affairs.

プレイヤー(青)は、幕府のお代官様(赤)から出されるムチャな年貢(税金)をこなしていくゲームです。
The player (blue) is a game that carries out an unpleasant nengu(tax) from the odaikan-sama(red).
odaikan-sama is mean Governmental Executive officer(shogunate's officer). 

プレイヤー(青)は必死に働き、告知から10分以内に年貢を収めないといけません。
The Player(BLUE) must a work and must store a nengu by the term for 10 minutes. 

要求される年貢は毎回ひどくなります。
The nengu(tax) required is bad every time.

年貢は、食料500の要求から始まり、終盤には、金、徴兵になります。
It begins from the taxation of the food 500 at first, and there are a gold, and the conscriptionenlistment. 

もし、年貢を収めなければ、反逆者として、処刑されます。
If nengu is not stored, executed as traitor.

ゲームクリアには、合計12回の課税を収めきるか、または、年貢を払わずに反逆者となり、革命を起こします。
Game is clearable ,If all the 12 times taxation is paid, or taxation is disregarded and revolution is start.

年貢を納付するには、お代官様(赤)に資源を送信してください。
To pay the nengu, please send the resource to odaikan-sama(red).

日本語版(jpn)と英語版(eng)があります。
There are Japanese version (jpn) and English version (eng).

オリジナルが日本語版で、機械翻訳したものが英語版です。
Original is Japanese version, machine translated is English version.

created by @super_rti
http://d.hatena.ne.jp/rti7743/

2014年に作ったけど、utf対応パッチで壊れてしまったので、ツールを使って復旧させました。
Trigger Studio ( Trigger Studio 1.2.x for HD, UserPatch, AoFE, AoF + SWGB )を使ってな。
I made it in 2014, but it was destroyed by utf correspondence of patch update, I made a tool and restored it.

ナノ秒単位の高性能な時刻がほしい時

beagleboneやraspberry piで、ナノ秒単位の正確な時間がほしい時について。
通常のtime関数とかでは遅すぎて困るときは、以下のようにすると、ナノ秒単位で時刻が取れます。
値は、CPUとかの動作クロックの影響をうけるので注意してください。

ボード メモリ位置 バイト長
beaglebone 0x4804003C 4バイト
raspberry pi 2-3 0x3F003004 4バイト

このメモリ位置は常にカウントアップされていきます。
値はunsigned int値で、オーバーフローすると0に戻ります。
ここを読みだすことでとても正確な時間を取得することができます。
今何時?という用途にはまったく使えませんが、処理時間の間隔を正確に測るとかの用途に向いています。


カーネルランドで読みだす場合は、 ioremapが便利だと思う。

//ナノ秒単位の高性能な時刻がほしい時。
//kernel land
void *g_timer = ioremap(0x4804003C,4); //beaglebone
void *g_timer = ioremap(0x3F003004,4); //raspberry pi 2-3

//一番オーバーヘッドを生まないであろうマクロ展開で読みだす.
#define dmtimer_get()  ((unsigned int)ioread32(g_timer))

printk(KERN_ALERT "timer: %u\n", dmtimer_get() );

iounmap(g_timer);


ユーザランドで読みだす場合は、 mmapするよろし。

//ナノ秒単位の高性能な時刻がほしい時。
//userland
int g_fd = open("/dev/mem", O_RDWR | O_SYNC);
if (g_fd < 0)
{
	printf("Could not open /dev/mem fd\n");
	return -1;
}

//mmap確保
//0x3F003004 とかを直接mmapすると落ちるので、ちょい手前から 0x100ぐらい適当に確保する.
//void* g_mmap = ( unsigned int*) mmap(NULL, 0x100, PROT_READ,MAP_SHARED,g_fd, 0x48040000); //beaglebone
unsigned int* g_mmap = ( unsigned int*) mmap(NULL, 0x100, PROT_READ,MAP_SHARED,g_fd, 0x3F003000); //raspberry pi 2-3
if (g_mmap == MAP_FAILED) {
	printf("Could not mmap %d\n",g_mmap);
	close(g_fd);
	g_fd=0;
	return -2;
}
//unsigned int* g_timer = &g_mmap[0x3C/sizeof(int)]; //0x4804003C
unsigned int* g_timer = &g_mmap[0x4/sizeof(int)]; //0x3F003004

//一番オーバーヘッドを生まないであろうマクロ展開で読みだす.
#define dmtimer_get()  (*g_timer)

for(int i = 0 ; i < 10 ;i++)
{
	printf("timer: %u\n", dmtimer_get() );
	sleep(1);
}

//unmap(g_mmap)を呼び出さなくてもプロセス終了時には自動解放される 
close(g_fd);

この高性能タイマー機能の名前がよくわからないのだが、dmtimer とか、high level timer とか、いろいろ名前があるらしい。
検索しにくいから統一させてほしいものである。

最初にコンピュータに仕事を奪われた人たち

AIの発達で、コンピュータが仕事を奪うという人達がいる。
確かに、近年のAIの進化は素晴らしく、幾つかの分野で人間を超える成績を出すものがある。

だが、忘れてはいけない。はるか昔にコンピュータに仕事を奪われた人がいたことを。
はるか昔に、コンピュータに仕事を奪われた人たち、それはコンピュータだ。

何言っているんだお前と思うかもしれないが、weikipediaにもちゃんと載っている。

https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF

英語の 「computer(コンピューター)」は算術演算(数値計算)を行う人を指す言葉だった。

computer というのは、もともとは計算をする人をさす言葉だった。
それが機械の方のコンピュータが発達して、驚異的な演算能力があったためだろうか、いつしかコンピュータは機械の方のコンピュータをさす言葉になってしまった。
そして、もともとコンピュータというのが職業だったというのも忘れ去られようとしている。


コンピュータに最初に仕事を奪われた人たちは、コンピュータだった。
私たちにできることと言えば、コンピュータが仕事を奪うと言うが、最初にコンピュータに仕事を奪われた人たちって、コンピュータだよねみたいな、このことを知らないと意味不明な文章を言って遊ぶことぐらいだろうか。

keras_iris_test

python初心者が kerasを使って、定番のiris分類をやった。
前回chainer使って作ってみたので、次はkerasでやってみようということで。

#
#とりあえず動くところまで作った iris分類.
#
import argparse
import numpy
import keras
from keras.layers.core import Dense, Dropout, Activation, Flatten
#from keras.layers.convolutional import Convolution2D, MaxPooling2D
numpy.random.seed(1192)  # for reproducibility

#分類した結果が文字列なので [0,1,2] という数字に変換する
def iris_name_to_index(s):
    if s == b'setosa':
        return 0   #正解データは0からスタートしないとダメ
    elif s == b'virginica':
        return 1
    elif s == b'versicolor':
        return 2
    else:
        print("Unknown Data:{}".format(s))
        raise()

#逆に、数字から、setosa/virginica/versicolor に変換する.
def iris_index_to_name(i):
    if i == 0:
        return 'setosa'
    elif i == 1:
        return 'virginica'
    elif i == 2:
        return 'versicolor'
    else:
        print("Unknown Label:{}".format(i))
        raise()


# 引数の処理
parser = argparse.ArgumentParser()
parser.add_argument('--mode',      type=str,   default='all') #train:学習だけ pred:分類だけ all:両方
parser.add_argument('--epoch',     type=int,   default=500) #何回学習を繰り返すか
parser.add_argument('--trainstart',type=int,   default=0)   #全データ150件のうち、何件から学習に使うか
parser.add_argument('--trainsize', type=int,   default=50)  #全データ150件のうち、何件を学習に使うか ディフォルト(150件中 0件から50件までを学習に使う)
parser.add_argument('--trainbatch',type=int,   default=50)  #学習するミニバッチに一度にかけるデータの個数
args = parser.parse_args()

#csv読込
#最初の4つが学習データ 最後の5番目が正解データ
csv = numpy.loadtxt("iris.csv",
    delimiter=",",                    #csvなので  , で、データは区切られている
    skiprows=1,                       #ヘッダーを読み飛ばす
    converters={4:iris_name_to_index} #4カラム目は分類がテキストでかかれているので 0から始まる数字ラベルに置き換える
    )

#学習データの定義
#学習データは float32の2次元配列
#例: [ [1,2,3,4],[5,6,7,8],[1,2,3,4],[5,6,7,8],[1,2,3,4] ].astype(numpy.float32)
data = csv[:,0:4].astype(numpy.float32)

#正解データの定義
#正解データは 0から始まる int32の1次元配列
#例: [ 0,1,2,1,0 ].astype(numpy.int32)
label= csv[:,4].astype(numpy.int32)

#学習
if args.mode in ['all','train']:

    model = keras.models.Sequential()
    model.add(Dense(100,input_dim=4))
    model.add(Activation('relu'))
    model.add(Dense(100))
    model.add(Activation('relu'))
    model.add(Dense(3))
    model.add(Activation('softmax'))

    model.compile(loss='sparse_categorical_crossentropy',
                  optimizer='adam',
                  metrics=['accuracy'])

    x = data[args.trainstart:args.trainstart+args.trainsize]
    y = label[args.trainstart:args.trainstart+args.trainsize]

    model.fit(x, y ,batch_size=args.trainbatch,nb_epoch=args.epoch,verbose=1)

    #学習結果を保存.
    model.save("model.dat")

#分類
if args.mode in ['all','pred']:

    #学習結果を読み込む
    model = keras.models.load_model("model.dat")

    #すべてのデータに対して、1件ずつ、分類を答えさせて、正しいか採点する.

    #keras組み込みの evaluateメソッドで一発なんだけど、 表示をこりたいので、forを回すよ.
    #score = model.evaluate(data, label, verbose=1)
    #print(score)

    ok_count = 0
    for i in range(len(data)):
        x = data[i:i+1]        #このデータについて調べたい.

        y = model.predict(x, batch_size=1, verbose=0) #分類の結果を取得

        pred = numpy.argmax(y)    #3つの分類のうち、どれの確率が一番高いのかを返す
        if label[i] == pred:
           ok_count = ok_count + 1
           #print("OK i:{} pred:{}({}) data:{}".format(i,iris_index_to_name(pred),iris_index_to_name(label[i]),data[i:i+1] ))
        else:
           print("NG i:{} pred:{}({}) data:{}".format(i,iris_index_to_name(pred),iris_index_to_name(label[i]),data[i:i+1] ))

    print("total:{} OK:{} NG:{} rate:{}".format(len(data),ok_count,len(data)-ok_count,ok_count/len(data)) )

ソースコードgithubにある https://github.com/rti7743/keras_iris_test

chainer_iris_testを改変してkeras版を作ったのでデータに対してはそれほど苦労としていない。
また、kerasは Tensorflowとかのラッパーであり、Tensorflowはwindowsインストール方法の解説が公式サイトに書いてあり、それが chainerのGPU対応ビルドと方法がほとんど同じなので、これも苦労しなかった。

Using TensorFlow backend.
Traceback (most recent call last):
  File "test.py", line 85, in <module>
    model.fit(x, y ,batch_size=args.trainbatch,nb_epoch=args.epoch,verbose=1)
  File "keras\models.py", line 664, in
fit
    sample_weight=sample_weight)
  File "keras\engine\training.py", line
 1068, in fit
    batch_size=batch_size)
  File "keras\engine\training.py", line
 985, in _standardize_user_data
    exception_prefix='model target')
  File "keras\engine\training.py", line
 113, in standardize_input_data
    str(array.shape))
ValueError: Error when checking model target: expected activation_3 to have shap
e (None, 3) but got array with shape (50, 1)

しかし、罠がなかったわけではない。
model.compile時に loss='categorical_crossentropy'を使うと上記エラーが発生して動かなかった。
いろいろ調べてみると、loss='categorical_crossentropy' なのがだめらしい。
sparse_categorical_crossentropyにするとうまく動作する。

#NG
#model.compile(loss='categorical_crossentropy',
#              optimizer='adam',
#              metrics=['accuracy'])

#OK
model.compile(loss='sparse_categorical_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])

たぶん、正解データの形式の問題かな・・・?
keras.np_utils.to_categoricalとかで用意すれば いいのかも。
まあ、どちらにせよ、loss='sparse_categorical_crossentropy'で動いたので気にしない方向で。


GPU利用については、バックエンドのTensorflowがなんかいい感じにしてくれるので、コードには何も書いていない。
何もしなくていいのは楽でいいと思った。

chainer_iris_test

python初心者が chainerを使って、定番のiris分類をやった。

人の作ったモデルを改変してばかりでは理解がすすまないので、iris分類を最初から作ってみた。

知りたかったのは、次の4つ。
1.モデルの定義方法と利用方法
2.csvの読込と、そのデータの活用方法
3.学習した分類データの保存
4.保存したデータの読み込みと、それを使って分類する方法

家に帰るまでが遠足ですので、分類と学習したモデルの保存、保存したモデルの活用法までわからないと意味ないじゃないかということで、一通りのことをやりたかった。
それと、trainerを使った書き方よりも、自分でforループを回す方が、より理解しやすいと思う。

これを作るにはいろいろと罠にはまって絶望しまくった。
その記録はこちらにある。 http://d.hatena.ne.jp/rti7743/20170105/1483602327

#
#とりあえず動くところまで作った iris分類.
#
import argparse
import numpy
import chainer
import chainer.functions as F
import chainer.links as L
import chainer.cuda as cuda

#irisを分類するモデル.
class IrisModel(chainer.Chain):
    def __init__(self):
        super(IrisModel, self).__init__(
            l1=L.Linear(4, 100),     #4つの素性を受け取り
            l2=L.Linear(100, 100),
            l3=L.Linear(100, 3),     #3つの分類のどれに近いかを返す.
        )

    def __call__(self, x):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        y = self.l3(h2)

        return y

#分類した結果が文字列なので [0,1,2] という数字に変換する
def iris_name_to_index(s):
    if s == b'setosa':
        return 0   #正解データは0からスタートしないとダメ
    elif s == b'virginica':
        return 1
    elif s == b'versicolor':
        return 2
    else:
        print("Unknown Data:{}".format(s))
        raise()

#逆に、数字から、setosa/virginica/versicolor に変換する.
def iris_index_to_name(i):
    if i == 0:
        return 'setosa'
    elif i == 1:
        return 'virginica'
    elif i == 2:
        return 'versicolor'
    else:
        print("Unknown Label:{}".format(i))
        raise()


# 引数の処理
parser = argparse.ArgumentParser()
parser.add_argument('--mode',      type=str,   default='all') #train:学習だけ pred:分類だけ all:両方
parser.add_argument('--gpu',       type=int,   default=0)   #GPUを使うかどうか
parser.add_argument('--epoch',     type=int,   default=500) #何回学習を繰り返すか
parser.add_argument('--trainstart',type=int,   default=0)   #全データ150件のうち、何件から学習に使うか
parser.add_argument('--trainsize', type=int,   default=50)  #全データ150件のうち、何件を学習に使うか ディフォルト(150件中 0件から50件までを学習に使う)
parser.add_argument('--trainbatch',type=int,   default=50)  #学習するミニバッチに一度にかけるデータの個数
args = parser.parse_args()

#cudaを使うなら初期化する.
if args.gpu > 0:
    cuda.init()

#csv読込
#最初の4つが学習データ 最後の5番目が正解データ
csv = numpy.loadtxt("iris.csv",
    delimiter=",",                    #csvなので  , で、データは区切られている
    skiprows=1,                       #ヘッダーを読み飛ばす
    converters={4:iris_name_to_index} #4カラム目は分類がテキストでかかれているので 0から始まる数字ラベルに置き換える
    )

#学習データの定義
#学習データは float32の2次元配列
#例: [ [1,2,3,4],[5,6,7,8],[1,2,3,4],[5,6,7,8],[1,2,3,4] ].astype(numpy.float32)
data = csv[:,0:4].astype(numpy.float32)

#正解データの定義
#正解データは 0から始まる int32の1次元配列
#例: [ 0,1,2,1,0 ].astype(numpy.int32)
label= csv[:,4].astype(numpy.int32)

#学習
if args.mode in ['all','train']:
    #分類機の用意
    model = L.Classifier(IrisModel())
    if args.gpu > 0:
        model.to_gpu()

    #最適化アルゴリズムの設定
    optimizer = chainer.optimizers.Adam()
    optimizer.setup(model)

    for epoch in range(args.epoch):
        print('epoch', epoch)

        #perm = numpy.random.permutation(args.trainsize)
        #サンプルとかを見ると perm[i:i+args.trainbatch] しているが、これを使う意味がよくわからんので外している.

        #学習を開始する.
        #学習に使うデータの範囲を args.trainbatchサイズに分けて学習器に投げ込む
        for i in range(args.trainstart, args.trainsize, args.trainbatch):
            x = data[i:i + args.trainbatch]
            y = label[i:i + args.trainbatch]
            if args.gpu > 0:
                x = cuda.to_gpu(x)
                y = cuda.to_gpu(y)

            x = chainer.Variable(x)
            y = chainer.Variable(y)

            optimizer.update(model, x, y)

    #学習結果を保存.
    chainer.serializers.save_npz("model.dat", model)

#分類
if args.mode in ['all','pred']:

    #学習結果を読み込む
    model = L.Classifier(IrisModel())
    chainer.serializers.load_npz("model.dat",model)
    if args.gpu > 0:
        model.to_gpu()
    else:
        model.to_cpu()

    #すべてのデータに対して、1件ずつ、分類を答えさせて、正しいか採点する.
    ok_count = 0
    for i in range(len(data)):
        x = data[i:i+1]        #このデータについて調べたい.
        if args.gpu > 0:
            x = cuda.to_gpu(x)

        x = chainer.Variable(x)

        y = model.predictor(x) #分類の結果を取得

        y = y.data             #chainer.Variableからデータの取出し
        if args.gpu > 0:
            y = cuda.to_cpu(y)

        pred = numpy.argmax(y)    #3つの分類のうち、どれの確率が一番高いのかを返す
        if label[i] == pred:
           ok_count = ok_count + 1
           #print("OK i:{} pred:{}({}) data:{}".format(i,iris_index_to_name(pred),iris_index_to_name(label[i]),data[i:i+1] ))
        else:
           print("NG i:{} pred:{}({}) data:{}".format(i,iris_index_to_name(pred),iris_index_to_name(label[i]),data[i:i+1] ))

    print("total:{} OK:{} NG:{} rate:{}".format(len(data),ok_count,len(data)-ok_count,ok_count/len(data)) )

コードとデータ一式はgithubにある。
https://github.com/rti7743/chainer_iris_test

git cloneしたあとで、python test.py とかやると、iris.csvを読み込んで先頭50件を使って学習し、学習した結果をもとに全150件の分類を答えます。

サンプルとかを見ると perm[i:i+args.trainbatch] しているが、これを使う意味がよくわからんので外している.
なんで、これを使わないといけないの知っている人は教えてほしい。
#perm = numpy.random.permutation(args.trainsize)

先にも書いたが、ディフォルトだと、とりあえず、 iris.csvを読み込んで、 先頭50件を使って学習します。
その後、学習したモデルをファイルに書きだします。
で、そのあとで、その保存したモデルを使って、 iris.csvの全データ150件のテスト分類をします。
だいたい正解率 96%-99%ぐらいです。
よくわからないが、実行する度に結果が変わる。numpy.random.permutationを排除しているから、乱数はないはずなんだけどライブラリの中で乱数使っているのかな・・・?初心者なのでよくわからない。

オプションで python test.py --gpu 1 とかすると、 GPUを使って計算します。
総数150件程度なので、この程度の規模だと、GPUはあってもなくてもあんまり変わらないみたいですが、とりあえず。

オプションで python test.py --mode train と、すると、学習だけやります。
オプションで python test.py --mode pred と、すると、分類だけやります。
ディフォルトは、 all となっており、両方やります。学習したあとで分類を実行して結果を返します。

python初心者が書いたコードなので間違っているかもしれないが、間違っていたら、クスリと笑った後で、なぜそれが間違っていてどうすればいいと思うかを教えてください。

苦労と試行

python初心者が chainerのエラーに遭遇して、ひたすら苦労しながら解決していった記録。
無慈悲なエラーメッセージと、それがどういう意味で、何を言いたくて、どうしなければいけないのかを記録していきたいと思う。

エラーなんて原因がわかってしまえばなんてことはないんだけど、わかるまでが大変。。。

windowsでcudaを利用する場合インストール時

windowsでcudaを利用する場合に、
pip install chainer でインストールすると、以下のエラーが出る場合がある。

cupy\cuda\cudnn.cpp(3662) : error C3861: 'cudnnAddTensor_v3'

githubにある新しいバージョンで修正されている。2016/12/31にpipで入れようとしたら、このバグ修正がまだpip版に反映されていなくてとても苦労した。
github版では修正されているので、githubからソースコードを持ってきてインストールするとOK。
https://github.com/pfnet/chainer/pull/2031

git clone https://github.com/pfnet/chainer
cd chainer
python setup.py install

正解データは0からの整数で出力数とあっていないといけないらしい。

Traceback (most recent call last):
  File "test.py", line 54, in <module>
    trainer.run()
  File "chainer\training\trainer.py", line 289, in run
    update()
  File "chainer\training\updater.py", line 170, in update
    self.update_core()
  File "chainer\training\updater.py", line 182, in update_core
    optimizer.update(loss_func, *in_vars)
  File "chainer\optimizer.py", line 390, in update
    loss = lossfun(*args, **kwds)
  File "chainer\links\model\classifier.py", line 68, in __call__
    self.loss = self.lossfun(self.y, t)
  File "chainer\functions\loss\softmax_cross_entropy.py", line 223, in softmax_cross_entropy
    use_cudnn, normalize, cache_score, class_weight)(x, t)
  File "chainer\function.py", line 199, in __call__
    outputs = self.forward(in_data)
  File "chainer\function.py", line 319, in forward
    return self.forward_cpu(inputs)
  File "chainer\functions\loss\softmax_cross_entropy.py", line 68, in forward_cpu
    log_p = log_yd[numpy.maximum(t.ravel(), 0), numpy.arange(t.size)]
IndexError: index 3 is out of bounds for axis 0 with size 3

データ(主に正解データ)を0からスタートしていないときや、
出力個数があっていない時にでるらしい。


たとえば、以下のようなモデルがあった場合、正解データは0-3のいづれかでないとダメらしい。

class IrisModel(Chain):
    def __init__(self):
        super(IrisModel, self).__init__(
            l1=L.Linear(4, 100),
            l2=L.Linear(100, 100),
            l3=L.Linear(100, 3),  #正解データ
        )

    def __call__(self, x):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        y = self.l3(h2)

        return y

l3=L.Linear(100, 正解データの個数)
正解データの個数 = 3 だった場合
正解データは、 [0,1,2] で合計 3つにならないといけないらしい。

それを間違えて、 [1,2,3] で合計 3つにすると、このエラーが発生する。
正解データは、 [0,1,2] で3つにしないといけないらしい。

学習データは、2次元のfloat32データ
np.array([ [1,2,3,4],[5,6,7,8],[9,10,11,12] ]).astype(np.float32)
正解データは、1次元のint32データで0から開始する
np.array([0,1,2]).astype(np.int32)

正解データは、一次元配列でなければならないっぽい

Traceback (most recent call last):
  File "test.py", line 54, in <module>
    trainer.run()
  File "chainer\training\trainer.py", line 289, in run
    update()
  File "chainer\training\updater.py", line 170, in update
    self.update_core()
  File "chainer\training\updater.py", line 182, in update_core
    optimizer.update(loss_func, *in_vars)
  File "chainer\optimizer.py", line 390, in update
    loss = lossfun(*args, **kwds)
  File "chainer\links\model\classifier.py", line 68, in __call__
    self.loss = self.lossfun(self.y, t)
  File "chainer\functions\loss\softmax_cross_entropy.py", line 223, in softmax_cross_entropy
    use_cudnn, normalize, cache_score, class_weight)(x, t)
  File "chainer\function.py", line 189, in __call__
    self._check_data_type_forward(in_data)
  File "chainer\function.py", line 280, in _check_data_type_forward
    type_check.InvalidType(e.expect, e.actual, msg=msg), None)
  File "<string>", line 2, in raise_from
chainer.utils.type_check.InvalidType:
Invalid operation is performed in: SoftmaxCrossEntropy (Forward)

Expect: in_types[1].ndim == in_types[0].ndim - 1
Actual: 2 != 1

正解データを、一次元の配列にしていない時に出る。

入力データは、 [0,1,2] みたいに、2次元配列でなければいけないらしい。
(そしてデータは0から始まるnumpy.int32型でないといけないっぽい)

学習データは、2次元のfloat32データ
np.array([ [1,2,3,4],[5,6,7,8],[9,10,11,12] ]).astype(np.float32)
正解データは、1次元のint32データで0から開始する
np.array([0,1,2]).astype(np.int32)

正解データが numpy.int32の配列になっていないとき

Traceback (most recent call last):
  File "test.py", line 54, in <module>
    trainer.run()
  File "chainer\training\trainer.py", line 289, in run
    update()
  File "chainer\training\updater.py", line 170, in update
    self.update_core()
  File "chainer\training\updater.py", line 182, in update_core
    optimizer.update(loss_func, *in_vars)
  File "chainer\optimizer.py", line 390, in update
    loss = lossfun(*args, **kwds)
  File "chainer\links\model\classifier.py", line 68, in __call__
    self.loss = self.lossfun(self.y, t)
  File "chainer\functions\loss\softmax_cross_entropy.py", line 223, in softmax_cross_entropy
    use_cudnn, normalize, cache_score, class_weight)(x, t)
  File "chainer\function.py", line 189, in __call__
    self._check_data_type_forward(in_data)
  File "chainer\function.py", line 280, in _check_data_type_forward
    type_check.InvalidType(e.expect, e.actual, msg=msg), None)
  File "<string>", line 2, in raise_from
chainer.utils.type_check.InvalidType:
Invalid operation is performed in: SoftmaxCrossEntropy (Forward)

Expect: in_types[1].dtype == <class 'numpy.int32'>
Actual: float32 != <class 'numpy.int32'>

このエラーは、正解データを、一次元の numpy.int32の配列にしていない時に出るっぽい。

入力データは、 [0,1,2] みたいに、1次元配列でなければいけない。
(そしてデータは0から始まるnumpy.int32型でないとダメ)
data.astype(numpy.int32) で型を明示的に指定するといい。

学習データは、2次元のfloat32データ
np.array([ [1,2,3,4],[5,6,7,8],[9,10,11,12] ]).astype(np.float32)
正解データは、1次元のint32データで0から開始する
np.array([0,1,2]).astype(np.int32)

学習データは numpy.float32 でなければならないらしい

Traceback (most recent call last):
  File "test.py", line 54, in <module>
    trainer.run()
  File "chainer\training\trainer.py", line 289, in run
    update()
  File "chainer\training\updater.py", line 170, in update
    self.update_core()
  File "chainer\training\updater.py", line 182, in update_core
    optimizer.update(loss_func, *in_vars)
  File "chainer\optimizer.py", line 390, in update
    loss = lossfun(*args, **kwds)
  File "chainer\links\model\classifier.py", line 67, in __call__
    self.y = self.predictor(*x)
  File "test.py", line 22, in __call__
    h1 = F.relu(self.l1(x))
  File "chainer\links\connection\linear.py", line 92, in __call__
    return linear.linear(x, self.W, self.b)
  File "chainer\functions\connection\linear.py", line 79, in linear
    return LinearFunction()(x, W, b)
  File "chainer\function.py", line 189, in __call__
    self._check_data_type_forward(in_data)
  File "chainer\function.py", line 280, in _check_data_type_forward
    type_check.InvalidType(e.expect, e.actual, msg=msg), None)
  File "<string>", line 2, in raise_from
chainer.utils.type_check.InvalidType:
Invalid operation is performed in: LinearFunction (Forward)

Expect: in_types[2].dtype == in_types[0].dtype
Actual: float32 != float64

このエラーは学習データを numpy.float32 にしていないと出るらしい。
data = data.astype(numpy.float32) として、numpy.float32へ変換すると解決できます。

学習データは、2次元のfloat32データ
np.array([ [1,2,3,4],[5,6,7,8],[9,10,11,12] ]).astype(np.float32)
正解データは、1次元のint32データで0から開始する
np.array([0,1,2]).astype(np.int32)

学習データの個数があっていないときのエラー

Traceback (most recent call last):
  File "test.py", line 54, in <module>
    trainer.run()
  File "chainer\training\trainer.py", line 289, in run
    update()
  File "chainer\training\updater.py", line 170, in update
    self.update_core()
  File "chainer\training\updater.py", line 182, in update_core
    optimizer.update(loss_func, *in_vars)
  File "chainer\optimizer.py", line 390, in update
    loss = lossfun(*args, **kwds)
  File "chainer\links\model\classifier.py", line 67, in __call__
    self.y = self.predictor(*x)
  File "test.py", line 22, in __call__
    h1 = F.relu(self.l1(x))
  File "chainer\links\connection\linear.py", line 92, in __call__
    return linear.linear(x, self.W, self.b)
  File "chainer\functions\connection\linear.py", line 79, in linear
    return LinearFunction()(x, W, b)
  File "chainer\function.py", line 189, in __call__
    self._check_data_type_forward(in_data)
  File "chainer\function.py", line 280, in _check_data_type_forward
    type_check.InvalidType(e.expect, e.actual, msg=msg), None)
  File "<string>", line 2, in raise_from
chainer.utils.type_check.InvalidType:
Invalid operation is performed in: LinearFunction (Forward)

Expect: prod(in_types[0].shape[1:]) == in_types[1].shape[1]
Actual: 5 != 4

このエラーは、学習データの個数があっていなときにでるっぽい。


たとえば、以下のようなモデルがあった場合、学習データは[ [1,2,3,4],[5,6,7,8],[9,10,11,12] ] みたいに、定義した数と個数があっていないといけないらしい。

class IrisModel(Chain):
    def __init__(self):
        super(IrisModel, self).__init__(
            l1=L.Linear(4, 100),  #学習データ
            l2=L.Linear(100, 100),
            l3=L.Linear(100, 3),
        )

    def __call__(self, x):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        y = self.l3(h2)

        return y

l1=L.Linear(学習データの個数, 100),
学習データの個数 = 4 だった場合
学習データは、 [ [1,2,3,4],[5,6,7,8],[9,10,11,12] ]みたいに、要素が4つの要素を持っていないとダメです。
上の例だと、len(arr[0])==4 len(arr[1])==4 len(arr[2])==4 です。( len(arr) ではなく、 len(arr[0])の方の要素数の話です。 )

それを間違えて、 [ [1,2,3,4,99],[5,6,7,8,99],[9,10,11,12,99] ] みたいに個数を間違えると、このエラーが発生します。

学習データは、2次元のfloat32データ
np.array([ [1,2,3,4],[5,6,7,8],[9,10,11,12] ]).astype(np.float32)
正解データは、1次元のint32データで0から開始する
np.array([0,1,2]).astype(np.int32)