質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • Python 3.x

    9815questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • 機械学習

    958questions

    機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

  • Chainer

    208questions

    Chainerは、国産の深層学習フレームワークです。あらゆるニューラルネットワークをPythonで柔軟に書くことができ、学習させることが可能。GPUをサポートしており、複数のGPUを用いた学習も直感的に記述できます。

機械学習でのPickle.loadの引数エラー

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,616

SuguruOki

score 86

前提・実現したいこと

現在ChainerのLSTMで予測モデルを作り、それを使って語義曖昧性解消の予測を行うということをやっております。
その中でpickle.loadを行う際に引数に関するエラーが発生し、どうしても解決できなかったため、どなたか助けていただけると幸いです。

発生している問題・エラーメッセージ

$ python lstm_prediction.py
Traceback (most recent call last):
  File "lstm_prediction.py", line 139, in <module>
    main()
  File "lstm_prediction.py", line 112, in main
    lstm = pickle.load(fl)
TypeError: __init__() takes from 2 to 4 positional arguments but 5 were given

予測モデルを作成するソースコード

import argparse
import os
import sys
import numpy as np
import chainer
from chainer import optimizers
import chainer.functions as F
import chainer.links as L
import pickle
# import cupy

global vocab
global n_vocab
global inv_vocab

vocab = {'<$>':0, '<s>':1, '<eos>':2}
n_vocab = len(vocab)
inv_vocab = {0:'<$>', 1:'<s>', 2:'<eos>'}  #逆引き辞書

n_units = 512  # 隠れ層のユニット数


# LSTMのネットワーク定義
class LSTM(chainer.Chain):
    state = {}

    def __init__(self, n_vocab, n_units):
        print(n_vocab, n_units)
        super(LSTM, self).__init__(
            l1_embed = L.EmbedID(n_vocab, n_units),
            l1_x = L.Linear(n_units, 4 * n_units),
            l1_h = L.Linear(n_units, 4 * n_units),
            l2_embed = L.EmbedID(n_vocab, n_units),
            l2_x = L.Linear(n_units, 4 * n_units),
            l2_h = L.Linear(n_units, 4 * n_units),
            l3_embed = L.EmbedID(n_vocab, n_units),
            l3_x = L.Linear(n_units, 4 * n_units),
            l3_h = L.Linear(n_units, 4 * n_units),
            l4_embed = L.EmbedID(n_vocab, n_units),
            l4_x = L.Linear(n_units, 4 * n_units),
            l4_h = L.Linear(n_units, 4 * n_units),
            l5_embed = L.EmbedID(n_vocab, n_units),
            l5_x = L.Linear(n_units, 4 * n_units),
            l5_h = L.Linear(n_units, 4 * n_units),
            l_umembed = L.Linear(n_units, n_vocab)
        )

    def forward(self, x1, x2, x3, x4, x5, t, train=True, dropout_ratio=0.5):
        h1 = self.l1_embed(chainer.Variable(np.asarray([x1], dtype=np.int32)))
        c1, y1 = F.lstm(chainer.Variable(np.zeros((1, n_units), dtype=np.float32)), F.dropout(self.l1_x(h1), ratio=dropout_ratio, train=train ) + self.l1_h(self.state['y1']))
        h2 = self.l2_embed(chainer.Variable(np.asarray([x2])))
        c2, y2 = F.lstm(self.state['c1'], F.dropout(self.l2_x(h2), ratio=dropout_ratio, train=train) + self.l2_h(self.state['y2']))
        h3 = self.l3_embed(chainer.Variable(np.asarray([x3])))
        c3, y3 = F.lstm(self.state['c2'], F.dropout(self.l3_x(h3), ratio=dropout_ratio, train=train) + self.l3_h(self.state['y3']))
        h4 = self.l4_embed(chainer.Variable(np.asarray([x4])))
        c4, y4 = F.lstm(self.state['c3'], F.dropout(self.l4_x(h4), ratio=dropout_ratio, train=train) + self.l4_h(self.state['y4']))
        h5 = self.l5_embed(chainer.Variable(np.asarray([x5])))
        c5, y5 = F.lstm(self.state['c4'], F.dropout(self.l5_x(h5), ratio=dropout_ratio, train=train) + self.l5_h(self.state['y5']))
        self.state = {'c1': c1, 'y1': y1, 'h1': h1, 'c2': c2, 'y2': y2, 'h2': h2, 'c3': c3, 'y3': y3, 'h3': h3, 'c4': c4, 'y4': y4, 'h4': h4, 'c5': c5, 'y5': y5, 'h5': h5}
        y = self.l_umembed(y5)
        #print('y:',vars(y))
        #print('ans:', np.asarray([t]), 'pred:', np.argmax(y.data))
        if train:
            return F.softmax_cross_entropy(y, np.asarray([t]))
        else:
            return F.softmax(y5), y5.data

    def initialize_state(self, n_units, batchsize=1, train=True):
        for name in ('c1', 'y1', 'h1', 'c2', 'y2', 'h2', 'c3', 'y3', 'h3', 'c4', 'y4', 'h4', 'c5', 'y5', 'h5'):
            self.state[name] = chainer.Variable(np.zeros((batchsize, n_units), dtype=np.float32), volatile=not train)

~~~~~~
def main():
    p = 5  # 文字列長
    w = 2  # 前後の単語の数
    epoch = 2 #繰り返し回数
    total_loss = 0  # 誤差関数の値を入れる変数

    # 引数の処理
    parser = argparse.ArgumentParser()
    parser.add_argument('--gpu', '-g', default=-1, type=int,
                        help='GPU ID (negative value indicates CPU)')
    args = parser.parse_args()


    # 訓練データ、評価データ、テストデータの読み込み
    os.chdir('/Users/suguruoki/practice/chainer/examples/ptb')
    train_data = load_data('last4.dat')
    pickle.dump(vocab, open('vocab.bin', 'wb'))
    pickle.dump(inv_vocab, open('inv_vocab.bin', 'wb'))

    n_vocab = len(vocab)
    #print(train_data[0:1000])

    # モデルの準備
    # 入力は単語数、中間層はmain関数冒頭で定義
    lstm = LSTM(n_vocab, n_units)
    lstm.initialize_state(n_units)
    model = L.Classifier(lstm)
    model.compute_accuracy = False

    if args.gpu >= 0:
        xp = cupy
    else: np

    if args.gpu >= 0:
        cupy.get_device(args.gpu).use()
        model.to_gpu()

    # optimizerの設定
    optimizer = optimizers.Adam()
    optimizer.setup(model)
    seq = []
    seq_append = seq.append

    # 5単語毎に分ける
    for i in range(epoch): # 同じデータをepoch数繰り返す
        print('Epoch =', i+1, file=sys.stderr)
        length = len(train_data)

        # 単語を順番に走査
        for t in range(length):

            print("{}/{}".format(t, length))
            # 文頭、文末を考慮する

            for k in range(t-w, t+w+1):
                if k >= 0:
                    if k == t:
                        seq.append(vocab['<$>'])
                    elif k > len(train_data)-1:
                        seq.append(vocab['<s>'])
                    else:
                        seq.append(train_data[k])
                else:
                    seq.append(vocab['<s>'])
            seq.append(train_data[t])
            # print('t =', t,', seq :', seq)
            tmp = np.array(seq, dtype='i')
            seq = []  # seq: 周辺単語のリスト

            loss = lstm.forward(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5])
            tmp = []

            # 出力する時はlossを記憶
            if i%epoch==0:
                total_loss += loss.data
            # 最適化の実行
            model.cleargrads()
            loss.backward()
            optimizer.update()
        # 学習結果を1epochごとにファイルに保存する
        # model.to_cpu()
        pickle.dump(model, open('LSTMmodel.pkl', 'wb'))
        pickle.dump(lstm, open('LSTMlstm.pkl', 'wb'))


~~~~省略

↑の全ソースはこちら

 予測を行うソースコード(エラーが出ているのはこちらのファイルです)

~~~~省略

n_units = 512 # 隠れ層のユニット数

# LSTMのネットワーク定義
class LSTM(chainer.Chain):
    state = {}

    def __init__(self, n_vocab, n_units):
        #print(n_vocab, n_units)
        super(LSTM, self).__init__(
            l1_embed = L.EmbedID(n_vocab, n_units),
            l1_x = L.Linear(n_units, 4 * n_units),
            l1_h = L.Linear(n_units, 4 * n_units),
            l2_embed = L.EmbedID(n_vocab, n_units),
            l2_x = L.Linear(n_units, 4 * n_units),
            l2_h = L.Linear(n_units, 4 * n_units),
            l3_embed = L.EmbedID(n_vocab, n_units),
            l3_x = L.Linear(n_units, 4 * n_units),
            l3_h = L.Linear(n_units, 4 * n_units),
            l4_embed = L.EmbedID(n_vocab, n_units),
            l4_x = L.Linear(n_units, 4 * n_units),
            l4_h = L.Linear(n_units, 4 * n_units),
            l5_embed = L.EmbedID(n_vocab, n_units),
            l5_x = L.Linear(n_units, 4 * n_units),
            l5_h = L.Linear(n_units, 4 * n_units),
            l_umembed = L.Linear(n_units, n_vocab)
        )


~~~~省略

    def initialize_state(self, n_units, batchsize=1, train=True):
        for name in ('c1', 'y1', 'h1', 'c2', 'y2', 'h2', 'c3', 'y3', 'h3', 'c4', 'y4', 'h4', 'c5', 'y5', 'h5'):
            self.state[name] = chainer.Variable(np.zeros((batchsize, n_units), dtype=np.float32), volatile=not train)


~~~~省略

def main():
    ''' main関数 '''
    p = 5 # 文字列長
    w = 2 # 前後の単語の数
    total_loss = 0  # 誤差関数の値を入れる変数
    vocab = {}
    n_vocab = len(vocab)
    inv_vocab={} #逆引き辞書

    # 引数の処理
    parser = argparse.ArgumentParser()
    parser.add_argument('--gpu', '-g', default=-1, type=int,
                        help='GPU ID (negative value indicates CPU)')
    args = parser.parse_args()
    # cuda環境では以下のようにすればよい
    xp = cuda.cupy if args.gpu >= 0 else np
    if args.gpu >= 0:
        cuda.get_device(args.gpu).use()
        model.to_gpu()

    with open('vocab.bin', 'rb') as fv:
        vocab = pickle.load(fv)
    with open('inv_vocab.bin', 'rb') as fi:
        inv_vocab = pickle.load(fi)
    # 訓練データ、評価データ、テストデータの読み込み
    os.chdir('/Users/suguruoki/practice/chainer/examples/ptb/')
    test_data = load_data('117-test-data.dat', vocab, inv_vocab)

    n_vocab = len(vocab)

    # モデルの準備
    # 入力は単語数、中間層はmain関数冒頭で定義
    lstm = LSTM(n_vocab , n_units)
    lstm.initialize_state(n_units)
    model = L.Classifier(lstm)
    model.compute_accuracy = False
    with open('LSTMlstm.pkl', 'rb') as fl:
         lstm = pickle.load(fl)           # =>エラーが出ているのはこの行です。 
    with open('LSTMmodel.pkl', 'rb') as fm:
         model = pickle.load(fm)

~~~~省略

↑の全ソースコードはこちら

補足情報(言語/FW/ツール等のバージョンなど)

  • Python => Python 3.5.2 :: Anaconda custom (x86_64)
  • chainer => 1.9.0

また何か必要な情報があれば、教えていただけると幸いです。
よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

pickleのデータを作成(dump)した時点と、ロード(load)した時点でLSTM__init__の引数の数が変わっていませんか?
(LSTMのクラス定義を変更しませんでしたか?)

http://qiita.com/s-wakaba/items/f15b4aa579c018880758

上記の記事にあるように、ユーザー定義のクラスをunpickle化(load)する際に、ユーザー定義のクラスを復元しようとします。
pickle化した時点とクラス構造が異なっていると、上手くunpickleする事ができません。


補足

少し調べてみたのですが、pickleを使ってシリアライズする方法がよく載っていますが、これはあまり良い方法ではない気がします。
上の記事でも分かるように、unpickleはものすごい複雑な処理をしますし、何よりバージョン間の互換性はありません。
serializersメソッドを使うほうが良いのではないかと思います。

http://hellkite.hatenablog.com/entry/chainer_model_save
http://studylog.hateblo.jp/entry/2016/01/05/212830

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/18 18:21

    最初にコードを読み間違えて、全く見当違いの回答をしてしまいました。
    失礼しました。

    キャンセル

  • 2017/07/18 18:40

    回答ありがとうございます!
    理解不足で恐縮なのですが、上記の場合だと、pickle化されている側のソースプログラムのLSTMクラスのinitとunpickleする側のソースプログラムのLSTMクラスのinitが同じだけではダメだということということでしょうか?このソースプログラムだと、pickle化された際はLSTMクラスを保存しているという理解なのですが、そうではないということですか?

    キャンセル

  • 2017/07/18 18:51

    > pickle化されている側のソースプログラムのLSTMクラスのinitとunpickleする側のソースプログラムのLSTMクラスのinitが同じだけではダメだということということでしょうか?

    LSTMのコードは変えていないという事でしょうか?
    それでしたら、pklファイルを作成したPythonとpklをloadしているPythonのバージョンが違うという事はありませんか?

    キャンセル

  • 2017/07/18 18:53 編集

    すみません、貼られているコードと全ソースのコードは違うようですが、どちらが最新でしょうか?

    少なくともlstmwsdのLSTM.__init__は間違っているように見えます。
    正しくはLSTM.__init__ではなく、super(LSTM, self).__init__では?

    キャンセル

  • 2017/07/20 19:27

    返信遅れまして申し訳ありません!
    initからその下でsuperで継承しているのですが、そうではなく、最初から継承ということで良いのですか?

    キャンセル

  • 2017/07/21 16:07

    「予測モデルを作成するソースコード」であるlstmwsdで、LSTMの__init__で親クラスのコンストラクタを呼ばずに、自身のコンストラクタを呼んでいるのですが、これは間違いではないのですか?

    LSTM.__init__( ... )

    となっていますが、本来ならば

    super(LSTM, self).__init__( ... )

    ですよね。
    アップされたコードではそうなっていますよ。

    キャンセル

  • 2017/07/24 10:21

    ところで、変わったLSTMですね。 h を繋いで積層構造にすることはよくやりますが、c を繋いでいます。
    Highway LSTMともまた違いますし。これはどんな事を期待した構造なのでしょうか?

    キャンセル

同じタグがついた質問を見る

  • Python 3.x

    9815questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • 機械学習

    958questions

    機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

  • Chainer

    208questions

    Chainerは、国産の深層学習フレームワークです。あらゆるニューラルネットワークをPythonで柔軟に書くことができ、学習させることが可能。GPUをサポートしており、複数のGPUを用いた学習も直感的に記述できます。