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

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

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

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

Q&A

受付中

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

nataba
nataba

総合スコア5

Python

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

1回答

0グッド

0クリップ

131閲覧

投稿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

以下のような質問にはグッドを送りましょう

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

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

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

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

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

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

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

適切な質問に修正を依頼しましょう。

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倍あります...

回答1

1

エラーに関して

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

総合スコア1043

meg_😄を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

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

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

このような回答には修正を依頼しましょう。

回答へのコメント

PondVillege

2023/01/26 11:54

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

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
86.02%

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

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

質問する

関連した質問

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

Python

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