过拟合与欠拟合:
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)