AlexNet模型学习

目录

工具:

代码学习:

test.py:

train.py:

model.py:


工具:

torch:神经网络和简单易用的优化库

matplotlib:  画图

transforms:  transforms在计算机视觉工具包torchvision下,torchvision.transforms : 常用的图像预处理方法

pycharm:

 

代码学习:

test.py:

# 标准化处理
data_transform = transforms.Compose(
    [transforms.Resize((224, 224)),  # 缩放到224*224
     transforms.ToTensor(),    #转为tensor类型
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])  # 这个操作的目的是为了使输入图像的像素值落在神经网络的激活函数的敏感范围内,更好地进行训练和预测。
     # output[channel] = (input[channel] - mean[channel]) / std[channel]


# load image
img = Image.open("玫瑰花预测.jpg")
print(type(img))
plt.imshow(img)  # 通过 imshow() 函数可以在 Matplotlib 查看器上绘制出相应的图像。
# [N, C, H, W]
print(img.size)
img = data_transform(img)
print(img.shape)  # torch.Size([3, 224, 224])
# expand batch dimension添加batch维度,添加到0维
img = torch.unsqueeze(img, dim=0)
# [1, C, H, W]
print(img.shape)  # torch.Size([1, 3, 224, 224])
# read class_indict

 

图片预处理:

        img->data_transform()

                使用transforms.Compose组合多个预处理操作,包括将图像大小调整为224x224像素、转换为Tensor格式、标准化像素值。

                Normalize()  使输入图像的像素值落在神经网络的激活函数的敏感范围内,更好地进行训练和预测

                pytorch个人学习笔记(2)—Normalize()参数详解及用法 ...

        img->unsqueeze()

                pytorch中unsqueeze()函数理解 - CSDN博客

                对图像应用之前定义的预处理操作,得到符合模型输入要求的Tensor格式的图像数据

output = model(img)
    print("output:{}".format(output))

output:  二维tenson类型

    output = torch.squeeze(model(img))
    print(output)

squeeze后降低一个维度方便使用。

Numpy库学习—squeeze()函数_squeeze函数_o_Eagle_o的 ...        

    predict = torch.softmax(output, dim=0)
    # 通过argmax获取概率最大的索引值
    predict_cla = torch.argmax(predict).numpy()

nullicon-default.png?t=N6B9https://blog.csdn.net/qq_43665602/article/details/126576622?ops_request_misc=&request_id=338663818b7f4b1790f4e064e2c9190b&biz_id=&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~koosearch~default-1-126576622-null-null.268^v1^control&utm_term=%E5%88%86%E7%B1%BB%E4%BB%BB%E5%8A%A1%E5%B8%B8%E7%94%A8%E6%BF%80%E6%B4%BB%E5%87%BD%E6%95%B0%E4%B9%8Bnn.Softmax%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0dim%E7%90%86%E8%A7%A3%EF%BC%88Pytorch%EF%BC%89

【深度学习】torch.argmax()函数讲解 | pytorch

Numpy库学习—squeeze()函数_squeeze函数_o_Eagle_o的 ...

通过argmax获取概率最大的索引值,argmax函数是numpy库中的一个函数,用于返回数组中最大值所在的索引。参数axis用于指定在哪个轴上进行比较。如果没有指定axis参数,则会将数组展平为一维数组进行比较。

import torch
from model import AlexNet
from PIL import Image
from torchvision import transforms
import matplotlib.pyplot as plt
import json

# 标准化处理
data_transform = transforms.Compose(
    [transforms.Resize((224, 224)),  # 缩放到224*224
     transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])  # 这个操作的目的是为了使输入图像的像素值落在神经网络的激活函数的敏感范围内,更好地进行训练和预测。
     # output[channel] = (input[channel] - mean[channel]) / std[channel]


# load image
img = Image.open("玫瑰花预测.jpg")
print(type(img))
plt.imshow(img)  # 通过 imshow() 函数可以在 Matplotlib 查看器上绘制出相应的图像。
# [N, C, H, W]
print(img.size)
img = data_transform(img)
print(img.shape)  # torch.Size([3, 224, 224])
# expand batch dimension添加batch维度,添加到0维
img = torch.unsqueeze(img, dim=0)
# [1, C, H, W]
print(img.shape)  # torch.Size([1, 3, 224, 224])
# read class_indict
try:
    # 打开索引文件
    json_file = open('./class_indices.json', 'r')
    # 解码成所需要的字典
    class_indict = json.load(json_file)
except Exception as e:
    print(e)
    exit(-1)

# create model
model = AlexNet(num_classes=5)
# load model weights
model_weight_path = "./AlexNet.pth"
# 载入网络模型
model.load_state_dict(torch.load(model_weight_path))
model.eval()    # 关闭dropout方法
with torch.no_grad():   #不让变量跟踪变量的损失梯度
    # predict class
    # 通过model正向传播进行输出,将输出压缩,把batch压缩掉

    output = torch.squeeze(model(img))
    predict = torch.softmax(output, dim=0)
    # 通过argmax获取概率最大的索引值
    predict_cla = torch.argmax(predict).numpy()

    # output = model(img)
    # predict = torch.softmax(output, dim=1)
    # print(predict)
    # predict_cla = torch.argmax(predict).numpy()
    # print(predict_cla)
    # output = model(img)
    # print("output:{}".format(output))
    # print("squeeze:{}".format(torch.squeeze(model(img))))
    # print('softmax:{}'.format(torch.softmax(torch.squeeze(model(img)), dim=0)))
    # print("argmax:{}".format(torch.argmax(torch.softmax(torch.squeeze(model(img)), dim=0)).numpy()))
    # print(output.argmax(1))
print(class_indict[str(predict_cla)], predict[predict_cla].item())
plt.show()

train.py:

device函数的使用:

torch.device函数

载入数据集:

        Pytorch模型训练-----------数据集加载之ImageFolder之全过程

train源码:

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 model import AlexNet
import os
import json
import time


def main():
    # 指定训练的设备
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    print("using {} device.".format(device))

    # 数据预处理函数
    data_transform = {
        "train": transforms.Compose([transforms.RandomResizedCrop(224),# 随机裁减到224
                                     transforms.RandomHorizontalFlip(),# 水平方向翻转
                                     transforms.ToTensor(),
                                     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))])}

    # 获取数据集
    # data_root = os.path.abspath(os.path.join(os.getcwd(), "../.."))  # get data root path
    image_path = os.path.join("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"])
    # 通过len函数获取训练集有多少张图片
    train_num = len(train_dataset)

    # {'daisy':0, 'dandelion':1, 'roses':2, 'sunflower':3, 'tulips':4}
    # 获取分类名称对应的索引
    flower_list = train_dataset.class_to_idx

    # 将key和val交换位置,变成{0:'daisy':,1: 'dandelion', 2:'roses', 3:'sunflower', 4:'tulips'}
    # 便于预测后根据索引打印类别
    cla_dict = dict((val, key) for key, val in flower_list.items())
    # write dict into json file
    # 将cla_dict字典编码成json格式
    json_str = json.dumps(cla_dict, indent=4)
    # 打开class_indices.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))

    # 通过DataLoader加载train_dataset
    # num_workers表示加载数据所需的线程个数,Windows下设置为0,表示使用主线程加载数据
    # linux下可设置成8,16等加快加载速度和训练速度
    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=batch_size, shuffle=False,
                                                  num_workers=nw)

    print("using {} images for training, {} images fot validation.".format(train_num,
                                                                           val_num))
    # # 随机查看测试集中的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))

# num_classes
    net = AlexNet(num_classes=5, init_weights=True)

    net.to(device)
    # 损失交叉熵函数
    loss_function = nn.CrossEntropyLoss()
    # pata = list(net.parameters())# 查看模型的参数
    # 使用Adam优化器,优化net的所有参数,学习率=0.0002
    optimizer = optim.Adam(net.parameters(), lr=0.0002)

    # 保存权重的路径
    save_path = './AlexNet.pth'
    best_acc = 0.0  # 保存最佳准确率
    for epoch in range(10):# 迭代10次
        # train
        # 使用net.train()和net.eval()管理dropout方法
        net.train() # 在训练过程中启用dropout方法
        running_loss = 0.0  # 统计训练过程中的平均损失
        t1 = time.perf_counter()    # 记录训练一个epoch开始的时间
        for step, data in enumerate(train_loader, start=0):
            images, labels = data   #将数据分为images和labels
            optimizer.zero_grad()   # 清空之前的梯度信息
            outputs = net(images.to(device))    # 进行正向传播
            loss = loss_function(outputs, labels.to(device))    # 计算预测值和真实值的损失
            loss.backward() # 将得到的损失反向传播到每个节点中
            optimizer.step()    #通过optimizer更新每个节点的参数

            # print statistics
            running_loss += loss.item()
            # print train process
            # 打印训练进度
            rate = (step + 1) / len(train_loader)
            a = "*" * int(rate * 50)
            b = "." * int((1 - rate) * 50)
            print("\rtrain loss: {:^3.0f}%[{}->{}]{:.3f}".format(int(rate * 100), a, b, loss), end="")
        print()
        print("所需时间:"+str(time.perf_counter()-t1))# 输出训练一个epoch所需的时间

        # validate验证
        net.eval()# 在测试过程中关闭dropout方法
        acc = 0.0  # accumulate accurate number / epoch
        with torch.no_grad():   # 防止对每个梯度进行跟踪
            for val_data in validate_loader:
                val_images, val_labels = val_data
                outputs = net(val_images.to(device))
                predict_y = torch.max(outputs, dim=1)[1]
                acc += (predict_y == val_labels.to(device)).sum().item()
            val_accurate = acc / val_num
            if val_accurate > best_acc:
                best_acc = val_accurate
                torch.save(net.state_dict(), save_path)
            print('[epoch %d] train_loss: %.3f  test_accuracy: %.3f' %
                  (epoch + 1, running_loss / step, val_accurate))

    print('Finished Training')


if __name__ == '__main__':
    main()

model.py:

import torch.nn as nn
import torch

class AlexNet(nn.Module):
    def __init__(self, num_classes=1000, init_weights=False):
        super(AlexNet, self).__init__()
        self.features = nn.Sequential(  # Sequential将一系列层结构打包
            # 卷积核个数均采用原AlexNet的一半
            nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2),  # input[3, 224, 224]  output[48, 55, 55]
            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(# 全连接层
            # Dropout加在两个全连接层之间
            nn.Dropout(p=0.5),# 神经元随机失活的比例=0.5

            # 展成一维的并且卷积核的个数为原AlexNet的一半
            # 因此不是256*6*6,而是128 * 6 * 6,且FC1的卷积核大小为2048
            nn.Linear(128 * 6 * 6, 2048),
            nn.ReLU(inplace=True),
            nn.Dropout(p=0.5),

            # 第二个全连接层
            nn.Linear(2048, 2048),
            nn.ReLU(inplace=True),

            # 第三个全连接层,输出num_classes的数值是训练集类别的个数
            # 对于花的数据集num_classes=5
            nn.Linear(2048, num_classes),
        )

        # 在pytorch中其实并不需要此函数
        # pytorch自动使用kaiming_normal_对卷积层和全连接层进行初始化
        if init_weights:# 初始化权重函数,init_weights=True时,会执行此函数
            self._initialize_weights()

    # 正向传播
    def forward(self, x):
        x = self.features(x)

        # 展平处理 pytorch的tensor排列顺序为[batch,channel,height,width]
        # 0维的batch不用,故start_dim=1,也可以使用view函数展平
        x = torch.flatten(x, start_dim=1)

        # 输入到分类结构中,即后面的三个全连接层
        x = self.classifier(x)
        return x

    def _initialize_weights(self):
        for m in self.modules():# 遍历之前定义的每一个层结构
            if isinstance(m, nn.Conv2d):# 判断属于哪个层类别
                # 如果是卷积层,kaiming_normal_
                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):
                # 如果是全连接层,通过正态分布对权重进行赋值,正态分布的均值=0,方差=0.01
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.constant_(m.bias, 0)

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值