神经网络——多层感知机(MLP)
原创约 808 字大约 3 分钟
神经网络——多层感知机(MLP)
- 在 神经网络基本概念 中已经介绍了感知机的概念,它是使用神经元进行二分类线性分类模型,本质也就是计算输入特征的线性组合来对样本进行分类。在训练过程中通过不断的修正参数来找到一个能够正确对样本进行分类的超平面(决策边界)。我们已经了解了感知机的基本结果以及工作流程,同时我们也知道感知机只能对线性可分的数据进行分类,而对线性不可分的数据无法处理。而多层感知机正是为了处理这一问题而提出的。
定义
多层感知机(Multilayer Perceptron)便是最基础的神经网络即人工神经网络(Artificial Neural Network),为了克服线性模型的限制,MLP中通常包含多个隐藏层,并且层与层直接进行全连接。
并且这些层与层之间各自的任务也不同,一般前层隐藏层都是为了对输入进行特征提取,通常称为表示层,第层即最后一层才是进行分类,称为决策层。即MLP网络如图所示
当然在基础篇中也提及过,MLP能进行非线性决策的最重要因素是引入了非线性的激活函数,否则即使构造多层线性网络也会退化成一层。
这里我们来看一个简单的猫狗分类例子
import os import torch import torch.nn as nn from torchvision.models import alexnet, resnet18 import torchvision.transforms as transforms from torch.utils.data import Dataset, DataLoader import PIL.Image class CustomDataset(Dataset): def __init__(self, path, transform) -> None: super().__init__() self.transform = transform self.imgs = self.make_dataset(path) def __getitem__(self, index): img_path, label = self.imgs[index] img = PIL.Image.open(img_path).convert('RGB') img = self.transform(img) return img, label def __len__(self): return len(self.imgs) @staticmethod def make_dataset(path): datasets = [] class_to_idx = {'cats': 0, 'dogs': 1} for root, dirs, _ in os.walk(path): for sub_dir in dirs: imgs = list(os.listdir(os.path.join(root, sub_dir))) for img in imgs: datasets.append(( os.path.join(root, sub_dir, img), class_to_idx[sub_dir] )) return datasets class MLP(nn.Module): def __init__(self): super(MLP, self).__init__() self.classifier = nn.Sequential( nn.Flatten(), nn.Linear(195075, 512), nn.ReLU(), nn.Linear(512, 256), nn.ReLU(), nn.Linear(256, 2) ) def forward(self, x): x = self.classifier(x) return x mean = [0.5875, 0.5591, 0.4995] std = [0.2898, 0.2873, 0.3088] train_transform = transforms.Compose([transforms.Resize((255,255)), # transforms.RandomVerticalFlip(), # transforms.RandomHorizontalFlip(), transforms.RandomCrop(255, padding=4), transforms.ToTensor(), transforms.Normalize(mean, std) ]) valid_transform = transforms.Compose([transforms.Resize((255,255)), transforms.ToTensor(), transforms.Normalize(mean, std) ]) train_dataset = CustomDataset('./datasets/train', transform=train_transform) valid_dataset = CustomDataset('./datasets/test', transform=valid_transform) train_loader = DataLoader(dataset=train_dataset, batch_size=4, shuffle=True) valid_loader = DataLoader(dataset=valid_dataset, batch_size=4, shuffle=True) model = MLP().to(device="cuda") criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=1e-2) for epoch in range(100): tsize = len(train_loader.dataset) tcorrect = 0 for batch, (X, y) in enumerate(train_loader): X, y = X.cuda(), y.cuda() pred = model(X) loss = criterion(pred, y) tcorrect += (pred.argmax(1) == y).type(torch.float).sum().item() optimizer.zero_grad() loss.backward() optimizer.step() if epoch % 5 == 0: model.eval() correct = 0 size = len(valid_loader.dataset) with torch.no_grad(): for X, y in valid_loader: X, y = X.cuda(), y.cuda() pred = model(X) correct += (pred.argmax(1) == y).type(torch.float).sum().item() print(f'Epoch {epoch}/100 Train Acc = {tcorrect/tsize}, Acc = {correct/size}')
数据集来自Cats and Dogs image classification 这里我们定义了一个包含两层隐藏层的MLP模型进行训练,最终效果在测试集上有61%的正确率,而且理论上还没收敛,多训练几轮效果应该还会更好。