使用 TimeDistributed 密集层解决多标签图像分类

数据挖掘 机器学习 深度学习 喀拉斯 图像分类 多标签分类
2021-10-13 07:39:05

我有一个具有 5 个标签的多标签图像数据集。每个图像可以同时具有多个标签。我正在使用卷积神经网络来提取特征,并且我将这些提取的特征提供给RepeatVector层以创建提取特征的 5 个副本,并且在RepeatVector层之后我将TimeDistributed层与TimeDistributed(Dense(2)).

y_train是一个 3D 数组,它的形状是 (1600, 5, 2),x_train是一个图像数组。

例如:

>>> x_train.shape
(1600, 3, 100, 100)

>>> y_train.shape 
(1600,5,2)

>>> y_train[0] = 
array([[0, 1],   # [0,1] = 1 label present and  [1,0] = 0 label abset
       [1, 0],
       [1, 0],
       [1, 0],
       [1, 0]])

代码:

def get_label(y):
  tmp = []
  d = {0:[1,0],1:[0,1]}   # 0 absent 1 present
  for i,value in enumerate(y):
    tmp.append( d[value] )
  return tmp


X,Y= get_data()
Y = Y.tolist()
y = []
for value in Y:
  y.append(get_label(value))

Y = np.array(y,dtype=int)


x_train, x_test, y_train, y_test = train_test_split(X,Y,test_size =0.2,random_state=100)


img_channels = 3
img_rows     = 100
img_cols     = 100
nb_classes   = 5 

model = Sequential()

model.add(Convolution2D(32, 3, 3, border_mode='same',input_shape=(img_channels, img_rows, img_cols)))
model.add(Activation('relu'))
model.add(Convolution2D(32, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Convolution2D(64, 3, 3, border_mode='same'))
model.add(Activation('relu'))
model.add(Convolution2D(64, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(RepeatVector(nb_classes))
model.add(TimeDistributed(Dense(2)))
model.add(Activation('softmax'))

# let's train the model using SGD + momentum (how original).
# opt = RMSprop(lr=0.001, rho=0.9, epsilon=1e-06)
opt = SGD(lr=0.01, momentum=0.0, decay=1e-6, nesterov=False)
model.compile(loss='categorical_crossentropy', optimizer=opt,metrics=['accuracy'])
model.fit(x_train,y_train,nb_epoch=10,batch_size=32,validation_data=(x_test,y_test),shuffle=True)
out = model.predict_classes(x_test)

但是在训练之后,我得到了测试集的全零。这种方法是错误的吗?

1个回答

无需重复任何功能。您要做的是将您的激活函数从 softmax 更改为 sigmoid,否则将其他所有内容保留为通常用于二进制分类的操作。

...
model = Sequential()

model.add(Convolution2D(32, 3, 3, border_mode='same',input_shape=(img_channels, img_rows, img_cols)))
model.add(Activation('relu'))
model.add(Convolution2D(32, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Convolution2D(64, 3, 3, border_mode='same'))
model.add(Activation('relu'))
model.add(Convolution2D(64, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dense(5)) # whatever the number of classes is
model.add(Activation('sigmoid'))
...

然后,您需要将 Y 张量从 简化N x 5 x 2N x 5,例如使用Y = Y[:, :, 0]

这可能是也可能不是你得到全零的原因,但它肯定是比使用 RepeatVector 和 TimeDistributed 更标准的多标签分类方法。其他要看的是你训练了多少,只有 1600 个示例的 5 个 epoch 并不多。同样,Dense(512)对于您的小数据集大小,a 非常大。也许减少到类似的东西Dense(16)