У меня есть эта CNN -> двунаправленная архитектура GRU https://github.com/bmcfee/ismir2017_chords, которая используется для прогнозирования последовательности / классификации нескольких активных шагов во времени. Это контролируемая проблема обучения, поэтому у меня есть свои ярлыки. Затем у меня есть другая UNet архитектура, с которой я хочу сделать то же самое, но без использования повторяющихся или плотных слоев. Для того, чтобы вы полностью поняли, что я хочу, я сначала опубликую архитектуру CNN-Bi-GRU:
x = pump.layers()['cqt/mag']
b = BatchNormalization()(x)
c0 = Convolution2D(1, (5, 5), padding='same', activation='relu',
data_format='channels_last')(b)
c1 = Convolution2D(36, (1, int(c0.shape[2])), padding='valid', activation='relu',
data_format='channels_last')(c0)
r1 = Lambda(lambda x: squeeze(x, axis=2))(c1)
rs = Bidirectional(GRU(64,
return_sequences=True))(r1)
# 1: pitch class predictor
pc_p = TimeDistributed(Dense(pump.fields['chord_struct/pitch'].shape[1], activation='sigmoid'),
name='chord_pitch')(rs)
# 2: root predictor
root_p = TimeDistributed(Dense(13, activation='softmax'),
name='chord_root')(rs)
# 3: bass predictor
bass_p = TimeDistributed(Dense(13, activation='softmax'),
name='chord_bass')(rs)
# 4: merge layer
codec = concatenate([rs, pc_p, root_p, bass_p])
p0 = Dense(len(pump['chord_tag'].vocabulary()), activation='softmax',
bias_regularizer= tf.keras.regularizers.l2())
tag = TimeDistributed(p0, name='chord_tag')(codec)
model = Model(x, [tag, pc_p, root_p, bass_p])
Сводка модели дает мне:
Слой (тип) Выходной параметр формы #
Подключен к
===================================== ================================================== ========== cqt / mag (InputLayer) (Нет, Нет, 216, 3) 0
__________________________________________________________________________________________________ batch_normalization_4 (BatchNor (Нет, нет, 216, 3) 12
cqt / mag [0] [0]
__________________________________________________________________________________________________ conv2d_8 (Conv2D) (нет, нет, 216, 1) 76
batch_normalization_4 [0] [0]
________________________________________________________________________________________________ conv2d_9 (Conv2D) (нет, 1 , 36) 7812
conv2d_8 [0] [0]
_____________________________________________________________________________________________ _____ лямбда_4 (лямбда) (нет, нет, 36) 0
conv2d_9 [0] [0]
__________________________________________________________________________________________________ двунаправленный (4) (нет, 128) 38784
лямбда_4 [0] [0]
__________________________________________________________________________________________________ chord_pitch (TimeDistributed) (Нет, Нет, 12) 1548
bidirectional_4 [0] [0]
__________________________________________________________________________________________________ chord_ root (TimeDistributed) (Нет, None, 13) 1677
двунаправленный_ ] [0]
__________________________________________________________________________________________________ chord_bass (TimeDistributed) (нет, отсутствует, 13) 1677
двунаправленный_4 [0] [0]
________________________________________________________________________________________________ concatenate_4 (объединенный) (нет, отсутствует, 166) 0
двунаправленный_ [0] [0]
chord_pitch [ 0] [0]
chord_root [0] [0]
chord_bass [0] [0]
__________________________________________________________________________________________________ chord_tag (TimeDistributed) (нет, нет, 170) 28390
concatenate_4 [0] [0] ]
=================================================== ================================================== == Всего параметров: 79 976 Обучаемых параметров: 79 970 Необучаемых параметров: 6
Входные данные для обеих моделей представляют собой одно и то же частотно-временное представление с формой (партия, Время, Частота, Каналы) для Рекуррентная архитектура и (пакет, каналы, время, частота) для архитектуры UNet. По существу, в рекуррентной архитектуре два уровня CNN сначала используются для извлечения соответствующих признаков, а затем лямбда-уровень отбрасывает частотные интервалы, и результат подается в двунаправленный GRU. Затем три слоя TimeDistributed Dense используются для классификации трех разных вещей, а именно (активных тонов, root и баса), и эти три слоя объединяются с выходом BI-GRU. На последнем этапе к объединенному слою применяется слой TimeDistributed Dense со 170 единицами (количество моих классов). Теперь предположим, что у меня есть UNet архитектура, которая состоит из настройки кодера / декодера. Мой последний UNet Блок перед обычным классификационным слоем имеет форму = (?, 51,?, 216) и называется mresblock8 . Теперь мое решение получить те же прогнозы из моего UNET состоит в следующем:
# 1: pitch class predictor
pc_p = Conv2D((pump.fields['chord_struct/pitch'].shape[1]),1 , 1 ,activation='sigmoid',
data_format='channels_first')(mresblock8)
# 2: root predictor
root_p = Conv2D(13, 1 , 1 ,activation='softmax',
data_format='channels_first')(mresblock8)
# 3: bass predictor
bass_p = Conv2D(13, 1, 1,activation='softmax',
data_format='channels_first')(mresblock8)
display(pc_p,root_p,bass_p)
<tf.Tensor 'conv2d_49/Sigmoid:0' shape=(?, 12, ?, 216) dtype=float32>
<tf.Tensor 'conv2d_53/truediv:0' shape=(?, 13, ?, 216) dtype=float32>
<tf.Tensor 'conv2d_54/truediv:0' shape=(?, 13, ?, 216) dtype=float32>
Кроме того, моя UNET модель имеет data_format = '' channel_first. Поэтому вместо использования TimeDistributed (Dense ...)) я использовал Conv2D с тем же количеством фильтров, что и при необходимости, и использовал размер фильтра (1,1). А затем соединили выходные данные моего последнего UNet слоя (mresblock8) с ранее упомянутыми тремя слоями Conv2D (pc_p, root_p, bass_p):
codec = concatenate([mresblock8,pc_p, root_p, bass_p],axis = 1)
codec
tf.Tensor 'concatenate_20 / concat: 0 'shape = (?, 89,?, 216) dtype = float32>
codec = BatchNormalization(axis=1, scale=False)(codec)
codec
tf.Tensor' batch_normalization_149 / cond / Merge: 0 'shape = (?, 89 ,?, 216) dtype = float32>
Затем вместо применения слоя TimeDistributed Dense к моему сцепленному слою (как рекуррентная архитектура) я применяю слой Conv2D со 170 фильтрами (количество моих классов ) к моему сцепленному слою, т.е.:
p0 = Conv2D(len(pump['chord_tag'].vocabulary()), 1, 1, activation='softmax', data_format = 'channels_first')(codec)
p0
tf.Tensor 'conv2d_58 / truediv: 0' shape = (?, 170,?, 216) dtype = float32>
и на последнем шаге я делаю:
model = Model(x, [p0, pc_p, root_p, bass_p])
Правильно ли мое решение / процесс мышления ?? Мне тоже нужно избавиться от оси частот ? или я могу позволить этому быть там ?? Для ясности, вы можете просто сравнить часть декодера рекуррентной архитектуры с моим предложенным решением / заменой? Кроме того, я должен использовать TimeDistributed (Conv2D (....)) или это нормально, если я просто использую Conv2D здесь ??
Любая помощь будет принята с благодарностью, и если что-то неясно, не стесняйтесь спрашивать меня о разъяснениях.
Приветствия,