本文主要是介绍pytorch速成,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
有其他框架的基础,看一下这个项目中的速成部分,能快速上手
https://github.com/ceo1207/pytorch-lesson-zh
新建网络
A、使用tensor运算,会自动构建网络
tensor运算
可以使用运算符,+、-等,可以使用torch.xx,也可以tensor.xx在原tensor上做运算
Tensor
sum(dim=None, keepdim=False, dtype=None) → Tensor
pow(exponent) → Tensor
mm(mat2) → Tensor
torch
torch.mm(mat1, mat2, out=None) → Tensor
torch.clamp(input, min, max, out=None) → Tensor
B、override forward and init
继承Module,复写相关函数,之后讲述
如何向网络输入,获取输出和loss,更新权重
可以全手动计算grad、更新参数,这对新手理解神经网络的传播和反向传播很有帮助
示例:
import torch
# M是样本数量,input_size是输入层大小
# hidden_size是隐含层大小,output_size是输出层大小
M, input_size, hidden_size, output_size = 64, 1000, 100, 10# 生成随机数当作样本
x = torch.randn(M, input_size) #size(64, 1000)
y = torch.randn(M, output_size) #size(64, 10)# 参数初始化
def init_parameters():w1 = torch.randn(input_size, hidden_size)w2 = torch.randn(hidden_size, output_size)b1 = torch.randn(1, hidden_size)b2 = torch.randn(1, output_size)return {"w1": w1, "w2":w2, "b1": b1, "b2": b2}# 定义模型
def model(x, parameters):Z1 = x.mm(parameters["w1"]) + parameters["b1"] # 线性层A1 = Z1.clamp(min=0) # relu激活函数Z2 = A1.mm(parameters["w2"]) + parameters["b2"] #线性层# 为了方便反向求导,我们会把当前求得的结果保存在一个cache中cache = {"Z1": Z1, "A1": A1}return Z2, cache# 计算损失
def loss_fn(y_pred, y):loss = (y_pred - y).pow(2).sum() # 我们这里直接使用 MSE(均方误差) 作为损失函数return loss# 反向传播,求出梯度
def backpropogation(x, y, y_pred, cache, parameters):m = y.size()[0] # m个样本# 以下是反向求导的过程:d_y_pred = 1/m * (y_pred - y)d_w2 = 1/m * cache["A1"].t().mm(d_y_pred)d_b2 = 1/m * torch.sum(d_y_pred, 0, keepdim=True)d_A1 = d_y_pred.mm(parameters["w2"].t())# 对 relu 函数求导: startd_Z1 = d_A1.clone()d_Z1[cache["Z1"] < 0] = 0# 对 relu 函数求导: endd_w1 = 1/m * x.t().mm(d_Z1)d_b1 = 1/m * torch.sum(d_Z1, 0, keepdim=True)grads = {"d_w1": d_w1, "d_b1": d_b1, "d_w2": d_w2, "d_b2": d_b2}return grads# 更新参数
def update(lr, parameters, grads):parameters["w1"] -= lr * grads["d_w1"]parameters["w2"] -= lr * grads["d_w2"]parameters["b1"] -= lr * grads["d_b1"]parameters["b2"] -= lr * grads["d_b2"]return parameters## 设置超参数 ##learning_rate = 1e-2
EPOCH = 400# 参数初始化
parameters = init_parameters()## 开始训练 ##
for t in range(EPOCH): # 向前传播y_pred, cache = model(x, parameters)# 计算损失loss = loss_fn(y_pred, y)if (t+1) % 50 == 0:print(loss)# 反向传播grads = backpropogation(x, y, y_pred, cache, parameters)# 更新参数parameters = update(learning_rate, parameters, grads)
由此我们知道,网络在更新计算的时候,需要根据结果和保存的每张feature map,来更新权重。
如果是mini-batch,则有一个统一的loss,然后根据各自的feature map,来反向传播更新n次,n=mini_batch_size
使用自动求导机制
from torch.autograd import Variable
新版本的torch已经废弃Variable。
The Variable API has been deprecated: Variables are no longer necessary to use autograd with tensors. Autograd automatically supports Tensors with requires_grad set to True.
只要创建tensor时,设置requires_grad set为真即可。
利用自动求导,使用backwards便可计算梯度
注意pytorch的梯度是累加的,每次backward之前,需要清零
使用优化器来更新权重
optimizer.zero_grad()# 计算梯度loss.backward()# 更新梯度optimizer.step()
常会有PyCharm can not resolve xxx, but code runs fine
pycharm的reference还有点问题,就这么放着吧
使用module建立网络模型
前向传播,调用call即可
# 向前传播
y_pred= model(x)
使用sequential和modulelist来创建网络结构
如何建立模型
class Net(torch.nn.Module): def __init__(self):super(Net, self).__init__()def forward(self, x): return tensor利用torch.nn.Sequential()容器进行快速搭建
def __init__(self):super(Net3, self).__init__()self.conv=torch.nn.Sequential() # 可以为每层建立不同的名字self.conv.add_module("conv1",torch.nn.Conv2d(3, 32, 3, 1, 1))self.conv.add_module("relu1",torch.nn.ReLU())self.conv.add_module("pool1",torch.nn.MaxPool2d(2))# 且可以使用有序字典创建sequential modelself.conv = torch.nn.Sequential(OrderedDict([("conv1", torch.nn.Conv2d(3, 32, 3, 1, 1)),("relu1", torch.nn.ReLU()),("pool", torch.nn.MaxPool2d(2))]))pytorch可以随意更改网络结构
model = torchvision.models.resnet18(pretrained=True)
for param in model.parameters():param.requires_grad = False
# Replace the last fully-connected layer
# Parameters of newly constructed modules have requires_grad=True by default
model.fc = nn.Linear(512, 100)# Optimize only the classifier
optimizer = optim.SGD(model.fc.parameters(), lr=1e-2, momentum=0.9)
如何使用dataloader
方法1:
读取数据,获得numpy array,转化为tensor
x_data = torch.from_numpy(xy) # 从numpy array创建tensor
使用dataset包装tensor
deal_dataset = TensorDataset(data_tensor=x_data, target_tensor=y_data)
dataloader
train_loader = DataLoader(dataset=deal_dataset,
batch_size=32,
shuffle=True,
num_workers=2)
方法2:
可以继承Dataset,定义自己的dataset类,需要重写 len 方法,该方法提供了dataset的大小; getitem 方法, 该方法支持从 0 到 len(self)的索引
定义自己的dataset类可以避免一次性读入所有数据。
pytorch的便利
pytorch提前处理了很多数据集
torchvision.datasets 是用来进行数据加载的,PyTorch团队在这个包中帮我们提前处理好了很多很多图片数据集。
使用预训练的模型
import torchvision.models as models
# 加载一个 resnet18 模型
resnet18 = models.resnet18()
print(resnet18)
import torchvision.models as models
resnet18 = models.resnet18(pretrained=True)如何获取中间层特征
# -----------------修改预训练好的 Alexnet 模型中的分类层-------------------------
alexnet.classifier = nn.Sequential(nn.Dropout(p=0.5),nn.Linear(in_features=9216, out_features=4096, bias=True),nn.ReLU(inplace=True),nn.Dropout(p=0.5),nn.Linear(in_features=4096, out_features=4096, bias=True),nn.ReLU(inplace=True),nn.Linear(in_features=4096, out_features=CLASS_NUM, bias=True)
)
需要修改网络结构,直接修改网络中的modules就可以。
并且,在优化时,# 训练的时候,我们只更新 classifier 层的参数
optimizer = optim.Adam(alexnet.classifier.parameters(), lr=learning_rate)
只向优化器输入想要优化的参数
这篇关于pytorch速成的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!