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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

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

Q&A

解決済

1回答

561閲覧

tensorflow.kerasでカテゴリごとの正解率を取得する

sigefuji

総合スコア125

Python 3.x

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

0グッド

0クリップ

投稿2022/08/29 08:27

前提

tensorflow.kerasで
出力層の予測/教師最適カテゴリ(クラス)あるはその誤差を学習ごとに取得すること
または、それらを評価している関数名を知ること。(その関数の動作を調べてそれらを取得するように修正)
目的はカテゴリごとの正解率を評価すること。

keras公式ページのコールバックの説明
Writing your own callbacks
https://keras.io/guides/writing_your_own_callbacks/
には、出力クラスごとの誤差、もしくは最適クラス(softmax)の情報は見当たらないようです。

この情報を各学習ごとに知ることはできないでしょうか。
これができないようなので出力クラスを選択評価する処理のソースを見なければなりませんが、
どこにあるか探すのに苦労しています。
多分site_packages.kerasのmodel.fitやmodel.evaluateあたりと目星をつけましたが探しきれません。(先のzeroからシリーズ本ではほとんど見えていたので目的は果たせた)

最後の手段は、keras以下のすべての.pyファイルをつなげたtextファイルを生成するプログラムを別途つくりエディタで調べるなんてことも考えられますが・・。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sigefuji

2022/08/29 12:07

こちらもご返事ありがとうございます。 完全には理解できかねていますけれど、求めているのは多分サイトのようなmetricsの種類ではなく、 ”正解ラベルのテンソルと予測ラベルのテンソルの2つを引数とし” とあることから推理するに、 予測ラベルのテンソルと言う意味を、pred-lbl(1,サンプル数)のテンソルと言う意味ならば、 まさに今求めている物です。これがcallbackなどで参照できれば良いのですが。公式サイトのcallback項目を見た限りではなかったように思います。 全体的なmtricsではなくラベルごとの正解数を知りたいのです。 そのためにはバッチ学習終了後(epoch単位で)改めてバッチなしの全サンプルの推論だけを行って、これを評価します。 zeroからシリーズでは、中身が見えるのでできました。
sigefuji

2022/08/29 12:17

余談です。jbpb0さんの自己画像はアオサギですね。私もバードウオッチを少しやっています。花の識別を画像認識でやっているところがあるようですが(最近発見)、鳥もやれるのかな??関係なければすみません。
sigefuji

2022/08/29 12:21

余談ついでに、ラベルごとの正解数の意味は、例えば鳥画像と花画像の画像認識があって、それぞれが正解であれば万々歳ですが、鳥と花の区別ができればよしとするようなことに相当します。
jbpb0

2022/08/29 15:35 編集

私が紹介したWebページの「TensorBoard」に、 「クラスごとのAccuracyやMacro Precisionなどがちゃんと表示されていますね!」 と書かれてます 質問に 「目的はカテゴリごとの正解率を評価すること。」 とあります ・私が紹介したページの「クラスごとのAccuracy」 ・質問の「カテゴリごとの正解率」 が同じ意味だと思い、紹介しました
sigefuji

2022/08/30 03:43

ご紹介のページは確かに同じ意味でしたが、説明不足でしたが、必要なことはカテゴリーごとの正解数とそのカテゴリーの数であり、それを後処理で利用できるデータの形で取得することであることと、tensorbordは現段階では利用しないつもり(将来は見るかも)でしたので、調査することをしませんでした。その旨をお知らせしなかったことはお詫びします。 その後さらに調べますと、(model.)output.data()のような形式で見るような記事をみまして、それの公式ページやQ&Aなどを探しているところです。そのようなメソッドもあっても不思議ではないですね。 すべてのクラスとメソッドやプロパティの説明があればいのですが。 どなたかが言っていましたが、ネット検索のコツなどがあるようです。 ようやく環境の修復も終わりましたので合わせて調べるところです。
sigefuji

2022/08/30 06:04

お! 今の世の中こんなのがあるのだ。すごい。AIとあるのがNN検索らしく、数秒で答えが出るとか、ほかはイメージ知識データベースのようですね。 花は、MNISTのようなデータがあるので、それ用と思いました。 実は3-10年前は両方とものめりこんでいましたが、今のハードの向上からすると、やってみたくなるような情勢ですね(今となっては余裕がありませんが) 先の余談失礼しました。
jbpb0

2022/08/31 09:03 編集

https://qiita.com/shiita0903/items/838d50598cc28766f84e の「準備」以降のコードを全部そのままgoogle colabにコピペしてから、下記を変更 from keras.utils import to_categorical ↓ from keras.utils.np_utils import to_categorical model.fit(x_train, y_train, validation_data=(x_test, y_test), batch_size=400, epochs=50, callbacks=[TensorBoard()]) ↓ history = model.fit(x_train, y_train, validation_data=(x_test, y_test), batch_size=400, epochs=50) コードの最後に下記を追加して実行 print(history.history.keys()) print(history.history['acc-0']) print(history.history['acc-9']) print(history.history['val_acc-0']) print(history.history['val_acc-9']) 上記の結果表示で、たとえば「print(history.history['acc-0'])」の結果には50個の数値が並んでますが、これは数字「0」画像の学習データの各エポックでの正解率です 同様に、「print(history.history['val_acc-9'])」の結果の50個の数値は、数字「9」画像のvalデータの各エポックでの正解率です 他にも取得できるものがたくさんあり、それらは「print(history.history.keys())」の結果を参照したら分かります 上記のようにして、model.fit()の各エポックでの「クラスごとのAccuracy」等を数値で取得できることが確認できましたが、これは > 後処理で利用できるデータの形で取得 にはならないでしょうか? なお、コードを実行して確認した時のtensorflowのバージョンは、2.8.2+zzzcolab20220719082949でした 参考にしたWebページのコードをたいして変更しなくても、tensorflow 2.*で動きました
sigefuji

2022/09/09 03:58

詳しく検討いただきありがとうございます。 こちらもご返事いただいていたのを見逃し、すみませんでした。 自己解決投稿した折に気が付きました。 詳しくは拝見できなかったですが、自己解決した方法とは多分異なると思います。 折角ですので、自己解決した具体的なコードを提示します。 インデントが反映されているとよいですが。 ポイントは ・model関数の戻り値に出力値の値が反映されていることを利用する。 ・コード中にある半正解数(ラベルの半数の範囲にあれば半正解とする。勝手な命名)を計算する。 ただし、提示のコードはいかにも非python風で力任せですので、もっとスマートなコードがあるのでは思います。ただ、この計算はepoch終了ごとで良いので、まあいいかなと。 def onehot2no(onehot): for n in range(p_out): if(onehot[n]>0.5): return n return -1 def train_step(x, t): outputs = model(x, training=True) # モデルに入力して順伝搬の出力値を取得 train_accuracy(t, outputs) # 求めたい正解数の計算 ct=[0 for ot in range(p_out)] win=[0 for ot in range(p_out)] win2=[0 for ot in range(p_out)] for bat in range(batch_size): maxv=0 maxot=0 print("outputs",outputs[bat,]) for ot in range(p_out): if outputs[bat,ot] > maxv: maxv = outputs[bat,ot] maxot = ot no = onehot2no(t[bat])   #onehotlabel をlaberスカラーに変換 print("t_bat", no) ct[maxot] += 1 if maxot==no: win[maxot] += 1     #カテゴリごとの正解数 if no<p_out/2: if maxot < p_out/2 : win2[maxot] +=1   #カテゴリごとの半正解数 elif no>p_out/2: if maxot > p_out/2: win2[maxot] += 1   #カテゴリごとの半正解数 print("train bat",bat,"max",maxv,maxot,"t",t[bat]) print("train ct ",ct) print("train win ",win) print("train win2",win2) return ct,win,win2
sigefuji

2022/09/09 04:02

この欄への投稿は先頭のスペースが無視されるので、見にくく済みません。
jbpb0

2022/09/09 23:55 編集

「train_step()」の使い方を教えてください kerasでの学習では、データを用意して、モデルを定義してから、 model.compile(... model.fit(... のようにしてモデルの学習を行いますが、その流れの中にどのようにして「train_step()」を組み込むのでしょうか? train_step_callback = keras.callbacks.LambdaCallback(on_epoch_end=lambda epoch,logs: train_step(x, t)) みたいなのを、「model.fit()」で 「callbacks=[train_step_callback]」 のように指定するのでしょうか?
sigefuji

2022/09/10 01:23

>「train_step()」の使い方を教えてください model.compile(... model.fit(... このような記述のサンプルも見たことがありますが、よくわかりません。 これは件の本の5.5章をべs-スにしたのですが、コードの抜粋を提示します。 これでいかがでしょうか。ちなみにこれはMLPとなっていてCNNではありません。 ``` ''' 1. データセットの読み込みと前処理 shuwa 5.5 ''' # tensorflowのインポート import tensorflow as tf import numpy as np import sys import math ''' 2. モデルの定義 ''' class MLP(tf.keras.Model): def __init__(self, hidden_dim, output_dim): super().__init__() self.fc1 = tf.keras.layers.Dense(hidden_dim, activation='relu') self.dropout = tf.keras.layers.Dropout(0.5) self.fc2 = tf.keras.layers.Dense(output_dim, activation='softmax') def call(self, x, training=None): '''MLPのインスタンスからコールバックされる関数 Parameters: x(ndarray(float32)):訓練データ、または検証データ Returns(float32): MLPの出力として要素数3の1階テンソル ''' x = self.fc1(x) # 第1層の出力 if training: # 訓練モードのときdropout x = self.dropout(x) x = self.fc2(x) # 出力層の出力 return x ''' 3. 損失関数とオプティマイザーの生成 ''' import tensorflow as tf # マルチクラス分類のクロスエントロピー誤差を求めるオブジェクト loss_fn = tf.keras.losses.CategoricalCrossentropy() # 勾配降下アルゴリズムを使用するオプティマイザーを生成 optimizer = tf.keras.optimizers.SGD(learning_rate=0.1) ''' 4. 勾配降下アルゴリズムによるパラメーターの更新処理を行うtrain_step()関数 ''' # 損失を記録するオブジェクトを生成 train_loss = tf.keras.metrics.Mean() # カテゴリカルデータの精度を記録するオブジェクトを生成 train_accuracy = tf.keras.metrics.CategoricalAccuracy() def onehot2no(onehot): for n in range(p_out): if(onehot[n]>0.5): return n return -1 def train_step(x, t): '''学習を1回行う Returns: ステップごとのクロスエントロピー誤差 ''' # 自動微分による勾配計算を記録するブロック with tf.GradientTape() as tape: # 訓練モードをTrueに指定し、 outputs = model(x, training=True) # モデルに入力して順伝搬の出力値を取得 #print("outputs",outputs.shape) tmp_loss = loss_fn(t, outputs) # 出力値と正解ラベルの誤差 # tapeに記録された操作を使用して誤差の勾配を計算 grads = tape.gradient( tmp_loss, # 現在のステップの誤差 # バイアス、重みのリストを取得 model.trainable_variables) # 勾配降下法の更新式を適用してバイアス、重みを更新 optimizer.apply_gradients(zip(grads, model.trainable_variables)) train_accuracy(t, outputs) # 以下は半正解数などを計算する処理 return ct,win,win2 ''' 8.モデルを生成して学習する ''' from sklearn.utils import shuffle epochs = 100 model = MLP(256, p_out) # 隠れ層256ユニット、出力層10ユニットのモデルを生成 # 学習を行う for epoch in range(epochs): x_, y_ = shuffle(tr_x, tr_y, ) ``` # 1ステップにおける訓練用ミニバッチを使用した学習 for step in range(tr_steps): ct,win,win2 = train_step(x_[start:end], y_[start:end]) ```
sigefuji

2022/09/10 03:41

MLPの次にcnnを調べていて、ご質問の意味がわかりました。 CNNでは model.compile(... model.fit(... model.evaluate() とかやっているのですね。 この場合は、確かに予測出力値は直ちには見れないのですね。それで、当初のこの質問をしたのだと思います。 それで、調べていきますと pred=model.predict() というのがあって、サンプルコードでprtint(pred)とすると、求めているカテゴリーごとの出力値が出ました。 ですので pred=model.pred(x_train) pred =model.pred(x_test) などとすればよさそうにみえます。これぐらいは本来あって当然な機能と思います。 それで、kerasのcnnを希望を持って進めることができそうですが、これはこれで問題に行き当っています。
sigefuji

2022/09/10 03:48

修正 pred=model.predict(x_train) pred =model.predict(x_test)
jbpb0

2022/09/10 05:09 編集

物体・画像認識と時系列データ処理入門 [TensorFlow2/PyTorch対応第2版] https://www.shuwasystem.co.jp/book/9784798063546.html で、cnnは ・6.2 TensorFlowスタイルによるCNNの構築 ・6.4.3 TensorFlowスタイルによるプログラミング ・7.1.4 TensorFlowスタイルでプログラミングしたCNNに飛行機、自動車、イヌ、ネコなどの10種類の画像を認識させてみる ・7.2.5 画像を拡張処理して精度90%を達成する(TensorFlow) が、 ・5.5 TensorFlowスタイルによるニューラルネットワークの構築 と同じやり方です ・339ページの下 ・362ページの上 を見ると、6.2,と6.4.3では「train_step()」とかは5.5のを使うと書かれてます 7.1.4では399ページからコードが書かれてますが、5.5のと比べても、ほとんど同じです 463ページの下〜464ページの上を見ると、7.2.5では「train_step()」とかは7.1.4のを使うと書かれてます
sigefuji

2022/09/10 05:02

339ページ以下の件はその通りでしたが、どうもご指摘の意図がわかりません。 6.2は自前datasetsではまだで、これからですが、そのあたりを含めてサンプルプログラムの構成は統一が取れているようで、そうでもない部分もあり戸惑うときがあります。 私の解決策の投稿はmodel.predict(モデル)につきます。
jbpb0

2022/09/10 05:36

> ご指摘の意図がわかりません。 6.2, 6.4.3, 7.1.4, 7.2.5を紹介したのは、 > MLPの次にcnnを調べていて、ご質問の意味がわかりました。 CNNでは model.compile(... model.fit(... model.evaluate() とかやっているのですね。 と書かれたからです mlpだから、cnnだから、ではなく、mlpもcnnもその書籍では ・TensorFlowスタイル ・Kerasスタイル ・PyTorch の三種類のコードが記載されてます、と述べただけです ・5.6 Kerasによるニューラルネットワークの構築 では、mlpですが「model.fit()」を使う一般的なkerasのやり方でコードが書かれてます cnnだから「model.fit()」を使ってる、というわけではありませんよね
jbpb0

2022/09/10 05:48

> 調べていきますと pred=model.predict() というのがあって、サンプルコードでprtint(pred)とすると、求めているカテゴリーごとの出力値が出ました。 「model.fit()」を使う一般的なkerasのやり方の場合は、学習の各エポックで「クラス別の正解率」の様な標準では用意されてない計算をするには、「model.fit()」の内部でその計算がされるように設定する必要があると思います 私が最初のコメントで紹介した https://qiita.com/shiita0903/items/838d50598cc28766f84e でやってる「model.compile()」の「metrics=」で指定する方法や、ちょっと上のコメントで質問した「model.fit()」の「callbacks=」で指定する方法は、どちらも上記のための設定方法です 私が勘違いしてて、そのような設定をしなくても、「model.fit()」を使う一般的なkerasのやり方の場合で、学習の各エポックでの「クラス別の正解率」が計算できるのでしょうか? もっと簡単にやれる方法があるなら教えてください 「model.fit()」での学習が全て終わった後に一回だけ「クラス別の正解率」を計算すればいいのなら、そこで > pred=model.predict(x_train) pred =model.predict(x_test) を実行すればいいですが、質問の > この情報を各学習ごとに知ることはできないでしょうか。 の「各学習」は、各エポックのことですよね? (そう思って、ずっと書いてました)
jbpb0

2022/09/10 06:05

誤解の無い様に書いておきますが、「model.fit()」を使う一般的なkerasのやり方と、書籍5.5の様なやり方と、どちらが良いとか、こうすべきとか思ってるのではありません 「model.fit()」を使う一般的なkerasのやり方は簡単に書けますが、詳細が隠蔽されてて融通が効かないので、学習過程を細かくカスタマイズしたい場合は、書籍5.5の様なやり方の方がやりやすくなります 公式のドキュメントにも、そんな様なことが書かれてます https://tensorflow.classcat.com/2021/01/16/tf24-guide-keras-writing-a-training-loop-from-scratch/
sigefuji

2022/09/10 08:14

詳しく幾度もご説明いただいたのですが、現在の実力ではその内容を十分に理解できませんでしたので、あるいは頓珍漢なことを申し上げたかも知れません。そうであればお詫びします。そのいきさつはだいぶわかりました。 特記事項として ・model.fit() と model.predict()とは いずれかの選択ではないですよね。predictはfitのオプションのような位置づけですね。 ・詳細が隠蔽されてて融通が効かない・・・のことはその通りだと思います。融通を効かせてかつ簡単なのがよいですが。理解が進めば使いわけられるかも。書籍等はブラックボックス的になり中身が見えないのが問題です。その点ゼロからシリーズ本はそれに期待して入手しましたがそこまでは進まず。 ・各学習ごとは、epochごとの積りです。model.predictではそれがきないのかしら。全epoch終了後のみであれば面白くない。いまから調べるところです。 自前データによる6.1ができたところです。(predictは未実装)苦労します。
jbpb0

2022/09/10 09:01 編集

> この欄への投稿は先頭のスペースが無視される ここではなくて回答なら、 ```python (pythonコード) ``` と書けばインデントが反映されますので、「自己解決」の回答を編集して、ぜひ解決したコードを追記してください 全部書くのが面倒なら、書籍のコードとの相違点を書くだけでも (その場合は、書籍名と、元コードが載ってるのが何ページかも書いた方がいいです) そうすれば、同様なことで悩んで、検索してこの質問を見つけた人の参考になります https://teratail.com/tour に 「質問・回答によって生まれたコンテンツを、同じ問題を持った人に最適な形で届けます。」 と書かれてるように、「teratail」にはそのような役割もありますので 私もそのコードを実行してみたいですし
guest

回答1

0

自己解決

その後調べた結果、モデルの出力値を取得できる方法がわかった。
出力値が取得できれば、カテゴリーごとの正解数を求めることは容易。
参考書籍(下記)を参考に試した2例を参考までに掲示します。

1.tensorflow/kerasのconv1Dモデルで学習をする場合
全epoch終了後,model.predictを使用して、全学習サンプルの出力値を取得できる。
この方法の問題点
・各epoch途中の出力値は取得できず、最後のepochの値が取得できるようだ。
・主力値の全サンプルを記憶するメモリが必要と思われる(gpuのメモリサイズに影響すると思う)
各ミニバッチ評価ごと、あるいはepochごとに取得できれば、最終的に必要なct/winのカテゴリ数だけのメモリで良い。
使用コード例抜粋
参考書籍6章1節(物体画像認識時系列データ処理入門第2版)

# 畳み込み層 model.add( Conv1D(filters=100, # フィルターの数は32 kernel_size=(3), # 3のフィルターを使用 padding='same', # ゼロパディングを行う input_shape=(1,xsz), # 入力データの形状 activation='relu' # 活性化関数はReLU )) ''' 3. 学習する ''' training_epochs = 100 # 学習を行って結果を出力 history = model.fit( x_train, # 訓練データ y_train, # 正解ラベル epochs=training_epochs, # 学習を繰り返す回数 batch_size=batch_size, # ミニバッチのサイズ verbose=0, # 学習の進捗状況を出力する #validation_split= 0.2, # 検証データとして使用する割合 shuffle=True, # 検証データを抽出する際にシャッフルする #callbacks=[early_stopping] # コールバックはリストで指定する ) # テストデータで学習を評価するデータを取得 score = model.evaluate(x_train, y_train, verbose=1) print('evaluate Train loss:', score[0]) # テストデータの損失を出力 print('Train accuracy:', score[1]) # テストデータの精度を出力 pred_train = model.predict(x_train) # 全訓練データの出力値を取得 ct=[0 for n in range(p_out)] win=[0 for n in range(p_out)] for n in range(len(x_train)):       # 全訓練データ数でループしてct/winを積算 b_y = pred_train[n].argmax() if b_y == y_train[n]: win[b_y] += 1 ct[b_y] += 1 print("train",ct) print("win",win)

2.MLPクラスの場合(隠れ層と出力層のみの単純な場合)

1サンプルの学習時に呼び出す outputs = model(x, training=True) の戻り値に出力値がセットされる。
これから普通に、最大値を選べば、予測ラベルになる。
第1のモデルに比しての功罪
・出力値を保存しておくメモリが不要

次に1次元データの場合の適用例を示す
参考書籍5章5節

''' 2. モデルの定義 ''' class MLP(tf.keras.Model): '''多層パーセプトロン Attributes: l1(Dense): 隠れ層 l2(Dense): 出力層 ''' def __init__(self, hidden_dim, output_dim): super().__init__() self.fc1 = tf.keras.layers.Dense(hidden_dim, activation='relu') self.dropout = tf.keras.layers.Dropout(0.5) self.fc2 = tf.keras.layers.Dense(output_dim, activation='softmax') def call(self, x, training=None): x = self.fc1(x) # 第1層の出力 if training: # 訓練モードのときdropout x = self.dropout(x) x = self.fc2(x) # 出力層の出力 return x ''' 4. 勾配降下アルゴリズムによるパラメーターの更新処理を行うtrain_step()関数 ''' train_loss = tf.keras.metrics.Mean() train_accuracy = tf.keras.metrics.CategoricalAccuracy() def train_step(x, t): '''学習を1回行う Returns: ステップごとのクロスエントロピー誤差 ''' with tf.GradientTape() as tape: outputs = model(x, training=True) # モデルに入力して順伝搬の出力値を取得 tmp_loss = loss_fn(t, outputs) # 出力値と正解ラベルの誤差 grads = tape.gradient( tmp_loss, # 現在のステップの誤差 model.trainable_variables) # 勾配降下法の更新式を適用してバイアス、重みを更新 optimizer.apply_gradients(zip(grads, model.trainable_variables)) train_loss(tmp_loss) train_accuracy(t, outputs) ct=[0 for ot in range(p_out)] win=[0 for ot in range(p_out)] for bat in range(batch_size): maxv=0 maxot=0 #print("outputs",outputs[bat,]) for ot in range(p_out): if outputs[bat,ot] > maxv: maxv = outputs[bat,ot] maxot = ot no = onehot2no(t[bat]) ct[maxot] += 1 if maxot==no: win[maxot] += 1 return ct,win

参考情報:
cpuの利用効率であるが、例1は100%であるのに、例2はなぜか20-40%と低い。
計算効率が何か異なるようだ。

投稿2022/09/09 01:16

編集2022/09/11 08:53
sigefuji

総合スコア125

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問