365天深度学习训练营-第P4周:猴痘病识别

 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
🍖 参考原作者:K同学啊|接辅导、项目定制

🏡 我的环境:

      语言环境:Python3.8

      深度学习环境:Pytorch

 需要分别进行:

一、前期准备

1.设置GPU

2.导入数据

3.划分数据集

二、构建简单的CNN网络

三、训练模型

1.设置超参数

2.编写训练函数

3.编写测试函数

4.正式训练

四、结果可视化

1.LOSS和ACCURACY图

2.指定图片进行预测

五、保存并加载模型

目标1.设置动态学习率

目标2.测试accuracy

整体代码:

import torch
import os,PIL,random,pathlib,warnings
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import torchvision,time
import torch.nn as nn
from torchsummary import summary
from torchvision.models import vgg16

num_class=2
def localDataset(data_dir):
    data_dir=pathlib.Path(data_dir)
    data_paths=list(data_dir.glob('*'))
    classNames=[str(path).split('\\')[-1] for path in data_paths]
    print("className:",classNames,'\n')
    train_transforms=torchvision.transforms.Compose([
        torchvision.transforms.Resize([224,224]),
        torchvision.transforms.ToTensor(),
        torchvision.transforms.Normalize(
            mean=[0.485,0.456,0.406],
            std=[0.229,0.224,0.225])
    ])
    total_data=torchvision.datasets.ImageFolder(data_dir,transform=train_transforms)
    print(total_data,'\n')

    train_size=int(0.8*len(total_data))
    test_size=len(total_data)-train_size
    print("Train_size:",train_size,"Test_size",test_size,'\n')
    train_data,test_data=torch.utils.data.random_split(total_data,[train_size,test_size])
    return classNames,train_data,test_data

def displayData(imgs,root,show_flag):
    plt.figure(figsize=(20,5))
    for i,imgs in enumerate(imgs[:20]):
        npimg=imgs.numpy().transpose(1,2,0)
        plt.subplot(20,5,i+1)
        plt.imshow(npimg,cmap=plt.cm.binary)
        plt.axis('off')
    plt.savefig(os.path.join(root,'DatasetDispaly.png'))
    if show_flag:
        plt.show()
    else:
        plt.close('all')

def loadData(train_ds,test_ds,batch_size,root='output',show_flag=False):
    train_dl=torch.utils.data.DataLoader(train_ds,batch_size=batch_size,shuffle=True)
    test_dl=torch.utils.data.DataLoader(test_ds,batch_size=batch_size)
    for x,y in train_dl:
        print("shape of x [N,C,H,W]:",x.shape)
        print("shape of y:",y.shape)
        break
    imgs,labels=next(iter(train_dl))
    print("Image shape:",imgs.shape,'\n')
    if not os.path.exists(root) or not os.path.isdir(root):
        os.mkdir(output)
    displayData(imgs,root,show_flag=show_flag)
    return train_dl,test_dl

class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.conv1=nn.Sequential(
            nn.Conv2d(3,12,kernel_size=5,padding=0),
            nn.BatchNorm2d(12),
            nn.ReLU()
        )
        self.conv2=nn.Sequential(
            nn.Conv2d(12,12,kernel_size=5,padding=0),
            nn.BatchNorm2d(12),
            nn.ReLU()
        )
        self.pool3=nn.Sequential(
            nn.MaxPool2d(2),
            nn.Dropout(p=0.2)
        )
        self.conv4=nn.Sequential(
            nn.Conv2d(12,24,kernel_size=5,padding=0),
            nn.BatchNorm2d(24),
            nn.ReLU()
        )
        self.conv5=nn.Sequential(
            nn.Conv2d(24,24,kernel_size=5,padding=0),
            nn.BatchNorm2d(24),
            nn.ReLU()
        )
        self.pool6=nn.Sequential(
            nn.MaxPool2d(2),
            nn.Dropout(p=0.2)
        )

        self.conv7=nn.Sequential(
            nn.Conv2d(24,48,kernel_size=5,padding=0),
            nn.BatchNorm2d(48),
            nn.ReLU()
        )
        self.conv8=nn.Sequential(
            nn.Conv2d(48,48,kernel_size=5,padding=0),
            nn.BatchNorm2d(48),
            nn.ReLU()
        )
        self.pool9=nn.Sequential(
            nn.MaxPool2d(2),
            nn.Dropout(p=0.2)
        )
        self.fc=nn.Sequential(
            nn.Linear(48*21*21,num_class)
        )

    def forward(self,x):
        batch_size=x.size(0)
        x=self.conv1(x)
        x=self.conv2(x)
        x=self.pool3(x)
        x=self.conv4(x)
        x=self.conv5(x)
        x=self.pool6(x)
        x=self.conv7(x)
        x=self.conv8(x)
        x=self.pool9(x)
        x=x.view(batch_size,-1)
        x=self.fc(x)
        return x


class Model_vgg16(nn.Module):
    def __init__(self):
        super(Model_vgg16, self).__init__()
        self.sequ1 = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1),  # 64*224*224
            nn.ReLU(inplace=True),
            nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1),  # 64*224*224
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False),  # 64*112*112
            nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),  # 128*112*112
            nn.ReLU(inplace=True),
            nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1),  # 128*112*112
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False),  # 128*56*56
            nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),  # 256*56*56
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),  # 256*56*56
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),  # 256*56*56
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False),  # 256*28*28
            nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),  # 512*28*28
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),  # 512*28*28
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),  # 512*28*28
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False),  # 512*14*14
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),  # 512*14*14
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),  # 512*14*14
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),  # 512*14*14
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)  # 512*7*7
        )
        self.pool2 = nn.AdaptiveAvgPool2d(output_size=(7, 7))  # 512*7*7
        self.sequ3 = nn.Sequential(
            nn.Flatten(),
            nn.Linear(in_features=25088, out_features=4096, bias=True),
            nn.ReLU(inplace=True),
            nn.Dropout(p=0.5, inplace=False),
            nn.Linear(in_features=4096, out_features=4096, bias=True),
            nn.ReLU(inplace=True),
            nn.Dropout(p=0.5, inplace=False),
            nn.Linear(in_features=4096, out_features=17,bias=True),
            nn.Linear(17,2)
        )

    def forward(self, x):
        x = self.sequ1(x)
        x = self.pool2(x)
        x=self.sequ3(x)
        return x


def autopad(k, p=None):  # kernel, padding
    # Pad to 'same'
    if p is None:
        p = k // 2 if isinstance(k, int) else [x // 2 for x in k]  # auto-pad
    return p


class Conv(nn.Module):
    # Standard convolution
    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groups
        super().__init__()
        self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)
        self.bn = nn.BatchNorm2d(c2)
        self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())

    def forward(self, x):
        return self.act(self.bn(self.conv(x)))

    def forward_fuse(self, x):
        return self.act(self.conv(x))


class Bottleneck(nn.Module):
    # Standard bottleneck
    def __init__(self, c1, c2, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, shortcut, groups, expansion
        super().__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c_, c2, 3, 1, g=g)
        self.add = shortcut and c1 == c2

    def forward(self, x):
        #print("Bottleneck")
        return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))


class C3(nn.Module):
    # CSP Bottleneck with 3 convolutions
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c1, c_, 1, 1)
        self.cv3 = Conv(2 * c_, c2, 1)  # act=FReLU(c2)
        self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))

    def forward(self, x):
        return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1))


class Model_K(nn.Module):
    def __init__(self):
        super(Model_K, self).__init__()

        # 卷积模块
        self.Conv = Conv(3, 32, 3, 2)

        # C3模块1
        self.C3_1 = C3(32, 64, 1, 2)

        # 全连接网络层,用于分类
        self.classifier = nn.Sequential(
            nn.Linear(in_features=802816, out_features=100),
            nn.ReLU(),
            nn.Linear(in_features=100, out_features=2)
        )

    def forward(self, x):
        x = self.Conv(x)
        x = self.C3_1(x)
        x = torch.flatten(x, start_dim=1)
        x = self.classifier(x)

        return x


def train(train_dl,model,loss_fn,opt):
    size=len(train_dl.dataset)
    num_batches=len(train_dl)
    train_acc,train_loss=0,0
    for x,y in train_dl:
        x,y=x.to(device),y.to(device)
        pre=model(x)
        loss=loss_fn(pre,y)
        opt.zero_grad()
        loss.backward()
        opt.step()

        train_acc +=(pre.argmax(1)==y).type(torch.float).sum().item()
        train_loss +=loss.item()
    train_acc/=size
    train_loss/=num_batches
    return train_acc,train_loss

def test(test_dl,model,loss_fn):
    size=len(test_dl.dataset)
    num_batches=len(test_dl)
    test_acc,test_loss=0,0
    with torch.no_grad():
        for x, y in test_dl:
            x, y = x.to(device), y.to(device)
            pre = model(x)
            loss = loss_fn(pre, y)
            test_acc += (pre.argmax(1) == y).type(torch.float).sum().item()
            test_loss += loss.item()
        test_acc /= size
        test_loss /= num_batches
        return test_acc, test_loss

def displayResult(train_acc,test_acc,train_loss,test_loss,start_epoch,epochs,output):
    epochs_range=range(start_epoch,epochs)
    plt.figure(figsize=(20,5))
    plt.subplot(1,2,1)
    plt.plot(epochs_range,train_acc,label="Train_acc")
    plt.plot(epochs_range,test_acc,label="Tesy_acc")
    plt.legend(loc="lower right")
    plt.title("train and test Acc")
    plt.subplot(1,2,2)
    plt.plot(epochs_range,train_loss,label="Train_loss")
    plt.plot(epochs_range,test_loss,label="Test_loss")
    plt.legend(loc="upper right")
    plt.title("Train and Test Loss")
    if not os.path.exists(output) or not os.path.isdir(output):
        os.mkdir(output)
    plt.savefig(os.path.join(output,"Accuracyloss.png"))
    plt.show()

def predict(model, img_path,classeNames):
    img = Image.open(img_path)
    train_transforms = torchvision.transforms.Compose([
        torchvision.transforms.Resize([224, 224]),  # 将输入图片resize成统一尺寸
        torchvision.transforms.ToTensor(),  # 将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间
        torchvision.transforms.Normalize(  # 标准化处理-->转换为标准正太分布(高斯分布),使模型更容易收敛
            mean=[0.485, 0.456, 0.406],
            std=[0.229, 0.224, 0.225])  # 其中 mean=[0.485,0.456,0.406]与std=[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。
    ])
    img = train_transforms(img)
    device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    img = img.to(device).unsqueeze(0)
    output = model(img)
    # print(output.argmax(1))

    _, indices = torch.max(output, 1)
    percentage = torch.nn.functional.softmax(output, dim=1)[0] * 100
    perc = percentage[int(indices)].item()
    result = classeNames[indices]
    print('predicted:', result, perc)

def save_file(output,model,epoche='best'):
    saveFile=os.path.join(output,'epoch'+str(epoche)+'.pkl')
    torch.save(model.state_dict(),saveFile)

if __name__=="__main__":
    device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    print("Using Device is {}".format(device))
    data_dir="./data"
    output='./output_vgg'
    num_classes,train_ds,test_ds=localDataset(data_dir)
    batch_size=64
    train_dl,test_dl=loadData(train_ds,test_ds,batch_size=batch_size,root=output,show_flag=True)
    epoches=100
    start_epoch=0
    train_acc=[]
    train_loss=[]
    test_acc=[]
    test_loss=[]
    best_acc=0.0
    #model=Model().to(device)
    model=Model_K().to(device)
    summary(model,(3,224,224))
    loss_fn=nn.CrossEntropyLoss()
    learn_rate=1e-3
    opt=torch.optim.SGD(model.parameters(),lr=learn_rate)
    print("---Starting train---")
    for epoche in range(start_epoch,epoches):
        model.train()
        epoch_train_acc,epoch_train_loss=train(train_dl,model,loss_fn,opt)
        model.eval()
        epoch_test_acc,epoch_test_loss=test(test_dl,model,loss_fn)
        train_acc.append(epoch_train_acc)
        train_loss.append(epoch_train_loss)
        test_acc.append(epoch_test_acc)
        test_loss.append(epoch_test_loss)
        if(epoch_test_acc>best_acc):
            best_acc=epoch_test_acc
            save_file(output, model)
        template=('Epoch:{:2d}/{:2d},train_acc:{:.1f}%,train_loss:{:.3f},test_acc{:.1f}%,test_loss{:.3f},best_acc:{:.1f}%')
        print(time.strftime('[%Y-%m-%d %H:%M:%S)]'),template.format(epoche+1,epoches,epoch_train_acc*100,epoch_train_loss,epoch_test_acc*100,epoch_test_loss,best_acc*100))
    print("Done")
    displayResult(train_acc,test_acc,train_loss,test_loss,start_epoch,epoches,output)
    imgs_path='./data/Monkeypox/M01_01_06.jpg'
    predict(model,imgs_path,classeNames=num_classes)
    # save_file(output,model,epoches)

模型图:

 

运行简短截图:

 

 学习总结:

调整模型参数和设置不同的动态学习率都会影响运行的结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值