导库
import torch import torch.nn as nn import torch.nn.functional as F from torch.utils import data from torch.optim import lr_scheduler import numpy as np import matplotlib.pyplot as plt import torchvision from torchvision import transforms import os import glob from PIL import Image
# 构建训练集, 测试集 all_pics = glob.glob(r"C:\Users\Administrator\Desktop\dataset\person_detect\第13章\hk\training\*.png") images = [p for p in all_pics if 'matte' not in p] anno = [p for p in all_pics if 'matte' in p]
# test 和 train 是平行的 # 构建训练集, 测试集 all_test_pics = glob.glob(r'C:\Users\Administrator\Desktop\dataset\person_detect\第13章\hk\testing\*.png') test_images = [p for p in all_test_pics if 'matte' not in p] test_anno = [p for p in all_test_pics if 'matte' in p] transform = transforms.Compose([ transforms.Resize((256, 256)), transforms.ToTensor(), ])
# 这个方法很有用, 让训练集和测试集有了 切片的功能 class Portrait_dataset(data.Dataset): def __init__(self, img_paths, anno_paths) -> None: super().__init__() self.imgs = img_paths self.annos = anno_paths def __getitem__(self, index): img = self.imgs[index] anno = self.annos[index] pil_img = Image.open(img) img_tensor = transform(pil_img) anno_img = Image.open(anno) anno_tensor = transform(anno_img) anno_tensor = torch.squeeze(anno_tensor).type(torch.long) anno_tensor[anno_tensor > 0] = 1 return img_tensor, anno_tensor def __len__(self): return len(self.imgs)
构建训练集和测试集
train_dataset = Portrait_dataset(images, anno) test_dataset = Portrait_dataset(test_images, test_anno) BATCH_SIZE = 12 train_dl = data.DataLoader( train_dataset, batch_size=BATCH_SIZE, shuffle=True) test_dl = data.DataLoader( test_dataset, batch_size=BATCH_SIZE, )
搭建网络
class Downsample(nn.Module): def __init__(self, in_channels, out_channels): super(Downsample, self).__init__() self.conv_relu = nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1), nn.ReLU(inplace=True) ) self.pool = nn.MaxPool2d(kernel_size=2) def forward(self, x, is_pool=True): if is_pool: x = self.pool(x) x = self.conv_relu(x) return x class Upsample(nn.Module): def __init__(self, channels): super().__init__() self.conv_relu = nn.Sequential( nn.Conv2d(2 * channels, channels, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(channels, channels, kernel_size=3, padding=1), nn.ReLU(inplace=True) ) self.upconv_relu = nn.Sequential( nn.ConvTranspose2d( channels, channels // 2, kernel_size=3, stride=2, padding=1, output_padding=1), nn.ReLU(inplace=True) ) def forward(self, x): x = self.conv_relu(x) x = self.upconv_relu(x) return x class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.down1 = Downsample(3, 64) self.down2 = Downsample(64, 128) self.down3 = Downsample(128, 256) self.down4 = Downsample(256, 512) self.down5 = Downsample(512, 1024) self.up = nn.Sequential( nn.ConvTranspose2d(1024, 512, kernel_size=3, stride=2, padding=1, output_padding=1), nn.ReLU(inplace=True) ) self.up1 = Upsample(512) self.up2 = Upsample(256) self.up3 = Upsample(128) self.conv_2 = Downsample(128, 64) self.last = nn.Conv2d(64, 2, kernel_size=1) def forward(self, x): x1 = self.down1(x, is_pool=False) x2 = self.down2(x1) x3 = self.down3(x2) x4 = self.down4(x3) x5 = self.down5(x4) x5 = self.up(x5) x5 = torch.cat([x4, x5], dim=1) # 32*32*1024 x5 = self.up1(x5) # 64*64*256) x5 = torch.cat([x3, x5], dim=1) # 64*64*512 x5 = self.up2(x5) # 128*128*128 x5 = torch.cat([x2, x5], dim=1) # 128*128*256 x5 = self.up3(x5) # 256*256*64 x5 = torch.cat([x1, x5], dim=1) # 256*256*128 x5 = self.conv_2(x5, is_pool=False) # 256*256*64 x5 = self.last(x5) # 256*256*3 return x5
训练网络
model = Net() if torch.cuda.is_available(): model.to('cuda') loss_fn = nn.CrossEntropyLoss() from torch.optim import lr_scheduler optimizer = torch.optim.Adam(model.parameters(), lr=0.001) exp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1) def fit(epoch, model, trainloader, testloader): correct = 0 total = 0 running_loss = 0 model.train() for x, y in trainloader: if torch.cuda.is_available(): x, y = x.to('cuda'), y.to('cuda') y_pred = model(x) print(y_pred.shape) print(y.shape) loss = loss_fn(y_pred, y) optimizer.zero_grad() loss.backward() optimizer.step() with torch.no_grad(): y_pred = torch.argmax(y_pred, dim=1) correct += (y_pred == y).sum().item() total += y.size(0) running_loss += loss.item() exp_lr_scheduler.step() epoch_loss = running_loss / len(trainloader.dataset) epoch_acc = correct / (total * 256 * 256) test_correct = 0 test_total = 0 test_running_loss = 0 model.eval() with torch.no_grad(): for x, y in testloader: if torch.cuda.is_available(): x, y = x.to('cuda'), y.to('cuda') y_pred = model(x) loss = loss_fn(y_pred, y) y_pred = torch.argmax(y_pred, dim=1) test_correct += (y_pred == y).sum().item() test_total += y.size(0) test_running_loss += loss.item() epoch_test_loss = test_running_loss / len(testloader.dataset) epoch_test_acc = test_correct / (test_total * 256 * 256) print('epoch: ', epoch, 'loss: ', round(epoch_loss, 3), 'accuracy:', round(epoch_acc, 3), 'test_loss: ', round(epoch_test_loss, 3), 'test_accuracy:', round(epoch_test_acc, 3) ) return epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc epochs = 30 train_loss = [] train_acc = [] test_loss = [] test_acc = [] for epoch in range(epochs): epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc = fit(epoch, model, train_dl, test_dl) train_loss.append(epoch_loss) train_acc.append(epoch_acc) test_loss.append(epoch_test_loss) test_acc.append(epoch_test_acc)