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

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

ただいまの
回答率

90.01%

'function' has no attribute 'eval' への対処法

解決済

回答 1

投稿 編集

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

knght

score 11

クラスを用いたNNのモデル作りに慣れおらず、
すっきりしたコーディングを身に付けるため、本を読みながら勉強しています。
ですが、詳解ディープラーニングP.171からのDNNのモデルをクラス化するところで躓いてしまいました。
少しコードは変えているのですが、本ではドロップアウトを用いているのをやめただけで、基本忠実に書きました。
大分省略しますが、最後のmodel.evaluate()のところで、
'function' object has no attribute 'eval'
というエラーが出てしまいます。
クラス内のevaluate関数の中で違う関数(accuracy)を呼び出し.evalで値を出すことにエラーが出ているようなのですが、どのようにすれば実現できますでしょうか??

class MLP:
    def __init__(self, input_n, output_n, hidden_n, func_n):
        #...
    def weight_variable(self, shape):
        #...
    def bias_variable(self, shape):
        #...
    def inference(self, x):
        #...
    def loss(self, y, t):
        #...
    def accuracy(self, y, t):
        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(t, 1))
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
        return accuracy
    def fit():
        #...モデル学習
    def evaluate(self, X_test, Y_test):
        return self.accuracy.eval(session=self._sess, feed_dict={
            self._x : X_test,
            self._t : Y_test
        })

model = MLP(input_n=784, output_n=10, hidden_n=[500, 300, 100], func_n=[0, 0, 0])
model.fit(X_train, Y_train, epochs=50, batch_size=200)
accuracy = model.evaluate(X_test, Y_test)
print('accuracy:', accuracy)

クラス内のコードの全文です。

# activation = [0, 1, 0 ,1]
# 0 : ReLU, 1 : sigmoid
class MLP(object):
    def __init__(self, input_n, output_n, hidden_n, func_n):
        self.input_n = input_n
        self.output_n = output_n
        self.hidden_n = hidden_n
        self.weights = []
        self.biases = []
        self.func_n = func_n
        self._x = None
        self._t = None
        self._sess = None
        self._history = {
            'accuracy' : [],
            'loss' : []
        }


    def weight_variable(self, shape):
        initial = tf.Variable(tf.random_normal(shape, stddev=0.01))
        return initial

    def bias_variable(self, shape):
        initial = tf.Variable(tf.zeros(shape))
        return initial

    def function(self, x, func):
        if func == 0:
            return tf.nn.relu(x)
        if func == 1:
            return tf.nn.sigmoi(x)

    def inference(self, x):
        # input-layer - hidden-layer, hidden-layer - hidden-layer
        for i, hidden in enumerate(self.hidden_n):
            if i == 0:
                inp = x
                input_dim = self.input_n
            else:
                inp = output
                input_dim = self.hidden_n[i-1]

            self.weights.append(self.weight_variable([input_dim, hidden]))
            self.biases.append(self.bias_variable([hidden]))

            h = tf.matmul(inp, self.weights[-1]) + self.biases[-1]
            output = self.function(h, self.func_n[i])

        self.weights.append(self.weight_variable([self.hidden_n[-1], self.output_n]))
        self.biases.append(self.bias_variable([self.output_n]))

        y = tf.nn.softmax(tf.matmul(output, self.weights[-1]) + self.biases[-1])

        return y


    def loss(self, y, t):
        loss = tf.reduce_mean(-tf.reduce_sum(
            t * tf.log(tf.clip_by_value(y, 1e-10, 1.0)), reduction_indices=[1]))
        return loss

    def training(self, loss):
        optimizer = tf.train.GradientDescentOptimizer(0.01)
        train_step = optimizer.minimize(loss)
        return(loss)

    def accuracy(self, y, t):
        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(t, 1))
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
        return accuracy

    def fit(self, X_train, Y_train, epochs=100, batch_size=100):
        x = tf.placeholder(tf.float32, [None, self.input_n])
        t = tf.placeholder(tf.float32, [None, self.output_n])

        # save for evaluate()
        self._x = x
        self._t = t

        y = self.inference(x)
        loss = self.loss(y, t)
        train_step = self.training(loss)
        accuracy = self.accuracy(y, t)

        init = tf.global_variables_initializer()
        sess = tf.Session()
        sess.run(init)

        # save for evaluate()
        self._sess = sess

        N_train = len(X_train)
        n_batches = N_train // batch_size

        for epoch in range(epochs):
            X_, Y_ = shuffle(X_train, Y_train)

            for i in range(n_batches):
                start = i * batch_size
                end = start + batch_size

                sess.run(train_step, feed_dict={
                    x : X_train[start:end],
                    t : Y_train[start:end]
                })
            loss_ = loss.eval(session=sess, feed_dict={
                x : X_train,
                t : Y_train
            })
            accuracy_ = accuracy.eval(session=sess, feed_dict={
                x : X_train,
                t : Y_train
            })

            # save to _history
            self._history['loss'].append(loss_)
            self._history['accuracy'].append(accuracy_)

        return self._history


    def evaluate(self, X_test, Y_test):
        return self.accuracy.eval(session=self._sess, feed_dict={
            self._x : X_test,
            self._t : Y_test
        })
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

tf.Tensor.eval() でノードの計算を行おうとしているということですよね?

'function' object has no attribute 'eval'

MLP.accuracy という function オブジェクトは eval を持っていないのでエラーになります。

self.accuracy() が返すテンソルの eval() を呼ぶのなら、self.accuracy().eval() とするべきではないでしょうか。

 追記

accuracy = self.accuracy(y, t) の部分で精度を計算するノードを作成しています。ただ、これはローカル変数なので、def evaluate() 内で self.accuracy としてもこの変数は参照されません。
そのかわりに accuracy(self, y, t) というメソッドのほうが参照されてしまい、今回の質問のエラーに繋がっています。
なので、evaluate() 内で作成した精度を計算するノード accuracy を参照するために、self.acc = self.accuracy(y, t) のように Attribute として記録しておき、evaluate(self, X_test, Y_test) 内で self.acc.eval(引数) とすれば、目的のことができるでしょう。

self.accuracy = self.accuracy(y, t) のようにしないよう注意してください。
Attribute とメソッドで同じ名前を使用した場合、メソッドのほうが隠蔽されてしまい、self.accuracy() と呼び出すことができなくなってしまいます。
今回のケースに限らず、メソッド名と Attribute 名が重複しないよう注意してください。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/10/23 00:00

    その通りなのですが、普通.eval()を使う際は、その関数を計算するためにfeed_dictで値を入れますよね?(知識が浅く間違ってたら申し訳ないのですが…)
    クラスの中で違うメソッドを呼び出すときにself.accuracy(引数).evalのように何か引数を入れるとなると、その関数も違うところからの値(inferenceの返り値など)を持ってきているので、入れようがないのかと思いまして…
    一度本のままにコードを書いてみようと思います。ですが本にはself.accuracy.eval()とありました。
    何度もご親切にありがとうございます。

    キャンセル

  • 2018/10/23 00:44

    追記しました。
    本のほうは、self.accuracy.eval() としていたとのことですが、だとしたら、self.accuracy は tf.Tensor オブジェクトのはずです。
    def accuracy(self, y, t) は質問者さんが作られた関数でしょうか?
    attribute とメソッドで同じ名前を使おうとして今回の混乱が生じている気がします。

    キャンセル

  • 2018/10/23 16:53

    追記のようにコードを修正したところ無事解決しました…!
    理由もわかり納得スッキリです。
    何度もご丁寧にありがとうございました :)

    キャンセル

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

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

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