• [pytorch笔记]02-主要组成模块&基础实战


    主要组成模块

    数据读取

    • 使用自带数据集
    • 导入自己收集的数据,然后转换为合适的Dataset
    DatasetDataLoader
    按需求生成特定数据集生成便于训练和测试的加载数据(实际用于模型的数据)
    #数据读入
    ##设置数据变换 此处即使将图片数据按设定转换为tensor
    from torchvision import transforms,datasets#pytorch的官方图像处理库
    image_size = 28
    data_transform = transforms.Compose([
        transforms.ToPILImage(),#读取什么
        transforms.Resize(image_size),#修改尺寸
        transforms.ToTensor(),#转换成tensor输出
    ])
    ##读取方式一:使用torchvision自带数据集,下载需要一段时间
    ##train=True代表训练集,False为测试集
    train_data = datasets.FashionMNIST(root='./',train=True,download=True,transform=data_transform)
    test_data = datasets.FashionMNIST(root='./',train=False,download=True,transform=data_transform)
    ##读取方式二:读入原始数据,然后自行构建Dataset类
    ##针对三个魔法函数__init__,__len__,__getitem__复写来构建
    class FMDataset(Dataset):
        def __init__(self,df,transform=None):#初始化
            self.df = df#数据
            self.transform = transform#转换方法
            self.images = df.iloc[:,1:].values.astype(np.uint8)#读取数据
            self.labels = df.iloc[:,0].values#读取标签
        def __len__(self):#返沪数据集的样本数
            return len(self.images)
        def __getitem__(self,idx):#逐个读取样本集合进行转换,返回符合需求的数据
            image = self.images[idx].reshape(28,28,1)#32*32的灰度图转为28*28
            label = int(self.labels[idx])#标签
            if self.transform is not None:#如果转换函数非空
                image = self.transform(image)#进行数据转换
            else:
                image = torch.tensor(image/255.,dtype=torch.float)
            label = torch.tensor(label,dtype=torch.long)
            return image,label
    train_df = pd.read_csv('./data/images/FashionMNIST/fashion-mnist_train.csv')
    test_df = pd.read_csv("./data/images/FashionMNIST/fashion-mnist_test.csv")
    train_data = FMDataset(train_df,data_transform)
    test_data = FMDataset(test_df,data_transform)
    ##定义DataLoader,便于训练和测试是加载数据
    ##shuffle是否打乱数据,drop_last是否去除最后
    train_loader = DataLoader(train_data,batch_size=batch_size,shuffle=True,num_workers=num_workers,drop_last=True)
    test_loader = DataLoader(test_data,batch_size=batch_size,shuffle=False,num_workers=num_workers)
    ##Dataset、DataLoader这两类较为简便,该
    ##
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    模型设计

    基本定义方法

    SequentialModuleList/ModuleDict
    直接搭建网络,定义顺序即为模型连接顺序List/Dict中元素顺序并不代表其网络中的真实位置顺序,需要forward函数指定各个层的连接顺序
    模型中间无法加入外部输入模型中间需要之前层的信息
    • 通过nn.Sequential()
    #模型设计
    import torch.nn as nn
    import collections
    class Net(nn.Module):
        def __init__(self):
            super(Net,self).__init__()#继承
            self.conv = nn.Sequential(
                nn.Conv2d(1,32,5),#卷积
                nn.ReLU(),#激活
                nn.MaxPool2d(2,stride=2),#
                nn.Dropout(0.3),#
                nn.Conv2d(32,64,5),#
                nn.ReLU(),
                nn.MaxPool2d(2,stride=2),
                nn.Dropout(0.3)
            )#设计
            self.fc = nn.Sequential(collections.OrderedDict([
                ('fc1',nn.Linear(64*4*4,512)),#要注意输入尺寸和输出尺寸的对应
                ('relu1',nn.ReLU()),
                ('fc2',nn.Linear(512,10))
            ])
                
            )
        def forward(self,x):
            x = self.conv(x)
            x = x.view(-1,64*4*4)
            x = self.fc(x)
            return x
        model = Net()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 通过nn.ModuleList()/nn.ModuleDict()
    # List
    class model(nn.Module):
      def __init__(self):
        super().__init__()
        self.modulelist = nn.ModuleList([nn.Linear(784, 256), nn.ReLU(),nn.Linear(256, 10)])
        
      def forward(self, x):
        for layer in self.modulelist:
          x = layer(x)
        return x
    # Dict
    class model(nn.Module):
      def __init__(self):
        super().__init__()
        self.moduledict = nn.ModuleDict({
        'linear': nn.Linear(784, 256),
        'act': nn.ReLU(),
        'output':nn.Linear(256, 10)
        })
        
      def forward(self, x):
        for layer in self.moduledict:
          x = layer(x)
        return x
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    损失函数

    常见损失函数及原理
    常见损失函数(分类与回归)
    CTC损失函数详解

    常见损失函数代码功能
    二分类交叉熵损失函数.nn.BCELoss计算二分类任务时的交叉熵
    交叉熵损失函数.nn.CrossEntropyLoss计算交叉熵
    L1损失函数nn.L1Loss计算输出y和真实标签之间的差值绝对值
    MSE损失函数nn.MSELoss计算输出y和真实标签之差的平方
    smooth L1nn.SmoothL1LossL1的平滑输出,其功能是减轻离群点带来的影响
    目标泊松分布的负对数似然损失nn.PoissonNLLLoss泊松分布的负对数似然损失函数
    Kl散度nn.KLDIvLoss计算相对熵
    MarginRanKingLossnn.MarginRanKingLoss计算两向量之间的相似度,用于排序任务
    多标签边界损失函数nn.MultiLabelMarginLoss用于多标签分类问题计算损失函数
    二分类损失函数nn.SoftMarginLoss计算二分类的logistic损失
    多分类的折页损失nn.MultiMarginLoss计算多分类的折页损失
    三元组损失nn.TripletMarginLoss计算三元组损失
    HingEmbeddingLossnn.HingEmbeddingLoss对输出的结果做Hing损失计算
    余弦相似度nn.CosineEmbeddingLoss对两个向量做余弦相似度
    CTC损失函数nn.CTCLoss用于解决时序类数据分类
    • 二分类交叉熵损失函数
    #二分类交叉熵损失函数
    ##weight:每个类别的loss设置权值
    ##size_average:True时,返回的loss为平均值,False时返回各样本的loss之和
    ##reduce:True时返回标量
    ##reduction:结果的计算函数‘mean’,‘sum’
    m = nn.Sigmoid()
    loss = nn.BCELoss()#
    input = torch.randn(3,requires_grad=True)
    target = torch.empty(3).random_(2)
    output = loss(m(input),target)
    output.backward()#损失函数计算结果
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 交叉熵损失函数
    #交叉熵损失函数
    loss = nn.CrossEntropyLoss()#交叉熵函数
    input = torch.randn(3,5,requires_grad=True)
    target = torch.empty(3,dtype=torch.long).random_(5)
    output = loss(input,target)
    output.backward()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • L1损失函数
    #L1损失函数
    loss = nn.L1Loss()
    input = torch.randn(3,5,requires_grad=True)
    target = torch.randn(3,5)
    output = loss(input,target)
    output.backward()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • MSE损失函数
    #MSE损失函数
    loss = nn.MSELoss()
    input = torch.randn(3,5,requires_grad=True)
    target = torch.randn(3,5)
    output = loss(input,target)
    output.backward()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 平滑L1(Smooth L1)损失函数
    #平滑L1(Smooth L1)损失函数
    loss = nn.SmoothL1Loss()
    input = torch.randn(3,5,requires_grad=True)
    target = torch.randn(3,5)
    output = loss(input,target)
    output.backward()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 目标泊松分布的负对数似然损失
    #目标泊松分布的负对数似然损失
    loss = nn.PoissonNLLLoss()
    log_input = torch.randn(5,2,requires_grad=True)
    target = torch.randn(5,2)
    output = loss(log_input,target)
    output.backward()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • KL散度
    #KL散度
    inputs = torch.tensor([[0.5,0.3,0.2],[0.2,0.3,0.5]])
    target = torch.tensor([[0.9,0.05,0.05],[0.1,0.7,0.2]],dtype=torch.float)
    loss = nn.KLDivLoss()
    output = loss(inputs,target)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • MarginRanKingLoss
    #MarginRanKingLoss
    loss = nn.MarginRankingLoss()
    input1 = torch.randn(3, requires_grad=True)
    input2 = torch.randn(3, requires_grad=True)
    target = torch.randn(3).sign()
    output = loss(input1, input2, target)
    output.backward()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 多标签边界损失函数
    #多标签边界损失函数
    loss = nn.MultiLabelMarginLoss()
    x = torch.FloatTensor([[0.9, 0.2, 0.4, 0.8]])
    # for target y, only consider labels 3 and 0, not after label -1
    y = torch.LongTensor([[3, 0, -1, 1]])# 真实的分类是,第3类和第0类
    output = loss(x, y)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 二分类损失函数
    #二分类损失函数
    inputs = torch.tensor([[0.3, 0.7], [0.5, 0.5]])  # 两个样本,两个神经元
    target = torch.tensor([[-1, 1], [1, -1]], dtype=torch.float)  # 该 loss 为逐个神经元计算,需要为每个神经元单独设置标签
    loss_f = nn.SoftMarginLoss()
    output = loss_f(inputs, target)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 多分类的折页损失
    #多分类的折页损失
    inputs = torch.tensor([[0.3, 0.7], [0.5, 0.5]]) 
    target = torch.tensor([0, 1], dtype=torch.long) 
    loss_f = nn.MultiMarginLoss()
    output = loss_f(inputs, target)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 三元组损失函数
    #三元组损失函数
    triplet_loss = nn.TripletMarginLoss(margin=1.0, p=2)
    anchor = torch.randn(100, 128, requires_grad=True)
    positive = torch.randn(100, 128, requires_grad=True)
    negative = torch.randn(100, 128, requires_grad=True)
    output = triplet_loss(anchor, positive, negative)
    output.backward()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • HingEmbeddingLoss
    #HingEmbeddingLoss
    loss_f = nn.HingeEmbeddingLoss()
    inputs = torch.tensor([[1., 0.8, 0.5]])
    target = torch.tensor([[1, 1, -1]])
    output = loss_f(inputs,target)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 余弦相似度
    #余弦相似度
    loss_f = nn.CosineEmbeddingLoss()
    inputs_1 = torch.tensor([[0.3, 0.5, 0.7], [0.3, 0.5, 0.7]])
    inputs_2 = torch.tensor([[0.1, 0.3, 0.5], [0.1, 0.3, 0.5]])
    target = torch.tensor([[1, -1]], dtype=torch.float)
    output = loss_f(inputs_1,inputs_2,target)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • CTC损失函数
    #CTC损失函数
    T = 50      # Input sequence length
    C = 20      # Number of classes (including blank)
    N = 16      # Batch size
    S = 30      # Target sequence length of longest target in batch (padding length)
    S_min = 10  # Minimum target length, for demonstration purposes
    # Initialize random batch of input vectors, for *size = (T,N,C)
    input = torch.randn(T, N, C).log_softmax(2).detach().requires_grad_()
    # Initialize random batch of targets (0 = blank, 1:C = classes)
    target = torch.randint(low=1, high=C, size=(N, S), dtype=torch.long)
    input_lengths = torch.full(size=(N,), fill_value=T, dtype=torch.long)
    target_lengths = torch.randint(low=S_min, high=S, size=(N,), dtype=torch.long)
    ctc_loss = nn.CTCLoss()
    loss = ctc_loss(input, target, input_lengths, target_lengths)
    loss.backward()
    
    # Target are to be un-padded
    T = 50      # Input sequence length
    C = 20      # Number of classes (including blank)
    N = 16      # Batch size
    # Initialize random batch of input vectors, for *size = (T,N,C)
    input = torch.randn(T, N, C).log_softmax(2).detach().requires_grad_()
    input_lengths = torch.full(size=(N,), fill_value=T, dtype=torch.long)
    # Initialize random batch of targets (0 = blank, 1:C = classes)
    target_lengths = torch.randint(low=1, high=T, size=(N,), dtype=torch.long)
    target = torch.randint(low=1, high=C, size=(sum(target_lengths),), dtype=torch.long)
    ctc_loss = nn.CTCLoss()
    loss = ctc_loss(input, target, input_lengths, target_lengths)
    loss.backward()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    优化器

    6种优化器
    梯度下降法及优化算法
    ASGD
    所有优化算法均继承于Optimizer

    Optimizer
    class Optimizer(object):
    	def __init__(self,params,defaults):
    		self.defaults = defaults
    		self.state = defaultdict(dict)
    		self.param_groups = []
    #属性
    ##defaults:存储的是优化器的超参数
    ##state:参数的缓存
    ##param_groups:管理的参数组
    
    #方法
    ##zero_grad():清空所管理参数的梯度,因为张量的梯度不自动清零,因此每次反向传播后都需清空梯度
    ##step():执行一步梯度更新,参数更新
    ##add_param_group():添加参数组
    ##load_state_dict():加载状态参数字典,可以用来进行模型的断点续训练,继续上次的参数进行训练
    ##state_dict():获取优化器当前状态信息字典
    
    #实际操作
    import os
    import torch
    
    # 设置权重,服从正态分布  --> 2 x 2
    weight = torch.randn((2, 2), requires_grad=True)
    # 设置梯度为全1矩阵  --> 2 x 2
    weight.grad = torch.ones((2, 2))
    
    # 实例化优化器
    optimizer = torch.optim.SGD([weight], lr=0.1, momentum=0.9)
    # 优化器执行
    optimizer.step()
    
    # 权重清零
    optimizer.zero_grad()
    
    # 输出参数
    print("optimizer.params_group is \n{}".format(optimizer.param_groups))
    # 查看参数位置,optimizer.param_groups[0]['params'][0]和weight的位置一样,注意不要将对weight进行值操作
    
    # 添加参数:weight2
    weight2 = torch.randn((3, 3), requires_grad=True)
    optimizer.add_param_group({"params": weight2, 'lr': 0.0001, 'nesterov': True})
    
    # 获取当前状态信息
    opt_state_dict = optimizer.state_dict()
    
    # 进行50次step操作
    for _ in range(50):
        optimizer.step()
    # 输出现有状态信息
    print("state_dict after step:\n", optimizer.state_dict())
    
    # 保存参数信息
    torch.save(optimizer.state_dict(),os.path.join(r".\", "optimizer_state_dict.pkl"))
    # 加载参数信息
    state_dict = torch.load(r".\optimizer_state_dict.pkl") # 需要修改为你自己的路径
    optimizer.load_state_dict(state_dict)
    
    # 输出最后属性信息
    print("\n{}".format(optimizer.defaults))#默认
    print("\n{}".format(optimizer.state))#状态
    print("\n{}".format(optimizer.param_groups))#参数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    训练和评估

    • 一个训练过程
    #如果训练状态,模型的参数应该支持反向传播的修改;如果验证/测试状态,则不应该修改模型参数
    #model.train()#训练状态
    #model.eval()#验证/测试状态
    
    #一个完整的图像分类的训练过程
    def train(epoch):
        model.train()
        train_loss = 0
        for data, label in train_loader:#循环读取DataLoader中的数据
            #data, label = data.cuda(), label.cuda()#将数据放到GPU上用于后续计算 只有CPU
            optimizer.zero_grad()#开始用当前批次数据做训练时,先优化器的梯度置零
            output = model(data)#送入模型中训练
            loss = criterion(label, output)#使用预定义的criterion计算损失函数
            loss.backward()#将loss反向传播回网络
            optimizer.step()#使用优化器更新模型参数
            train_loss += loss.item()*data.size(0)#每一批样本的损失值之和
        train_loss = train_loss/len(train_loader.dataset)#加权平均数
    		print('Epoch: {} \tTraining Loss: {:.6f}'.format(epoch, train_loss))
    #一个完整的图像分类的训练过程
    def val(epoch):       
        model.eval()
        val_loss = 0
        gt_labels = []
        pred_labels = []
        with torch.no_grad():
            for data, label in test_loader:
                #data, label = data.cuda(), label.cuda()
                output = model(data)
                preds = torch.argmax(output, 1)
                gt_labels.append(label.cpu().data.numpy())
                pred_labels.append(preds.cpu().data.numpy())
                loss = criterion(output, label)
                val_loss += loss.item()*data.size(0)
        val_loss = val_loss/len(test_loader.dataset)
        gt_labels, pred_labels = np.concatenate(gt_labels), np.concatenate(pred_labels)
        acc = np.sum(gt_labels==pred_labels)/len(pred_labels)#计算准确率
        print('Epoch: {} \tValidation Loss: {:.6f}, Accuracy: {:6f}'.format(epoch, val_loss, acc))
    for epoch in range(1, epochs+1):#进行迭代训练
        train(epoch)
        val(epoch)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    参考

    模型设计
    pytorch中文文档

    实战练习项目

    FashionMNIST

  • 相关阅读:
    Linux:network:socket:ip_unprivileged_port_start CAP_NET_BIND_SERVICE
    算法复杂度分析中的渐近分析(基于输入大小)
    aspnetcore6.0源代码编译调试
    Mybatis操作数据库流程源码
    Internet Download Manager永久版功能强大的网络下载器
    基于Spring Boot的考研资讯平台设计与实现
    北京君正客户应用案例:掌静脉3D人脸猫眼视屏智能锁
    【经历】跨境电商公司目前已在职近2年->丰富且珍贵
    ISCSLP 2022 | AccentSpeech—从众包数据中学习口音来构建目标说话人的口音语音合成系统
    一文教会你 Spring Boot中的热部署与单元测试(简单易懂,附源码实战)
  • 原文地址:https://blog.csdn.net/qq_42947060/article/details/126848161