[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这两类较为简便,该
##

模型设计

基本定义方法

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()
  • 通过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

损失函数

常见损失函数及原理
常见损失函数(分类与回归)
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()#损失函数计算结果
  • 交叉熵损失函数
#交叉熵损失函数
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()
  • L1损失函数
#L1损失函数
loss = nn.L1Loss()
input = torch.randn(3,5,requires_grad=True)
target = torch.randn(3,5)
output = loss(input,target)
output.backward()
  • MSE损失函数
#MSE损失函数
loss = nn.MSELoss()
input = torch.randn(3,5,requires_grad=True)
target = torch.randn(3,5)
output = loss(input,target)
output.backward()
  • 平滑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()
  • 目标泊松分布的负对数似然损失
#目标泊松分布的负对数似然损失
loss = nn.PoissonNLLLoss()
log_input = torch.randn(5,2,requires_grad=True)
target = torch.randn(5,2)
output = loss(log_input,target)
output.backward()
  • 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)
  • 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()
  • 多标签边界损失函数
#多标签边界损失函数
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)
  • 二分类损失函数
#二分类损失函数
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)
  • 多分类的折页损失
#多分类的折页损失
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)
  • 三元组损失函数
#三元组损失函数
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()
  • 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)
  • 余弦相似度
#余弦相似度
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)
  • 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()

优化器

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))#参数

训练和评估

  • 一个训练过程
#如果训练状态,模型的参数应该支持反向传播的修改;如果验证/测试状态,则不应该修改模型参数
#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)

参考

模型设计
pytorch中文文档

实战练习项目

FashionMNIST

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值