首页 > 解决方案 > Keras Binary Conv2D 错误“ValueError:logits 和标签必须具有相同的形状 ((None, 1) vs (None, 4500))”

问题描述

我正在使用 CNN 对 DNA 序列进行二元分类,但无论我如何重构我的数据/网络,我都无法让二维二元分类 CNN 工作。我可以对标签进行一次热编码,并使用具有二元分类损失函数的 2 个神经元、softmax、密集层,但准确率仅徘徊在 50% 左右,更不用说完全错误地结合使用激活和损失。

数据是 5000 个 DNA 序列(分为 4500 个序列/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 架构/参数或数据/标签形状中的某个位置,但如果我可能遗漏了什么。有什么建议么?

标签: pythonnumpytensorflowkerasconv-neural-network

解决方案


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

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

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


推荐阅读