一些存储在各种类型张量的公用数据集类型:
Tensor(sizes) | 基础构造函数 |
---|---|
tensor(data) | 类似于np.array |
ones(sizes) | 全1 |
zeros(sizes) | 全0 |
eye(sizes) | 对角为1,其余为0 |
arange(s,e,step) | 从s到e,步长为step |
linspace(s,e,steps) | 从s到e,均匀分成steps份 |
rand/randn(sizes) | rand是[0,1)均匀分布;randn是服从N(0,1)的正态分布 |
normal(mean,std) | 正态分布(均值为mean,标准差是std) |
randperm(m) | 随机排列 |
dtype
设置数据类型。加法操作
x+y#方式1
torch.add(x,y)#方式2
y.add_(x)#方式3,把x+y赋给y
索引操作(类似于numpy)
.copy()
等方法。维度变换
.view()
(共享内存).clone()
方法构建张量副本,然后用.view()
方法进行维度变换。取值操作
.item()
来获取tensor内部某个元素的精确值同numpy
如果设置tensor的requires_grad
为 True
,那么它将会追踪对于该张量的所有操作。当完成计算后可以通过调用.backward()
来自动计算所有的梯度。这个张量的所有梯度将会自动累加到.grad
属性。
.detach()
方法将其与计算历史分离,并阻止它未来的计算记录被跟踪。为了防止跟踪历史记录(和使用内存),可以将代码块包装在 with torch.no_grad():
中。在评估模型时特别有用,因为模型可能具有 requires_grad = True
的可训练的参数,但是我们不需要在此过程中对他们进行梯度计算。autograd
的实现非常重要:Function
。Tensor 和 Function 互相连接生成了一个无环图 (acyclic graph),它编码了完整的计算历史。每个张量都有一个.grad_fn
属性,该属性引用了创建 Tensor 自身的Function(除非这个张量是用户手动创建的,即这个张量的grad_fn
是 None
)。.requires_grad_(...)
可以原地改变现有张量的requires_grad
标志。如果没有指定的话,默认输入的这个标志是False
。tensor.data
进行操作。cuda()
时,其功能是让我们的模型或者数据迁移到GPU当中,通过GPU开始计算。import os
import numpy as np
import torch
import torch.nn as nn
from torch.utils.data import Dataset,DataLoader
import torch.optim as optimizer
batch_size=20#batch size
lr=1e-4#初始学习率(初始)
max_epochs=100#训练次数
#GPU设置
#方案一:使用os.environ,这种情况如果使用GPU不需要设置
os.environ["CUDA_VISIBLE_DEVICES"]="0"
#方案二:使用“device”,后续对要使用GPU的变量用.to(device)即可
device=torch.device("cuda:1" if torch.cuda.is_available() else "cpu")
Dataset
datasets.ImageFolder()
DataLoader
batch_size
:每次读入的样本数num_workers
:有多少个进程用于读取数据shuffle
:是否将读入的数据打乱drop_last
:对于样本最后一部分没有达到批次数的样本,使其不再参与训练自定义层:
常见的层:
模型示例:
torch.nn.init
提供了常用的初始化方法,如:
torch.nn.init.uniform_
(tensor, a=0.0, b=1.0)torch.nn.init.normal_
(tensor, mean=0.0, std=1.0)torch.nn.init.constant_
(tensor, val)torch.nn.init.ones_
(tensor)torch.nn.init.zeros_
(tensor)torch.nn.init.eye_
(tensor)通常使用isinstance()
来进行判断模块属于什么类型,对于不同的类型层,我们就可以设置不同的权值初始化的方法。
人们常常将各种初始化方法定义为一个initialize_weights()
的函数并在模型初始后进行使用。
torch.nn.BCELoss
(weight=None, size_average=None, reduce=None, reduction=‘mean’)torch.nn.CrossEntropyLoss
(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction=‘mean’)torch.nn.L1Loss
(size_average=None, reduce=None, reduction=‘mean’)torch.nn.MSELoss
(size_average=None, reduce=None, reduction=‘mean’)torch.nn.SmoothL1Loss
(size_average=None, reduce=None, reduction=‘mean’, beta=1.0)torch.nn.PoissonNLLLoss
(log_input=True, full=False, size_average=None, eps=1e-08, reduce=None, reduction=‘mean’)torch.nn.KLDivLoss
(size_average=None, reduce=None, reduction=‘mean’, log_target=False)torch.nn.MarginRankingLoss
(margin=0.0, size_average=None, reduce=None, reduction=‘mean’)torch.nn.MultiLabelMarginLoss
(size_average=None, reduce=None, reduction=‘mean’)torch.nn.SoftMarginLoss
(size_average=None, reduce=None, reduction=‘mean’)torch.nn.(size_average=None, reduce=None, reduction=‘mean’)torch.nn.MultiMarginLoss
(p=1, margin=1.0, weight=None, size_average=None, reduce=None, reduction=‘mean’)torch.nn.TripletMarginLoss
(margin=1.0, p=2.0, eps=1e-06, swap=False, size_average=None, reduce=None, reduction=‘mean’)torch.nn.HingeEmbeddingLoss
(margin=1.0, size_average=None, reduce=None, reduction=‘mean’)torch.nn.CosineEmbeddingLoss
(margin=0.0, size_average=None, reduce=None, reduction=‘mean’)torch.nn.CTCLoss
(blank=0, reduction=‘mean’, zero_infinity=False)model.train() # 训练状态
model.eval() # 验证/测试状态
读取数据
for data, label in train_loader:
之后将数据放到GPU上用于后续计算,此处以.cuda()为例
data, label = data.cuda(), label.cuda()
开始用当前批次数据做训练时,应当先将优化器的梯度置零:
optimizer.zero_grad()
之后将data送入模型中训练:
output = model(data)
根据预先定义的criterion计算损失函数:
loss = criterion(output, label)
将loss反向传播回网络:
loss.backward()
使用优化器更新模型参数:
optimizer.step()
torch.optim
提供了多种优化器,如:
Optimizer
import os
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
from torch.utils.data import Dataset,DataLoader
import torch.optim as optimizer
import torchvision
batch_size=256# batch size
num_workers=0# 对于Windows用户,这里应设置为0,否则会出现多线程错误
lr=1e-4# 初始学习率(初始)
max_epochs=18# 训练次数
#GPU设置
#方案一:使用os.environ,这种情况如果使用GPU不需要设置
os.environ["CUDA_VISIBLE_DEVICES"]="0"
#方案二:使用“device”,后续对要使用GPU的变量用.to(device)即可
device=torch.device("cuda:1" if torch.cuda.is_available() else "cpu")
from torchvision import transforms
image_size=28
data_transform=transforms.Compose([
# Converts a torch.*Tensor of shape C x H x W or a numpy ndarray of shape H x W x C to a PIL Image while preserving the value range。
transforms.ToPILImage(),# 这一步取决于后续的数据读取方式,如果使用内置数据集则不需要。
# 调整PILImage对象的尺寸,注意不能是用io.imread或者cv2.imread读取的图片,这两种方法得到的是ndarray。下一行表示将图片短边缩放至image_size,长宽比保持不变。
transforms.Resize(image_size),
# Convert a ``PIL Image`` or ``numpy.ndarray`` to tensor。
transforms.ToTensor()
])
train_df=pd.read_csv("./dataset/fashion-mnist/fashion-mnist_train.csv")
test_df=pd.read_csv("./dataset/fashion-mnist/fashion-mnist_test.csv")
print(train_df.head())
class FMDataset(Dataset):
def __init__(self,df,transform=None):
self.df=df
self.transform=transform
# df.values:Return a Numpy representation of the DataFrame。
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):
# Converts 784 to a numpy ndarray of shape H x W x C。
image=self.images[idx].reshape(28,28,1)
label=int(self.labels[idx])
# 把image transform一下,注意返回tensor类型
if self.transform is not None:
image=self.transform(image)
else:
image=torch.tensor(image/255.,dtype=torch.float)
# Converts label to a torch.*Tensor
label=torch.tensor(label,dtype=torch.long)
return image,label
train_data=FMDataset(train_df,data_transform)
test_data=FMDataset(test_df,data_transform)
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)
import matplotlib.pyplot as plt
image,label=next(iter(train_loader))
print(image.shape,label.shape)# torch.Size([batch_size,C,H,W]),torch.Size([batch_size])
plt.imshow(image[0][0],cmap="gray")
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
# torch.nn.Sequential是一个有序的容器,该类将按照传入构造器的顺序,依次创建相应的函数,并记录在Sequential类对象的数据结构中,同时以神经网络模块为元素的有序字典也可以作为传入参数。
self.conv=nn.Sequential(
# torch.nn.Conv2d(in_channels, out_channels, kernel_size)
nn.Conv2d(1,32,5),
nn.ReLU(),
# nn.MaxPool2d(kernel_size,stride),stride不指定则默认和kernel_size大小一致。
nn.MaxPool2d(2,stride=2),
# 在训练过程的前向传播中,nn.Dropout(p)让每个神经元以一定概率p处于不激活的状态,以达到减少过拟合的效果。
nn.Dropout(0.3),
nn.Conv2d(32,64,5),
nn.ReLU(),
nn.MaxPool2d(2,stride=2),
nn.Dropout(0.3)
)
self.fc=nn.Sequential(
# nn.Linear(in_features,out_features)
# in_features的数量决定的参数的个数;out_features的数量决定了全连接层中神经元的个数,因为每个神经元只有一个输出。
nn.Linear(64*4*4,512),
nn.ReLU(),
nn.Linear(512,10)
)
def forward(self,x):
x=self.conv(x)
x=x.view(-1,64*4*4)
x=self.fc(x)
# x = nn.functional.normalize(x)
return x
model=Net()
model.cuda()
# model = nn.DataParallel(model).cuda() # 多卡训练时的写法。
criterion=nn.CrossEntropyLoss()
# criterion = nn.CrossEntropyLoss(weight=[1,1,1,1,3,1,1,1,1,1])
optimizer=optimizer.Adam(model.parameters(),lr=1e-3)
两者的主要区别:
def train(epoch):
# prep model for training
model.train()
train_loss=0
for data,label in train_loader:
data,label=data.cuda(),label.cuda()
optimizer.zero_grad()
output=model(data)
loss=criterion(output,label)
loss.backward()
optimizer.step()
# 除了loss.backward()之外的loss调用都写成loss.item()
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)
# torch.argmax(input, dim=None, keepdim=False)返回指定维度最大值的序号。
preds=torch.argmax(output,1)
# 输出数据去cuda,转为numpy,因为计算预测acc、auc这类型的评估参数时,实在cpu上进行的,所以模型evaluate时,需要将loss之类的转到cpu上。
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,max_epochs+1):
train(epoch)
val(epoch)
参考:DataWhale——深入浅出的PyTorch