我目前正在使用 FCN,并希望使我的代碼更方便。我當前的模型或多或少是硬編碼的,分別在編碼器和解碼器路徑中有三層。我的目標是定義一個包含每個階段過濾器數量的串列,并相應地自動創建模型。
我使用兩個自定義層(編碼器和解碼器)設定我的模型。FullyConvolutionalNetwork 類(tf.keras.models.Model 的子類)使用這些自定義層來構建最終模型。
# define the layers needed
class EncoderBlock(layers.Layer):
def __init__(self,
num_conv: int,
kernel: int = None,
stride: int = None,
activation: str = "relu",
padding: str = "same",
name: str = "Encoder1D",
data_format: str = "channels_last",
*args, **kwargs):
super(EncoderBlock, self).__init__(name=name, *args, **kwargs)
if kernel is None:
kernel = 3
if stride is None:
stride = 1
self.conv = Conv1D(num_conv, kernel, strides=stride, activation=activation,
padding=padding, data_format=data_format)
self.pool = MaxPool1D(2, strides=2, padding=padding, data_format=data_format)
@tf.function
def call(self, input_tensor, training=False):
x = self.conv(input_tensor)
return self.pool(x)
class DecoderBlock(layers.Layer):
def __init__(self,
num_conv: int,
kernel: int = None,
stride: int = None,
activation: str = "relu",
padding: str = "same",
name: str = "Decoder1D",
data_format: str = "channels_last",
*args, **kwargs):
super(DecoderBlock, self).__init__(name=name, *args, **kwargs)
if kernel is None:
kernel = 3
if stride is None:
stride = 1
self.conv = Conv1D(num_conv, kernel, strides=stride, activation=activation,
padding=padding, data_format=data_format)
self.pool = Conv1DTranspose(num_conv, 3, strides=2, padding=padding, data_format=data_format)
@tf.function
def call(self, input_tensor, training=False):
x = self.conv(input_tensor)
return self.pool(x)
# now define the model
class FullyConvolutionalNetwork(Model, ABC):
def __init__(self,
num_filter: list,
name: str = "FullyConvolutionalNetwork",
activation: str = "relu",
alpha: float = None,
data_format: str = "channels_last",
*args, **kwargs):
super(FullyConvolutionalNetwork, self).__init__(name=name, *args, **kwargs)
# encoder layers
self.encoder1 = EncoderBlock(num_filter[0], name="enc1", data_format=data_format,
activation=activation)
self.encoder2 = EncoderBlock(num_filter[1], name="enc2", data_format=data_format,
activation=activation)
self.encoder3 = EncoderBlock(num_filter[2], name="enc3", data_format=data_format,
activation=activation)
# decoder layers
self.decoder1 = DecoderBlock(num_filter[2], name="dec1", data_format=data_format,
activation=activation)
self.decoder2 = DecoderBlock(num_filter[1], name="dec2", data_format=data_format,
activation=activation)
self.decoder3 = DecoderBlock(num_filter[0], name="dec3", data_format=data_format,
activation=activation)
# output section
self.conv1x1 = Conv1D(1, 1, strides=1, padding='same', name="1x1", data_format=data_format)
self.flatten = Flatten() # remove channel dimension!
@tf.function
def call(self, input_tensor, training=False):
x = self.encoder1(input_tensor)
x = self.encoder2(x)
x = self.encoder3(x)
x = self.decoder1(x)
x = self.decoder2(x)
x = self.decoder3(x)
x = self.conv1x1(x)
return self.flatten(x)
my_model = FullyConvolutionalNetwork(num_filters=[8, 16, 32])
my_model.build(input_shape=[None, 512, 10])
我現在想讓我的模型深度可變。我已經通過向 self 寫入盡可能多的層來實作可變數量的類屬性。dict我需要在模型建構式中,如下所示:
# define symmetric encoder and decoder blocks
for i, f in enumerate(num_filter):
self.__dict__[f"encoder{i}"] = EncoderBlock(f, activation=activation, alpha=alpha, name=f"enc{i}", data_format=data_format)
self.__dict__[f"decoder{i}"] = DecoderBlock(f, activation=activation, alpha=alpha, name=f"dec{i}", data_format=data_format)
這在理論上應該替換行 self.encoder1 = ..., self.encoder2 = ... 。但是,我現在無法從我的 dict 構建模型。我的理解是所有層都存盤為模型。dict,這樣我應該能夠在回圈中添加我的圖層:
@tf.function
def call(self, input_tensor, training=False):
for count, layer in enumerate([self.__dict__[f"encoder{i}"] for i, _ in enumerate(num_filter)]):
if count == 0:
x = layer(input_tensor)
else:
x = layer(x)
# and same for the decoder layers...
# output section
x = self.conv1x1(x)
return self.flatten(x)
我仔細檢查了所有圖層都在字典中可用。但它們沒有添加到我的模型中,即 model.summary() 僅顯示最后兩層(1x1 卷積和展平)。當我從我的字典中手動添加圖層時也是如此:
@tf.function
def call(self, input_tensor, training=False):
x = self.__dict__["encoder0"](input_tensor)
x = self.__dict__["encoder1"](x)
...
你對我的嘗試在哪里以及為什么失敗有什么建議嗎?提前致謝!
uj5u.com熱心網友回復:
使用setattr(self, key, value)而不是手動撰寫所有內容來self.__dict__做到這一點!您只需要注意圖層的順序,因為它們似乎按時間順序排列在def __init__(self, ...).
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/409764.html
標籤:
