全连接神经网络:过拟合与欠拟合、数据增强、批量标准化(BN)

过拟合与欠拟合:

import torch
from torch import nn, optim
from torch.utils.data import TensorDataset, DataLoader
from PIL import Image
from torchvision import transforms
from matplotlib import pyplot as plt

class MyNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(100, 50)
        self.fc2 = nn.Linear(50, 10)
        self.fc3 = nn.Linear(10, 1)
        self.relu = nn.ReLU()

    def forward(self, x):
        x = self.relu(self.fc1(x))
        x = self.relu(self.fc2(x))
        x = self.fc3(x)
        return x

def train():
    x = torch.randn(1000, 100)
    y = torch.randn(1000, 1)
    dataset = TensorDataset(x, y)
    dataloader = DataLoader(dataset, batch_size=100, shuffle=True)
    model = MyNet()
    criterion = nn.MSELoss()
    # weight_decay:使用L2正则化,参数值是L2的权重参数\lambda
    opt = optim.Adam(model.parameters(), lr=0.1, betas=(0.9, 0.999), eps=1e-8, weight_decay=0.01)
    # opt = optim.Adam(model.parameters(), lr=0.1, betas=(0.9, 0.999), eps=1e-8)
    for epoch in range(10):
        loss_sum = 0.0
        for data, label in dataloader:
            opt.zero_grad()
            y_pred = model(data)
            loss = criterion(y_pred, label)
            loss.backward()
            opt.step()
            loss_sum += loss.item()
        print(f'epoch: {epoch}, loss: {loss_sum / len(dataloader).dataset}')

def test02():
    dropout = nn.Dropout(0.2)
    x = torch.randint(0, 10, (5, 6), dtype=torch.float)
    print(x)
    print(dropout(x))

def test03():
    torch.manual_seed(0)
    w = torch.randn(12, 1, requires_grad=True)
    x = torch.randint(0, 8, (3, 12)).float()
    output = x @ w
    output = output.sum()
    output.backward()
    print(w.grad.flatten())

def test04():
    dropout = nn.Dropout(0.8)
    w = torch.randn(12, 1, requires_grad=True)
    x = torch.randint(0, 8, (3, 12)).float()
    x = dropout(x)
    output = x @ w
    output = output.sum()
    output.backward()
    print(w.grad.flatten())

def test05():
    path = "./img/100.jpg"
    img = Image.open(path)
    transform = transforms.Compose([
        transforms.Resize((224, 224)),
        transforms.ToTensor(),
    ])
    t_img = transform(img)
    print(t_img.shape)
    t_img = t_img.unsqueeze(0)
    dropout = nn.Dropout2d(p=0.2)
    d_img = dropout(t_img)
    t_img = t_img.squeeze(0).permute(1, 2, 0).numpy()
    d_img = d_img.squeeze(0).permute(1, 2, 0).numpy()
    fig = plt.figure()
    ax1 = fig.add_subplot(1, 2, 1)
    ax2 = fig.add_subplot(1, 2, 2)
    ax1.imshow(t_img)
    ax2.imshow(d_img)
    plt.show()

if __name__ == '__main__':
    # train()
    # test02()
    # test03()
    # test04()
    test05()

数据增强:

import torch
from PIL import Image
from torchvision import transforms, datasets
from matplotlib import pyplot as plt
from torch.utils.data import DataLoader

path = "./img/100.jpg"

def test01():
    img = Image.open(path)
    # 随机裁剪
    transform = transforms.Compose([
        transforms.RandomCrop((224, 224)),
        transforms.ToTensor()
    ])
    img = transform(img)
    print(img.shape)
    img = img.permute(1, 2, 0)
    plt.imshow(img)
    plt.show()

def test02():
    img = Image.open(path)

    transform = transforms.Compose([
        # 随机水平翻转
        # 参数:p--图片翻转的概率
        # transforms.RandomHorizontalFlip(p=0.5),
        # 颜色调整
        # 参数:
        # brightness:亮度调整,可以是float或(min,max)元组
        # 如果是float类型,则默认在"[max(0,1-0.2),1+0.2]=[0.8,1.2]"范围内随机缩放
        # 如果是(min,max)元组,则按照设置的元组的值进行调整
        # contrast:对比度调整,同上
        # saturation:饱和度调整,同上
        # hue:色调调整,取值范围在[-0.5,0.5]之间
        # transforms.ColorJitter(brightness=0.3, contrast=0.4, saturation=0.2, hue=0.2),
        # 随机旋转
        # 参数:degress:随机旋转的角度
        # 如果是float类型,在[-30.,30.]范围内随机旋转
        # 如果是(min,max)元组,则在元组的范围内随机旋转
        # transforms.RandomRotation(90),
        transforms.ToTensor(),
        # 标准化
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    ])
    img = transform(img)
    print(img.shape)
    img = img.permute(1, 2, 0)
    plt.imshow(img)
    plt.show()

def test03():
    transform = transforms.Compose([
        transforms.RandomRotation(30),
        transforms.RandomHorizontalFlip(0.5),
        transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.2),
        transforms.ToTensor(),
        # 标准化需要放在ToTensor后执行,否则会报错
        transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
    ])
    dataset = datasets.CIFAR10(root="./cifar10", train=True, download=True, transform=transform)
    dataloader = DataLoader(dataset, batch_size=4, shuffle=True)
    data, labels = next(iter(dataloader))
    for i in range(4):
        img = data[i]
        # 反归一化
        img = img / 2 + 0.5
        img = transforms.ToPILImage()(img)
        plt.imshow(img)
        plt.show()

if __name__ == '__main__':
    # test01()
    # test02()
    test03()

批量标准化(BN):

from sklearn.datasets import make_circles
import torch
from sklearn.model_selection import train_test_split
from torch import nn, optim
from matplotlib import pyplot as plt

# 数据准备
x, y = make_circles(n_samples=2000, noise=0.1, factor=0.5, random_state=22)
x = torch.tensor(x, dtype=torch.float)
y = torch.tensor(y)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=22)

# 构建模型
# 使用BN(批量标准化)的网络
class NetWithBN(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(2, 64)
        self.bn1 = nn.BatchNorm1d(64)
        self.fc2 = nn.Linear(64, 32)
        self.bn2 = nn.BatchNorm1d(32)
        self.fc3 = nn.Linear(32, 2)
        self.relu = nn.ReLU()

    def forward(self, x):
        x = self.relu(self.bn1(self.fc1(x)))
        x = self.relu(self.bn2(self.fc2(x)))
        # 多分类输出层不需要单独使用softmax激活函数,该函数在交叉熵中被调用
        x = self.fc3(x)
        return x

# 未使用BN(批量标准化)的网络
class NetWithoutBN(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(2, 64)
        self.fc2 = nn.Linear(64, 32)
        self.fc3 = nn.Linear(32, 2)
        self.relu = nn.ReLU()

    def forward(self, x):
        x = self.relu(self.fc1(x))
        x = self.relu(self.fc2(x))
        x = self.fc3(x)
        return x

def train(model, x_train, y_train, x_test, y_test, name, lr=0.1, epochs=10):
    criterion = nn.CrossEntropyLoss()
    opt = optim.SGD(model.parameters(), lr=lr)
    # opt = optim.Adam(model.parameters(), lr=lr)
    train_loss = []
    test_acc = []
    for epoch in range(epochs):
        # 表示训练阶段
        model.train()
        y_pred = model(x_train)
        loss = criterion(y_pred, y_train)
        opt.zero_grad()
        loss.backward()
        opt.step()
        train_loss.append(loss.item())
        if epoch % 10 == 0:
            print(f"name:{name}, epoch:{epoch}, loss:{loss.item()}")
        # 验证阶段
        model.eval()
        # 验证阶段不需要计算梯度
        with torch.no_grad():
            y_test_pred = model(x_test)
            # 根据结果中最大的概率找到对应的标签值
            _, pred = torch.max(y_test_pred, dim=1)
            correct = (pred == y_test).sum().item()
            test_acc.append(correct / len(y_test))
    return train_loss, test_acc

def plot(bn_train_loss, nobn_train_loss, bn_test_acc, nobn_test_acc):
    fig = plt.figure(figsize=(12, 5))
    ax1 = fig.add_subplot(1, 2, 1)
    ax1.plot(bn_train_loss, 'b', label='BN')
    ax1.plot(nobn_train_loss, 'r', label='NoBN')
    ax1.legend()

    ax2 = fig.add_subplot(1, 2, 2)
    ax2.plot(bn_test_acc, 'b', label='BN')
    ax2.plot(nobn_test_acc, 'r', label='NoBN')
    ax2.legend()
    plt.show()

bnmodel = NetWithBN()
nobnmodel = NetWithoutBN()
bn_train_loss, bn_test_acc = train(bnmodel, x_train, y_train, x_test, y_test, "BN", lr=0.1, epochs=100)
nobn_train_loss, nobn_test_acc = train(nobnmodel, x_train, y_train, x_test, y_test, "NoBN", lr=0.1, epochs=100)
print(bn_test_acc)
print(nobn_test_acc)
plot(bn_train_loss, nobn_train_loss, bn_test_acc, nobn_test_acc)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值