天天看点

科大讯飞CV赛baseline:图像分类实践+0.55

赛题名称:科大讯飞人脸情绪识别挑战赛

赛题类型:cv 图像分类

赛题介绍

人脸表情是传播人类情感信息与协调人际关系的重要方式,表情识别是指从静态照片或视频序列中选择出表情状态,从而确定对人物的情绪与心理变化。

科大讯飞CV赛baseline:图像分类实践+0.55

在日常生活中人类习惯从面部表情中吸收非言语暗示,那么计算机可以完成类似任务吗?答案是肯定的,但是需要训练它学会识别情绪。

赛事任务

给定人脸照片完成具体的情绪识别,选手需要根据训练集数据构建情绪识别任务,并对测试集图像进行预测,识别人脸的7种情绪。

赛题数据由训练集和测试集组成,训练集数据集按照不同情绪的文件夹进行存放。其中:

  • 训练集:2.8W张人脸图像;
  • 测试集:7K张人脸图像;

为了简化任务赛题图像只包含单张人脸,所有图像的尺寸为48*48像素。数据集包括的情绪标签包括以下7类:

  • angry
  • disgusted
  • fearful
  • happy
  • neutral
  • sad
  • surprised

赛题baseline思路

赛题为一个典型的图像分类任务,所以可以使用CNN来完成图像分类过程。具体实现步骤如下:

  • 定义数据读取和数据扩增
  • 定义CNN模型
  • 模型训练与验证

Keras实现

首先定义网络模型,这里可以自定义一个多层CNN网络模型结构,最后加上全连接层。

model = Sequential()
model.add(Conv2D(16, (5, 5), padding='same', input_shape=(48, 48, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(32, (5, 5), padding='same', ))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(32, (5, 5), padding='same', ))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(7, activation="softmax"))

model.compile(loss='categorical_crossentropy',
              optimizer=Adam(learning_rate=0.001),
              metrics=['accuracy'])      

定义数据读取,划分20%数据作为验证集:

train_datagen = ImageDataGenerator(
  rescale=1./255,validation_split=0.2)
  
val_datagen = ImageDataGenerator(
  rescale=1./255, validation_split=0.2)      

一行代码完成模型训练过程:

model.fit_generator(
        train_data,
        epochs=5,
        validation_data=val_data,
        validation_steps=200)
model.save_weights('first_try.h5')       

Pytorch实现

定义网络模型,这里可以用预训练的CNN网络模型,精度会更高:

class XunFeiNet(nn.Module):
    def __init__(self):
        super(XunFeiNet, self).__init__()
                
        model = models.resnet18(True)
        model.avgpool = nn.AdaptiveAvgPool2d(1)
        model.fc = nn.Linear(512, 7)
        self.resnet = model
         
    def forward(self, img):        
        out = self.resnet(img)
        return out      

定义模型的正常传播和反向传播:

def train(train_loader, model, criterion, optimizer, epoch):
    model.train()

    acc1 = []
    for i, (input, target) in enumerate(train_loader):
        input = input.cuda(non_blocking=True)
        target = target.cuda(non_blocking=True)
        output = model(input)
        loss = criterion(output, target)

        acc1.append((output.argmax(1) == target).float().mean().item())
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        if i % 100 == 0:
            print('Train: {0}'.format(np.mean(acc1)))      
model = XunFeiNet().cuda()
criterion = nn.CrossEntropyLoss().cuda()
optimizer = torch.optim.SGD(model.parameters(), 0.003)
best_acc = 0.0
for epoch in range(10):
    train(train_loader, model, criterion, optimizer, epoch)
    val_acc = validate(val_loader, model, criterion)