Advertisement

DenseNet算法实现乳腺癌识别

阅读量:

- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊

一:前期准备

1.设置GPU

复制代码
 import torch

    
 import torch.nn as nn
    
 import torchvision.transforms as transforms
    
 import torchvision
    
 import torch.nn.functional as F
    
 from torchvision import transforms,datasets
    
 import os,PIL,pathlib,warnings
    
  
    
 warnings.filterwarnings('ignore')
    
 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    
 print(device)
    
    
    
    

2.导入数据

复制代码
 data_dir = '/content/drive/MyDrive/J3-data'

    
 data_dir = pathlib.Path(data_dir)
    
  
    
 data_path = list(data_dir.glob('*'))
    
 class_names = [str(path).split("/")[-1] for path in data_path]  
    
 print(class_names)
    
    
    
    
复制代码
 train_transforms = transforms.Compose([

    
     transforms.Resize([224,224]), #将输入图片resize成统一尺寸
    
     transforms.ToTensor(), #将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间
    
     transforms.Normalize(  #标准化处理-->转换为标准正态分布(高斯分布),使模型更容易收敛
    
     mean = [0.485,0.456,0.406],
    
     std = [0.229,0.224,0.225]) #mean和std从数据中随机抽样计算得到
    
 ])
    
  
    
 test_transforms = transforms.Compose([
    
     transforms.Resize([224,224]), #将输入图片resize成统一尺寸
    
     transforms.ToTensor(), #将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间
    
     transforms.Normalize(  #标准化处理-->转换为标准正态分布(高斯分布),使模型更容易收敛
    
     mean = [0.485,0.456,0.406],
    
     std = [0.229,0.224,0.225]) #mean和std从数据中随机抽样计算得到
    
 ])
    
  
    
 total_data = datasets.ImageFolder(root = data_dir,transform = train_transforms)
    
 total_data
    
    
    
    

3.划分数据集

复制代码
 train_size = int(0.8*len(total_data))

    
 test_size = len(total_data)-train_size
    
 train_datasize , test_datasize = torch.utils.data.random_split(total_data,[train_size,test_size])
    
 train_datasize,test_datasize
    
    
    
    
复制代码
 batch_size = 32

    
 train_dl = torch.utils.data.DataLoader(train_datasize,batch_size,shuffle = True)
    
 test_dl = torch.utils.data.DataLoader(test_datasize,batch_size,shuffle=True)
    
    
    
    
复制代码
 for X,y in test_dl:

    
   print("shape of X [N,C,H,W]:",X.shape)
    
   print("shape of y:",y.shape,y.dtype)
    
   break
    
    
    
    

二:搭建网络模型

复制代码
 from collections import OrderedDict

    
 import torch
    
 import torch.nn as nn
    
 import torch.nn.functional as F
    
    
    
    

1.DenseLayer模块

复制代码
  
    
 class DenseLayer(nn.Sequential):
    
     def __init__(self,in_channel,growth_rate,bn_size,drop_rate):
    
     super(DenseLayer,self).__init__()
    
     self.add_module('norm1',nn.BatchNorm2d(in_channel))
    
     self.add_module('relu1',nn.ReLU(inplace=True))
    
     self.add_module('conv1',
    
                     nn.Conv2d(in_channel,bn_size*growth_rate,
    
                               kernel_size=1,stride=1,bias=False))
    
     self.add_module('norm2',nn.BatchNorm2d(bn_size*growth_rate))
    
     self.add_module('relu2',nn.ReLU(inplace=True))
    
     self.add_module('conv2',
    
                     nn.Conv2d(bn_size*growth_rate,growth_rate,
    
                               kernel_size=3,stride=1,padding=1,bias=False))
    
     self.drop_rate=drop_rate
    
     
    
     def forward(self,x):
    
     new_feature=super(DenseLayer,self).forward(x)
    
     if self.drop_rate>0:
    
         new_feature=F.drop_rate(new_feature,p=self.drop_rate,training=self.training)
    
     return torch.cat([x,new_feature],1)
    
    
    
    

2.DenseBlock模块

复制代码
 """DenseBlock"""

    
 class DenseBlock(nn.Sequential):
    
     def __init__(self,num_layers,in_channel,bn_size,growth_rate,drop_rate):
    
     super(DenseBlock,self).__init__()
    
     for i in range(num_layers):
    
         layer=DenseLayer(in_channel+i*growth_rate,growth_rate,bn_size,drop_rate)
    
         self.add_module('denselayer%d'%(i+1),layer)
    
    
    
    

3.Transition模块

复制代码
 """Transition layer between two adjacent DenseBlock"""

    
 class Transition(nn.Sequential):
    
     def __init__(self,in_channel,out_channel):
    
     super(Transition,self).__init__()
    
     self.add_module('norm',nn.BatchNorm2d(in_channel))
    
     self.add_module('relu',nn.ReLU(inplace=True))
    
     self.add_module('conv',
    
                     nn.Conv2d(in_channel,out_channel,
    
                               kernel_size=1,stride=1,bias=False))
    
     self.add_module('pool',nn.AvgPool2d(2,stride=2))
    
    
    
    

4.构建DenseNet

复制代码
 class DenseNet(nn.Module):

    
     def __init__(self,growth_rate=32,block_config=(6,12,24,16),init_channel=64,
    
              bn_size=4,compression_rate=0.5,drop_rate=0,num_classes=1000):
    
     super(DenseNet,self).__init__()
    
     #first Conv2d
    
     self.features=nn.Sequential(OrderedDict([
    
         ('conv0',nn.Conv2d(3,init_channel,kernel_size=7,stride=2,padding=3,bias=False)),
    
         ('norm0',nn.BatchNorm2d(init_channel)),
    
         ('relu0',nn.ReLU(inplace=True)),
    
         ('pool0',nn.MaxPool2d(3,stride=2,padding=1))
    
     ]))
    
     
    
     #DenseBlock
    
     num_features=init_channel
    
     for i,num_layers in enumerate(block_config):
    
         block=DenseBlock(num_layers,num_features,bn_size,growth_rate,drop_rate)
    
         self.features.add_module('denseblock%d' % (i+1),block)
    
         num_features+=num_layers*growth_rate
    
         if i!=len(block_config)-1:  
    
             transition=Transition(num_features,int(num_features*compression_rate))
    
             self.features.add_module('transition%d' % (i+1),transition)
    
             num_features=int(num_features*compression_rate)
    
     
    
     #final BN+ReLU
    
     self.features.add_module('norm5',nn.BatchNorm2d(num_features))
    
     self.features.add_module('relu5',nn.ReLU(inplace=True))
    
     #分类层
    
     self.classifier=nn.Linear(num_features,num_classes)
    
     
    
     #参数初始化
    
     for m in self.modules():
    
         if isinstance(m,nn.Conv2d):
    
             nn.init.kaiming_normal_(m.weight)
    
         elif isinstance(m,nn.BatchNorm2d):
    
             nn.init.constant_(m.bias,0)
    
             nn.init.constant_(m.weight,1)
    
         elif isinstance(m,nn.Linear):
    
             nn.init.constant_(m.bias,0)
    
             
    
     def forward(self,x):
    
     x=self.features(x)
    
     x=F.avg_pool2d(x,7,stride=1).view(x.size(0),-1)
    
     x=self.classifier(x)
    
     return x
    
    
    
    

5.构建densenet121

复制代码
 DenseNet121=DenseNet(init_channel=64,

    
                  growth_rate=32,
    
                  block_config=(6,12,24,16),
    
                  num_classes=len(classeNames))
    
  
    
 model=DenseNet121.to(device)
    
 model
    
    
    
    
复制代码
 import torchsummary as summary

    
 summary.summary(model,(3,224,224))
    
    
    
    

三:训练模型

1.编写训练函数

复制代码
 def train(dataloader,model,loss_fn,optimizer):

    
     size=len(dataloader.dataset) #训练集的大小
    
     num_batches=len(dataloader) #批次数目
    
     
    
     train_loss,train_acc=0,0 #初始化训练损失和正确率
    
     
    
     for x,y in dataloader: #获取图片及其标签
    
     x,y=x.to(device),y.to(device)
    
     
    
     #计算预测误差
    
     pred=model(x) #网络输出
    
     loss=loss_fn(pred,y) #计算网络输出和真实值之间的差距,二者差值即为损失
    
     
    
     #反向传播
    
     optimizer.zero_grad() #grad属性归零
    
     loss.backward() #反向传播
    
     optimizer.step() #每一步自动更新
    
     
    
     #记录acc与loss
    
     train_acc+=(pred.argmax(1)==y).type(torch.float).sum().item()
    
     train_loss+=loss.item()
    
     
    
     train_acc/=size
    
     train_loss/=num_batches
    
     
    
     return train_acc,train_loss
    
    
    
    

2.编写测试函数

复制代码
 def test(dataloader,model,loss_fn):

    
     size=len(dataloader.dataset) #测试集的大小
    
     num_batches=len(dataloader) #批次数目
    
     test_loss,test_acc=0,0
    
     
    
     #当不进行训练时,停止梯度更新,节省计算内存消耗
    
     with torch.no_grad():
    
     for imgs,target in dataloader:
    
         imgs,target=imgs.to(device),target.to(device)
    
         
    
         #计算loss
    
         target_pred=model(imgs)
    
         loss=loss_fn(target_pred,target)
    
         
    
         test_loss+=loss.item()
    
         test_acc+=(target_pred.argmax(1)==target).type(torch.float).sum().item()
    
         
    
     test_acc/=size
    
     test_loss/=num_batches
    
     
    
     return test_acc,test_loss
    
    
    
    

3.正式训练

复制代码
 import copy

    
 opt=torch.optim.Adam(model.parameters(),lr=1e-7) #创建优化器,并设置学习率
    
 loss_fn=nn.CrossEntropyLoss() #创建损失函数
    
  
    
 epochs=20
    
  
    
 train_loss=[]
    
 train_acc=[]
    
 test_loss=[]
    
 test_acc=[]
    
  
    
 best_acc=0 #设置一个最佳准确率,作为最佳模型的判别指标
    
  
    
 for epoch in range(epochs):
    
     
    
     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)
    
     
    
     #保存最佳模型到J3_model
    
     if epoch_test_acc>best_acc:
    
     best_acc=epoch_test_acc
    
     J3_model=copy.deepcopy(model)
    
     
    
     train_acc.append(epoch_train_acc)
    
     train_loss.append(epoch_train_loss)
    
     test_acc.append(epoch_test_acc)
    
     test_loss.append(epoch_test_loss)
    
     
    
     #获取当前学习率
    
     lr=opt.state_dict()['param_groups'][0]['lr']
    
     
    
     template=('Epoch:{:2d},Train_acc:{:.1f}%,Train_loss:{:.3f},Test_acc:{:.1f}%,Test_loss:{:.3f},Lr:{:.2E}')
    
     print(template.format(epoch+1,epoch_train_acc*100,epoch_train_loss,
    
                        epoch_test_acc*100,epoch_test_loss,lr))
    
     
    
 #保存最佳模型到文件中
    
 PATH='./best_model.pth'
    
 torch.save(model.state_dict(),PATH)
    
 print("Done")
    
    
    
    

四:结果可视化

复制代码
 import matplotlib.pyplot as plt

    
 #隐藏警告
    
 import warnings
    
 warnings.filterwarnings("ignore")   #忽略警告信息
    
 plt.rcParams['font.sans-serif']=['SimHei']   #正常显示中文标签
    
 plt.rcParams['axes.unicode_minus']=False   #正常显示负号
    
 plt.rcParams['figure.dpi']=300   #分辨率
    
  
    
 epochs_range=range(epochs)
    
 plt.figure(figsize=(12,3))
    
  
    
 plt.subplot(1,2,1)
    
 plt.plot(epochs_range,train_acc,label='Training Accuracy')
    
 plt.plot(epochs_range,test_acc,label='Test Accuracy')
    
 plt.legend(loc='lower right')
    
 plt.title('Training and Validation Accuracy')
    
  
    
 plt.subplot(1,2,2)
    
 plt.plot(epochs_range,train_loss,label='Training Loss')
    
 plt.plot(epochs_range,test_loss,label='Test Loss')
    
 plt.legend(loc='upper right')
    
 plt.title('Training and Validation Loss')
    
 plt.show()
    
    
    
    

五:总结

这周学习了如何将DenseNet运用到乳腺癌的检测中去,写此篇时网络情况较差,训练结果耗时太长,暂时无法给出。

全部评论 (0)

还没有任何评论哟~