形状(None,1)和(None,3)不兼容,多类分类。

3

我有一个多类别分类的问题。我想编译我的模型:

feature_layer = DenseFeatures(feature_columns) # A layer that produces a dense Tensor
model = Sequential([

feature_layer,
  Dense(32, activation='relu'),
  Dense(3, activation='softmax')
])

所以我使用分类交叉熵损失:

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

model.fit(train_ds,
          validation_data=val_ds,
          epochs=10)

当然,我知道to_categorical方法,但它不接受BatchDataset作为参数,而train_ds和val_ds却是BatchDataset类型。

请指导我应该如何操作。

更新:我尝试进行以下操作:

def df_to_dataset(df, shuffle=True, batch_size=32): 
  df = df.copy()
  labels = df.pop('class')
  ds = tf.data.Dataset.from_tensor_slices((dict(df), labels))
  if shuffle:
    ds = ds.shuffle(buffer_size=len(df))
    ds = ds.batch(batch_size).map(lambda x, y: (x, tf.one_hot(y, depth=3)))
  return ds

batch_size = 32
train_ds = df_to_dataset(train, batch_size=batch_size)  # error
val_ds = df_to_dataset(val, shuffle=False, batch_size=batch_size)
test_ds = df_to_dataset(test, shuffle=False, batch_size=batch_size)

并且它给了我:

传递给参数'indices'的值具有数据类型字符串,不在允许的值列表中:uint8、int32、int64

我的类别列具有字符串值(它告诉对象是恒星、星系还是类星体,其他是int/float),但我已经弹出了它:

def df_to_dataset(df, shuffle=True, batch_size=32): 
  df = df.copy()
  labels = df.pop('class')
  ds = tf.data.Dataset.from_tensor_slices((dict(df), labels))
  if shuffle:
    ds = ds.shuffle(buffer_size=len(df))
  return ds
df_to_dataset(df)

标签:

<ShuffleDataset shapes: ({objid: (), ra: (), dec: (), u: (), g: (), r: (), i: (), z: (), run: (), rerun: (), camcol: (), field: (), specobjid: (), redshift: (), plate: (), mjd: (), fiberid: ()}, ()), types: ({objid: tf.float64, ra: tf.float64, dec: tf.float64, u: tf.float64, g: tf.float64, r: tf.float64, i: tf.float64, z: tf.float64, run: tf.int64, rerun: tf.int64, camcol: tf.int64, field: tf.int64, specobjid: tf.float64, redshift: tf.float64, plate: tf.int64, mjd: tf.int64, fiberid: tf.int64}, tf.string)>

1
@NicolasGervais 不。 - Elizabeth Grant
1个回答

3

您可以将您的标签转换为独热编码标签,并使用categorical_crossentropy损失函数:

one_hot_encoded_train_ds = train_ds.map(lambda x, y: (x, tf.one_hot(y, depth=3)))
one_hot_encoded_val_ds = val_ds.map(lambda x, y: (x, tf.one_hot(y, depth=3)))

或者将您的损失函数更改为 sparse_categorical_crossentropy,并将标签保留为整数:
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

更新:将您的字符串标签转换为整数:

def df_to_dataset(df, shuffle=True, batch_size=32): 
  df = df.copy()
  labels = df.pop('class')
  dicts = {'STAR': 0, 'GALAXY': 1, 'QSO': 2}
  converted_labels = np.array([dicts[l] for l in labels.to_list()])
  ds = tf.data.Dataset.from_tensor_slices((dict(df), converted_labels))
  if shuffle:
    ds = ds.shuffle(buffer_size=len(df))
  return ds
df_to_dataset(df)

我不太确定我理解你的意思,能否请您举个sparse_categorical_crossentropy的例子? - Elizabeth Grant
非常感谢您的回复!我已经尝试了第二种方法,但它给了我另一个问题:) 您能否请看一下编辑后的问题? - Elizabeth Grant
好的,你只能使用整数值...在将它们输入到模型之前,你需要消除那些字符串或进行编码处理...根据你的输出层,你只有3个标签Dense(3, activation='softmax')。所以我真的不确定你想要做什么。 - AloneTogether
输出层中神经元的数量应该是类别数目,对吧?(如果不是二分类)然后,我们解释每个神经元的值就像对象在特定类中存在的可能性。 - Elizabeth Grant
这些只是浮点/整数特征,告诉我们一个物体是恒星、类星体还是星系,目标只是最后一列 - 'class'。 - Elizabeth Grant
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接