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

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

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

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

Q&A

解決済

1回答

544閲覧

深層学習のモデルをkerasのFunctional APIを用いて実装

nataba

総合スコア6

Python

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

0グッド

0クリップ

投稿2023/01/25 12:23

前提

深層学習のモデルをkerasのFunctional APIを用いて実装しようとしています。
皆様の知恵を貸していただけると幸いです。

実現したいこと

モデルを定義したのですが、エラーを吐いてしまい動きません。
画像を2次元convをした後、Flattenで1次元化、その後全結合層で繋いでいければと考えております。

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

ResourceExhaustedError Traceback (most recent call last)
<ipython-input-13-d13a46859390> in <module>
67
68 y = Flatten()(y)
---> 69 y = Dense(4096, activation='relu')(y)
70

ResourceExhaustedError:
OOM when allocating tensor with shape[131072,4096] and type float on /job:localhost/replica:0/task:0/device:GPU:0 by allocator GPU_0_bfc [Op:Add]

該当のソースコード

class_num=5

#InputA
inputA = Input(shape=(inputA_shape[0],inputA_shape[1],1), name="inputA")

x = Conv2D(64,(3,3), strides=(1, 1), padding='same', activation='relu')(inputA)
x = Conv2D(64,(3,3), strides=(1, 1), padding='same', activation='relu')(x)
x = MaxPooling2D((2, 2), padding='valid')(x)

x = Conv2D(128,(3,3), strides=(1, 1), padding='same', activation='relu')(x)
x = Conv2D(128,(3,3), strides=(1, 1), padding='same', activation='relu')(x)
x = MaxPooling2D((2, 2), padding='valid')(x)

x = Conv2D(256,(3,3), strides=(1, 1), padding='same', activation='relu')(x)
x = Conv2D(256,(3,3), strides=(1, 1), padding='same', activation='relu')(x)
x = Conv2D(256,(3,3), strides=(1, 1), padding='same', activation='relu')(x)
x = MaxPooling2D((2, 2), padding='valid')(x)

x = Conv2D(512,(3,3), strides=(1, 1), padding='same', activation='relu')(x)
x = Conv2D(512,(3,3), strides=(1, 1), padding='same', activation='relu')(x)
x = Conv2D(512,(3,3), strides=(1, 1), padding='same', activation='relu')(x)
x = MaxPooling2D((2, 2), padding='valid')(x)

x = Conv2D(512,(3,3), strides=(1, 1), padding='same', activation='relu')(x)
x = Conv2D(512,(3,3), strides=(1, 1), padding='same', activation='relu')(x)
x = Conv2D(512,(3,3), strides=(1, 1), padding='same', activation='relu')(x)
x = MaxPooling2D((2, 2), padding='valid')(x)

x = Flatten()(x)
x = Dense(4096, activation='relu')(x)

#InputB
inputB = Input(shape=(inputB_shape[0],inputB_shape[1],1), name="inputB")
y = Conv2D(64,(3,3), strides=(1, 1), padding='same', activation='relu')(inputB)
y = Conv2D(64,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = MaxPooling2D((2, 2), padding='valid')(y)

y = Conv2D(128,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = Conv2D(128,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = MaxPooling2D((2, 2), padding='valid')(y)

y = Conv2D(256,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = Conv2D(256,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = Conv2D(256,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = Conv2D(256,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = MaxPooling2D((2, 2), padding='valid')(y)

y = Conv2D(512,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = Conv2D(512,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = Conv2D(512,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = Conv2D(512,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = MaxPooling2D((2, 2), padding='valid')(y)

y = Conv2D(512,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = Conv2D(512,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = Conv2D(512,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = Conv2D(512,(3,3), strides=(1, 1), padding='same', activation='relu')(y)
y = MaxPooling2D((2, 2), padding='valid')(y)

y = Flatten()(y)
y = Dense(4096, activation='relu')(y)

#Concatenate
z = concatenate([x, y])
z = Dense(8192, activation='relu')(z)
z = Dense(4096, activation='relu')(z)
z = Dense(1000, activation='relu')(z)
output = Dense(class_num, activation='softmax', name="output")(z)

試したこと

エラーとしての意味(メモリに乗り切れていない)ということは理解できました。
しかし、Flatttenをすることで一次元化し、全結合につながるため、エラーのように[131072,4096]とはならず、[None,4096]になると思っております。
なぜか何回か実行するとモデルが通るときがありますが、いざ実行しようとしてもその際に同様のエラーを吐いてしまいます。

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

Python 3.7.10
keras 2.4.3
tensorflow-gpu 2.3.0

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

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

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

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

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

PondVillege

2023/01/25 13:39

inputA_shapeとinputB_shapeは何ですか? 不明でしたので代わりにどちらもshape = (256, 256)であるとしてモデルをビルドしたところ,Total paramsが402,648,309になりました.
meg_

2023/01/25 14:16

OOMであればバッチサイズを小さくしたら回避できませんか? OSのマネージャーで実際にOOMが起きていたか確認はされましたか?
nataba

2023/01/25 14:30

inputA_shapeとinputB_shapeは512*512を想定しております。 バッチサイズは1で動かすため、最低限のメモリしか食わないはずだと考えております。 そもそも、動かす段階ではなく、モデルのビルドの時点でエラーが起きております。 なぜ、Flatten(None, num)が入力であるのにDenseが(num,4096)になるのか理解できません。。 普通は(None,4096)になるのではないでしょうか?
PondVillege

2023/01/25 15:45 編集

512x512ではTotal paramが1,207,954,677になり,バッチサイズ1でも10GB前後のメモリを必要とします.足りてますか?普通のCNNではこれの1割ぐらいのパラメータ数で実装されることに注意してください. > Flatten(None, num)が入力であるのにDenseが(num,4096)になるのか Flatten()の出力は(None, 131072)になり,Denseの出力が(None, 4096)であるため,重み行列として131072x4096のサイズのものを作成することになります.Denseの出力が(num, 4096)になったのではなく,Denseに必要な重み行列が(131072, 4096)になっているだけの話です.それを用意しようとしてOOMエラーが起きたのでしょう.質問者の認識は間違っておらず,状況はエラー文 ResourceExhaustedError: OOM when allocating tensor with shape[131072,4096] の通りです.
nataba

2023/01/26 02:45

ps_aux_grepさん 丁寧な解説ありがとうございました。 メモリ10GBは足りているのですが、やはり少し重いようです... またモデルを見直し、少しでも軽量化していきたいと思います。
PondVillege

2023/01/26 04:35 編集

現状2つの画像入力に対して1つずつCNNが構築されてますが,2つの画像入力の分析を1つのCNNに纏めることはできます.恐らくこれが1番軽量化できますがいかがでしょうか? また,Flatten()による平滑化ではなく,GlobalAveragePooling2Dによる平滑化の方がパラメータ数が少なくなります. とにかく,件のDenseたった1つで持つパラメータ数536,870,912はいくらなんでも多すぎます.ここだけでResNet-152の10倍あります...
guest

回答1

0

ベストアンサー

エラーに関して

Flattenの出力は(None, 131072)になり,Denseの出力が(None, 4096)であるため,重み行列として131072x4096のサイズのものを作成することになります.Denseの出力が(num, 4096)になったのではなく,Denseに必要な重み行列が(131072, 4096)になっているだけの話です.それを用意しようとしてOOMエラーが起きたのでしょう.質問者の認識は間違っておらず,状況はエラー文ResourceExhaustedError: OOM when allocating tensor with shape[131072,4096]の通りです.

パラメータ削減

現状,パラメータ数が1,207,954,677と非常に多いです.

削減案1

CNNをinputAinputBで共有することで大幅に削減可能です.

Python

1class_num = 5 2 3cnn_layers = [ 4 Conv2D(64, 3, padding = "same", activation = "relu"), 5 Conv2D(64, 3, padding = "same", activation = "relu"), 6 MaxPooling2D(2, padding = "valid"), 7 Conv2D(128, 3, padding = "same", activation = "relu"), 8 Conv2D(128, 3, padding = "same", activation = "relu"), 9 MaxPooling2D(2, padding = "valid"), 10 Conv2D(256, 3, padding = "same", activation = "relu"), 11 Conv2D(256, 3, padding = "same", activation = "relu"), 12 Conv2D(256, 3, padding = "same", activation = "relu"), 13 MaxPooling2D(2, padding = "valid"), 14 Conv2D(512, 3, padding = "same", activation = "relu"), 15 Conv2D(512, 3, padding = "same", activation = "relu"), 16 Conv2D(512, 3, padding = "same", activation = "relu"), 17 MaxPooling2D(2, padding = "valid"), 18 Conv2D(512, 3, padding = "same", activation = "relu"), 19 Conv2D(512, 3, padding = "same", activation = "relu"), 20 Conv2D(512, 3, padding = "same", activation = "relu"), 21 MaxPooling2D(2, padding = "valid"), 22 Flatten(), 23 Dense(4096, activation = "relu"), 24] 25 26def cnn(x): 27 for layer in cnn_layers: 28 x = layer(x) 29 return x 30 31inputA = Input(shape = (512, 512, 1), name = "input_a") 32x = cnn(inputA) 33 34inputB = Input(shape = (512, 512, 1), name = "input_b") 35y = cnn(inputB) 36 37z = Concatenate(axis = -1)([x, y]) 38z = Dense(8192, activation = "relu")(z) 39z = Dense(4096, activation = "relu")(z) 40z = Dense(1000, activation = "relu")(z) 41output = Dense(class_num, activation = "softmax", name = "output")(z) 42 43model = Model([inputA, inputB], output)

これでパラメータ数が656,366,133まで46%程削減できました.

削減案2

最後のFlattenGlobalAveragePooling2Dにするとその次のDenseのパラメータ数を減らせます.

Python

1class_num = 5 2 3cnn_layers = [ 4 Conv2D(64, 3, padding = "same", activation = "relu"), 5 Conv2D(64, 3, padding = "same", activation = "relu"), 6 MaxPooling2D(2, padding = "valid"), 7 Conv2D(128, 3, padding = "same", activation = "relu"), 8 Conv2D(128, 3, padding = "same", activation = "relu"), 9 MaxPooling2D(2, padding = "valid"), 10 Conv2D(256, 3, padding = "same", activation = "relu"), 11 Conv2D(256, 3, padding = "same", activation = "relu"), 12 Conv2D(256, 3, padding = "same", activation = "relu"), 13 MaxPooling2D(2, padding = "valid"), 14 Conv2D(512, 3, padding = "same", activation = "relu"), 15 Conv2D(512, 3, padding = "same", activation = "relu"), 16 Conv2D(512, 3, padding = "same", activation = "relu"), 17 MaxPooling2D(2, padding = "valid"), 18 Conv2D(512, 3, padding = "same", activation = "relu"), 19 Conv2D(512, 3, padding = "same", activation = "relu"), 20 Conv2D(512, 3, padding = "same", activation = "relu"), 21 MaxPooling2D(2, padding = "valid"), 22 GlobalAveragePooling2D(), 23 Dense(4096, activation = "relu"), 24] 25 26def cnn(x): 27 for layer in cnn_layers: 28 x = layer(x) 29 return x 30 31inputA = Input(shape = (512, 512, 1), name = "input_a") 32x = cnn(inputA) 33 34inputB = Input(shape = (512, 512, 1), name = "input_b") 35y = cnn(inputB) 36 37z = Concatenate(axis = -1)([x, y]) 38z = Dense(8192, activation = "relu")(z) 39z = Dense(4096, activation = "relu")(z) 40z = Dense(1000, activation = "relu")(z) 41output = Dense(class_num, activation = "softmax", name = "output")(z) 42 43model = Model([inputA, inputB], output)

これでパラメータ数が121,592,373まで更に81%削減できました.

削減案3

Conv2Dを一部MobileNet同様にDepthwiseConv2Dに置き換えることで削減可能です.また,Dense(8192)を入れるより,Dense(4096)の次にDense(2048)を入れた方が次元数的に一貫性があり,削減に繋がります.

Python

1class_num = 5 2 3cnn_layers = [ 4 Conv2D(64, 3, padding = "same", activation = "relu"), 5 DepthwiseConv2D(3, 2, padding = "same", activation = "relu"), 6 Conv2D(128, 3, padding = "same", activation = "relu"), 7 DepthwiseConv2D(3, 2, padding = "same", activation = "relu"), 8 Conv2D(256, 3, padding = "same", activation = "relu"), 9 DepthwiseConv2D(3, 2, padding = "same", activation = "relu"), 10 Conv2D(256, 3, padding = "same", activation = "relu"), 11 Conv2D(512, 3, padding = "same", activation = "relu"), 12 DepthwiseConv2D(3, 2, padding = "same", activation = "relu"), 13 Conv2D(512, 3, padding = "same", activation = "relu"), 14 Conv2D(512, 3, padding = "same", activation = "relu"), 15 DepthwiseConv2D(3, 2, padding = "same", activation = "relu"), 16 Conv2D(512, 3, padding = "same", activation = "relu"), 17 GlobalAveragePooling2D(), 18 Dense(4096, activation = "relu"), 19] 20 21def cnn(x): 22 for layer in cnn_layers: 23 x = layer(x) 24 return x 25 26inputA = Input(shape = (512, 512, 1), name = "input_a") 27x = cnn(inputA) 28 29inputB = Input(shape = (512, 512, 1), name = "input_b") 30y = cnn(inputB) 31 32z = Concatenate(axis = -1)([x, y]) 33z = Dense(4096, activation = "relu")(z) 34z = Dense(2048, activation = "relu")(z) 35z = Dense(1000, activation = "relu")(z) 36output = Dense(class_num, activation = "softmax", name = "output")(z) 37 38model = Model([inputA, inputB], output)

これでパラメータ数が55,338,485まで更に54%削減できました.当初のモデルと比較して95%もの削減になっています.

削減案4

inputAinputBに大きな特徴の差異があっても良いように,序盤の畳み込みは各個別で行った上で流行を取り入れて次のようにします.Denseが5段あるのは多い気がしますがDropoutで過学習をカバーします.

Python

1from tensorflow.keras.layers import Input, Dense, Flatten, Concatenate, Activation 2from tensorflow.keras.layers import Dropout, BatchNormalization 3from tensorflow.keras.layers import Conv2D, MaxPooling2D, GlobalAveragePooling2D, DepthwiseConv2D 4from tensorflow.keras.models import Model 5from keras.utils import plot_model 6 7class_num = 5 8 9kwargs = { 10 "padding": "same", 11 "kernel_initializer": "he_uniform", 12} 13 14cnn_layers = [ 15 Conv2D(128, 3, **kwargs), 16 BatchNormalization(), 17 Activation("swish"), 18 DepthwiseConv2D(3, 2, **kwargs), 19 BatchNormalization(), 20 Activation("swish"), 21 Conv2D(256, 3, **kwargs), 22 BatchNormalization(), 23 Activation("swish"), 24 DepthwiseConv2D(3, 2, **kwargs), 25 BatchNormalization(), 26 Activation("swish"), 27 Conv2D(256, 3, **kwargs), 28 BatchNormalization(), 29 Activation("swish"), 30 Conv2D(512, 3, **kwargs), 31 BatchNormalization(), 32 Activation("swish"), 33 DepthwiseConv2D(3, 2, **kwargs), 34 BatchNormalization(), 35 Activation("swish"), 36 Conv2D(512, 3, **kwargs), 37 BatchNormalization(), 38 Activation("swish"), 39 Conv2D(512, 3, **kwargs), 40 BatchNormalization(), 41 Activation("swish"), 42 DepthwiseConv2D(3, 2, **kwargs), 43 BatchNormalization(), 44 Activation("swish"), 45 Conv2D(512, 3, **kwargs), 46 BatchNormalization(), 47 Activation("swish"), 48 GlobalAveragePooling2D(), 49 Dense(1024, activation = "swish", kernel_initializer = "he_uniform"), 50] 51 52def cnn(x): 53 x = Conv2D(64, 5, **kwargs)(x) 54 x = BatchNormalization()(x) 55 x = Activation("swish")(x) 56 x = DepthwiseConv2D(4, 2, **kwargs)(x) 57 x = BatchNormalization()(x) 58 x = Activation("swish")(x) 59 for layer in cnn_layers: 60 x = layer(x) 61 return x 62 63inputA = Input(shape = (512, 512, 1), name = "input_a") 64x = cnn(inputA) 65 66inputB = Input(shape = (512, 512, 1), name = "input_b") 67y = cnn(inputB) 68 69z = Concatenate(axis = -1)([x, y]) 70z = Dropout(0.25)(z) 71z = Dense(2048, activation = "swish", kernel_initializer = "he_uniform")(z) 72z = Dropout(0.25)(z) 73z = Dense(1024, activation = "swish", kernel_initializer = "he_uniform")(z) 74z = Dropout(0.25)(z) 75z = Dense(256, activation = "swish", kernel_initializer = "he_uniform")(z) 76output = Dense(class_num, activation = "softmax", name = "output")(z) 77 78model = Model([inputA, inputB], output)

活性化関数を経る回数は質問のモデルと変わらないのにも関わらず,モデルのパラメータ数を16,339,205,すなわち99%近くまで削減できました.これでOOMの心配はないでしょう.

投稿2023/01/26 06:59

編集2023/01/26 07:17
PondVillege

総合スコア1579

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

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

PondVillege

2023/01/26 11:54

運用するのは私じゃないのであまり気にしていませんでしたが,VGG系はパラメータ数の割に精度が出ないので実装は簡単でも推奨はしかねます.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問