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)
还没有任何评论哟~
