Keras Binary Conv2D error "ValueError: logits and labels must have the same shape ((None, 1) vs (None, 4500))"

Keras Binary Conv2D error "ValueError: logits and labels must have the same shape ((None, 1) vs (None, 4500))"

我正在使用 CNN 对 DNA 序列进行二元分类,但无论我如何重组我的 data/network,我都无法让二维二元分类 CNN 工作。我可以对标签进行热编码,并使用 2 个神经元、softmax、具有二元分类损失函数的密集层,但这只能徘徊在 50% 左右的准确率,不要介意激活和损失的结合使用完全错误。

数据是 5000 个 DNA 序列(分成 4500 个 train/500 验证),每个 1000 个核苷酸长,被标记化并且一个热编码为 4x1000 矩阵(A、T、C、G)。标签只是 0/1 来表示它们是否有特定的主题。

# Returns Pandas dataframe of names, sequences, and labels that I generated
totalSeqs = GenSeqs()

# Splitting data and labels in to train/validation sets
x_tr, x_val, y_tr, y_val = train_test_split(totalSeqs.Sequences.tolist(), totalSeqs.Labels.tolist(), test_size = 0.1)
x_tr, x_val, y_tr, y_val = np.array(x_tr), np.array(x_val), np.array(y_tr), np.array(y_val)

#Tokenizing sequences
tk = Tokenizer(num_words=None, char_level=True)
tk.fit_on_texts(x_tr)
tokenTrain = tk.texts_to_sequences(x_tr)

# One hot encoding tokenized sequences
oneHotTrain = OneHot(tokenTrain)

# Resizing to fit Conv2D and making sure there aren't any array/list conflicts
# Saw someone else had this issue, so I went overboard on preventing it
oneHotTrain = np.array(oneHotTrain).reshape(-1, 4500, 1000, 4)
for x in oneHotTrain:
    x = np.array(x)
    for i in x:
        i = np.array(i)
        for j in i:
            j = np.array(j)
print(oneHotTrain.shape)

trainLabels = np.array(y_tr).reshape(-1, 4500, 1)
for x in trainLabels:
    x = np.array(x)
    for i in x:
        i = np.array(i)
        for j in i:
            j = np.array(j)
print(trainLabels.shape)

这全部输出序列的形状 (1, 4500, 1000, 4) 和标签的形状 (1, 4500, 1)。根据我的理解,这些是正确的形状,但很难获得有关标签形状的准确信息。

从这里开始,我创建了 CNN:

model = Sequential()
model.add(Conv2D(32, 4, activation='relu', input_shape = (4500, 1000, 4)))
model.add(MaxPooling2D(2))
model.add(Conv2D(64, 3, activation='relu'))
model.add(MaxPooling2D(2))
model.add(Flatten())
model.add(Dense(64, activation='relu'))
model.add(Dense(1, activation='sigmoid'))

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

model.summary()
          
final = model.fit(oneHotTrain, trainLabels, batch_size = 100, epochs = 3, verbose = 1)

供参考,这是我使用的一个热门编码函数:

def OneHot(data):
    num_classes = 4
    new_data = []

    for x in data:
        class_vector = np.array(x)
        categorical = np.zeros(class_vector.shape+(num_classes,))
        for c in range(1,5,1):
            categorical[np.where(class_vector == c)]=np.array([1 if i == c else 0.0 for i in range(1,5,1)])
        new_data.append(categorical)
        
    return new_data

它的输出结果很好,我用来生成“DNA”的函数只创建了 1000 个字符长的序列,并且仅由 A/T/C/G 组成。我已经通过从 Tokenizer 输出信息、它们的长度等验证了所有这些,无论哪种方式,最后一个热矩阵结果都很好,所以我认为问题不存在,甚至不在一个热函数本身.

我的假设是错误存在于 CNN architecture/parameters 或 data/labels 形状中的某处,但如果我可能遗漏了一些东西。有什么建议吗?

我发现了这个问题,后来变成了一连串的问题...

  1. 第一个 Conv2D 层的 input_size 需要 3 个维度,前 2 个是 length/width,最后一个是深度。因为我处理的是单个文本序列,所以我的输入是 (1000, 4, 1)。如果您正在处理彩色图像,那么我假设您的最终值为 3,以说明颜色通道。
  2. 设置完成后,我收到关于 Conv2D 层的预期 ndim 和负尺寸的错误。首先,我将我的数据重塑为 (4500, 1000, 4, 1),这很有效,我认为应该反映每个数据级别的细分,但还没有完全清楚地理解它。
  3. 最后,负维度的问题来自 Conv2D 和 MaxPooling2D 层中的内核大小。因为我分别将它们设置为 4 和 2,这意味着它们是 (4,4)(2,2),它们试图将 4 和 2 平方维度应用于序列的各个 4x1 部分(因为它们是一个热编码).为了解决这个问题,我只是将第一个 Conv2D 和 MaxPooling2D 层更改为 (4,1)(2,1).

完成所有这些之后,效果很好,我终于得到了不错的结果。这只是我为了理解为什么我的研究 CNN 不起作用而创建的一个玩具示例,所以一旦我能够弄清楚这一点,我就得到了研究 CNN 抽出结果。感觉不错。