欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

pytorch搭建卷积神经网络(alexnet、vgg16、resnet50)以及训练

程序员文章站 2022-07-04 22:59:19
...

(注:文章中所有path指文件的路径)

因毕业设计需要,接触卷积神经网络。由于pytorch方便使用,所以最后使用pytorch来完成卷积神经网络训练。

接触到的网络有Alexnet、vgg16、resnet50,毕业答辩完后,一直在训练Alexnet。

1.卷积神经网络搭建

  pytorch中有torchvision.models,里面有许多已搭建好的模型。如果采用预训练模型,只需要修改最后分类的类别。

虽然这样但是我还是inception v3模型修改上失败。

alexnet和vgg16修改的是全连接层的最后一层。

model.classifier = nn.Sequential(nn.Linear(25088, 4096),      #vgg16
                                 nn.ReLU(),
                                 nn.Dropout(p=0.5),
                                 nn.Linear(4096, 4096),
                                 nn.ReLU(),
                                 nn.Dropout(p=0.5),
                                 nn.Linear(4096, 2))
alexnet_model.classifier = nn.Sequential(
            nn.Dropout(),
            nn.Linear(256 * 6 * 6, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Linear(4096, 2),
        )

resnet50只需要修改最后的fc层。

model.fc = nn.Linear(2048, 2)

简单的修改,就可以完成。

如果采用要采用预训练模型的话,还需要对修改处参数的进行修改。(vgg16和alexnet需要,resnet50不需要,原因我认为是修改的地方不同)

 for index, parma in enumerate(model.classifier.parameters()):
     if index == 6:
        parma.requires_grad = True

2.训练

pytorch搭建卷积神经网络(alexnet、vgg16、resnet50)以及训练

这张图是我所认为的神经网络训练的七步吧。

(1) 模型的创建上文已介绍。

(2) 数据集的建立:在PyTorch中对于数据集的文件格式有一定的要求。如图4-10所示,在目录下分别建catdog文件夹,这就相当于做标签

pytorch搭建卷积神经网络(alexnet、vgg16、resnet50)以及训练

(3)对数据集进行预处理:这里采用的是数据增强变化的方法,包括对图片大小进行压缩和输入像素统一,都为224224,还有图像翻转以及归一化。

data_transform = transforms.Compose([
    transforms.Scale((224,224), 2),                           #对图像大小统一
    transforms.RandomHorizontalFlip(),                        #图像翻转
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[    #图像归一化
                             0.229, 0.224, 0.225])
         ])

(4)数据集的加载,加载方式有三种:1.如果采用pytorch模块自带的数据集就可以使用torchvision.datasets.       来添加数据集。2.和我下面代码一样,使用torchvision.datasets.ImageFolder,不过文件夹要按照(2)中固定格式来创建数据集。3.参照pytorch中的源码自己写一个相对应的函数。

train_dataset = torchvision.datasets.ImageFolder(root='/path/data/train/',transform=data_transform)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size = batch_size, shuffle=True, num_workers=0)

val_dataset = torchvision.datasets.ImageFolder(root='/path/data/val/', transform=data_transform)
val_loader = torch.utils.data.DataLoader(val_dataset, batch_size = batch_size, shuffle=True, num_workers=0)

(5)  模型的训练

    for epoch in range(num_epochs):
        batch_size_start = time.time()
        running_loss = 0.0
        for i, (inputs, labels) in enumerate(train_loader):
            if epoch >= 5:
                optimizer = torch.optim.SGD(model.classifier.parameters(), lr=lr2)
                print("lr", lr2)
            else:
                optimizer = torch.optim.SGD(model.classifier.parameters(), lr=lr1)
                print("lr", lr1)
            inputs = Variable(inputs)
            labels = Variable(labels)
            optimizer.zero_grad()
            outputs = model(inputs)
            criterion = nn.CrossEntropyLoss()
            loss = criterion(outputs, labels)        #交叉熵
            loss.backward()
            optimizer.step()                          #更新权重
            running_loss += loss.data[0]

        print('Epoch [%d/%d], Loss: %.4f,need time %.4f'
                  % (epoch + 1, num_epochs, running_loss / (4000 / batch_size), time.time() - batch_size_start))

(6)验证集的验证  ,代码中有模型的保存

        correct = 0
        total = 0
        model.eval()
        for (images, labels) in val_loader:
            batch_size_start = time.time()
            images = Variable(images)
            outputs = model(images)
            _, predicted = torch.max(outputs.data, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum()

        # print("正确的数量:", correct)
        print(" Val BatchSize cost time :%.4f s" % (time.time() - batch_size_start))
        print('Test Accuracy of the model on the %d Val images: %.4f' % (total, float(correct) / total))
        if (float(correct) / total) >= 0.99:
            print('the Accuracy>=0.98 the num_epochs:%d'% epoch)
            break
        x_epoch.append(epoch)
        Acc = round((float(correct) / total), 3)
        y_acc.append(Acc)

        picName = os.path.join(codeDirRoot, "log", "pic",
                               "alexnet%s.png" % experimentSuffix)
        line_chart(x_epoch, y_acc, picName)

        # if (epoch + 1) % adjustLREpoch == 0:
        #     adjust_learning_rate(optimizer, LRModulus)

        if (epoch+1) % saveModelEpoch != 0:
            continue
        saveModelName = os.path.join(codeDirRoot, "model", "alexnet%s_model.pkl"%experimentSuffix + "_" + str(epoch))
        torch.save(model.state_dict(), saveModelName)

(7) 测试集的测试,代码中包含模型的加载。

model.load_state_dict(torch.load(
    "/path/cnn/model/vgg16/39_vgg16_model.pkl",map_location=lambda storage, loc: storage))
model.eval()
correct = 0
total = 0
for images, labels in test_loader:
    images = Variable(images)
    outputs = model(images)
    _, predicted = torch.max(outputs.data, 1)
    total += labels.size(0)
    correct += (predicted == labels).sum()
print("正确的数量%d,所有图片数量%d:" % (correct, total))
print('val accuracy of the %d val images:%.4f' % (total, float(correct) / total))

这是完整的过程。在这个过程中加入了,警告忽略、日志保存、图形化数据。代码如下。

import warnings
warnings.filterwarnings("ignore")
class Logger(object):

    def __init__(self, filename="Default.log"):
        self.terminal = sys.stdout
        self.log = open(filename, "a")

    def write(self, message):
        self.terminal.write(message)
        self.log.write(message)

    def flush(self):
        pass
sys.stdout = Logger("/path/cnn/log/resnet50_image_show.txt")
# 画折线图形并保存
def line_chart(x_epoch, y_acc, picName):
    plt.figure()#创建绘图对象
    plt.plot(x_epoch, y_acc, "b--", linewidth=1)   #在当前绘图对象绘图(X轴,Y轴,蓝色虚线,线宽度)
    plt.ylim(0.00, 1.00)
    plt.xlabel("epoch")            #X轴标签
    plt.ylabel("accuracy")               #Y轴标签
    plt.title("alexnet-Line _chart")          #图标题
    # plt.savefig(os.path.join(codeDirRoot, "log", "pic", "resnet50%s.png"%experimentSuffix))  # 保存图
    plt.savefig(picName)  # 保存图

我在老师要求下,做了最后的识别结果输出。下面是完整的代码。

warnings.filterwarnings("ignore")     #忽略警告
class Logger(object):                                #保存日志函数
    def __init__(self, filename="Default.log"):
        self.terminal = sys.stdout
        self.log = open(filename, "a")

    def write(self, message):
        self.terminal.write(message)
        self.log.write(message)

    def flush(self):
        pass
sys.stdout = Logger("path/cnn/log/alexnet_image_show.txt")

#显示图片函数
def imshow(inp, title=None):
    """Imshow for Tensor."""
    inp = inp.numpy().transpose((1, 2, 0))
    mean = np.array([0.485, 0.456, 0.406])
    std = np.array([0.229, 0.224, 0.225])
    inp = std * inp + mean
    inp = np.clip(inp, 0, 1)
    plt.imshow(inp)
    if title is not None:
        plt.title(title)
    plt.pause(0.001)
# 模型搭建
model = models.alexnet(pretrained=False)
model.classifier = nn.Sequential(nn.Linear(9216, 4096),
                                 nn.ReLU(),
                                 nn.Dropout(p=0.5),
                                 nn.Linear(4096, 4096),
                                 nn.ReLU(),
                                 nn.Dropout(p=0.5),
                                 nn.Linear(4096, 2))
print("model", model)
#加载预训练模型
model.load_state_dict(torch.load("/path/cnn/model/alexnet_model.pkl", map_location=lambda storage, loc: storage))
#数据预处理
data_transform = transforms.Compose([
    transforms.Scale((224, 224), 2),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    ])
#创建数据集
test_dataset = torchvision.datasets.ImageFolder("/path/data/show", data_transform)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=1, shuffle=True)
#分类的类别
class_names = test_dataset.classes
# 显示一些图片预测函数
def visualize_model(model, num_images):
    model.eval()
    images_so_far = 0

    for i, data in enumerate(test_loader):
        inputs, labels = data
        inputs, labels = Variable(inputs), Variable(labels)
        outputs = model(inputs)
        _, predicted = torch.max(outputs.data, 1)

        for j in range(inputs.size()[0]):
            images_so_far += 1
            ax = plt.subplot(num_images//2, 2, images_so_far)
            ax.axis('off')
            ax.set_title('predicted: {}'.format(class_names[predicted[j]]))
            imshow(inputs.cpu().data[j])
            if images_so_far == num_images:
                return
visualize_model(model, 10)       显示十张图片

# plt.ioff()     #“关闭交互模式”。
plt.savefig("/path/cnn/log/pic/alexnet.png")  # 保存图
plt.show()

pytorch搭建卷积神经网络(alexnet、vgg16、resnet50)以及训练

这就是整个过程。