栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

理解一个AlexNet的训练代码

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

理解一个AlexNet的训练代码

  1. AlexNet的代码:pytorch实现AlexNet
  2. 学了一下tmux的使用tmux命令,不然连接一断就没了。
一、TMUX的常用命令
  1. 新建tmux会话:
    tmux 没有名字,默认代号为0开始
    tmux new -s 名字为<>内的内容,默认代号为0开始
  2. 分离会话
    ctrl+b d 或输入 tmux detach
  3. 查看所有tmux会话
    tmux ls
  4. 接入会话tmux attach -t 0(<名称>)
  5. 杀死会话tmux kill-session -t 0(<名称>)
  6. 切换会话tmux switch -t 0(<名称>)
  7. 窗格tmux split-window(-h)分割后是同一个tmux会话,分出了不同窗口
    ctrl+b x关闭当前pane窗格
二、读代码 训练部分
  1. 指定device,这里的device是张量或模型被分配的位置,cpu或cuda以及具体哪一块编号。如果0号gpu存在,就分到gpu上跑、没的话就在cpu上跑。之后会有to_device,把数据传送过去。

      device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    
  2. 数据转换-有一定的数据增强作用
    data_transform是一个字典,包含“train”和“val”。分别代表训练集和验证集的操作。
    transforms.Compose函数就是将transforms组合在一起,每一个transforms都有自己的功能。最终使用定义好的data_transforme循序处理transforms。
    train:图像按照中心随机切割到224*224;随机概率水平翻转;转为tensor类型;对像素值进行归一化
    val: 照比例把图像最小的一个边长放缩到224,另一边按照相同比例放缩;转为tensor类型;对像素值进行归一化

    data_transform = {
        "train": transforms.Compose([transforms.RandomResizedCrop(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))])}
    
  3. 定义和加载好测试集和验证集路径
    ImageFolder的解释
    参数为:
    root:数据集路径;
    transform:对照片预处理变换;
    target_transform:对label处理,默认为0,1,2…;
    loader:加载方式,默认;
    is_valid_file:图像有没有损坏
    返回值为:
    self.classes:用一个 list 保存类别名称;[a,b,c]
    self.class_to_idx:类别对应的索引,与不做任何转换返回的 target 对应;{‘a’:0,‘b’:1,…}
    self.imgs:保存(图片路径, 类别) tuple的 list[(‘D:/…’,0),(‘D:…’,1)…]

    image_path = "path"  # flower data set path
    train_dataset = datasets.ImageFolder(root=image_path + "/train",
                                         transform=data_transform["train"])
    train_num = len(train_dataset)
    validate_dataset = datasets.ImageFolder(root=image_path + "/val",
                                        transform=data_transform["val"])
    val_num = len(validate_dataset)
    
  4. flower_list是上面标签和对应的索引,cla_dict是索引对应的标签,相当于f的key是c的value,f的value是c的key。

    flower_list = train_dataset.class_to_idx
    cla_dict = dict((val, key) for key, val in flower_list.items())
    
  5. 每个批大小为32,torch.utils.data.DataLoader使用解释,将一个batch封装成一个tensor
    参数:
    dataset (Dataset) – 决定数据从哪读取或者从何读取;
    batch_size (python:int, optional) – 批尺寸(每次训练样本个数,默认为1)
    shuffle (bool, optional) –每一个 epoch是否为乱序 (default: False).
    num_workers (python:int, optional) – 是否多进程读取数据(默认为0);
    drop_last (bool, optional) – 当样本数不能被batchsize整除时,最后一批数据是否舍弃(default: False)
    pin_memory(bool, optional) - (默认为false)锁页内存解释

    batch_size = 32
    train_loader = torch.utils.data.DataLoader(train_dataset,
                                           batch_size=batch_size, shuffle=True,
                                           num_workers=2)
    validate_loader = torch.utils.data.DataLoader(validate_dataset,
                                              batch_size=batch_size, shuffle=True,
                                              num_workers=2)
    
  6. 迭代验证集的iamge和label。但是后面的代码里面也没有用到test_image和test_label,我不知道有啥用QAQ

    test_data_iter = iter(validate_loader)
    test_image, test_label = test_data_iter.next()
    
  7. 使用AlexNet神经网络,类别有5个,初始化权重。
    将数据传送到device上
    定义使用的损失函数
    定义优化器

    net = AlexNet(num_classes=5, init_weights=True)
    
    net.to(device)
    #损失函数:这里用交叉熵
    loss_function = nn.CrossEntropyLoss()
    #优化器 这里用Adam
    optimizer = optim.Adam(net.parameters(), lr=0.0002)
    #定义训练参数保存路径
    save_path = './AlexNet.pth'
    #训练过程中最高准确率
    best_acc = 0.0
    
  8. 循环10个epoch,在每个epoch中:
    a. net.train()是因为net.train()解释
    我不理解具体实现,只知道适用于训练集和测试集不一致的情况,例如dropout、BatchNorm。这里用到了dropout。
    b. for step, data in enumerate(train_loader, start=0) 这句其实我有点不理解QAQ,他的意思大概是一次一次的加载每一个batch,step就是第几次,从0开始。data是一个list,data[0]是这个batch构成的tensor,data[1]是相对应的label编号。在这个数据集上,bs=32,3306张图,遍历了103次。
    c. with torch.no_grad():解释
    d predict_y = torch.max(outputs, dim=1)[1]返回每一行的最大值,dim=1表示行。outputs是一个batch中每个图片对每个类别的预测概率,返回的是最大的概率值和对应的索引。后面的[1]取出了索引值。
    e .item()主要是把数据从tensor取出来,变成python的数据类型。这里为float。
    f torch.save(net.state_dict(), save_path),保存网络的参数

    for epoch in range(10):
        # train
        net.train()    #训练过程中,使用之前定义网络中的dropout
        running_loss = 0.0#初始化loss
        t1 = time.perf_counter()#打开计时器,计算时间
        for step, data in enumerate(train_loader, start=0):
            images, labels = data
            optimizer.zero_grad() #梯度置0
            outputs = net(images.to(device)) #计算输出y_pred
            loss = loss_function(outputs, labels.to(device))#计算loss
            loss.backward() #反向传播得到梯度
            optimizer.step() #更新所有参数
    
            # print statistics
            running_loss += loss.item()
    
        # 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')
    
分类部分 1. 定义变换
data_transform = transforms.Compose(
    [transforms.Resize((224, 224)),
     transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
2. 加载图片

touch.unsqueeze是啥:解释对tensor插入维度。原来img为3×224×224,执行完之后为1×3×224×224。不知道是不是因为训练时是一batch为单位的,网络的输入要求是4维tensor,所以增加1的这个维度,方便使用。

img = Image.open("图片路径")
plt.imshow(img) #显示图片
img = data_transform(img) #做变换
img = torch.unsqueeze(img, dim=0)
class_indict={'0': 'daisy', '1': 'dandelion', '2': 'roses', '3': 'sunflowers', '4': 'tulips'} #定义编号对应的类别
3. 设置模型
model = AlexNet(num_classes=5)
model_weight_path = "./AlexNet.pth"      #训练模型时保存的参数的路径
model.load_state_dict(torch.load(model_weight_path)) #加载参数
model.eval() #设置为测试状态
4. 测试
with torch.no_grad():   #不对w求导
    # predict class
    output = torch.squeeze(model(img))     #降维删除1的维度
    predict = torch.softmax(output, dim=0)  #对output的数据进行处理
    predict_cla = torch.argmax(predict).numpy()  #返回 input 张量中所有元素的最大值的索引,再转为numpy
print(class_indict[str(predict_cla)], predict[predict_cla].item())
plt.show()
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/460942.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号