使用pytorch搭建AlexNet并训练花分类数据集

深度学习学习笔记

导师博客:https://blog.csdn.net/qq_37541097/article/details/103482003
导师github:https://github.com/WZMIAOMIAO/deep-learning-for-image-processing
代码用的导师的,自己又加了些备注,就放在自己的github里了:
https://github.com/Petrichor223/Deep_Learning/tree/master

网络结构

在这里插入图片描述
网络介绍及结构这一部分导师写的很详细:AlexNet网络结构详解与模型的搭建

数据集介绍

花分类数据集下载:http://download.tensorflow.org/example_images/flower_photos.tgz

训练集和测试集的划分:
参考:https://github.com/WZMIAOMIAO/deep-learning-for-image-processing/tree/master/data_set
下载完成后将压缩包放在data_set文件夹下并解压到新建的flower_data文件夹下,然后再data_set文件夹下按住shift + 右键打开Powershell窗口,在窗口中输入python .\split_data.py去运行脚本,就会按照9:1进行数据集的划分
在这里插入图片描述
划分完成后在flower_data文件夹下就会有生成的训练集和验证集
在这里插入图片描述

项目文件

AlexNet
├─ model.py      
├─ predict.py
├─ train.py
├─ flower_data

1. model.py

Alexnet所有层的参数表:
在这里插入图片描述

import torch.nn as nn
import torch


class AlexNet(nn.Module):
    def __init__(self, num_classes=1000, init_weights=False):       #初始化函数来定义网络在正向传播过程中使用的层结构
        super(AlexNet, self).__init__()
        # n.Sequential能够将一系列的层结构进行打包组合成新的结构,如果像LeNet那样定义每一层会非常麻烦
        self.features = nn.Sequential(                              #这里对应特征提取
            #对照Alexnet所有层参数表进行设配置
            nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2),  # input[3, 224, 224] output[48, 55, 55]  由于花分类数据集较小,将卷积核个数减半,为了方便直接将padding设置为2
            nn.ReLU(inplace=True),                                  #inplace可以理解为pytorch增加计算量但降低内存使用
            nn.MaxPool2d(kernel_size=3, stride=2),                  # output[48, 27, 27]
            nn.Conv2d(48, 128, kernel_size=5, padding=2),           # output[128, 27, 27]   这里卷积核个数同样减半,下同
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),                  # output[128, 13, 13]
            nn.Conv2d(128, 192, kernel_size=3, padding=1),          # output[192, 13, 13]
            nn.ReLU(inplace=True),
            nn.Conv2d(192, 192, kernel_size=3, padding=1),          # output[192, 13, 13]
            nn.ReLU(inplace=True),
            nn.Conv2d(192, 128, kernel_size=3, padding=1),          # output[128, 13, 13]
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),                  # output[128, 6, 6]
        )
        self.classifier = nn.Sequential(           #将全连接层打包,组合成分类器
            nn.Dropout(p=0.5),                     #一般加载全连接层之间,默认失活比例为0.5
            nn.Linear(128 * 6 * 6, 2048),
            nn.ReLU(inplace=True),
            nn.Dropout(p=0.5),
            nn.Linear(2048, 2048),
            nn.ReLU(inplace=True),
            nn.Linear(2048, num_classes),
        )
        if init_weights:                           #初始化权重
            self._initialize_weights()

    def forward(self, x):                          #正向传播过程
        x = self.features(x)                       #首先将输入的训练样本x输入到features中
        x = torch.flatten(x, start_dim=1)          #将上一步的输出进行展平处理,维度从dim=1开始(0维度为batch,1维度为channel)
        x = self.classifier(x)                     #展平后将其输入到分类结构中
        return x

    # 网络权重初始化,实际上 pytorch 在构建网络时会自动初始化权重
    def _initialize_weights(self):
        for m in self.modules():                  #遍历self.modules模块,通过self.modules模块会迭代定义的每一个层结构,判断其属于哪个类别
            if isinstance(m, nn.Conv2d):          #如果是卷积层,就用kaiming_normal对卷积权重w进行初始化
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                if m.bias is not None:            #如果偏置不为空,就用0对其进行初始化
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):        #如果是全连接层,那么采用normal对权重进行赋值,对偏置初始化为0
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.constant_(m.bias, 0)

2. train.py

pytorch官方demo实现图像分类的train脚本差不多

数据预处理

 data_transform = {
        "train": transforms.Compose([transforms.RandomResizedCrop(224),      #随机裁剪成224x224大小
                                     transforms.RandomHorizontalFlip(),      #随机翻转,水平方向
                                     transforms.ToTensor(),                  #转化成Tensor
                                     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
        "val": transforms.Compose([transforms.Resize((224, 224)),  # cannot 224, must (224, 224)
                                   transforms.ToTensor(),
                                   transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}    #标准化处理

载入数据集

#os.getcwd()获取当前文件所在的目录;os.path.join()将输入的路径连接在一起;..表示返回上层目录;../..表示返回上上层目录
    data_root = os.path.abspath(os.path.join(os.getcwd(), "../.."))  # get data root path获取数据集所在的根目录
    image_path = os.path.join(data_root, "data_set/flower_data")  # flower data set path
    assert os.path.exists(image_path), "{} path does not exist.".format(image_path)
    train_dataset = datasets.ImageFolder(root=os.path.join(image_path, "train"),   #加载数据集路径
                                         transform=data_transform["train"])        #数据预处理
    train_num = len(train_dataset)                                                 #通过len()函数打印训练集有多少张图片

这里的数据集是在模型文件夹之外存放的,如果数据集存放在别的地方可以将data_root隐去,设置自己的路径

查看数据集

    #查看数据集,查看之前要把batch_size修改成4,随机打乱shuffle改成True
    # test_data_iter = iter(validate_loader)
    # test_image, test_label = test_data_iter.next()
    #
    # def imshow(img):
    #     img = img / 2 + 0.5  # unnormalize
    #     npimg = img.numpy()
    #     plt.imshow(np.transpose(npimg, (1, 2, 0)))
    #     plt.show()
    #
    # print(' '.join('%5s' % cla_dict[test_label[j].item()] for j in range(4)))
    # imshow(utils.make_grid(test_image))

完整train.py代码

import os
import sys
import json

import torch
import torch.nn as nn
from torchvision import transforms, datasets, utils
import matplotlib.pyplot as plt
import numpy as np
import torch.optim as optim
from tqdm import tqdm

from model import AlexNet


def main():
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")     #有GPU就用,没有就不用
    print("using {} device.".format(device))
    #对数据进行预处理
    data_transform = {
        "train": transforms.Compose([transforms.RandomResizedCrop(224),      #随机裁剪成224x224大小
                                     transforms.RandomHorizontalFlip(),      #随机翻转,水平方向
                                     transforms.ToTensor(),                  #转化成Tensor
                                     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
        "val": transforms.Compose([transforms.Resize((224, 224)),  # cannot 224, must (224, 224)
                                   transforms.ToTensor(),
                                   transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}    #标准化处理
    #os.getcwd()获取当前文件所在的目录;os.path.join()将输入的路径连接在一起;..表示返回上层目录;../..表示返回上上层目录
    data_root = os.path.abspath(os.path.join(os.getcwd(), "../.."))  # get data root path获取数据集所在的根目录
    image_path = os.path.join(data_root, "./flower_data")  # flower data set path
    assert os.path.exists(image_path), "{} path does not exist.".format(image_path)
    train_dataset = datasets.ImageFolder(root=os.path.join(image_path, "train"),   #加载数据集路径
                                         transform=data_transform["train"])        #数据预处理
    train_num = len(train_dataset)                                                 #通过len()函数打印训练集有多少张图片

    # # 字典,类别:索引 {'daisy':0, 'dandelion':1, 'roses':2, 'sunflower':3, 'tulips':4}
    flower_list = train_dataset.class_to_idx                               # 将 flower_list 中的 key 和 val 调换位置
    cla_dict = dict((val, key) for key, val in flower_list.items())
    # write dict into json file
    json_str = json.dumps(cla_dict, indent=4)                              # 将 cla_dict 写入 json 文件中,方便在预测时读取信息
    with open('class_indices.json', 'w') as json_file:
        json_file.write(json_str)

    batch_size = 32
    nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8])  # number of workers
    print('Using {} dataloader workers every process'.format(nw))
    #载入train_dataset
    train_loader = torch.utils.data.DataLoader(train_dataset,
                                               batch_size=batch_size, shuffle=True,
                                               num_workers=nw)
    #载入测试集
    validate_dataset = datasets.ImageFolder(root=os.path.join(image_path, "val"),
                                            transform=data_transform["val"])
    val_num = len(validate_dataset)
    validate_loader = torch.utils.data.DataLoader(validate_dataset,
                                                  batch_size=4, shuffle=False,
                                                  num_workers=nw)

    print("using {} images for training, {} images for validation.".format(train_num,
                                                                           val_num))
    #查看数据集,查看之前要把batch_size修改成4,随机打乱shuffle改成True
    # test_data_iter = iter(validate_loader)
    # test_image, test_label = test_data_iter.next()
    #
    # def imshow(img):
    #     img = img / 2 + 0.5  # unnormalize
    #     npimg = img.numpy()
    #     plt.imshow(np.transpose(npimg, (1, 2, 0)))
    #     plt.show()
    #
    # print(' '.join('%5s' % cla_dict[test_label[j].item()] for j in range(4)))
    # imshow(utils.make_grid(test_image))

    net = AlexNet(num_classes=5, init_weights=True)    #实例化网络,数据集有五个类别,初始化权重

    net.to(device)                                     #将网络指定到设备上
    loss_function = nn.CrossEntropyLoss()              #定义损失函数,
    # pata = list(net.parameters())
    optimizer = optim.Adam(net.parameters(), lr=0.0002)   #Adam优化器

    epochs = 10
    save_path = './AlexNet.pth'
    best_acc = 0.0                                      #最佳准确率,在训练网络过程中保存准确率最高的模型
    train_steps = len(train_loader)
    for epoch in range(epochs):
        # train  在网络搭建中使用了dropout方法,会在正向传播过程中随机失活一部分神经。但是只希望在训练过程中使用,在预测过程中不使用,因此通过net.train和net.eval来管理dropout(也可以管理BN层)
        net.train()                                              #在训练过程中调用net.train会启用dropout
        running_loss = 0.0                                       #统计在训练过程中的平均损失
        train_bar = tqdm(train_loader, file=sys.stdout)
        for step, data in enumerate(train_bar):                  #遍历数据集
            images, labels = data                                #将数据集分为图像和标签
            optimizer.zero_grad()                                #清空之前的梯度信息进行正向传播
            outputs = net(images.to(device))                     #将训练图像指定到设备上
            loss = loss_function(outputs, labels.to(device))     #计算预测值与真实值之间的损失
            loss.backward()                                      #将得到的损失反向传播到每个节点中
            optimizer.step()                                     #更新每个节点的参数

            # print statistics
            running_loss += loss.item()

            train_bar.desc = "train epoch[{}/{}] loss:{:.3f}".format(epoch + 1,    #打印训练过程中的训练进度
                                                                     epochs,
                                                                     loss)

        # validate
        net.eval()                                               #在验证过程中调用net.eval会关闭dropout
        acc = 0.0  # accumulate accurate number / epoch
        with torch.no_grad():                                    #禁止pytorch对参数跟踪,即在验证过程中不进行损失计算
            val_bar = tqdm(validate_loader, file=sys.stdout)
            for val_data in val_bar:                             #遍历验证集对图片进行划分
                val_images, val_labels = val_data
                outputs = net(val_images.to(device))
                predict_y = torch.max(outputs, dim=1)[1]         #求得输出的最大值作为预测
                acc += torch.eq(predict_y, val_labels.to(device)).sum().item()  #将预测与真是标签作对比

        val_accurate = acc / val_num                             #求测试集准确率
        print('[epoch %d] train_loss: %.3f  val_accuracy: %.3f' %
              (epoch + 1, running_loss / train_steps, val_accurate))

        if val_accurate > best_acc:                             #求得最大准确率,保存其权重
            best_acc = val_accurate
            torch.save(net.state_dict(), save_path)

    print('Finished Training')

3. predict.py

def main():
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    #对载入图片进行预处理
    data_transform = transforms.Compose(
        [transforms.Resize((224, 224)),
         transforms.ToTensor(),
         transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

    # load image
    img_path = "../tulip.jpg"
    assert os.path.exists(img_path), "file: '{}' dose not exist.".format(img_path)
    img = Image.open(img_path)

    plt.imshow(img)
    # [N, C, H, W]
    img = data_transform(img)
    # expand batch dimension
    img = torch.unsqueeze(img, dim=0)     #对图片扩充一个维度(0 batch)

    # read class_indict
    json_path = './class_indices.json'
    assert os.path.exists(json_path), "file: '{}' dose not exist.".format(json_path)

    json_file = open(json_path, "r")
    class_indict = json.load(json_file)

    # create model
    model = AlexNet(num_classes=5).to(device)

    # load model weights
    weights_path = "./AlexNet.pth"
    assert os.path.exists(weights_path), "file: '{}' dose not exist.".format(weights_path)
    model.load_state_dict(torch.load(weights_path))

    model.eval()
    with torch.no_grad():
        # predict class
        output = torch.squeeze(model(img.to(device))).cpu()
        predict = torch.softmax(output, dim=0)
        predict_cla = torch.argmax(predict).numpy()

    print_res = "class: {}   prob: {:.3}".format(class_indict[str(predict_cla)],
                                                 predict[predict_cla].numpy())
    plt.title(print_res)
    for i in range(len(predict)):
        print("class: {:10}   prob: {:.3}".format(class_indict[str(i)],
                                                  predict[i].numpy()))
    plt.show()
  • 0
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: TensorFlow AlexNet是一种基于深度学习的图像分类模型,它是由Alex Krizhevsky等人在2012年提出的。该模型使用卷积神经网络(CNN)来学习图像特征,并使用softmax分类器对图像进行分类。它在ImageNet数据集上取得了很好的表现,成为了深度学习图像分类的里程碑之一。 ### 回答2: TensorFlow AlexNet是用TensorFlow实现的一个基于深度学习的图像分类模型。该模型基于AlexNet结构,包括5个卷积层(其中有池化和局部响应归一化),3个全连接层以及最后的softmax层。AlexNet模型能够有效地对大量的数据进行训练并精确地分类出图片,参数调整优化后更可以在ImageNet数据集上获得超过当时其他模型的表现。 AlexNet的一大亮点是引用了ReLU激活函数,避免了神经网络中的梯度消失问题,同时也在训练时提高了收敛速度。 在实现TensorFlow AlexNet时,我们需要准备大量的图片数据集,例如ImageNet或CIFAR-10等。然后使用TensorFlow构建AlexNet模型,进行参数初始化和训练。同时,这个模型还需要设置适当的参数和超参数来控制学习过程。在训练完成之后,我们可以使用这个模型来对新的图片进行分类。 TensorFlow AlexNet的实现过程需要涉及到很多知识点和技术,如深度学习理论、卷积神经网络、梯度下降算法、图像预处理等。因此,对于初学者来说,需要一定的基础知识和实践经验才能熟练掌握。 总之,TensorFlow AlexNet模型是一种强大的图像分类工具,能够为我们解决许多图像分类的问题,同时也是深度学习领域的重要进展。 ### 回答3: TensorFlow是一种流行的人工智能深度学习框架,可用于多种任务,如图像分类AlexNet是一种经典的卷积神经网络,是图像分类任务的标准参考模型之一。它可以使用TensorFlow框架在Python语言中进行实现。 基于TensorFlow框架实现AlexNet图像分类需要以下步骤: 1. 数据准备:准备训练集和测试集,例如图像数据集。 2. 数据预处理:对数据进行标准化处理和归一化处理,以改善模型性能。 3. 模型定义:定义一个包含多个卷积层、池化层、全连接层和Softmax层的AlexNet模型。 4. 模型训练使用训练集来训练模型,使用反向传播算法来更新权重和偏置值。 5. 模型评估:使用测试集来评估模型,计算准确率和损失等指标,以判断模型的表现。 在TensorFlow框架中,可以使用tf.keras模块非常简单地实现AlexNet图像分类。以下是一个简单的代码示例: ``` import tensorflow as tf model = tf.keras.Sequential([ tf.keras.layers.Conv2D(96, (11, 11), strides=(4, 4), activation='relu', input_shape=(224, 224, 3)), tf.keras.layers.MaxPooling2D((3, 3), strides=(2, 2)), tf.keras.layers.Conv2D(256, (5, 5), activation='relu', padding="same"), tf.keras.layers.MaxPooling2D((3, 3), strides=(2, 2)), tf.keras.layers.Conv2D(384, (3, 3), activation='relu', padding="same"), tf.keras.layers.Conv2D(384, (3, 3), activation='relu', padding="same"), tf.keras.layers.Conv2D(256, (3, 3), activation='relu', padding="same"), tf.keras.layers.MaxPooling2D((3, 3), strides=(2, 2)), tf.keras.layers.Flatten(), tf.keras.layers.Dense(4096, activation='relu'), tf.keras.layers.Dense(4096, activation='relu'), tf.keras.layers.Dense(1000, activation='softmax') ]) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) model.fit(train_data, epochs=10) ``` 在这个示例中,我们定义了一个使用ReLU作为激活函数的AlexNet模型。我们使用训练数据对其进行了10次迭代训练,并使用adam作为优化器来更新模型参数。在模型完成训练后,我们可以使用测试数据集来评估模型的表现。 通过使用TensorFlow框架来实现AlexNet图像分类,我们可以简单而快速地实现一个强大的神经网络模型,用于对图像进行分类。这种方法对于许多实际应用非常有用,如人脸识别、智能安防,以及内容分类等等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值