PyTrch深度学习简明实战7 - 卷积神经网络 - 四种天气识

2023-03-18  本文已影响0人  薛东弗斯

学习笔记10:四种天气识别(ImageFolder数据预处理、Dropout层、BN层) - pbc的成长之路 - 博客园 (cnblogs.com)

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import torchvision
# from torchvision.transforms import ToTensor
import os
import shutil    #用于拷贝文件

# torchvison.datasets.ImageFolder  # 从分类的文件夹中创建dataset数据

# 创建文件夹
base_dir = './data/4_weather'
if not os.path.isdir(base_dir):
    os.mkdir(base_dir)    
train_dir = os.path.join(base_dir,"train")
if not os.path.isdir(train_dir):
    os.mkdir(train_dir)
test_dir = os.path.join(base_dir,"test")
if not os.path.isdir(test_dir):
    os.mkdir(test_dir)

specises = ['cloudy','rain','shine','sunrise']
for train_or_test in ['train','test']:
    for spec in specises:
        if not os.path.isdir(os.path.join(base_dir,train_or_test,spec)):
            os.mkdir(os.path.join(base_dir,train_or_test,spec))

image_dir = r'./data/dataset2/'
for i,img in enumerate(os.listdir(image_dir)):
    for spec in specises:
        if spec in img:      
            s = os.path.join(image_dir,img)  # 原始图片目录
            if i%5 == 0:
                d = os.path.join(base_dir,'test',spec,img)    # 1/5的数据copy到test
            else:
                d = os.path.join(base_dir,'train',spec,img)   # 其余数据copy到train
                
            shutil.copy(s,d)    # 数据copy
查看每个类别中分别有多少张图片
for train_or_test in ['train','test']:
    for spec in specises:
        print(train_or_test,spec,len(os.listdir(os.path.join(base_dir,train_or_test,spec))))
# train cloudy 240
# train rain 172
# train shine 202
# train sunrise 286
# test cloudy 60
# test rain 43
# test shine 51
# test sunrise 71

数据集的创建/可视化

# 数据加载

BATCHSIZE = 16  # The definition of BATCHSIZE determined by video memory size. if too large, may lead video memory overflow.
train_dl= torch.utils.data.DataLoader(
    train_ds,
    batch_size=BATCHSIZE,
    shuffle=True
)
# dataloader可以帮我们处理批次,乱序,多GPU
test_dl= torch.utils.data.DataLoader(
    test_ds,
    batch_size=BATCHSIZE,
    # № need to apply shuffle in test dataset
)

imgs,labels = next(iter(train_dl))    # use next to get 1 batch data.
# print(imgs.shape)
# torch.Size([16, 3, 96, 96])   batch, channel, width, height. 拿到16张3channel,96*96像素的图片

# imgs[0].shape     3 channel, width=96. height=96 , imgs[0] get 1st picture
# torch.Size([3, 96, 96])

im = imgs[0].permute(1,2,0)   # 由默认的channel(0),width(1),height(2) 变成width/height/channel. 改变显示顺序
# print(im.shape)               # torch.Size([96, 96, 3])
im = im.numpy()     # 数据类型由torch变成numpy的ndarray
# print(im.shape)     # (96, 96, 3)
im = (im + 1)/2     # 将取值范围变为0-1之间
# plt.imshow(im)  打印图片
# print(labels[0]) 打印标签
# 标签定义:{'cloudy': 0, 'rain': 1, 'shine': 2, 'sunrise': 3}
id_to_class = dict((v,k) for k,v in train_ds.class_to_idx.items())
# print(id_to_class)  # {0: 'cloudy', 1: 'rain', 2: 'shine', 3: 'sunrise'}

plt.figure(figsize=(12,8))
for i,(img,label) in enumerate(zip(imgs[:6],labels[:6])):  # zip 同时对img和label进行迭代
    img = (img.permute(1,2,0).numpy()+1)/2
    plt.subplot(2,3,i+1) # 绘制到2行3列的第i+1个位置上面。i从0开始
    plt.title(id_to_class.get(label.item()))
    plt.imshow(img)
image.png

四种天气分类模型的创建

class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__()  # 继承父类所有属性
        self.conv1 = nn.Conv2d(3,16,3)  # channel=16, 16个卷积核, 卷积核选用3*3大小
        self.conv2 = nn.Conv2d(16,32,3) # input 16 channel, out 32 channel, kernel_size=3*3
        self.conv3 = nn.Conv2d(32,64,3) # 选用成倍增长的卷积核,模仿vgg卷积结构
        #self.fc1 = nn.Linear(64*12*12,1024)# 如果输入是96*96,经过3个pool层,96/2/2=12. 如果由填充,最后输出的卷积核大小为64,
                                           # 所以此处假设输入尺寸为64*12*12. 假定输出1024个单元
        self.fc1 = nn.Linear(64*10*10,1024)
        self.fc2 = nn.Linear(1024,4)    # 分为4类
 
    def  forward(self, x):
        x = F.relu(self.conv1(x))   # 调用第一层卷积,并通过F.relu激活
        x = F.max_pool2d(x,2)   # 将图片减少为原来的一半
        x = F.relu(self.conv2(x))
        x = F.max_pool2d(x,2)   # 将图片减少为原来的一半  
        x = F.relu(self.conv3(x))
        x = F.max_pool2d(x, 2)
#         print(x.size())   # 用于定义linear层的input大小。
        # 实际输出torch.Size([16, 64, 10, 10]),所以前面应该定义输入尺寸的大小是64*10*10
#         x = x.view(-1,x.size(1)*x.size(2)*x.size(3))    # 展平,第一维是batch,这里设置为-1 让系统自动计算; 
        # 第2个维度自动计算。通过x.size(1) * x.size(2) * x.size(3); 64*10*10
        x = x.view(-1,64*10*10)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)  # 此处不用激活,使用CorssEntropy
        return x   # 返回前向传播的结果

model = Net()
preds = model(imgs)# torch.Size([16, 64, 10, 10]) 
# imgs.shape   # torch.Size([16, 3, 96, 96])
# preds.shape    # torch.Size([16, 4])
torch.argmax(preds, 1)  # 1 代表第2个维度    # tensor([2, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0])

卷积模型的训练

device = "cuda" if torch.cuda.is_available() else "cpu"
print("Using {} device".format(device))

model = Net().to(device)

loss_fn = nn.CrossEntropyLoss()
optim = torch.optim.Adam(model.parameters(),lr=0.0005)  

def train(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)
    train_loss, correct = 0, 0
    model.train()
    for X, y in dataloader:
        X, y = X.to(device), y.to(device)

        # Compute prediction error
        pred = model(X)
        loss = loss_fn(pred, y)

        # Backpropagation
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        with torch.no_grad():
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()
            train_loss += loss.item()
    train_loss /= num_batches
    correct /= size
    return train_loss, correct

def test(dataloader, model):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)
    model.eval()
    test_loss, correct = 0, 0
    with torch.no_grad():
        for X, y in dataloader:
            X, y = X.to(device), y.to(device)
            pred = model(X)
            test_loss += loss_fn(pred, y).item()
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()
    test_loss /= num_batches
    correct /= size

    return test_loss, correct

epochs = 30

train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
    epoch_loss, epoch_acc = train(train_dl, model, loss_fn, optimizer)
    epoch_test_loss, epoch_test_acc = test(test_dl, model)
    train_loss.append(epoch_loss)
    train_acc.append(epoch_acc)
    test_loss.append(epoch_test_loss)
    test_acc.append(epoch_test_acc)
    
    template = ("epoch:{:2d}, train_loss: {:.5f}, train_acc: {:.1f}% ," 
                "test_loss: {:.5f}, test_acc: {:.1f}%")
    print(template.format(
          epoch, epoch_loss, epoch_acc*100, epoch_test_loss, epoch_test_acc*100))
    
print("Done!")

上面代码执行不太理想。 改成如下

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import torchvision
import glob
from torchvision import transforms
from torch.utils import data
from PIL import Image

img_dir = r'./data/dataset2/*.jpg'
imgs = glob.glob(img_dir)
# imgs[:3]

species = ['cloudy', 'rain', 'shine', 'sunrise']
species_to_idx = dict((c, i) for i, c in enumerate(species))
# species_to_idx   # {'cloudy': 0, 'rain': 1, 'shine': 2, 'sunrise': 3}
idx_to_species = dict((v, k) for k, v in species_to_idx.items())
# idx_to_species  # {0: 'cloudy', 1: 'rain', 2: 'shine', 3: 'sunrise'}

labels = []
for img in imgs:
   for i, c in enumerate(species):
       if c in img:
           labels.append(i)
           
transforms = transforms.Compose([
   transforms.Resize((96, 96)),
   transforms.ToTensor(),
   transforms.Normalize(mean=[.5, .5, .5], std=[.5, .5, .5])
])

class WT_dataset(data.Dataset):
   def __init__(self, imgs_path, lables):
       self.imgs_path = imgs_path
       self.lables = lables

   def __getitem__(self, index):
       img_path = self.imgs_path[index]
       lable = self.lables[index]
       
       pil_img = Image.open(img_path)
       pil_img = pil_img.convert("RGB")
       pil_img = transforms(pil_img)
       return pil_img, lable

   def __len__(self):
       return len(self.imgs_path)
   
dataset = WT_dataset(imgs, labels)
count = len(dataset)

train_count = int(0.8*count)
test_count = count - train_count
train_dataset, test_dataset = data.random_split(dataset, [train_count, test_count])
# print(len(train_dataset), len(test_dataset))

BTACH_SIZE = 16

train_dl = torch.utils.data.DataLoader(
                                      train_dataset,
                                      batch_size=BTACH_SIZE,
                                      shuffle=True
)

test_dl = torch.utils.data.DataLoader(
                                      test_dataset,
                                      batch_size=BTACH_SIZE,
)

imgs, labels = next(iter(train_dl))
# imgs.shape   #torch.Size([16, 3, 96, 96])
# imgs[0].shape  #torch.Size([3, 96, 96])

im = imgs[0].permute(1, 2, 0)
# im.shape   #torch.Size([96, 96, 3])
im = im.numpy()
# type(im)  #numpy.ndarray
# im.shape  #(96, 96, 3)
# im.max(), im.min()  #(1.0, -0.9764706)
im = (im + 1)/2
# im.max(), im.min()  # (1.0, 0.011764705)
# plt.imshow(im)
# plt.title(idx_to_species[labels[0].item()])

# plt.figure(figsize=(12, 8))
# for i, (img, label) in enumerate(zip(imgs[:6], labels[:6])):
#     img = (img.permute(1, 2, 0).numpy() + 1)/2
#     plt.subplot(2, 3, i+1)
#     plt.title(idx_to_species.get(label.item()))
#     plt.imshow(img)

class Net(nn.Module):
   def __init__(self):
       super(Net, self).__init__()
       self.conv1 = nn.Conv2d(3, 16, 3)
       self.conv2 = nn.Conv2d(16, 32, 3)
       self.conv3 = nn.Conv2d(32, 64, 3)
       self.fc1 = nn.Linear(64*10*10, 1024)
       self.fc2 = nn.Linear(1024, 4)
   def forward(self, x):
       x = F.relu(self.conv1(x))
       x = F.max_pool2d(x, 2)
       x = F.relu(self.conv2(x))
       x = F.max_pool2d(x, 2)
       x = F.relu(self.conv3(x))
       x = F.max_pool2d(x, 2)
       x = x.view(-1, 64*10*10)
       x = F.relu(self.fc1(x))
       x = self.fc2(x)
       return x
   
device = "cuda" if torch.cuda.is_available() else "cpu"
print("Using {} device".format(device))

model = Net().to(device)
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.0005)

#此处使用训练代码
def train(dataloader, model, loss_fn, optimizer):
   size = len(dataloader.dataset)
   num_batches = len(dataloader)
   train_loss, correct = 0, 0
   model.train()
   for X, y in dataloader:
       X, y = X.to(device), y.to(device)

       # Compute prediction error
       pred = model(X)
       loss = loss_fn(pred, y)

       # Backpropagation
       optimizer.zero_grad()
       loss.backward()
       optimizer.step()
       
       with torch.no_grad():
           correct += (pred.argmax(1) == y).type(torch.float).sum().item()
           train_loss += loss.item()
   train_loss /= num_batches
   correct /= size
   return train_loss, correct

def test(dataloader, model):
   size = len(dataloader.dataset)
   num_batches = len(dataloader)
   model.eval()
   test_loss, correct = 0, 0
   with torch.no_grad():
       for X, y in dataloader:
           X, y = X.to(device), y.to(device)
           pred = model(X)
           test_loss += loss_fn(pred, y).item()
           correct += (pred.argmax(1) == y).type(torch.float).sum().item()
   test_loss /= num_batches
   correct /= size

   return test_loss, correct

epochs = 30

train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
   epoch_loss, epoch_acc = train(train_dl, model, loss_fn, optimizer)
   epoch_test_loss, epoch_test_acc = test(test_dl, model)
   train_loss.append(epoch_loss)
   train_acc.append(epoch_acc)
   test_loss.append(epoch_test_loss)
   test_acc.append(epoch_test_acc)
   
   template = ("epoch:{:2d}, train_loss: {:.5f}, train_acc: {:.1f}% ," 
               "test_loss: {:.5f}, test_acc: {:.1f}%")
   print(template.format(
         epoch, epoch_loss, epoch_acc*100, epoch_test_loss, epoch_test_acc*100))
   
print("Done!")

结果如下,可以看到,出现了典型的过拟合

Using cpu device
epoch: 0, train_loss: 0.68748, train_acc: 70.3% ,test_loss: 0.51200, test_acc: 78.7%
epoch: 1, train_loss: 0.44641, train_acc: 80.7% ,test_loss: 0.44766, test_acc: 83.6%
epoch: 2, train_loss: 0.35408, train_acc: 86.1% ,test_loss: 0.45204, test_acc: 81.3%
epoch: 3, train_loss: 0.28549, train_acc: 88.2% ,test_loss: 0.36997, test_acc: 86.7%
epoch: 4, train_loss: 0.28846, train_acc: 88.6% ,test_loss: 0.33302, test_acc: 86.7%
epoch: 5, train_loss: 0.20706, train_acc: 91.0% ,test_loss: 0.39258, test_acc: 85.3%
epoch: 6, train_loss: 0.14972, train_acc: 94.6% ,test_loss: 0.36199, test_acc: 89.3%
epoch: 7, train_loss: 0.12087, train_acc: 95.9% ,test_loss: 0.39664, test_acc: 86.2%
epoch: 8, train_loss: 0.13703, train_acc: 95.8% ,test_loss: 0.38577, test_acc: 87.1%
epoch: 9, train_loss: 0.07256, train_acc: 97.5% ,test_loss: 0.34249, test_acc: 88.0%
epoch:10, train_loss: 0.03893, train_acc: 99.3% ,test_loss: 0.37080, test_acc: 87.1%
epoch:11, train_loss: 0.03140, train_acc: 99.4% ,test_loss: 0.35255, test_acc: 88.4%
epoch:12, train_loss: 0.01772, train_acc: 99.7% ,test_loss: 0.41663, test_acc: 85.3%
epoch:13, train_loss: 0.01291, train_acc: 99.7% ,test_loss: 0.37951, test_acc: 87.1%
epoch:14, train_loss: 0.00878, train_acc: 99.9% ,test_loss: 0.42552, test_acc: 87.6%
epoch:15, train_loss: 0.00959, train_acc: 99.8% ,test_loss: 0.47467, test_acc: 88.4%
epoch:16, train_loss: 0.03479, train_acc: 98.4% ,test_loss: 0.52727, test_acc: 85.8%
epoch:17, train_loss: 0.04033, train_acc: 98.3% ,test_loss: 0.55592, test_acc: 84.4%
epoch:18, train_loss: 0.01262, train_acc: 99.8% ,test_loss: 0.51468, test_acc: 84.9%
epoch:19, train_loss: 0.00689, train_acc: 99.9% ,test_loss: 0.51769, test_acc: 85.8%
epoch:20, train_loss: 0.00187, train_acc: 100.0% ,test_loss: 0.51874, test_acc: 85.8%
epoch:21, train_loss: 0.00081, train_acc: 100.0% ,test_loss: 0.52987, test_acc: 84.9%
epoch:22, train_loss: 0.00062, train_acc: 100.0% ,test_loss: 0.54441, test_acc: 85.3%
epoch:23, train_loss: 0.00049, train_acc: 100.0% ,test_loss: 0.55355, test_acc: 84.9%
epoch:24, train_loss: 0.00038, train_acc: 100.0% ,test_loss: 0.56715, test_acc: 85.3%
epoch:25, train_loss: 0.00033, train_acc: 100.0% ,test_loss: 0.57268, test_acc: 84.9%
epoch:26, train_loss: 0.00029, train_acc: 100.0% ,test_loss: 0.58034, test_acc: 84.9%
epoch:27, train_loss: 0.00026, train_acc: 100.0% ,test_loss: 0.59031, test_acc: 85.3%
epoch:28, train_loss: 0.00023, train_acc: 100.0% ,test_loss: 0.59435, test_acc: 84.9%
epoch:29, train_loss: 0.00021, train_acc: 100.0% ,test_loss: 0.60332, test_acc: 84.9%
Done!

绘图看效果

plt.plot(range(1, epochs+1), train_loss, label='train_loss')
plt.plot(range(1, epochs+1), test_loss, label='test_loss')
plt.legend()
# plt.savefig('10-4.jpg')
image.png

plt.plot(range(1, epochs+1), train_acc, label='train_acc')
plt.plot(range(1, epochs+1), test_acc, label='test_acc')
plt.legend()

plt.savefig('10-5.jpg')

![image.png](https://img.haomeiwen.com/i3968643/346d5e8be83b580e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

添加dropout层

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import torchvision
import glob
from torchvision import transforms
from torch.utils import data
from PIL import Image

img_dir = r'./data/dataset2/*.jpg'
imgs = glob.glob(img_dir)

imgs[:3]

species = ['cloudy', 'rain', 'shine', 'sunrise']
species_to_idx = dict((c, i) for i, c in enumerate(species))

species_to_idx # {'cloudy': 0, 'rain': 1, 'shine': 2, 'sunrise': 3}

idx_to_species = dict((v, k) for k, v in species_to_idx.items())

idx_to_species # {0: 'cloudy', 1: 'rain', 2: 'shine', 3: 'sunrise'}

labels = []
for img in imgs:
for i, c in enumerate(species):
if c in img:
labels.append(i)

transforms = transforms.Compose([
transforms.Resize((96, 96)),
transforms.ToTensor(),
transforms.Normalize(mean=[.5, .5, .5], std=[.5, .5, .5])
])

class WT_dataset(data.Dataset):
def init(self, imgs_path, lables):
self.imgs_path = imgs_path
self.lables = lables

def __getitem__(self, index):
    img_path = self.imgs_path[index]
    lable = self.lables[index]
    
    pil_img = Image.open(img_path)
    pil_img = pil_img.convert("RGB")
    pil_img = transforms(pil_img)
    return pil_img, lable

def __len__(self):
    return len(self.imgs_path)

dataset = WT_dataset(imgs, labels)
count = len(dataset)

train_count = int(0.8*count)
test_count = count - train_count
train_dataset, test_dataset = data.random_split(dataset, [train_count, test_count])

print(len(train_dataset), len(test_dataset))

BTACH_SIZE = 16

train_dl = torch.utils.data.DataLoader(
train_dataset,
batch_size=BTACH_SIZE,
shuffle=True
)

test_dl = torch.utils.data.DataLoader(
test_dataset,
batch_size=BTACH_SIZE,
)

imgs, labels = next(iter(train_dl))

imgs.shape #torch.Size([16, 3, 96, 96])

imgs[0].shape #torch.Size([3, 96, 96])

im = imgs[0].permute(1, 2, 0)

im.shape #torch.Size([96, 96, 3])

im = im.numpy()

type(im) #numpy.ndarray

im.shape #(96, 96, 3)

im.max(), im.min() #(1.0, -0.9764706)

im = (im + 1)/2

im.max(), im.min() # (1.0, 0.011764705)

plt.imshow(im)

plt.title(idx_to_species[labels[0].item()])

plt.figure(figsize=(12, 8))

for i, (img, label) in enumerate(zip(imgs[:6], labels[:6])):

img = (img.permute(1, 2, 0).numpy() + 1)/2

plt.subplot(2, 3, i+1)

plt.title(idx_to_species.get(label.item()))

plt.imshow(img)

class Net(nn.Module):
def init(self):
super(Net, self).init()
self.conv1 = nn.Conv2d(3, 16, 3)
self.conv2 = nn.Conv2d(16, 32, 3)
self.conv3 = nn.Conv2d(32, 64, 3)
self.fc1 = nn.Linear(641010, 1024)
self.fc2 = nn.Linear(1024, 4)
def forward(self, x):
x = F.relu(self.conv1(x))
x = F.max_pool2d(x, 2)
x = F.relu(self.conv2(x))
x = F.max_pool2d(x, 2)
x = F.relu(self.conv3(x))
x = F.max_pool2d(x, 2)
x = x.view(-1, 641010)
x = F.dropout(x) # dropout层常加在模型的后半部分
x = F.relu(self.fc1(x))
x = F.dropout(x) # dropout训练的时候发挥作用,预测的时候不发挥作用
x = self.fc2(x)
return x

device = "cuda" if torch.cuda.is_available() else "cpu"
print("Using {} device".format(device))

model = Net().to(device)
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.0005)

此处使用训练代码

def train(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset)
num_batches = len(dataloader)
train_loss, correct = 0, 0
model.train()
for X, y in dataloader:
X, y = X.to(device), y.to(device)

    # Compute prediction error
    pred = model(X)
    loss = loss_fn(pred, y)

    # Backpropagation
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    with torch.no_grad():
        correct += (pred.argmax(1) == y).type(torch.float).sum().item()
        train_loss += loss.item()
train_loss /= num_batches
correct /= size
return train_loss, correct

def test(dataloader, model):
size = len(dataloader.dataset)
num_batches = len(dataloader)
model.eval()
test_loss, correct = 0, 0
with torch.no_grad():
for X, y in dataloader:
X, y = X.to(device), y.to(device)
pred = model(X)
test_loss += loss_fn(pred, y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= num_batches
correct /= size

return test_loss, correct

epochs = 30

train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
epoch_loss, epoch_acc = train(train_dl, model, loss_fn, optimizer)
epoch_test_loss, epoch_test_acc = test(test_dl, model)
train_loss.append(epoch_loss)
train_acc.append(epoch_acc)
test_loss.append(epoch_test_loss)
test_acc.append(epoch_test_acc)

template = ("epoch:{:2d}, train_loss: {:.5f}, train_acc: {:.1f}% ," 
            "test_loss: {:.5f}, test_acc: {:.1f}%")
print(template.format(
      epoch, epoch_loss, epoch_acc*100, epoch_test_loss, epoch_test_acc*100))

print("Done!")

运行结果,发现模型在测试集上的精度可以达到93%,过拟合程度有所减轻

Using cpu device
epoch: 0, train_loss: 0.83255, train_acc: 65.7% ,test_loss: 0.51496, test_acc: 78.7%
epoch: 1, train_loss: 0.53236, train_acc: 78.9% ,test_loss: 0.38309, test_acc: 84.4%
epoch: 2, train_loss: 0.43129, train_acc: 84.3% ,test_loss: 0.37356, test_acc: 84.4%
epoch: 3, train_loss: 0.34785, train_acc: 86.2% ,test_loss: 0.31637, test_acc: 85.3%
epoch: 4, train_loss: 0.29846, train_acc: 89.2% ,test_loss: 0.29301, test_acc: 86.2%
epoch: 5, train_loss: 0.27856, train_acc: 90.2% ,test_loss: 0.35346, test_acc: 86.2%
epoch: 6, train_loss: 0.25940, train_acc: 90.3% ,test_loss: 0.27922, test_acc: 88.9%
epoch: 7, train_loss: 0.25393, train_acc: 90.6% ,test_loss: 0.24733, test_acc: 90.2%
epoch: 8, train_loss: 0.20988, train_acc: 92.6% ,test_loss: 0.24222, test_acc: 91.6%
epoch: 9, train_loss: 0.18069, train_acc: 95.1% ,test_loss: 0.36781, test_acc: 87.1%
epoch:10, train_loss: 0.19070, train_acc: 92.5% ,test_loss: 0.22535, test_acc: 92.9%
epoch:11, train_loss: 0.12348, train_acc: 95.4% ,test_loss: 0.21885, test_acc: 91.1%
epoch:12, train_loss: 0.10145, train_acc: 95.5% ,test_loss: 0.27175, test_acc: 92.4%
epoch:13, train_loss: 0.07581, train_acc: 97.3% ,test_loss: 0.33245, test_acc: 88.4%
epoch:14, train_loss: 0.14387, train_acc: 95.5% ,test_loss: 0.30863, test_acc: 87.6%
epoch:15, train_loss: 0.18415, train_acc: 93.5% ,test_loss: 0.25011, test_acc: 91.1%
epoch:16, train_loss: 0.07594, train_acc: 97.7% ,test_loss: 0.28527, test_acc: 91.1%
epoch:17, train_loss: 0.04944, train_acc: 98.4% ,test_loss: 0.24389, test_acc: 93.8%
epoch:18, train_loss: 0.05305, train_acc: 98.3% ,test_loss: 0.24843, test_acc: 91.6%
epoch:19, train_loss: 0.03309, train_acc: 98.9% ,test_loss: 0.23819, test_acc: 92.0%
epoch:20, train_loss: 0.03388, train_acc: 99.0% ,test_loss: 0.28514, test_acc: 90.7%
epoch:21, train_loss: 0.04579, train_acc: 98.6% ,test_loss: 0.28422, test_acc: 88.9%
epoch:22, train_loss: 0.02961, train_acc: 98.9% ,test_loss: 0.24673, test_acc: 92.9%
epoch:23, train_loss: 0.01210, train_acc: 99.8% ,test_loss: 0.29757, test_acc: 93.3%
epoch:24, train_loss: 0.03507, train_acc: 98.6% ,test_loss: 0.40753, test_acc: 89.8%
epoch:25, train_loss: 0.06492, train_acc: 97.9% ,test_loss: 0.23913, test_acc: 93.3%
epoch:26, train_loss: 0.02402, train_acc: 99.2% ,test_loss: 0.34266, test_acc: 90.2%
epoch:27, train_loss: 0.01186, train_acc: 99.9% ,test_loss: 0.29447, test_acc: 90.7%
epoch:28, train_loss: 0.00844, train_acc: 100.0% ,test_loss: 0.31380, test_acc: 91.6%
epoch:29, train_loss: 0.04880, train_acc: 98.2% ,test_loss: 0.28779, test_acc: 93.8%
Done!

![image.png](https://img.haomeiwen.com/i3968643/3797854ba59da03a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![image.png](https://img.haomeiwen.com/i3968643/7e9589c5386ba949.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
# BN层

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import torchvision
import glob
from torchvision import transforms
from torch.utils import data
from PIL import Image

img_dir = r'./data/dataset2/*.jpg'
imgs = glob.glob(img_dir)

imgs[:3]

species = ['cloudy', 'rain', 'shine', 'sunrise']
species_to_idx = dict((c, i) for i, c in enumerate(species))

species_to_idx # {'cloudy': 0, 'rain': 1, 'shine': 2, 'sunrise': 3}

idx_to_species = dict((v, k) for k, v in species_to_idx.items())

idx_to_species # {0: 'cloudy', 1: 'rain', 2: 'shine', 3: 'sunrise'}

labels = []
for img in imgs:
for i, c in enumerate(species):
if c in img:
labels.append(i)

transforms = transforms.Compose([
transforms.Resize((96, 96)),
transforms.ToTensor(),
transforms.Normalize(mean=[.5, .5, .5], std=[.5, .5, .5])
])

class WT_dataset(data.Dataset):
def init(self, imgs_path, lables):
self.imgs_path = imgs_path
self.lables = lables

def __getitem__(self, index):
    img_path = self.imgs_path[index]
    lable = self.lables[index]
    
    pil_img = Image.open(img_path)
    pil_img = pil_img.convert("RGB")
    pil_img = transforms(pil_img)
    return pil_img, lable

def __len__(self):
    return len(self.imgs_path)

dataset = WT_dataset(imgs, labels)
count = len(dataset)

train_count = int(0.8*count)
test_count = count - train_count
train_dataset, test_dataset = data.random_split(dataset, [train_count, test_count])

print(len(train_dataset), len(test_dataset))

BTACH_SIZE = 16

train_dl = torch.utils.data.DataLoader(
train_dataset,
batch_size=BTACH_SIZE,
shuffle=True
)

test_dl = torch.utils.data.DataLoader(
test_dataset,
batch_size=BTACH_SIZE,
)

imgs, labels = next(iter(train_dl))

imgs.shape #torch.Size([16, 3, 96, 96])

imgs[0].shape #torch.Size([3, 96, 96])

im = imgs[0].permute(1, 2, 0)

im.shape #torch.Size([96, 96, 3])

im = im.numpy()

type(im) #numpy.ndarray

im.shape #(96, 96, 3)

im.max(), im.min() #(1.0, -0.9764706)

im = (im + 1)/2

im.max(), im.min() # (1.0, 0.011764705)

plt.imshow(im)

plt.title(idx_to_species[labels[0].item()])

plt.figure(figsize=(12, 8))

for i, (img, label) in enumerate(zip(imgs[:6], labels[:6])):

img = (img.permute(1, 2, 0).numpy() + 1)/2

plt.subplot(2, 3, i+1)

plt.title(idx_to_species.get(label.item()))

plt.imshow(img)

class Net(nn.Module):
def init(self):
super(Net, self).init()
self.conv1 = nn.Conv2d(3, 16, 3)
self.bn1 = nn.BatchNorm2d(16)
self.conv2 = nn.Conv2d(16, 32, 3)
self.bn2 = nn.BatchNorm2d(32)
self.conv3 = nn.Conv2d(32, 64, 3)
self.bn3 = nn.BatchNorm2d(64)
self.fc1 = nn.Linear(641010, 1024)
self.fc2 = nn.Linear(1024, 4)
def forward(self, x):
x = F.relu(self.conv1(x))
x = self.bn1(x) # bn层加载每个卷积层的后面
x = F.max_pool2d(x, 2)
x = F.relu(self.conv2(x))
x = self.bn2(x)
x = F.max_pool2d(x, 2)
x = F.relu(self.conv3(x))
x = self.bn3(x)
x = F.max_pool2d(x, 2)
x = x.view(-1, 641010)
x = F.dropout(x)
x = F.relu(self.fc1(x))
x = F.dropout(x) # dropout层常加载模型的后半部分,relu激活之后
x = self.fc2(x)
return x

device = "cuda" if torch.cuda.is_available() else "cpu"
print("Using {} device".format(device))

model = Net().to(device)
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.0005)

此处使用训练代码

def train(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset)
num_batches = len(dataloader)
train_loss, correct = 0, 0
model.train()
for X, y in dataloader:
X, y = X.to(device), y.to(device)

    # Compute prediction error
    pred = model(X)
    loss = loss_fn(pred, y)

    # Backpropagation
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    with torch.no_grad():
        correct += (pred.argmax(1) == y).type(torch.float).sum().item()
        train_loss += loss.item()
train_loss /= num_batches
correct /= size
return train_loss, correct

def test(dataloader, model):
size = len(dataloader.dataset)
num_batches = len(dataloader)
model.eval()
test_loss, correct = 0, 0
with torch.no_grad():
for X, y in dataloader:
X, y = X.to(device), y.to(device)
pred = model(X)
test_loss += loss_fn(pred, y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= num_batches
correct /= size

return test_loss, correct

epochs = 30

train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
epoch_loss, epoch_acc = train(train_dl, model, loss_fn, optimizer)
epoch_test_loss, epoch_test_acc = test(test_dl, model)
train_loss.append(epoch_loss)
train_acc.append(epoch_acc)
test_loss.append(epoch_test_loss)
test_acc.append(epoch_test_acc)

template = ("epoch:{:2d}, train_loss: {:.5f}, train_acc: {:.1f}% ," 
            "test_loss: {:.5f}, test_acc: {:.1f}%")
print(template.format(
      epoch, epoch_loss, epoch_acc*100, epoch_test_loss, epoch_test_acc*100))

print("Done!")

发现添加BN层以后,过拟合程度又有所缓解

Using cpu device
epoch: 0, train_loss: 0.70215, train_acc: 76.1% ,test_loss: 0.41067, test_acc: 88.0%
epoch: 1, train_loss: 0.34076, train_acc: 88.7% ,test_loss: 0.37571, test_acc: 88.9%
epoch: 2, train_loss: 0.28711, train_acc: 90.1% ,test_loss: 0.43254, test_acc: 89.8%
epoch: 3, train_loss: 0.33113, train_acc: 91.5% ,test_loss: 0.36966, test_acc: 92.0%
epoch: 4, train_loss: 0.43764, train_acc: 90.6% ,test_loss: 0.39042, test_acc: 89.8%
epoch: 5, train_loss: 0.23872, train_acc: 92.0% ,test_loss: 0.38543, test_acc: 91.6%
epoch: 6, train_loss: 0.14291, train_acc: 94.4% ,test_loss: 0.51747, test_acc: 90.7%
epoch: 7, train_loss: 0.07774, train_acc: 97.0% ,test_loss: 0.50244, test_acc: 92.4%
epoch: 8, train_loss: 0.21562, train_acc: 95.0% ,test_loss: 0.41490, test_acc: 88.9%
epoch: 9, train_loss: 0.16212, train_acc: 95.1% ,test_loss: 0.82729, test_acc: 84.9%
epoch:10, train_loss: 0.31971, train_acc: 94.4% ,test_loss: 0.46296, test_acc: 91.1%
epoch:11, train_loss: 0.32646, train_acc: 93.9% ,test_loss: 0.42989, test_acc: 91.1%
epoch:12, train_loss: 0.16973, train_acc: 94.6% ,test_loss: 0.51918, test_acc: 92.4%
epoch:13, train_loss: 0.18273, train_acc: 96.2% ,test_loss: 0.28969, test_acc: 94.7%
epoch:14, train_loss: 0.21432, train_acc: 97.4% ,test_loss: 0.70219, test_acc: 88.4%
epoch:15, train_loss: 0.14481, train_acc: 95.7% ,test_loss: 0.49484, test_acc: 90.7%
epoch:16, train_loss: 0.15458, train_acc: 96.1% ,test_loss: 0.50004, test_acc: 90.7%
epoch:17, train_loss: 0.21481, train_acc: 95.7% ,test_loss: 0.41386, test_acc: 93.3%
epoch:18, train_loss: 0.19341, train_acc: 94.1% ,test_loss: 0.41717, test_acc: 92.0%
epoch:19, train_loss: 0.05077, train_acc: 98.2% ,test_loss: 0.58097, test_acc: 92.9%
epoch:20, train_loss: 0.03630, train_acc: 99.0% ,test_loss: 0.44665, test_acc: 94.7%
epoch:21, train_loss: 0.10373, train_acc: 98.4% ,test_loss: 0.53761, test_acc: 91.6%
epoch:22, train_loss: 0.12990, train_acc: 98.0% ,test_loss: 0.67024, test_acc: 91.1%
epoch:23, train_loss: 0.24553, train_acc: 95.3% ,test_loss: 0.77951, test_acc: 90.2%
epoch:24, train_loss: 0.21235, train_acc: 96.2% ,test_loss: 0.58993, test_acc: 92.9%
epoch:25, train_loss: 0.11087, train_acc: 98.1% ,test_loss: 0.55715, test_acc: 94.7%
epoch:26, train_loss: 0.10319, train_acc: 97.0% ,test_loss: 0.74915, test_acc: 92.0%
epoch:27, train_loss: 0.08751, train_acc: 97.2% ,test_loss: 0.79789, test_acc: 92.0%
epoch:28, train_loss: 0.08388, train_acc: 97.9% ,test_loss: 0.61166, test_acc: 91.6%
epoch:29, train_loss: 0.18168, train_acc: 96.2% ,test_loss: 0.86462, test_acc: 92.0%
Done!


# 也可以定义一个fit函数,方便直接调用进行训练

def fit(epochs, train_dl, test_dl, model, loss_fn, optimizer, exp_lr_scheduler=None):
train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
    epoch_loss, epoch_acc = train(train_dl, model, loss_fn, optimizer)
    epoch_test_loss, epoch_test_acc = test(test_dl, model)
    train_loss.append(epoch_loss)
    train_acc.append(epoch_acc)
    test_loss.append(epoch_test_loss)
    test_acc.append(epoch_test_acc)
    if exp_lr_scheduler:
        exp_lr_scheduler.step()       # 学习速率衰减

    template = ("epoch:{:2d}, train_loss: {:.5f}, train_acc: {:.1f}% ," 
                "test_loss: {:.5f}, test_acc: {:.1f}%")
    print(template.format(
          epoch, epoch_loss, epoch_acc*100, epoch_test_loss, epoch_test_acc*100))
    
print("Done!")
return train_loss, test_loss, train_acc, test_acc



上一篇 下一篇

猜你喜欢

热点阅读