使用python在GPU上构建和训练卷积神经网络

我将对代码进行补充演练,以构建在数据集上训练的任何类型的图像分类器。在这个例子中,我将使用花卉数据集,其中包括102种不同类型的花。需要数据集和代码都可以私信我。

使用python在GPU上构建和训练卷积神经网络

来自花卉数据集的图像和相应标签的示例

Pytorch是机器学习和Python上的免费软件包,非常易于使用。语法模拟numpy,因此,如果你在python中有一些科学计算经验,那么会相当有用的。只需几行代码,就可以下载预先训练的数据集,使用定义的变换对图像进行标准化,然后运行训练。

创建和扩充数据集

为了增加数据集,我使用' google_images_download'API从互联网上下载了相关图像。显然,您可以使用此API不仅可以扩充现有数据集,还可以从头开始创建自己的数据集。

from google_images_download import google_images_download as gid #importing the library
...
response = gid.googleimagesdownload() #class instantiation
for i in range(NUM_OF_LABELS):
 folder_name = str(i + 1)
 request = cat_to_names[folder_name][1]
 
 #creating list of arguments
 arguments = {"keywords" : request, 
 "limit" : 100, 
 "print_urls" : False, 
 "output_directory" : './downloads/', 
 "image_directory" : folder_name
 } 
 paths = response.download(arguments) # passing the arguments to 
 print(paths) #printing absolute paths of the downloaded images

使用python在GPU上构建和训练卷积神经网络

确保从图像中挑选出异常值(损坏的文件或偶然出现的无关图像)。

图像标准化

为了使图像具有相同的大小和像素变化,可以使用pytorch的transfors模块:

mean = [0.485, 0.456, 0.406]
std = [0.229, 0.224, 0.225]
data_transforms= transforms.Compose(
 [transforms.Resize(size = 224),transforms.CenterCrop(224),
 transforms.RandomRotation(20),transforms.ToTensor(),
 transforms.Normalize(mean,std)]
)

使用python在GPU上构建和训练卷积神经网络

转移学习

从头开始训练的模型可能不是最明智的选择,因为有许多网络可用于各种数据集。简单地说,像edge-和其他简单形状检测器等低级特征对于不同的模型是相似的,即使clasificators是针对不同目的进行训练的。在本项目中,我使用了一个预训练网络Resnet152,只有最后一个完全连接的层重新用于新任务,即使这样也会产生相当好的效果。

import torch
from torch import nn as nn
import torchvision.models as models
def prepare_model():
 model = models.resnet152(pretrained = True)
 for param in model.parameters():
 param.requires_grad = False
 model._modules['fc'] = nn.Linear(2048, 102)
 model._modules['fc'].requires_grad = True
 return model

使用python在GPU上构建和训练卷积神经网络

在这里,我将除最后一层之外的所有层都设置为具有固定权重(requires_grad = False),因此只有最后层中的参数将通过梯度下降进行更新。

训练模型

下面介绍一下进行训练的函数:

def train(n_epochs, data_dir, batch_size, num_workers, data_transforms):
 train_dir = data_dir + '/train'
 valid_dir = data_dir + '/valid'
 
 # defining the datasets for training and validation with the
 # specified set of transformations 
 image_datasets_train = datasets.ImageFolder(root=train_dir, transform=data_transforms)
 image_datasets_valid = datasets.ImageFolder(root=valid_dir, transform=data_transforms)
 
 # defining the generator objects to get the batches of 
 # standardized images from
 trainloader = torch.utils.data.DataLoader(image_datasets_train, batch_size=batch_size,shuffle=True,
 num_workers=num_workers)
 validloader = torch.utils.data.DataLoader(image_datasets_valid, batch_size=batch_size,
 num_workers=num_workers)
 
 # get the device to train your model at (pgu or cpu)
 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
 
 # building your neural network
 model = prepare_model()
 # send the network to specified device (gpu if it's available)
 model = model.to(device)
 
 # defining the cost function
 criterion = nn.CrossEntropyLoss()
 
 # spesifying the optimization method
 optimizer = optim.Adam(model._modules['fc'].parameters(), lr=0.001)
 
 # set your model into the training regime
 model.train()
 
 # training loop
 for epoch in range(n_epochs):
 # monitor training loss
 train_loss = 0.0
 for data, target in trainloader:
 # get batch of images
 data = data.to(device)
 
 # get the correct labels for the images
 target = target.to(device)
 
 # clean the buffer from previous gradients
 optimizer.zero_grad()
 
 # get the predicted lables
 output = model(data)
 
 # compute the objective function
 loss = criterion(output, target)
 
 # compute the grads with respect to the network weights
 loss.backward()
 
 # make an update of weights
 optimizer.step()
 
 train_loss += loss.item()*data.size(0)
 train_loss = train_loss/len(trainloader.dataset)
 print('Epoch: {} 	 Training Loss {:.6f}'.format(epoch+1,train_loss))
 
 # set your model in evaluation regime 
 # (disables dropout, the gradients are not computed)
 model.eval()
 test_loss, accuracy = validation(model, validloader, criterion)
 model.train()
 print('Test Loss: {}	 Accuracy: {}'.format(test_loss, accuracy))
 
 # save your model if it's better then the one before!
 if accuracy > best_accuracy:
 best_accuracy = accuracy
 print('Saving the model')
 file_save_to = "models/model_" + str(100*np.round(best_accuracy,2)) + ".pth"
 save_model(model.cpu(), file_save_to)
 model = model.to(device)

使用python在GPU上构建和训练卷积神经网络

如何获得GPU?

当然,对CPU的训练太慢了。根据我自己的经验,在GPU仅需要一个小时就可以完成12次训练周期,但是在CPU上相同数量的训练周期可能需要花费大约15个小时。

如果您没有本地可用的GPU,则可以考虑使用云GPU。为了加速CNN的训练,我使用了floydhub(www.floydhub.com)上提供的云GPU 。

这项服务非常指的使用:总有很好的文档和大量的提示,所以你会很清楚的知道下一步需要如何去做。在floydhub上对于使用GPU的收费也是可以接受的。

首先,需要将数据集上传到服务器

然后,需要创建项目。需要在计算机上安装floydhub客户端,将数据集上载到其网站并在终端中运行以下命令:

floyd run --gpu --env pytorch-1.0 --data username/datasets/flower_data/i:flower_data 'python run_classificator.py'

使用python在GPU上构建和训练卷积神经网络

其中'username'是您的登录名,'i'是数据集所在的文件夹。

这样子在训练网络时就会很轻松了

结果和改进想法

得到的模型在数据集上训练了1.5小时,并在验证数据集上达到了95%的准确度。

  • 为了提高准确度,不仅可以对网络的最后一个完全连接的层应用梯度更新,还可以对最终输出之前的几个层应用梯度更新。
  • 如果你有足够的时间和免费的GPU,你可以设计自己的网络,并从头开始训练约30-50个训练周期,使网络达到预期的效果。
  • 获得更多的准确的数据也能带来更好的准确度。

相关推荐