如何为 softmax 分类指定 onehot 标签数组的形状?

Posted

技术标签:

【中文标题】如何为 softmax 分类指定 onehot 标签数组的形状?【英文标题】:How to specify shape of onehot label array for softmax classification? 【发布时间】:2019-07-24 02:18:39 【问题描述】:

我正在做一个简单的图像分类,我希望将图像放入 16 个类别之一。我的标签是 16 长的单热 ndarray。

当我调用 fit() 时,很明显模型需要 16 个样本,而不是由一个大小为 16 的数组组成的标签。我不知道我需要什么魔法告诉 Keras 我在喂它什么。

代码和喷射如下。尝试忽略传递给 Dense() 的无关大小,这只是一个玩具项目。我有意一次通过一批样品。

def main():
FLAGS, unparsed = ut.parseArgs()
print(FLAGS)
# TEST_DATA_PATH      = FLAGS.test_data_path
SAMPLE_FILE = FLAGS.train_data_path + FLAGS.sample
IMG_SHAPE   = ut.get_image_shape(filename=SAMPLE_FILE, scale=FLAGS.scale, show=FLAGS.show)
img = ut.read_image(filename=SAMPLE_FILE, show=False)
img = np.array(img)
IMG_SHAPE=img.shape
(x_train, y_train), (x_test, y_test)=load_data(numclasses=FLAGS.numclasses, train_path=FLAGS.train_data_path, sample_file=SAMPLE_FILE, onehot=True)


model = tf.keras.models.Sequential()


print(f'IMG_SHAPE:IMG_SHAPE,  y_train shape:y_train[0].shape')

model.add(tf.keras.layers.Dense(256,activation='relu',input_shape=IMG_SHAPE, name='d1'))
model.add(tf.keras.layers.Dense(64, activation='sigmoid', name='d2'))
model.add(tf.keras.layers.Flatten(data_format='channels_last'))
model.add(tf.keras.layers.Dense(32, activation='softmax', name='d3'))

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

model.summary()
for nx in range(len(x_train)):
    file = x_train[nx]
    img = ut.read_image(filename=FLAGS.train_data_path+file, show=False)
    img=np.array(img)
    img = np.expand_dims(img, axis=0)
    model.fit(x=img, y=y_train[nx],verbose=2)

这是呕吐物:

"C:\Users\WascallyWabbit\AppData\Local\Programs\Python\Python36\python.exe" “C:/Users/WascallyWabbit/PycharmProjects/sentdex_keras/sentdex_keras.py” 命名空间(batch_size=4, epochs=1, learning_rate=0.01, numclasses=16, 样本='0cdf5b5d0ce1_01.jpg',比例=1.0,显示=假,目标='mnist', tb_dir='/Users/WascallyWabbit/tensorlog/', test_data_path='/Users/WascallyWabbit/Downloads/carvana/test/', train_data_path='/Users/WascallyWabbit/Downloads/carvana/train/') IMG_SHAPE:(1280, 1918, 2), y_train 形状:(16,) _________________________________________________________________ 图层(类型)输出形状参数 # ==================================================== =============== d1(密集)(无、1280、1918、256)768 _________________________________________________________________ d2(密集)(无、1280、1918、64)16448 _________________________________________________________________ 展平(展平)(无,157122560)0 _________________________________________________________________ d3(密集)(无,32)732954656 ==================================================== =============== 总参数:732,971,872 可训练参数:732,971,872 不可训练 参数:0 ___________________________________________________ 回溯(最近一次通话最后):文件 "C:/Users/WascallyWabbit/PycharmProjects/sentdex_keras/sentdex_keras.py", 第 113 行,在 main() 文件“C:/Users/WascallyWabbit/PycharmProjects/sentdex_keras/sentdex_keras.py”, 第 74 行,主要 model.fit(x=img, y=y_train[nx],verbose=2) 文件“C:\Users\WascallyWabbit\AppData\Roaming\Python\Python36\站点包\tensorflow\python\keras\engine\training.py", 第 1536 行,合适 validation_split=validation_split) 文件 "C:\Users\WascallyWabbit\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\keras\engine\training.py", 第 992 行,在 _standardize_user_data class_weight, batch_size) 文件 "C:\Users\WascallyWabbit\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\keras\engine\training.py", 第 1169 行,在 _standardize_weights 中 training_utils.check_array_lengths(x, y, sample_weights) 文件“C:\Users\WascallyWabbit\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\keras\engine\training_utils.py”, 第 426 行,在 check_array_lengths 'and ' + str(list(set_y)[0]) + 'target samples.') ValueError: 输入数组的样本数应与目标数组相同。 找到 1 个输入样本和 16 个目标样本

进程以退出代码 1 结束

还是卡住了,抱歉。

我已将问题简化为:

import tensorflow as tf
import numpy as np
in_shape=(128,128,3)
a=np.zeros(shape=in_shape,dtype='float32')
np.fill_diagonal(a[:,:,0],1.)
np.fill_diagonal(a[:,:,1],1.)
np.fill_diagonal(a[:,:,2],1.)

model = tf.keras.models.Sequential([
    tf.keras.layers.Dense(64, input_shape=in_shape, activation=tf.nn.relu, batch_size=1,name='d0'),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(16, activation=tf.nn.softmax,name='d1')
])

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

Y=np.empty(16)
Y.fill(1.)
#forgot to make one of them 'hot' , does not matter now

#this line barfs
model.fit(x=np.expand_dims(a, axis=0), y=np.expand_dims(Y, axis=0),steps_per_epoch=1)

输出是:

"C:\Users\WascallyWabbit\AppData\Local\Programs\Python\Python36\python.exe" “C:/Users/WascallyWabbit/.PyCharmCE2018.2/config/scratches/scratch_39.py” Traceback(最近一次通话最后一次):文件 "C:/Users/WascallyWabbit/.PyCharmCE2018.2/config/scratches/scratch_39.py", 第 28 行,在 model.fit(x=np.expand_dims(a, axis=0), y=np.expand_dims(Y, axis=0),steps_per_epoch=1) 文件 "C:\Users\WascallyWabbit\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\keras\engine\training.py", 第 1536 行,合适 validation_split=validation_split) 文件 "C:\Users\WascallyWabbit\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\keras\engine\training.py", 第 992 行,在 _standardize_user_data class_weight, batch_size) 文件 "C:\Users\WascallyWabbit\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\keras\engine\training.py", 第 1154 行,在 _standardize_weights exception_prefix='target') 文件 "C:\Users\WascallyWabbit\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\keras\engine\training_utils.py", 第 332 行,在 standardize_input_data 中 ' 但得到了形状为 ' + str(data_shape)) 的数组 形状为 (16,)

我想要一个 16 元素的概率数组来针对 16 元素标签数组进行“softmax”。玩弄 np.expand_dims(...,axis=) 并没有带来任何乐趣。

我没看到什么?

【问题讨论】:

最终的 Dense 层需要与您的类具有相同数量的节点。在这种情况下,16 个节点。 softmax 激活将为您提供这 16 个节点(即类)的概率分数 问题不在于类的数量,错误明确说x_train有1个样本,y_train有16个样本,这些数字应该相等。例如,x_train 和 y_train 的第一个维度必须相同。 【参考方案1】:

如果使用 sparse_categorical_crossentropy,则 y 值应以整数形式提供,因此会观察到错误预期 shape(1,)。当损失函数为 categorical_crossentropy 时,以 one-hot 编码形式提供 y。

这个链接有一个很好的插图。 https://jovianlin.io/cat-crossentropy-vs-sparse-cat-crossentropy/

所以,解决办法是

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

此外,np.expand_dims 或 y_train[nx][None] 可用于创建批处理维度。

model.fit(x=img, y = np.expand_dims(y_train[nx], 0), verbose=2)

【讨论】:

凹凸。谢谢,但不这样做。我解决了这个问题。 出现问题是因为使用的损失函数是sparse_categorical_crossentropy而不是categorical_crossentropy。tensorflow.org/api_docs/python/tf/keras/backend/… 嘭!完毕。谢谢你,先生。

以上是关于如何为 softmax 分类指定 onehot 标签数组的形状?的主要内容,如果未能解决你的问题,请参考以下文章

如何为@Valid 指定验证组?

图片验证码识别,标签中onehot编码对应多个1怎么做?

Softmax矩阵到0/1(一个热)编码矩阵?

多个正分类的 TensorFlow 损失计算

word2vec (CBOW分层softmax负采样)

如何用softmax和sigmoid来做多类分类和多标签分类