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

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

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

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

Python

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

Q&A

解決済

1回答

1622閲覧

keras 自作 損失関数 正解ラベル 予測ラベル 異なる形

sakuramochi

総合スコア13

Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

Python

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

0グッド

0クリップ

投稿2018/11/10 02:40

編集2018/11/10 12:51

###損失関数を自作したい
初めての投稿になります.慣れておらず,間違っている部分がありましたら,すみません.
損失関数を自作したいですが,プログラムがうまく動かず,困っています.症状としては,実行した際にすごく時間がかかり止まってしまいました.
loss関数を作成するのは初めてで,調べながら取り組んだものの,コードは明らかに間違っていると思いますが,自分の作りたいloss関数をどう実装すればいいのか分かりません.

CNNモデルは16×16の画像を入力とし,50次元の1次元ベクトルを出力としています.

作りたいloss関数は正解ラベル(教師ベクトル)であるy_true75次元((x,y,c)×25),予測ラベルであるy_pred50次元((x,y)×50)において,xとyのmseに正解ラベルのcをかけたものをlossとしたいです.

(y_true[0]-y_pred[0])^2 * + (y_true[1]-y_pred[1])^2 *y_true[2] がひとまとまりで、(y_true[3]-y_pred[3])^2 * + (y_true[4]-y_pred[4])^2 *y_true[5] 、、、
と順番に足していくイメージです。

(y_trueはx,y,c,x,y,c...y_predはx,y,x,y,...という順番で入っています.)
loss関数には引数として(y_true,y_predict)を用い,それぞれの形はy_true[batchsize][row][col][ch]となっていると思います.
batchsizeは30に指定したので今回はy_true[30][75]のような形になっていると思います.それを踏まえた上でコードを作成しましたが,そもそも損失関数というのはbatchsizeごとに出しているのかも曖昧です.
各,xy要素ごとでしたら,mseで実装できますが,入力のみそこにcが入り込み,入力と出力の形が異なるためにどのようにコードを書けばいいかが全く分かりません.

初心者すぎる質問で申し訳ありません.

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

実行できない
出たエラーを消してしまい,今実行できる状況になく,貼れません.

該当のソースコード

def originalloss(y_true,y_pred): loss = 0 for i in range(30): gap = 0 for j in range(25): xgap = 0 ygap = 0 xgap = ( y_true[i][3*j]-y_pred[i][2*j] ) * ( y_true[i][3*j]-y_pred[i][2*j] ) ygap = ( y_true[i][3*j+1]-y_pred[i][2*j]+1 ) * ( y_true[i][3*j+1]-y_pred[i][2*j+1] ) gap = gap + (xgap + ygap) * y_true[i][3*j+2] gap = gap / 50 #平均    loss = loss + gap loss = loss/30 #平均 return loss return loss

試したこと

上記コードの実行.

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

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

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

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

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

Paalon

2018/11/10 02:47

数式でやりたいことを書いたほうが分かりやすいと思います。
Paalon

2018/11/10 02:50

このコードはPythonだと思いますが、インデントがずれていたりして、変に見えるので、確認して修正してみてください。
tiitoi

2018/11/10 03:51 編集

> 入力75次元((x,y,c)×25),出力50次元((x,y)×50)のCNN モデルの入力は (25, H, W, C) で出力は (50, H, W, 1) ということでしょうか?なぜバッチサイズが出力で変わっているのでしょうか? 意図がよくわからないので、Keras でしたら、model.summary() の結果と損失関数の数式を変えていただけるとありがたいです。
sakuramochi

2018/11/10 03:56 編集

入力は(30,75,1,1)で出力が(30,50,1,1)になると思いますので、バッチサイズは30で一定です。 model.summaryを今送ることができないので、でき次第送ります! ありがとうございます。
tiitoi

2018/11/10 06:56 編集

for 文を使うと非常に遅くなるので、こういう計算はforを書かないでできるように工夫しましょう。ちなみになぜ (batchsize, input_dim, 1, 1) なのでしょうか?入力が画像でなく、(batchsize, input_dim, channels) の場合は Conv2D ではなく、Conv1D を使うべきだと思いますが。
sakuramochi

2018/11/10 10:39

すみません、入力は[batchsize][16][16]の画像データです。y_trueが[batchsize][75]でy_predが[batchsize][50]になっています。入力とy_trueを勘違いしていました。ごめんなさい。
guest

回答1

0

ベストアンサー

Python では数値計算を行うための for 文は基本的に遅くなるため NG です。
for 文を使わないで計算できるようにしましょう。

問題設定

BatchSize=30, LabelDim=75, OutputDim=50

モデルの入力 data: (BatchSize, 16, 16, 1) の配列
モデルの出力 Y_pred: (BatchSize, OutputDim) の配列
ラベル labels: (BatchSize, LabelDim) の配列

サンプルコード

テスト用に入力及びラベルを作成する。

python

1import numpy as np 2 3batch_size = 30 # バッチサイズ 4input_shape = (16, 16, 1) # モデルの入力サイズ 5label_dim = 75 # ラベルの次元数 6output_dim = 50 # 出力の次元数 7 8# ダミーの入力データ及びラベルを作成する。 9data = np.random.randn(batch_size, *input_shape) # データ 10labels = np.random.randn(batch_size, label_dim) # ラベル 11print('data.shape', data.shape) # data.shape (30, 16, 16, 1) 12print('labels.shape', labels.shape) # labels.shape (30, 75)

テスト用に簡単なモデルを作成する。

python

1import tensorflow as tf 2from keras.models import Sequential 3from keras.layers import Conv2D, GlobalMaxPooling2D 4 5# 入力が (BatchSize, 16, 16, 1) で出力が (BatchSize, 50) のダミーのモデルを作成する。 6model = Sequential() 7model.add(Conv2D(output_dim, kernel_size=(3, 3), input_shape=input_shape)) 8model.add(GlobalMaxPooling2D()) 9model.summary()
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_1 (Conv2D) (None, 14, 14, 50) 500 _________________________________________________________________ global_max_pooling2d_1 (Glob (None, 50) 0 ================================================================= Total params: 500 Trainable params: 500 Non-trainable params: 0 _________________________________________________________________

損失関数の定義

python

1def custom_loss(labels, Y_pred): 2 # ラベルから Y_true を抽出する。 3 mask = tf.tile([True, True, False], (label_dim // 3,)) 4 Y_true = tf.boolean_mask(labels, mask, axis=1) 5 6 # ラベルから重み係数を抽出する。 7 mask = tf.math.logical_not(mask) 8 coeff = tf.boolean_mask(labels, mask, axis=1) 9 10 # 重み係数を作成する。 11 ones = tf.ones_like(coeff) 12 W = tf.reshape( 13 tf.concat([ones[..., tf.newaxis], coeff[..., tf.newaxis]], axis=-1), 14 [tf.shape(ones)[0], -1]) 15 16 return tf.reduce_mean((Y_true - Y_pred) ** 2 * W)

損失関数の値計算

model.compile(loss=custom_loss, optimizer='adam') model.fit(data, labels, epochs=3) loss1 = model.evaluate(data, labels) print(loss1) # 0.6780742406845093

numpy での計算

# モデルの出力 Y_pred = model.predict(data) # ラベルから Y_true を抽出する。 mask = np.ones(labels.shape[1], dtype=bool) mask[2::3] = False Y_true = labels[:, mask] # ラベルから重み係数を抽出する。 mask = np.logical_not(mask) coeff = labels[:, mask] # 重み係数を作成する。 W = np.ones_like(Y_true) W[:, 1::2] = coeff loss2 = np.mean((Y_true - Y_pred) ** 2 * W) # 計算した値が numpy と TensorFlow で一致するか print(np.allclose(loss1, loss2))

追記

各処理がなにをやっているのか簡単な例を追加しました。
TensorFlow のテンソルに対して、numpy の indexing のような操作ができないようなので、少々わかりづらいやり方を取らざる得なくなっています。

python

1 import tensorflow as tf 2 3 with tf.Session() as sess: 4 label_dim = 6 5 labels = tf.constant([[1, 2, 3, 4, 5, 6], 6 [7, 8, 9, 10, 11, 12], 7 [13, 14, 15, 16, 17, 18]]) 8 9 # ラベルから Y_true を抽出する。 10 mask = tf.tile([True, True, False], (label_dim // 3,)) 11 print(mask.eval()) # [ True True False True True False] 12 13 # 各サンプルの 1, 2, 4, 5 列目を抜き出している。 14 Y_true = tf.boolean_mask(labels, mask, axis=1) 15 print(Y_true.eval()) 16 # [[ 1 2 4 5] 17 # [ 7 8 10 11] 18 # [13 14 16 17]] 19 20 # ラベルから重み係数を抽出する。 21 mask = tf.math.logical_not(mask) 22 print(mask.eval()) # [False False True False False True] 23 24 # 各サンプルの 3, 6 列目を抜き出している。 25 coeff = tf.boolean_mask(labels, mask, axis=1) 26 print(coeff.eval()) 27 # [[ 3 6] 28 # [ 9 12] 29 # [15 18]] 30 31 # 末尾に次元を1つ追加している。ones のほうも同様 32 print(tf.shape(coeff).eval()) # [3 2] 33 print(tf.shape(coeff[..., tf.newaxis]).eval()) # [3 2 1] 34 35 # 次元を1つ増やし、axis=-1 で結合している。 36 ones = tf.ones_like(coeff) 37 concat = tf.concat([ones[..., tf.newaxis], coeff[..., tf.newaxis]], axis=-1) 38 print(concat.eval()) 39 # [[[ 1 3] 40 # [ 1 6]] 41 # [[ 1 9] 42 # [ 1 12]] 43 # [[ 1 15] 44 # [ 1 18]]] 45 46 # [3 2 2] を [3, 4] に戻している。 47 W = tf.reshape(concat, [tf.shape(ones)[0], -1]) 48 print(tf.shape(concat).eval()) # [3 2 2] 49 print(tf.shape(W).eval()) # [3 4] 50 51 print(W.eval()) 52 # [[ 1 3 1 6] 53 # [ 1 9 1 12] 54 # [ 1 15 1 18]]

投稿2018/11/10 06:52

編集2018/11/10 16:37
tiitoi

総合スコア21956

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

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

sakuramochi

2018/11/10 10:56

初歩的な質問で申し訳ないのですが、numpyを用いたコードでは、動かすことができないのでしょうか? コードがPythonなので普通に動くと思っていました、、、。 kerasを使う以上lambda関数を用いないと実装できないということでしょうか?
tiitoi

2018/11/10 12:37 編集

自作の損失関数 originalloss(y_true,y_pred) を使うのですよね? その場合、学習時に渡ってくる y_true,y_pred は numpy の配列でなく、テンソルなので、numpy の関数は使えません。
sakuramochi

2018/11/10 13:01

回答ありがとうございます. はい,そのつもりでした.y_trueとy_predはnumpy配列ではないのですね. 逆に,自作の損失関数を作成するときには,numpy配列を用いて実装することは可能なのでしょうか. 重ねて,numpyコードについて質問があるのでさせて下さい. 入力の次元は私が間違えて75と言ってしまいましたが,それは正解ラベルのことでした.実際入力に用いるのは16×16の画像です. ただloss関数では入力のものは関係なく,正解ラベルと予測ラベルを比較したいということになります. ここでy_trueが正解ラベル,y_predが予測ラベルと認識しているのですが,実際loss関数を書くときにこの場合は入力の次元は関係ないと思いますが,それであっていますでしょうか. また,9行目のy_pred.shape(3,8,1,1)はどのような意味でしょうか. (30,50,1,1)であると考えていました. 重み係数の形が(30,50,1,1)になっているのも(30,25,1,1)であると思っていて,理解できませんでした.(正解ラベルの75次元中重みは3の倍数のみなので25個だという認識です) 最後のmeanはbatchsizeの30で割っているという認識でいいでしょうか. 機械学習のpythonプログラミングを始めたばかりで,初歩的な質問をたくさんすみません.
tiitoi

2018/11/10 14:25

すいません。当初の解釈に誤りがあったため修正しました。 モデルの入力 data: (30, 16, 16, 1) の配列 モデルの出力 Y_pred: (30, 50) の配列 ラベル labels: (30, 75) の配列 という理解であっていますでしょうか? そうである場合のサンプルコードを回答に書きました。
sakuramochi

2018/11/10 15:40

返信ありがとうございます. いえいえ,とんでもないです. 始めに間違えたのはこちらの方で,誤解をさせてしまって申し訳ありませんでした. そのような認識です. 損失関数の定義のコードにおいて,25次元のものを[1,c1,1,c2...1,c25]と50次元の形に合わせていると思いますが, W = tf.reshape( tf.concat([ones[..., tf.newaxis], coeff[..., tf.newaxis]], axis=-1), [tf.shape(ones)[0], -1]) の部分がどのようになっているのか詳しく教えていただけたら幸いです.cancatで結合しているのはわかるのですがtf.newaxisは自動で決まっているのでしょうか.特に最後の [tf.shape(ones)[0], -1]の部分が全く分かりません. よろしくお願い致します.
sakuramochi

2018/11/10 15:42

またloss関数はbatchsizeに関わらず1つずつ行っているという認識で正しいでしょうか.
tiitoi

2018/11/10 16:43 編集

> どのようになっているのか詳しく教えていただけたら幸いです 簡単な例で各処理がどうなっているのか示すサンプルを追加しました。 テンソルに対して numpy のような indexing 操作ができない制約上、処理がわかりづらくなっています。 newaxis は numpy 同様、次元1を追加する処理になります。 a = np.ones((3, 4)) # a は (3, 4) の配列 a = a[..., np.newaxis] # a は (3, 4, 1) の配列 > loss関数はbatchsizeに関わらず1つずつ行っているという認識で正しいでしょうか. バッチサイズ分のサンプルに対して一度に計算しています。
sakuramochi

2018/11/12 07:31

丁寧に解説してくださり、本当にありがとうございました。色々実行してみることでtfを用いた方法の理解を深めることができました。 また機会がありましたらよろしくお願い致します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問