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

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

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

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

CNN (Convolutional Neural Network)

CNN (Convolutional Neural Network)は、全結合層のみではなく畳み込み層とプーリング層で構成されるニューラルネットワークです。画像認識において優れた性能を持ち、畳み込みニューラルネットワークとも呼ばれています。

NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python 3.x

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

Q&A

解決済

1回答

775閲覧

model.fitに二つのジェネレーターを入力するか変換を行う項目と行わない項目を作りたい

semisemi

総合スコア18

Keras

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

CNN (Convolutional Neural Network)

CNN (Convolutional Neural Network)は、全結合層のみではなく畳み込み層とプーリング層で構成されるニューラルネットワークです。画像認識において優れた性能を持ち、畳み込みニューラルネットワークとも呼ばれています。

NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python 3.x

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

0グッド

0クリップ

投稿2022/11/03 09:31

編集2022/11/07 06:53

前提

三項目の分類をしようとしており、三項目の内一つだけ正規化し他の二項目はいろいろな変換処理をできるようにしたいです。

実現したいこと

・ImageDatageneratorの変換を行う項目と行わない項目を作る

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

追記していただいたy[i].argmax()でエラーなく動くようになりました。
しかし、画像にあるよう学習の進行度を表すゲージが表示されておらず1エポックも終わらない状態になってしまいました。

イメージ説明

該当のソースコード

python

1import numpy as np 2from PIL import Image 3import tensorflow as tf 4import time 5import matplotlib.pyplot as plt 6# import os 7# os.environ["CUDA_VISIBLE_DEVICES"] = "-1" 8from tensorflow.keras.models import Model 9from tensorflow.keras.preprocessing import image 10from tensorflow.keras.preprocessing.image import ImageDataGenerator 11from tensorflow.keras.optimizers import Adam 12from tensorflow.keras.callbacks import EarlyStopping, LearningRateScheduler,ReduceLROnPlateau, ModelCheckpoint 13 14Image.MAX_IMAGE_PIXELS = None 15 16#-------切り取り定義------- 17def kiritori(img): 18 img_array=np.array(img,dtype='int16') #(50行,83列,3次元)の3次元配列 19 a=np.split(img_array,img.height/50) 20 img_data=np.split(a[0],img.width/50,axis=1)#stackする土台づくり 21 for i in range(len(a)-1): 22 img_data=np.vstack([img_data,np.split(a[i+1],img.width/50,axis=1)]) 23 24 return img_data 25 26#-------切り取り処理(トレーニングデータ)------- 27x_train=kiritori(Image.open('3Gatu_Data/DJI_0708.JPG'))#(#(1200,100,100,3) 28 29train_label=np.loadtxt(fname='label/3Gatu_708_50.csv',delimiter=',',dtype='int16')#(30, 40) 30train_label=np.reshape(train_label,(train_label.size)) #(1200) 31 32a_train_data = x_train[np.where(train_label==0)] 33b_train_data =x_train[np.where(train_label==1)] 34c_train_data =x_train[np.where(train_label==2)] 35 36 37#-------データをまとめる------- 38x_train=a_train_data 39x_train=np.vstack([x_train,b_train_data]) 40x_train=np.vstack([x_train,c_train_data]) 41 42#-------テストデータ処理------- 43val_test=kiritori(Image.open('3Gatu_Data/mai_0330_2022.JPG')) 44 45test_label=np.loadtxt(fname='label/3Gatu_mai_50.csv',delimiter=',',dtype='int16')#(30,40) 46test_label=np.reshape(test_label,(test_label.size)) #(1200) 47 48a_test_data = val_test[np.where(test_label==0)] 49b_test_data = val_test[np.where(test_label==1)] 50c_test_data = val_test[np.where(test_label==2)] 51 52val_test = a_test_data 53val_test = np.vstack([val_test,b_test_data]) 54val_test = np.vstack([val_test,c_test_data]) 55 56y_train=np.full((a_train_data.shape[0],1),0) 57y_train=np.vstack([y_train,np.full((b_train_data.shape[0],1),[1])]) 58y_train=np.vstack([y_train,np.full((c_train_data.shape[0],1),[2])]) 59 60y_test=np.full((a_test_data.shape[0],1),[0]) 61y_test=np.vstack([y_test,np.full((b_test_data.shape[0],1),[1])]) 62y_test=np.vstack([y_test,np.full((c_test_data.shape[0],1),[2])]) 63 64from tensorflow.keras.utils import to_categorical 65y_train = to_categorical(y_train,3) 66y_test = to_categorical(y_test,3) 67 68## 変換処理 69x_datagen_base = ImageDataGenerator( 70 rescale = 1 / 255, 71 dtype = np.float64 72) 73 74 75x_datagen_partial = image.ImageDataGenerator( 76 rescale = 1./255, 77 rotation_range = 180, 78 fill_mode="constant", 79 vertical_flip = True, 80 # brightness_range = [0.7, 1.117], 81 horizontal_flip = True, 82 dtype = np.float64 83 ) 84 85x_train_generator = x_datagen_base.flow(x_train, y_train, batch_size= 13) 86 87val_datagen = image.ImageDataGenerator(rescale=1./ 255) 88val_test_generator = val_datagen.flow(val_test, y_test,batch_size = 13) 89 90def myflow(gen: ImageDataGenerator): 91 for x, y in gen: 92 for i, _x in enumerate(x): 93 if y[i].argmax() != 0: 94 x[i] = x_datagen_base.apply_transform( 95 _x, 96 x_datagen_partial.get_random_transform(_x.shape) 97 ) 98 yield x, y 99 100 101 102 103from tensorflow.python.keras.models import Sequential 104model = Sequential() 105 106from tensorflow.python.keras.layers import Conv2D 107from tensorflow.keras.layers import PReLU 108from tensorflow.python.keras.layers import BatchNormalization 109model.add( #畳み込み 110 Conv2D( 111 filters=64, #出力 112 input_shape=(50,50,3), 113 kernel_size=(3,3), #フィルタサイズ 114 strides=(1,1), 115 padding='valid', 116 kernel_initializer = "he_uniform" 117)) 118 119model.add(BatchNormalization()) 120model.add(PReLU(alpha_initializer=tf.constant_initializer(0.25))) 121 122 123from tensorflow.python.keras.layers import MaxPooling2D 124from tensorflow.python.keras.layers import Dropout 125 126 127model.add(MaxPooling2D(pool_size=(2,2))) #マックスプーリング 128 #ドロップアウト 129 130#追加畳み込み 131model.add( 132 Conv2D( 133 filters =128, 134 kernel_size = (3,3), 135 strides = (1,1), 136 padding = 'valid', 137 kernel_initializer = "he_uniform", 138 )) 139 140model.add(BatchNormalization()) 141model.add(PReLU(alpha_initializer=tf.constant_initializer(0.25))) 142 143 144model.add(MaxPooling2D(pool_size=(2,2))) 145 146 147#追加畳み込み 148model.add( 149 Conv2D( 150 filters = 256, 151 kernel_size = (3,3), 152 strides = (1,1), 153 padding = 'valid', 154 kernel_initializer = "he_uniform", 155 )) 156 157model.add(BatchNormalization()) 158model.add(PReLU(alpha_initializer=tf.constant_initializer(0.25))) 159 160model.add(MaxPooling2D(pool_size=(2,2))) 161 162 163#追加畳み込み 164model.add( 165 Conv2D( 166 filters = 512, 167 kernel_size = (3,3), 168 strides = (1,1), 169 padding = 'valid', 170 kernel_initializer = "he_uniform", 171 )) 172 173model.add(BatchNormalization()) 174model.add(PReLU(alpha_initializer=tf.constant_initializer(0.25))) 175 176model.add(MaxPooling2D(pool_size=(2,2))) 177 178 179from tensorflow.python.keras.layers import Flatten 180model.add(Flatten()) #2次元配列に 181 182from tensorflow.python.keras.layers import Dense 183 184model.add(Dense(units=1536)) 185 186model.add(PReLU(alpha_initializer=tf.constant_initializer(0.25))) 187 188model.add(Dropout(0.5)) 189model.add(Dense(units=3,activation='softmax',name="f3")) 190 191model.summary(); 192 193reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=10, min_lr=0.0001) 194 195model.compile( 196 optimizer = Adam(), #自動で学習率が設定される 197 loss = 'categorical_crossentropy', #多分類のときにしていできる交差エントロピー 198 metrics = ['accuracy'] 199) 200 201history_model = model.fit( 202 myflow(x_train_generator), 203 epochs = 10, 204 validation_data = val_test_generator, 205 validation_steps = None, 206 shuffle = True, 207 callbacks = [reduce_lr] 208 ) 209 210## モデルの保存 211model_json_str = model.to_json() 212open('Output_file/9/cnn_model_3Gatu_50_500.json', 'w').write(model_json_str) 213model.save_weights('Output_file/9/mnist_mlp_3Gatu_50_500_weights2.h5'); 214 215score = model.evaluate( val_test_generator, verbose=0) 216print('Test loss :', score[0]) 217print('Test accuracy :', score[1]) 218 219 220loss = history_model.history['loss'] #訓練データの誤差 221val_loss = history_model.history['val_loss'] #テストデータ誤差 222accuracy = history_model.history['accuracy'] #訓練データの誤差 223val_accuracy = history_model.history['val_accuracy'] #テストデータ誤差

試したこと

myflowの適用をしてみました。

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

windows11(64bit)
anacondaを使用
python 3.8.13
TensorFlow 2.3
Spyder 5.3.3を利用

トレーニングデータはもっとあるのですが、省略させていただきました。

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

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

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

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

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

guest

回答1

0

ベストアンサー

model.fit()に2つ渡すことはできないので,代わりにランダムにx_train_generatorx_train_generator2のいずれかを適用したものを返す,というように作ることは可能です.が,ジェネレータが交互に同じデータを返すこともあるので,これを避けるため交互に返さないように書く必要があり非常に大変です.項目別に選びたいという後述の要件から,ジェネレータに渡すデータを切り分けようとしていることが伺えますが,model.fit()に渡すからには項目をシャッフルしたいですし切り分けて混ぜる,というのは非常にめんどくさいです.

なので,3項目の内1つだけ正規化し他の2項目はいろいろな変換処理をできるようにすることを推奨します.そのためにyieldを使って次のようにジェネレータを定義します.

ここで大事なのは,「yieldで1バッチ分のデータを返す」ということです.これさえ叶えばジェネレータの中身はなんだって良いです.したがって

Python

1def myflow(gen: ImageDataGenerator): 2 for x, y in gen: 3 yield x, y

と書けば何もしないデータジェネレータの完成です.

例えば,ラベルIDが0以外のものy[i] != 0を変換できるように書くと,次のようになります.

Python

1def myflow(gen: ImageDataGenerator): 2 for x, y in gen: 3 for i, _x in enumerate(x): 4 if y[i] != 0: 5 x[i] = x_datagen_base.apply_transform( 6 _x, 7 x_datagen_partial.get_random_transform(_x.shape) 8 ) 9 yield x, y

x_datagen_baseは正規化のみ,x_datagen_partialは色々な変換処理を組み込みました.
必ずしもx_datagen_partialである必要はなく,1枚の画像変換ができる処理であればなんでも良いです.

その際は独自の変換関数image_transform()などを作成してx[i] = data_transform(x[i])と書くことができます.ImageDataGeneratorに無いような,Random ErasingやCutout,Grid MaskなどさまざまなData Augmentation手法の適用が可能です.

Python

1import tensorflow as tf 2from tensorflow.python import keras 3from keras.preprocessing.image import ImageDataGenerator 4import numpy as np 5 6N, W, H, C = 64, 32, 32, 3 7x_train = np.random.randint(0, 255, N * W * H * C).reshape(N, W, H, C) 8y_train = np.random.randint(0, 3, N).reshape(N, -1) 9 10x_datagen_base = ImageDataGenerator( 11 rescale = 1 / 255, 12 dtype = np.float64 13) 14 15x_datagen_partial = ImageDataGenerator( 16 rotation_range = 180, 17 fill_mode = "constant", 18 vertical_flip = True, 19 #brightness_range = [0.7, 1.117], 20 horizontal_flip = True, 21 dtype = np.float64 22) 23 24def myflow(gen: ImageDataGenerator): 25 for x, y in gen: 26 for i, _x in enumerate(x): 27 if y[i] != 0: 28 x[i] = x_datagen_base.apply_transform( 29 _x, 30 x_datagen_partial.get_random_transform(_x.shape) 31 ) 32 yield x, y 33 34batch_size = 8 35train = x_datagen_base.flow(x_train, y_train, batch_size = batch_size) 36 37model.fit( 38 myflow(train), 39 batch_size = 8, 40 epochs = 50, 41 validation_data = (x_valid, y_valid), 42 steps_per_epoch = int(x_train.shape[0] / batch_size) 43)

brightness_range = [0.7, 1.117],が入っていると変換後全部0になるのでコメントアウトしておきました.適宜変更してください.
最終的にmodel.fit()にはジェネレータmyflow(train)を渡してください.同様に,validationも自作ジェネレータmyflow()を通してmodel.fit()に渡すと良いでしょう.

詳しい扱い方は次の公式サイトを確認してください.
TensorFlow v2.10.0 - tf.keras.preprocessing.image.ImageDataGenerator

追記

予測値y[i]をOne-Hot Encodingしている場合,y[i].argmax()でラベル値を取得する必要がある.

Python

1import tensorflow as tf 2from tensorflow.python import keras 3from keras.preprocessing.image import ImageDataGenerator 4from keras.utils import to_categorical 5import numpy as np 6 7N, W, H, C = 64, 32, 32, 3 8x_train = np.random.randint(0, 255, N * W * H * C).reshape(N, W, H, C) 9y_train = np.random.randint(0, 3, N).reshape(N, -1) 10y_train = to_categorical(y_train) 11 12x_datagen_base = ImageDataGenerator( 13 rescale = 1 / 255, 14 dtype = np.float64 15) 16 17x_datagen_partial = ImageDataGenerator( 18 rotation_range = 180, 19 fill_mode = "constant", 20 vertical_flip = True, 21 #brightness_range = [0.7, 1.117], 22 horizontal_flip = True, 23 dtype = np.float64 24) 25 26def myflow(gen: ImageDataGenerator): 27 for x, y in gen: 28 for i, _x in enumerate(x): 29 if y[i].argmax() != 0: # labelが0以外であれば変換処理 30 x[i] = x_datagen_base.apply_transform( 31 _x, 32 x_datagen_partial.get_random_transform(_x.shape) 33 ) 34 yield x, y 35 36batch_size = 8 37train = x_datagen_base.flow(x_train, y_train, batch_size = batch_size) 38 39model.fit( 40 myflow(train), 41 batch_size = 8, 42 epochs = 50, 43 validation_data = (x_valid, y_valid), 44 steps_per_epoch = int(x_train.shape[0] / batch_size) 45)

投稿2022/11/03 10:37

編集2022/11/07 06:54
PondVillege

総合スコア1579

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

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

semisemi

2022/11/04 12:09

回答ありがとうございます。 回答いただいたmyflowを適用してみたところmodel.fitで、 ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() が出ました。 model.fitには、質問にある該当ソースコードのx_train_generatorのみmyflowを適用しvalidation_dataには正規化のみしたかったため通常の正規化のみ行うジェネレータを適用しています。 validationにもmyflowを少し変えて正規化のみ行うようにするのでしょうか?
PondVillege

2022/11/06 11:35 編集

エラー全文を示していただいていないので不明ですがy[i] != 0で出たもので間違い無いでしょうか. ここのコメント欄でコードブロックが使えないので,質問を編集いただいて,書いてみたコードとエラー全文を追記いただけると助かります. 多分,y[i].argmax() != 0とかの比較文が正しく動作するものと思われます. 回答に書いたコードは簡単のため,One-Hot Encodingしていないので動いていますた, もしそちらでOne-Hot Encodingされているのであればそれ用の判定を行う必要があります. validationには正規化のみ適用したいのであれば,全然それで構いません.
semisemi

2022/11/07 06:24

質問に使用しているコードの追記をいたしましたので読んでいただけると幸いです。
PondVillege

2022/11/07 07:00 編集

model.fitにキーワード引数steps_per_epochを渡してください.値は画像サイズ / バッチサイズを与えてください.回答を編集して書き加えておきましたので参照願います.
semisemi

2022/11/07 08:02 編集

ありがとうございます。無事動くようになったのですが質問させていただきたいです。 今までは、変換された画像を下記のコードで確認していたのですが gen = x_train_datagen.flow(x_train, batch_size= 2) for i in range(4): batches = gen.next() plt.figure(i) # 4次元から3次元データにし、配列から画像にする。 gen_img = array_to_img(batches[0]) plt.imshow(gen_img) plt.show() myflowを適用させた場合の画像を確認する方法はあるでしょうか? 結果が芳しくなかったので確認したいです。 何度もすみません。
PondVillege

2022/11/07 10:22 編集

gen = myflow(x_train_datagen.flow(x_train, y_train, batch_size= 2)) for i in range(4):  batches = next(gen)  plt.figure(i)  gen_img = array_to_img(batches[0])  plt.imshow(gen_img)  plt.show() で良いと思います.kerasのジェネレータ gen は gen.next() や next(gen) が動かせますが,簡易に自作した今回は後者の next(gen) しか使えないので,このような形になるはずです.(コード記述に当たって全角スペースインデントにしています,注意してください) ランダムに変換するので,実際にネットワークに与えたものにならない可能性が高いこと注意してください.
semisemi

2022/11/07 11:12

ありがとうございます! 無事画像を確認することはできたのですが、確認したところラベル0に関しては正規化のみできていそうでした。しかし、ラベル1と2のfill_mode = "constant"の部分のみ反映されていないようでした。 fill_mode については変更の方法はございますか? また、brightness_rangeに関しましてはx_datagen_partialに入っていても0にはならず変化がない状態でした。 こちらを変更したい場合はimagedatageneratorでは難しいのでしょうか?
PondVillege

2022/11/07 11:30 編集

そうですね,apply_transformに出来ることが限られているので自作関数の利用を推奨します.一応ちょっとめんどくさいですがImageDataGeneratorでも書けます
semisemi

2022/11/07 13:43 編集

すみません。 私が、fill_mode="constant"に相当する処理を実装できそうにないためできればImageDataGeneratorで書く方法を教えていただきたいです。
PondVillege

2022/11/07 14:55

動くかわかりませんが,現状の x[i] = x_datagen_base.apply_transform(_x, x_datagen_partial.get_random_transform(_x.shape)) の代わりに x[i] = x_datagen_partial.random_transform(x[i]) と書いてしまうのはどうでしょう.正規化のための統計が取れてないので使えない変換がある気がします.
semisemi

2022/11/08 06:32

ありがとうございます。 x[i] = x_datagen_partial.random_transform(x[i])と書くことで、ラベル1,2の輝度値や黒で補完するなどの変換はできたのですがラベル0,1,2の正規化ができていないようでした。 flowする前にx_train = x_train/255.も試したのですができませんでした。
PondVillege

2022/11/08 06:53

じゃあmyflowの中で x[i] = x_datagen_partial.random_transform(x[i]) / 255 にしたらいいんじゃないでしょうか
semisemi

2022/11/08 06:59

ありがとうございます! 無事したかったことができました。 また、何度も質問させていただいた際に丁寧かつ迅速な回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問