1. 程式人生 > >人臉表情識別——定製自己的資料載入方式

人臉表情識別——定製自己的資料載入方式

背景

將人臉分割成幾部分,送入並行的網路結構。出現的問題是:
使用torchvision.datasets.ImageLoader函式載入資料集後,當使用torch.utils.data.DataLoader進行shuffle後,這幾部分的影象的Label無法一一對應,即無法再並行網路中對各部分的影象特徵進行融合。
以下是我的解決方案,直接給程式碼,有時間在來詳細解釋。

程式碼

1.重寫ImageFolder類

folder.py

# -*- coding: utf-8 -*-
import os
import torch
import torchvision
from PIL import
Image from torchvision import datasets, transforms import matplotlib.pyplot as plt import random IMG_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm'] def make_dataset(dir, class_to_idx): images = [] dir = os.path.expanduser(dir) for target in sorted(os.listdir(dir)): d = os.path.join(dir, target) if
not os.path.isdir(d): continue for root, _, fnames in sorted(os.walk(d)): for fname in sorted(fnames): if is_image_file(fname): path = os.path.join(root, fname) item = (path, class_to_idx[target]) images.append(item) random.shuffle(images) # 在這裡進行洗牌,從而代替DataLoader中的shuffle
return images def is_image_file(filename): """Checks if a file is an image. Args: filename (string): path to a file Returns: bool: True if the filename ends with a known image extension """ filename_lower = filename.lower() return any(filename_lower.endswith(ext) for ext in IMG_EXTENSIONS) def find_classes(dir): classes = [d for d in os.listdir(dir) if os.path.isdir(os.path.join(dir, d))] classes.sort() class_to_idx = {classes[i]: i for i in range(len(classes))} return classes, class_to_idx def default_loader(path): from torchvision import get_image_backend if get_image_backend() == 'accimage': return accimage_loader(path) else: return pil_loader(path) def pil_loader(path): # open path as file to avoid ResourceWarning (https://github.com/python-pillow/Pillow/issues/835) with open(path, 'rb') as f: with Image.open(f) as img: return img.convert('RGB') def accimage_loader(path): import accimage try: return accimage.Image(path) except IOError: # Potentially a decoding problem, fall back to PIL.Image return pil_loader(path) # 重寫ImageFolder類 class MyImageFolder(datasets.ImageFolder): def __init__(self, imgs, root, transform=None, target_transform=None, loader=default_loader): super(MyImageFolder, self).__init__(root, transform, target_transform, loader) self.imgs = imgs def imshow(inp, title=None): """Imshow for Tensor.""" inp = inp.numpy().transpose((1, 2, 0)) plt.imshow(inp) if title is not None: plt.title(title) plt.pause(10) # pause a bit so that plots are updated data_tranform = transforms.Compose([ transforms.ToTensor() ]) if __name__ == '__main__': data_dir = r'E:\Experiment\fer2013\datasets\test' class_names = ['nature', 'anger', 'disgust', 'fear', 'happy', 'sadness', 'surprise'] classes, class_to_idx = find_classes(data_dir) print(classes) print(class_to_idx) imgs = make_dataset(data_dir, class_to_idx) print(len(imgs)) sets = MyImageFolder(imgs, data_dir, transform=data_tranform) print(len(sets)) loader = torch.utils.data.DataLoader(sets, batch_size=4, shuffle=False, num_workers=4) inputs, targets = next(iter(loader)) out = torchvision.utils.make_grid(inputs) imshow(out, title=[class_names[x] for x in targets])

定義loader

mydataloader.py

# -*- coding: utf-8 -*-
import torch
import os
import numpy as np
import matplotlib.pyplot as plt
import torchvision
from torchvision import datasets, transforms
from folder import MyImageFolder, make_dataset, find_classes

batch_size = 4
ck_folders = r'E:\FERS\CK+\CK_FACEPARTS_DB1'
folders = ['folder_0', 'folder_1', 'folder_2', 'folder_3', 'folder_4']
global_sets = [os.path.join(x, 'global') for x in folders]
lefteye_sets = [os.path.join(x, 'lefteye') for x in folders]
righteye_sets = [os.path.join(x, 'righteye') for x in folders]
mouth_sets = [os.path.join(x, 'mouth') for x in folders]

data_transform = {
    'global': transforms.Compose([
        transforms.Grayscale(),
        transforms.Resize((64, 64)),
        transforms.ToTensor(),
    ]),
    'eye': transforms.Compose([
        transforms.Grayscale(),
        transforms.Resize((64, 64)),
        transforms.ToTensor(),
    ]),
    'mouth': transforms.Compose([
        transforms.Grayscale(),
        transforms.Resize((32, 64)),
        transforms.ToTensor(),
    ])
}

classes, class_to_idx = find_classes(os.path.join(ck_folders, global_sets[0]))
g_imgs = [make_dataset(os.path.join(ck_folders, global_sets[x]), class_to_idx) for x in range(5)]
lefteye_imgs = [[(item[0].replace('global', 'lefteye'), item[1]) for item in imgs] for imgs in g_imgs]
righteye_imgs = [[(item[0].replace('global', 'righteye'), item[1]) for item in imgs] for imgs in g_imgs]
moutn_imgs = [[(item[0].replace('global', 'mouth'), item[1]) for item in imgs] for imgs in g_imgs]
# global face
ck_global_datasets = [MyImageFolder(g_imgs[x], os.path.join(ck_folders, global_sets[x]),
                                    transform=data_transform['global']) for x in range(5)]
ck_global_dataset_0 = torch.utils.data.ConcatDataset([ck_global_datasets[i] for i in range(5) if i != 0])  # testset 0
ck_global_dataset_1 = torch.utils.data.ConcatDataset([ck_global_datasets[i] for i in range(5) if i != 1])  # testset 1
ck_global_dataset_2 = torch.utils.data.ConcatDataset([ck_global_datasets[i] for i in range(5) if i != 2])  # testset 2
ck_global_dataset_3 = torch.utils.data.ConcatDataset([ck_global_datasets[i] for i in range(5) if i != 3])  # testset 3
ck_global_dataset_4 = torch.utils.data.ConcatDataset([ck_global_datasets[i] for i in range(5) if i != 4])  # testset 4

ck_global_trainloader = torch.utils.data.DataLoader(ck_global_dataset_0, batch_size=batch_size, shuffle=False, num_workers=4)
ck_global_testloader = torch.utils.data.DataLoader(ck_global_datasets[0], batch_size=batch_size, shuffle=False, num_workers=4)

# left eye
ck_lefteye_datasets = [MyImageFolder(lefteye_imgs[x], os.path.join(ck_folders, lefteye_sets[x]),
                                            transform=data_transform['eye']) for x in range(5)]
ck_lefteye_dataset_0 = torch.utils.data.ConcatDataset([ck_lefteye_datasets[i] for i in range(5) if i != 0])  # testset 0
ck_lefteye_dataset_1 = torch.utils.data.ConcatDataset([ck_lefteye_datasets[i] for i in range(5) if i != 1])  # testset 1
ck_lefteye_dataset_2 = torch.utils.data.ConcatDataset([ck_lefteye_datasets[i] for i in range(5) if i != 2])  # testset 2
ck_lefteye_dataset_3 = torch.utils.data.ConcatDataset([ck_lefteye_datasets[i] for i in range(5) if i != 3])  # testset 3
ck_lefteye_dataset_4 = torch.utils.data.ConcatDataset([ck_lefteye_datasets[i] for i in range(5) if i != 4])  # testset 4

ck_lefteye_trainloader = torch.utils.data.DataLoader(ck_lefteye_dataset_0, batch_size=batch_size, shuffle=False, num_workers=4)
ck_lefteye_testloader = torch.utils.data.DataLoader(ck_lefteye_datasets[0], batch_size=batch_size, shuffle=False, num_workers=4)

# right eye
ck_righteye_datasets = [MyImageFolder(righteye_imgs[x], os.path.join(ck_folders, righteye_sets[x]),
                                             transform=data_transform['eye']) for x in range(5)]
ck_righteye_dataset_0 = torch.utils.data.ConcatDataset([ck_righteye_datasets[i] for i in range(5) if i != 0])  # testset 0
ck_righteye_dataset_1 = torch.utils.data.ConcatDataset([ck_righteye_datasets[i] for i in range(5) if i != 1])  # testset 1
ck_righteye_dataset_2 = torch.utils.data.ConcatDataset([ck_righteye_datasets[i] for i in range(5) if i != 2])  # testset 2
ck_righteye_dataset_3 = torch.utils.data.ConcatDataset([ck_righteye_datasets[i] for i in range(5) if i != 3])  # testset 3
ck_righteye_dataset_4 = torch.utils.data.ConcatDataset([ck_righteye_datasets[i] for i in range(5) if i != 4])  # testset 4

ck_righteye_trainloader = torch.utils.data.DataLoader(ck_righteye_dataset_0, batch_size=batch_size, shuffle=False, num_workers=4)
ck_righteye_testloader = torch.utils.data.DataLoader(ck_righteye_datasets[0], batch_size=batch_size, shuffle=False, num_workers=4)

# mouth
ck_mouth_datasets = [MyImageFolder(moutn_imgs[x], os.path.join(ck_folders, mouth_sets[x]),
                                          transform=data_transform['mouth']) for x in range(5)]
ck_mouth_dataset_0 = torch.utils.data.ConcatDataset([ck_mouth_datasets[i] for i in range(5) if i != 0])  # testset 0
ck_mouth_dataset_1 = torch.utils.data.ConcatDataset([ck_mouth_datasets[i] for i in range(5) if i != 1])  # testset 1
ck_mouth_dataset_2 = torch.utils.data.ConcatDataset([ck_mouth_datasets[i] for i in range(5) if i != 2])  # testset 2
ck_mouth_dataset_3 = torch.utils.data.ConcatDataset([ck_mouth_datasets[i] for i in range(5) if i != 3])  # testset 3
ck_mouth_dataset_4 = torch.utils.data.ConcatDataset([ck_mouth_datasets[i] for i in range(5) if i != 4])  # testset 4

ck_mouth_trainloader = torch.utils.data.DataLoader(ck_mouth_dataset_0, batch_size=batch_size, shuffle=False, num_workers=4)
ck_mouth_testloader = torch.utils.data.DataLoader(ck_mouth_datasets[0], batch_size=batch_size, shuffle=False, num_workers=4)


def imshow(inp, title=None):
    """Imshow for Tensor."""
    inp = inp.numpy().transpose((1, 2, 0))
    # mean = np.array([0.485, 0.456, 0.406])
    # std = np.array([0.229, 0.224, 0.225])
    # inp = std * inp + mean
    inp = np.clip(inp, 0, 1)
    plt.imshow(inp)
    if title is not None:
        plt.title(title)
    plt.pause(2)  # pause a bit so that plots are updated


if __name__ == '__main__':
    # for imgs in g_imgs:
    #     print(imgs[:3])
    # print('-' * 10)
    # for imgs in lefteye_imgs:
    #     print(imgs[:3])
    # print('-' * 10)
    # for imgs in righteye_imgs:
    #     print(imgs[:3])
    # print('-' * 10)
    # for imgs in moutn_imgs:
    #     print(imgs[:3])

    # (0=neutral, 1=anger, 2=contempt, 3=disgust, 4=fear, 5=happy, 6=sadness, 7=surprise)
    # class_names = ['nature', 'anger', 'contempt', 'disgust', 'fear', 'happy', 'sadness', 'surprise']
    class_names = ['nature', 'anger', 'disgust', 'fear', 'happy', 'sadness', 'surprise']

    # global face
    print('train size: {}, train batch nums:{}'.format(len(ck_global_dataset_0), len(ck_global_trainloader)))
    print('test size: {}, test batch nums:{}'.format(len(ck_global_datasets[0]), len(ck_global_testloader)))
    inputs, classes = next(iter(ck_global_trainloader))
    out = torchvision.utils.make_grid(inputs)
    imshow(out, title=[class_names[x] for x in classes])

    # left eye
    print('train size: {}, train batch nums:{}'.format(len(ck_lefteye_dataset_0), len(ck_lefteye_trainloader)))
    print('test size: {}, test batch nums:{}'.format(len(ck_lefteye_datasets[0]), len(ck_lefteye_testloader)))
    inputs, classes = next(iter(ck_lefteye_trainloader))
    out = torchvision.utils.make_grid(inputs)
    imshow(out, title=[class_names[x] for x in classes])

    # left eye
    print('train size: {}, train batch nums:{}'.format(len(ck_righteye_dataset_0), len(ck_righteye_trainloader)))
    print('test size: {}, test batch nums:{}'.format(len(ck_righteye_datasets[0]), len(ck_righteye_testloader)))
    inputs, classes = next(iter(ck_righteye_trainloader))
    out = torchvision.utils.make_grid(inputs)
    imshow(out, title=[class_names[x] for x in classes])

    # mouth
    print('train size: {}, train batch nums:{}'.format(len(ck_mouth_dataset_0), len(ck_mouth_trainloader)))
    print('test size: {}, test batch nums:{}'.format(len(ck_mouth_datasets[0]), len(ck_mouth_testloader)))
    inputs, classes = next(iter(ck_mouth_trainloader))
    out = torchvision.utils.make_grid(inputs)
    imshow(out, title=[class_names[x] for x in classes])