深度学习记录

发布于:2022-07-24 ⋅ 阅读:(334) ⋅ 点赞:(0)

ResNet

一般来说,网络越深、越宽,特征提取能力就会越好。但是当网络达到一定层数时,随着层数的增加,精度会降低,网络的收敛速度也会变慢。

为了解决这个问题,ResNet有两个创新:

提出快捷连接,右边直接连接的部分称为标识映射;

残余块

提出瓶颈块来丰富特征:包括1x1、3x3、1x1卷积和残差结构

 

ResNet代码

导入项目使用的库

importtorch.optimasoptim importtorch importtorch.nnasnn importtorch.nn.parallel importtorch.optim importtorch.utils.data importtorch.utils.data.distributed importtorchvision.transformsastransforms importtorchvision.datasetsasdatasets importtorchvision.models fromeffnetv2importeffnetv2_s fromtorch.autogradimportVariable

 

设置全局参数

设置BatchSize、学习率和epochs,判断是否有cuda环境,如果没有设置为cpu。

#设置全局参数 modellr=1e-4 BATCH_SIZE=64 EPOCHS=20 DEVICE=torch.device('cuda'iftorch.cuda.is_available()else'cpu')

图像预处理

在做图像与处理时,train数据集的transform和验证集的transform分开做,train的图像处理出了resize和归一化之外,还可以设置图像的增强,比如旋转、随机擦除等一系列的操作,验证集则不需要做图像增强,另外不要盲目的做增强,不合理的增强手段很可能会带来负作用,甚至出现Loss不收敛的情况。

#数据预处理 transform=transforms.Compose([ transforms.Resize((224,224)), transforms.ToTensor(), transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5]) ]) transform_test=transforms.Compose([ transforms.Resize((224,224)), transforms.ToTensor(), transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5]) ])

读取数据

使用Pytorch的默认方式读取数据。数据的目录如下图:

img

训练集,取了猫狗大战数据集中,猫狗图像各一万张,剩余的放到验证集中。

#读取数据 dataset_train=datasets.ImageFolder('data/train',transform) print(dataset_train.imgs) #对应文件夹的label print(dataset_train.class_to_idx) dataset_test=datasets.ImageFolder('data/val',transform_test) #对应文件夹的label print(dataset_test.class_to_idx) #导入数据 train_loader=torch.utils.data.DataLoader(dataset_train,batch_size=BATCH_SIZE,shuffle=True) test_loader=torch.utils.data.DataLoader(dataset_test,batch_size=BATCH_SIZE,shuffle=False)

设置模型

使用交叉熵作为loss,模型采用resnet18,建议使用预训练模型,我在调试的过程中,使用预训练模型可以快速得到收敛好的模型,使用预训练模型将pretrained设置为True即可。更改最后一层的全连接,将类别设置为2,然后将模型放到DEVICE。优化器选用Adam。

#实例化模型并且移动到GPU criterion=nn.CrossEntropyLoss() model=torchvision.models.resnet18(pretrained=False) num_ftrs=model.fc.in_features model.fc=nn.Linear(num_ftrs,2) model.to(DEVICE) #选择简单暴力的Adam优化器,学习率调低 optimizer=optim.Adam(model.parameters(),lr=modellr) defadjust_learning_rate(optimizer,epoch): """SetsthelearningratetotheinitialLRdecayedby10every30epochs""" modellrnew=modellr*(0.1**(epoch//50)) print("lr:",modellrnew) forparam_groupinoptimizer.param_groups: param_group['lr']=modellrnew

设置训练和验证

#定义训练过程 deftrain(model,device,train_loader,optimizer,epoch): model.train() sum_loss=0 total_num=len(train_loader.dataset) print(total_num,len(train_loader)) forbatch_idx,(data,target)inenumerate(train_loader): data,target=Variable(data).to(device),Variable(target).to(device) output=model(data) loss=criterion(output,target) optimizer.zero_grad() loss.backward() optimizer.step() print_loss=loss.data.item() sum_loss+=print_loss if(batch_idx+1)%50==0: print('TrainEpoch:{}[{}/{}({:.0f}%)]\tLoss:{:.6f}'.format( epoch,(batch_idx+1)*len(data),len(train_loader.dataset), 100.*(batch_idx+1)/len(train_loader),loss.item())) ave_loss=sum_loss/len(train_loader) print('epoch:{},loss:{}'.format(epoch,ave_loss)) defval(model,device,test_loader): model.eval() test_loss=0 correct=0 total_num=len(test_loader.dataset) print(total_num,len(test_loader)) withtorch.no_grad(): fordata,targetintest_loader: data,target=Variable(data).to(device),Variable(target).to(device) output=model(data) loss=criterion(output,target) _,pred=torch.max(output.data,1) correct+=torch.sum(pred==target) print_loss=loss.data.item() test_loss+=print_loss correct=correct.data.item() acc=correct/total_num avgloss=test_loss/len(test_loader) print('\nValset:Averageloss:{:.4f},Accuracy:{}/{}({:.0f}%)\n'.format( avgloss,correct,len(test_loader.dataset),100*acc)) #训练 forepochinrange(1,EPOCHS+1): adjust_learning_rate(optimizer,epoch) train(model,DEVICE,train_loader,optimizer,epoch) val(model,DEVICE,test_loader) torch.save(model,'model.pth')

这是有预训练模型的情况下训练的结果,1个epoch就已经得到很好的结果了。

img

验证

测试集存放的目录如下图:

第一步 定义类别,这个类别的顺序和训练时的类别顺序对应,一定不要改变顺序!!!!我们在训练时,cat类别是0,dog类别是1,所以我定义classes为(cat,dog)。

第二步 定义transforms,transforms和验证集的transforms一样即可,别做数据增强。

第三步 加载model,并将模型放在DEVICE里,

第四步 读取图片并预测图片的类别,在这里注意,读取图片用PIL库的Image。不要用cv2,transforms不支持。

importtorch.utils.data.distributed importtorchvision.transformsastransforms fromtorch.autogradimportVariable importos fromPILimportImage classes=('cat','dog') transform_test=transforms.Compose([ transforms.Resize((224,224)), transforms.ToTensor(), transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5]) ]) DEVICE=torch.device("cuda:0"iftorch.cuda.is_available()else"cpu") model=torch.load("model.pth") model.eval() model.to(DEVICE) path='data/test/' testList=os.listdir(path) forfileintestList: img=Image.open(path+file) img=transform_test(img) img.unsqueeze_(0) img=Variable(img).to(DEVICE) out=model(img) #Predict _,pred=torch.max(out.data,1) print('ImageName:{},predict:{}'.format(file,classes[pred.data.item()]))

运行结果:

img

其实在读取数据,也可以巧妙的用datasets.ImageFolder,下面我们就用datasets.ImageFolder实现对图片的预测。改一下test数据集的路径,在test文件夹外面再加一层文件件,取名为dataset,如下图所示:

img

然后修改读取图片的方式。代码如下:

importtorch.utils.data.distributed importtorchvision.transformsastransforms importtorchvision.datasetsasdatasets fromtorch.autogradimportVariable classes=('cat','dog') transform_test=transforms.Compose([ transforms.Resize((224,224)), transforms.ToTensor(), transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5]) ]) DEVICE=torch.device("cuda:0"iftorch.cuda.is_available()else"cpu") model=torch.load("model.pth") model.eval() model.to(DEVICE) dataset_test=datasets.ImageFolder('data/datatest',transform_test) print(len(dataset_test)) #对应文件夹的label forindexinrange(len(dataset_test)): item=dataset_test[index] img,label=item img.unsqueeze_(0) data=Variable(img).to(DEVICE) output=model(data) _,pred=torch.max(output.data,1) print('ImageName:{},predict:{}'.format(dataset_test.imgs[index][0],classes[pred.data.item()])) index+=1

完整代码:

train.py

importtorch.optimasoptim importtorch importtorch.nnasnn importtorch.nn.parallel importtorch.optim importtorch.utils.data importtorch.utils.data.distributed importtorchvision.transformsastransforms importtorchvision.datasetsasdatasets importtorchvision.models fromeffnetv2importeffnetv2_s fromtorch.autogradimportVariable #设置超参数 BATCH_SIZE=16 EPOCHS=10 DEVICE=torch.device('cuda'iftorch.cuda.is_available()else'cpu') #数据预处理 transform=transforms.Compose([ transforms.Resize((128,128)), #transforms.RandomVerticalFlip(), #transforms.RandomCrop(50), #transforms.ColorJitter(brightness=0.5,contrast=0.5,hue=0.5), transforms.ToTensor(), transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5]) ]) transform_test=transforms.Compose([ transforms.Resize((128,128)), transforms.ToTensor(), transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5]) ]) #读取数据 dataset_train=datasets.ImageFolder('data/train',transform) print(dataset_train.imgs) #对应文件夹的label print(dataset_train.class_to_idx) dataset_test=datasets.ImageFolder('data/val',transform_test) #对应文件夹的label print(dataset_test.class_to_idx) #导入数据 train_loader=torch.utils.data.DataLoader(dataset_train,batch_size=BATCH_SIZE,shuffle=True) test_loader=torch.utils.data.DataLoader(dataset_test,batch_size=BATCH_SIZE,shuffle=False) modellr=1e-4 #实例化模型并且移动到GPU criterion=nn.CrossEntropyLoss() #model=effnetv2_s() #num_ftrs=model.classifier.in_features #model.classifier=nn.Linear(num_ftrs,2) model=torchvision.models.resnet18(pretrained=False) num_ftrs=model.fc.in_features model.fc=nn.Linear(num_ftrs,2) model.to(DEVICE) #选择简单暴力的Adam优化器,学习率调低 optimizer=optim.Adam(model.parameters(),lr=modellr) defadjust_learning_rate(optimizer,epoch): """SetsthelearningratetotheinitialLRdecayedby10every30epochs""" modellrnew=modellr*(0.1**(epoch//50)) print("lr:",modellrnew) forparam_groupinoptimizer.param_groups: param_group['lr']=modellrnew #定义训练过程 deftrain(model,device,train_loader,optimizer,epoch): model.train() sum_loss=0 total_num=len(train_loader.dataset) print(total_num,len(train_loader)) forbatch_idx,(data,target)inenumerate(train_loader): data,target=Variable(data).to(device),Variable(target).to(device) output=model(data) loss=criterion(output,target) optimizer.zero_grad() loss.backward() optimizer.step() print_loss=loss.data.item() sum_loss+=print_loss if(batch_idx+1)%50==0: print('TrainEpoch:{}[{}/{}({:.0f}%)]\tLoss:{:.6f}'.format( epoch,(batch_idx+1)*len(data),len(train_loader.dataset), 100.*(batch_idx+1)/len(train_loader),loss.item())) ave_loss=sum_loss/len(train_loader) print('epoch:{},loss:{}'.format(epoch,ave_loss)) defval(model,device,test_loader): model.eval() test_loss=0 correct=0 total_num=len(test_loader.dataset) print(total_num,len(test_loader)) withtorch.no_grad(): fordata,targetintest_loader: data,target=Variable(data).to(device),Variable(target).to(device) output=model(data) loss=criterion(output,target) _,pred=torch.max(output.data,1) correct+=torch.sum(pred==target) print_loss=loss.data.item() test_loss+=print_loss correct=correct.data.item() acc=correct/total_num avgloss=test_loss/len(test_loader) print('\nValset:Averageloss:{:.4f},Accuracy:{}/{}({:.0f}%)\n'.format( avgloss,correct,len(test_loader.dataset),100*acc)) #训练 forepochinrange(1,EPOCHS+1): adjust_learning_rate(optimizer,epoch) train(model,DEVICE,train_loader,optimizer,epoch) val(model,DEVICE,test_loader) torch.save(model,'model.pth')

test1.py

importtorch.utils.data.distributed importtorchvision.transformsastransforms fromtorch.autogradimportVariable importos fromPILimportImage classes=('cat','dog') transform_test=transforms.Compose([ transforms.Resize((224,224)), transforms.ToTensor(), transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5]) ]) DEVICE=torch.device("cuda:0"iftorch.cuda.is_available()else"cpu") model=torch.load("model.pth") model.eval() model.to(DEVICE) path='data/test/' testList=os.listdir(path) forfileintestList: img=Image.open(path+file) img=transform_test(img) img.unsqueeze_(0) img=Variable(img).to(DEVICE) out=model(img) #Predict _,pred=torch.max(out.data,1) print('ImageName:{},predict:{}'.format(file,classes[pred.data.item()]))

test2.py

importtorch.utils.data.distributed importtorchvision.transformsastransforms importtorchvision.datasetsasdatasets fromtorch.autogradimportVariable classes=('cat','dog') transform_test=transforms.Compose([ transforms.Resize((224,224)), transforms.ToTensor(), transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5]) ]) DEVICE=torch.device("cuda:0"iftorch.cuda.is_available()else"cpu") model=torch.load("model.pth") model.eval() model.to(DEVICE) dataset_test=datasets.ImageFolder('data/datatest',transform_test) print(len(dataset_test)) #对应文件夹的label forindexinrange(len(dataset_test)): item=dataset_test[index] img,label=item img.unsqueeze_(0) data=Variable(img).to(DEVICE) output=model(data) _,pred=torch.max(output.data,1) print('ImageName:{},predict:{}'.format(dataset_test.imgs[index][0],classes[pred.data.item()])) index+=1

 

本文含有隐藏内容,请 开通VIP 后查看