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

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

ただいまの
回答率

90.45%

  • Python

    12371questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • TensorFlow

    962questions

TensorFlowでモデルを保存して復元できない

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 769

donafudo

score 38

問題

本を参考にしながらRNNで言語モデルを作って、いざ文章を生成しようとすると、
トレーニングと生成を同時に実行するとそれらしい文章が出来るが、
トレーニングと生成を別々に実行すると、ちゃんとrestoreされていないのか、でたらめな文章が生成される。

saver.save()で保存されたファイルは以下の4つ
checkpoint
language-model.ckpt.data-00000-of-00001
language-model.ckpt.index
language-model.ckpt.meta

tensorflowのあるバージョンからはmetaファイルが生成されるので
self.saver = tf.train.import_meta_graph(os.path.join(ckpt_dir, 'language-model.ckpt.meta'))
が必要という情報があったので試してみても結果は変わらず、
エラーも特に出ていないので手詰まり状態です。
下記のコードに問題があるところはありますでしょうか?

環境

OS:macOS High Sierra 10.13.6
tensorflow 1.9.0
Pyton3.6 

import numpy as np

# テキストを読み込んで処理
with open('wordDataSet', 'r', encoding='utf-8')as f:
    text = f.read()

text = text[:]

chars = set(text)
char2int = {ch: i for i, ch in enumerate(chars)}
int2char = dict(enumerate(chars))
text_ints = np.array([char2int[ch] for ch in text], dtype=np.int32)


def reshape_data(sequence, batch_size, num_steps):
    tot_batch_length = batch_size * num_steps
    num_batches = int(len(sequence) / tot_batch_length)
    print(len(sequence))
    if num_batches * tot_batch_length + 1 > len(sequence):
        num_batches = num_batches - 1

    # シーケンスの最後の部分から完全なバッチにならない半端な文字を削除
    x = sequence[0:num_batches * tot_batch_length]
    y = sequence[1:num_batches * tot_batch_length + 1]


    # xとyをシーケンスのバッチのリストに分割
    x_batch_splits = np.split(x, batch_size)
    y_batch_splits = np.split(y, batch_size)

    # それらのバッチを結合
    # batch_size×tot_batch_length
    x = np.stack(x_batch_splits)
    y = np.stack(y_batch_splits)

    return x, y


def create_batch_generator(data_x, data_y, num_steps):
    batch_size, tot_batch_length = data_x.shape
    num_batches = int(tot_batch_length / num_steps)
    for b in range(num_batches):
        yield (data_x[:, b * num_steps:(b + 1) * num_steps],
               data_y[:, b * num_steps:(b + 1) * num_steps])


def get_top_char(probas, char_size, top_n=2):
    p = np.squeeze(probas)
    p[np.argsort(p)[:-top_n]] = 0.0
    p = p / np.sum(p)
    ch_id = np.random.choice(char_size, 1, p=p)[0]
    return ch_id


import tensorflow as tf
import os

class CharRNN(object):
    def __init__(self, num_classes, batch_size=64, num_steps=100,
                 lstm_size=128, num_layers=1, learning_rate=0.001,
                 keep_prob=0.5, grad_clip=5, sampling=False):
        self.num_classes = num_classes
        self.batch_size = batch_size
        self.num_steps = num_steps
        self.lstm_size = lstm_size
        self.num_layers = num_layers
        self.learning_rate = learning_rate
        self.keep_prob = keep_prob
        self.grad_clip = grad_clip

        self.g = tf.Graph()
        with self.g.as_default():
            tf.set_random_seed(123)

            self.build(sampling=sampling)
            self.saver = tf.train.Saver(max_to_keep=2)
            self.init_op = tf.global_variables_initializer()

    def build(self, sampling):
        if sampling == True:
            batch_size, num_steps = 1, 1
        else:
            batch_size = self.batch_size
            num_steps = self.num_steps

        tf_x = tf.placeholder(tf.int32,
                              shape=[batch_size, num_steps],
                              name='tf_x')
        tf_y = tf.placeholder(tf.int32,
                              shape=[batch_size, num_steps],
                              name='tf_y')
        tf_keepprob = tf.placeholder(tf.float32,
                                     name='tf_keepprob')

        # one-hotエンコーディングを適用
        x_onehot = tf.one_hot(tf_x, depth=self.num_classes)
        y_onehot = tf.one_hot(tf_y, depth=self.num_classes)

        # 多層RNNのセルを構築
        cells = tf.contrib.rnn.MultiRNNCell([tf.contrib.rnn.DropoutWrapper(
            tf.contrib.rnn.BasicLSTMCell(self.lstm_size),
            output_keep_prob=tf_keepprob) for _ in range(self.num_layers)])

        # 初期状態を定義
        self.initial_state = cells.zero_state(batch_size, tf.float32)

        # RNNで各シーケンスステップを実行
        lstm_outputs, self.final_state = tf.nn.dynamic_rnn(cells, x_onehot, initial_state=self.initial_state)

        print(' << lstm_outputs >>', lstm_outputs)

        # 二次元テンソルに変形
        seq_output_reshaped = tf.reshape(lstm_outputs,
                                         shape=[-1, self.lstm_size],
                                         name='seq_output_reshaped')

        # そう入力を取得
        logits = tf.layers.dense(inputs=seq_output_reshaped,
                                 units=self.num_classes,
                                 activation=None,
                                 name='logits')

        # 次の文字バッチの確率を計算
        proba = tf.nn.softmax(logits, name='probabilities')

        # コスト関数を定義
        y_reshaped = tf.reshape(y_onehot,
                                shape=[-1, self.num_classes],
                                name='y_reshaped')
        cost = tf.reduce_mean(
            tf.nn.softmax_cross_entropy_with_logits(logits=logits,
                                                    labels=y_reshaped),
            name='cost')

        # 勾配発散問題を回避するための勾配刈り込み
        tvars = tf.trainable_variables()
        grads, _ = tf.clip_by_global_norm(tf.gradients(cost, tvars),
                                          self.grad_clip)

        # オプティマイザを定義
        optimizer = tf.train.AdamOptimizer(self.learning_rate)
        train_op = optimizer.apply_gradients(zip(grads, tvars),
                                             name='train_op')

    def train(self, train_x, train_y, num_epochs, ckpt_dir='./model/'):

        # チェックポイントディレクトリがまだ存在しない場合は作成
        if not os.path.exists(ckpt_dir):
            os.mkdir(ckpt_dir)

        with tf.Session(graph=self.g) as sess:
            sess.run(self.init_op)

            n_batches = int(train_x.shape[1] / self.num_steps)
            iterations = n_batches * num_epochs
            for epoch in range(num_epochs):

                # ネットワークをトレーニング
                new_state = sess.run(self.initial_state)
                loss = 0

                # ミニバッチジェネレータ
                bgen = create_batch_generator(train_x, train_y, self.num_steps)
                for b, (batch_x, batch_y) in enumerate(bgen, 1):
                    iteration = epoch * n_batches + b

                    feed = {'tf_x:0': batch_x,
                            'tf_y:0': batch_y,
                            'tf_keepprob:0': self.keep_prob,
                            self.initial_state: new_state}
                    batch_cost, _, new_state = sess.run(
                        ['cost:0', 'train_op',
                         self.final_state],
                        feed_dict=feed)

                    if iteration % 10 == 0:
                        print('Epoch %d/%d iteration %d| Training loss: %.4f' %
                              (epoch + 1, num_epochs, iteration, batch_cost))

                # トレーニング済みのモデルを保存
                self.saver.save(sess,
                                os.path.join(ckpt_dir, 'language-model.ckpt'))

    def sample(self, output_length, ckpt_dir, starter_seq="電子書籍"):
        observed_seq = [ch for ch in starter_seq]
        with tf.Session(graph=self.g)as sess:
            self.saver = tf.train.import_meta_graph(os.path.join(ckpt_dir, 'language-model.ckpt.meta'))
            self.saver.restore(sess, tf.train.latest_checkpoint(ckpt_dir))

            # 1: starter_seqを使ってモデルを実行
            new_state = sess.run(self.initial_state)
            for ch in starter_seq:
                x = np.zeros((1, 1))
                x[0, 0] = char2int[ch]
                feed = {'tf_x:0': x, 'tf_keepprob:0': 1.0,
                        self.initial_state: new_state}
                proba, new_state = sess.run(
                    ['probabilities:0', self.final_state],
                    feed_dict=feed)

                ch_id = get_top_char(proba, len(chars))
                observed_seq.append(int2char[ch_id])

            # 2: 更新されたobserved_seqを使ってモデルを実行
            for i in range(output_length):
                x[0, 0] = ch_id
                feed = {'tf_x:0': x, 'tf_keepprob:0': 1.0,
                        self.initial_state: new_state}
                proba, new_state = sess.run(
                    ['probabilities:0', self.final_state],
                    feed_dict=feed)

                ch_id = get_top_char(proba, len(chars))
                observed_seq.append(int2char[ch_id])
        return ''.join(observed_seq)


batch_size = 32
num_steps = 30
train_x, train_y = reshape_data(text_ints, batch_size, num_steps)

# モデルのトレーニング
rnn=CharRNN(num_classes=len(chars),batch_size=batch_size)
rnn.train(train_x,train_y,num_epochs=1000,ckpt_dir='./model-100/')
del rnn

# 文章生成
np.random.seed(123)
rnn = CharRNN(len(chars), sampling=True)
print(rnn.sample(ckpt_dir='./model-100/', output_length=500,starter_seq='明日は'))
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

0

参考になるかわかりませんけど自分の環境ではsave,restoreは以下のように記述したらrestoreできてるような気がします。

#self.saver
self.saver = tf.train.Saver()

#モデルの保存
self.saver.save(self.sess,"./checkpoint/m.ckpt")

#restore
ckpt = tf.train.get_checkpoint_state('./checkpoint')
if ckpt:#モデルファイルがあるとき
    last_model = ckpt.model_checkpoint_path
    self.saver.restore(self.sess, last_model)

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/08/23 14:44

    回答ありがとうございます。
    同じ記述でやってみたのですが、結果は変わりませんでした。
    一度、別の環境で試してみます。

    キャンセル

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

  • ただいまの回答率 90.45%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

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

  • Python

    12371questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • TensorFlow

    962questions