Следующий фрагмент кода использовался для определения архитектуры CNN в keras с бэкэндом tensorflow:
class DownBlock(object):
def __init__(self, prev_layer, num_chann = 16, depthwise_initializer = 'glorot_uniform', kernel_initializer = 'glorot_uniform', bias_initializer = 'zeros', drop_rate = None, spdrop_rate = None, activation = 'relu', pool = True):
self.prev_layer = prev_layer
if pool == True:
self.prev_layer = MaxPooling2D((2, 2)) (self.prev_layer)
self.prev_layer = Conv2D(num_chann, (1, 1), kernel_initializer = kernel_initializer, bias_initializer = bias_initializer) (self.prev_layer)
self.convo = Activation(activation) (self.prev_layer)
self.convo = BatchNormalization() (self.convo)
if not spdrop_rate == None:
self.convo = SpatialDropout2D(spdrop_rate) (self.convo)
if not drop_rate == None:
self.convo = Dropout(drop_rate) (self.convo)
self.convo = Conv2D(num_chann, (1, 1), kernel_initializer = kernel_initializer, bias_initializer = bias_initializer) (self.convo)
self.convo = DepthwiseConv2D((3, 3), depthwise_initializer = depthwise_initializer, bias_initializer = bias_initializer, padding = 'same') (self.convo)
self.convo = Conv2D(num_chann, (1, 1), kernel_initializer = kernel_initializer, bias_initializer = bias_initializer) (self.convo)
self.convo = Activation(activation) (self.convo)
self.convo = BatchNormalization() (self.convo)
if not spdrop_rate == None:
self.convo = SpatialDropout2D(spdrop_rate) (self.convo)
if not drop_rate == None:
self.convo = Dropout(drop_rate) (self.convo)
self.convo = DepthwiseConv2D((3, 3), depthwise_initializer = depthwise_initializer, bias_initializer = bias_initializer, padding = 'same') (self.convo)
self.convo = Conv2D(num_chann, (1, 1), kernel_initializer = kernel_initializer, bias_initializer = bias_initializer) (self.convo)
self.convo = Add([self.prev_layer, self.convo])
def get(self):
return self.convo
class UpBlock(object):
def __init__(self, prev_layer, bridge_layer, num_chann = 16, depthwise_initializer = 'glorot_uniform', kernel_initializer = 'glorot_uniform', bias_initializer = 'zeros', drop_rate = None, spdrop_rate = None, activation = 'relu', up = True):
self.prev_layer = prev_layer
self.bridge_layer = bridge_layer
self.convo = Activation(activation) (self.prev_layer)
self.convo = BatchNormalization() (self.convo)
if not spdrop_rate == None:
self.convo = SpatialDropout2D(spdrop_rate) (self.convo)
if not drop_rate == None:
self.convo = Dropout(drop_rate) (self.convo)
self.convo = Conv2D(num_chann, (1, 1), kernel_initializer = kernel_initializer, bias_initializer = bias_initializer) (self.convo)
self.convo = DepthwiseConv2D((3, 3), depthwise_initializer = depthwise_initializer, bias_initializer = bias_initializer, padding = 'same') (self.convo)
self.convo = Conv2D(num_chann, (1, 1), kernel_initializer = kernel_initializer, bias_initializer = bias_initializer) (self.convo)
self.convo = Activation(activation) (self.convo)
self.convo = BatchNormalization() (self.convo)
if not spdrop_rate == None:
self.convo = SpatialDropout2D(spdrop_rate) (self.convo)
if not drop_rate == None:
self.convo = Dropout(drop_rate) (self.convo)
self.convo = DepthwiseConv2D((3, 3), depthwise_initializer = depthwise_initializer, bias_initializer = bias_initializer, padding = 'same') (self.convo)
self.convo = Conv2D(num_chann, (1, 1), kernel_initializer = kernel_initializer, bias_initializer = bias_initializer) (self.convo)
self.convo = Add([self.prev_layer, self.convo])
if up == True:
self.convo = Conv2D(num_chann/2, (1, 1), kernel_initializer = kernel_initializer, bias_initializer = bias_initializer) (self.convo)
self.convo = Conv2DTranspose(num_chann/2, (2, 2), strides = (2, 2), kernel_initializer = kernel_initializer, bias_initializer = bias_initializer, padding = 'same') (self.convo)
self.convo = Add([self.bridge_layer, self.convo])
def get(self):
return self.convo
inputs = Input((IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS))
s = Lambda(lambda x: x / 255) (inputs)
s = Conv2D(8, (1, 1)) (s)
d1 = DownBlock(s, num_chann = 16, drop_rate = 0.1)
d2 = DownBlock(d1.get(), num_chann = 32, drop_rate = 0.1)
d3 = DownBlock(d2.get(), num_chann = 64, drop_rate = 0.1)
d4 = DownBlock(d3.get(), num_chann = 128, drop_rate = 0.1)
d5 = DownBlock(d4.get(), num_chann = 256, drop_rate = 0.1)
m = DownBlock(d5.get(), num_chann = 512, drop_rate = 0.1)
u5 = UpBlock(m.get(), d4.get(), num_chann = 256, drop_rate = 0.1)
u4 = UpBlock(u5.get(), d3.get(), num_chann = 128, drop_rate = 0.1)
u3 = UpBlock(u4.get(), d2.get(), num_chann = 64, drop_rate = 0.1)
u2 = UpBlock(u3.get(), d1.get(), num_chann = 32, drop_rate = 0.1)
u1 = UpBlock(u2.get(), s, num_chann = 16, drop_rate = 0.1)
final = Conv2D(1, (1, 1)) (u1.get())
# final = SpatialDropout2D(0.1) (final)
final = Dropout(0.1) (final)
final = BatchNormalization() (final)
outputs = Activation("sigmoid") (final)
model = Model(inputs = [inputs], outputs = [outputs])
При выполнении внутри блокнота Jupyter создается следующая трассировка стека:
TypeError Traceback (most recent call last)
<ipython-input-31-f23b70d0be6d> in <module>()
79 s = Conv2D(8, (1, 1)) (s)
80
---> 81 d1 = DownBlock(s, num_chann = 16, drop_rate = 0.1)
82
83 d2 = DownBlock(d1.get(), num_chann = 32, drop_rate = 0.1)
<ipython-input-31-f23b70d0be6d> in __init__(self, prev_layer, num_chann, depthwise_initializer, kernel_initializer, bias_initializer, drop_rate, spdrop_rate, activation, pool)
29 self.convo = Conv2D(num_chann, (1, 1), kernel_initializer = kernel_initializer, bias_initializer = bias_initializer) (self.convo)
30
---> 31 self.convo = Add([self.prev_layer, self.convo])
32
33 def get(self):
TypeError: __init__() takes 1 positional argument but 2 were given
Последняя строчка в след...
TypeError: __init__() takes 1 positional argument but 2 were given
... говорит о передаче двух позиционных аргументов первому вызову UpBlock(), тогда как я явно передал один-
d1 = DownBlock(s, num_chann = 16, drop_rate = 0.1)
Где другой позиционный аргумент и почему я получаю эту ошибку, если ее нет?
Хотя ошибка возникает из-за вашего вызова конструктора DownBlock
, Python также отмечает, что обратная трассировка ошибки — это (most recent call last)
. Эта ошибка относится к передаче двух аргументов конструктору Add
. Python говорит вам, что ваш вызов Add()
имеет слишком много аргументов.
Хитрость здесь, хотя кажется, что вы предоставляете только один аргумент списка для Add()
, заключается в том, что все функции конструктора класса Python получают неявный аргумент self
в качестве своего первого позиционного аргумента. См. документы Python.
из комментариев:
При использовании функционального API в Keras сначала необходимо создать объекты слоя, как в a = Add()
, а затем добавить слой в граф вычислений, вызвав результирующий объект, как в:
out = a([input1, input2, ...])
или в вашем исходном примере:
self.convo = Add()([self.prev_layer, self.convo])
Этот ответ в основном правильный, но его можно расширить следующим образом: при использовании функционального API в Keras сначала необходимо создать объекты слоя, как в a = Add()
, а затем добавить слой в граф вычислений, вызвав результирующий объект, как в out = a([input1, input2, ...])
.
Я обновлю, чтобы включить это более подробное объяснение
Итак, @quiet_laika это означает, что Add() не принимает никаких позиционных аргументов, кроме неявного «я», если я правильно понимаю?
@Asef, это в основном правильно. Я немного покопался здесь: github.com/keras-team/keras/blob/master/keras/layers/merge.py и, чтобы быть на 100% точным, похоже, что Add()
наследует свой __init__()
метод от _Merge
, который принимает некоторые необязательные аргументы ключевого слова. Это означает, что некоторые экземпляры _Merge
могут иметь аргументы, но похоже, что Add
специально их не принимает.
Исправить стену кода очень сложно. Не могли бы вы попытаться изолировать вашу проблему немного лучше? См. Как создать минимальный, полный и проверяемый пример для получения дополнительной информации.