Pytorch学习记录-使用Pytorch进行深度学习,使用案例学习Pytorch

首页.jpg

注意确定已经安装了torch和torchvision
使用案例学习Pytorch
在完成60分钟入门之后,接下来有六节tutorials和五节关于文本处理的tutorials。争取一天一节。不过重点是关注神经网络构建和数据处理部分。
教程通过下面的几个例子介绍了Pytorch的基本概念。Pytorch的核心是以下两个特性:

  • n维张量,和numpy类似但可以在GPU上运行
  • 构建和训练神经网络的自动微分功能

接下来教程会使用全连接Relu网络作为运行案例,这个网络有一个隐藏层hy,使用梯度下降进行训练拟合随即数据。
下面是教程目录。
1.Tensors(张量)
1.1 Warm-up:numpy
1.2 PyTorch:Tensors
2.Autograd(自动梯度)
2.1 PyTorch:Variables and autograd (变量和自动梯度)
2.2 PyTorch : Defining new autograd functions(定义新的自动梯度函数)
2.3 TensorFlow: Static Graphs (静态图)
3.nn module
3.1 PyTorch: nn
3.2 PyTorch: optim
3.3 PyTorch: Custom nn Modules (定制nn模块)
3.4 PyTorch: Control Flow + Weight Sharing (控制流+权重分享)

1. Tensor

1.1 热身

介绍Pytorch之前使用numpy实现一个网络。numpy提供的是一个n维数组对象,以及操作这些数组的函数。但是numpy不是为计算图、深度学习、梯度计算而生,在这里生成一个两层的网络,然后使用随即数据拟合,前向、后向传播均使用numpy操作。

# -*- coding:utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt

N, D_in, H, D_out = 64, 1000, 100, 10
x = np.random.randn(N, D_in)
y = np.random.randn(N, D_out)

w1 = np.random.randn(D_in, H)
w2 = np.random.randn(H, D_out)

learning_rate = 1e-6
for t in range(500):
    h = x.dot(w1)
    h_relu = np.maximum(h, 0)
    y_pred = h_relu.dot(w2)

    loss = np.square(y_pred - y).sum()
    print(t, loss)

    grad_y_pred = 2.0 * (y_pred - y)
    grad_w2 = h_relu.T.dot(grad_y_pred)
    grad_h_relu = grad_y_pred.dot(w2.T)
    grad_h = grad_h_relu.copy()
    grad_h[h < 0] = 0
    grad_w1 = x.T.dot(grad_h)

    w1 -= learning_rate * grad_w1
    w2 -= learning_rate * grad_w2

我们输出一下损失函数


image.png

1.2 PyTorch:Tensors

Pytorch的基本概念Tensor,Tensor与numpy的array类似,是一个n维的array。
Pytorch提供多种进行Tensor运算,教程中还提到,Pytorch同样也不是专门进行深度学习、计算图、计算梯度的。但是优势在于能在GPU上运行。
在这里使用Pytorch Tensor来拟合一个2层的网络,需要手动执行前向和反向操作。

import torch
import matplotlib.pyplot as plt

dtype = torch.float
device = torch.device('cpu')
N, D_in, H, D_out = 64, 1000, 100, 10
x = torch.randn(N, D_in, device=device, dtype=dtype)
y = torch.randn(N, D_out, device=device, dtype=dtype)

w1 = torch.randn(D_in, H, device=device, dtype=dtype)
w2 = torch.randn(H, D_out, device=device, dtype=dtype)

learning_rate = 1e-6
loss_list = []
t_list = []

for t in range(500):
    h = x.mm(w1)
    h_relu = h.clamp(min=0)
    y_pred = h_relu.mm(w2)
    loss = (y_pred - y).pow(2).sum().item()
    print(t, loss)
    loss_list.append(loss)
    t_list.append(t)

    grad_y_pred = 2.0 * (y_pred - y)
    grad_w2 = h_relu.t().mm(grad_y_pred)
    grad_h_relu = grad_y_pred.mm(w2.t())
    grad_h = grad_h_relu.clone()
    grad_h[h < 0] = 0
    grad_w1=x.t().mm(grad_h)

    w1-=learning_rate*grad_w1
    w2-=learning_rate*grad_w2
image.png

2.Autograd(自动梯度)

2.1 PyTorch:Tensors and autograd

实际操作中肯定不能像上面那样手动操作,这样,就需要有一个自动求梯度,自动反向传递。
在之前60分钟已经做了介绍,那就是autograd包,在使用autograd时,前向通道定义一个计算图(computational graph),图中的节点是Tensor,边是依据输入Tensor产生的输出Tensro的函数,这样图的反向传播就可以计算梯度了。
操作历程如下

  • 将Tensors打包到Variable对象中(一个Variable代表一个计算图中的节点。如果x是一个Variable,那么x. data 就是一个Tensor),x.grad是另一个Tensor,这个Tensor通过对某个标量保持x的梯度
    这里使用Tensor和autograd来实现上面的那个两层网络,不再需要手动实现反向传播了!
import torch

dtype = torch.float
device = torch.device('cpu')

N, D_in, H, D_out = 64, 1000, 100, 10

x = torch.randn(N, D_in, device=device, dtype=dtype)
y = torch.randn(N, D_out, device=device, dtype=dtype)
# 在这里设置requires_grad为True,就可以在接下来进行反向传播计算
w1 = torch.randn(D_in, H, device=device, dtype=dtype, requires_grad=True)
w2 = torch.randn(H, D_out, device=device, dtype=dtype, requires_grad=True)

learning_rate = 1e-6

for t in range(500):
    y_pred = x.mm(w1).clamp(min=0).mm(w2)

    #计算损失,这时损失已经是一个Tensor,shape为(1,),loss.item()获取的就是损失的标量值
    loss=(y_pred-y).pow(2).sum()
    print(t,loss.item())

    loss.backward()
    with torch.no_grad():
        w1-=learning_rate*w1.grad
        w2-=learning_rate*w2.grad

        #在使用完之后将梯度归零
        w1.grad.zero_()
        w2.grad.zero_()

对比之前的操作,会发现Pytorch大大降低了手工操作的负担,只需要在设定的时候增加requires_grad=True,在最后对权重进行归零即可。

2.2 PyTorch : Defining new autograd functions(定义新的自动梯度函数)

在底层,每次原始的autograd操作都是对Tensor的两个方法的操作。

  • forward方法用于计算输入Tensor
  • backward方法获取输出的梯度,并且计算输入Tensors相对于该相同标量值的梯度
    在Pytorch中,可以容易定义自己的autograd操作,通过定义子类torch.autograd.Function来实现forward和backward函数,然后就可以通过构建实例并进行调用来使用新的autograd运算符。传递包含输入数据的Variables。

这个例子就是定制一个autograd函数来执行Relu非线性,进一步执行两层神经网络。

import torch

class MyRelu(torch.autograd.Function):
    @staticmethod
    def forward(ctx, input):
        '''
        ctx是一个上下文对象,可用于存储信息以进行反向计算。
        :param ctx: 
        :param input: 
        :return: 
        '''
        ctx.save_for_backward(input)
        return input.clamp(min=0)

    @staticmethod
    def backward(ctx, grad_output):
        '''
        在backwward中,获取一个含有损失的梯度的Tensor,并且计算相对于输入的损失的梯度。
        :param ctx: 
        :param grad_output: 
        :return: 
        '''
        input, = ctx.saved_tensors
        grad_input = grad_output.clone()
        grad_input[input < 0] = 0
        return grad_input


dtype = torch.float
device = torch.device("cpu")
N, D_in, H, D_out = 64, 1000, 100, 10

x = torch.randn(N, D_in, device=device, dtype=dtype)
y = torch.randn(N, D_out, device=device, dtype=dtype)
w1 = torch.randn(D_in, H, device=device, dtype=dtype, requires_grad=True)
w2 = torch.randn(H, D_out, device=device, dtype=dtype, requires_grad=True)

learning_rate = 1e-6
for t in range(500):
    relu = MyRelu.apply

    y_pred = relu(x.mm(w1)).mm(w2)
    loss = (y_pred - y).pow(2).sum()

    print(t, loss.item())
    loss.backward()

    with torch.no_grad():
        w1 -= learning_rate * w1.grad
        w2 -= learning_rate * w2.grad

        w1.grad.zero_()
        w2.grad.zero_()

2.3 TensorFlow: Static Graphs (静态图)

这一节空出来,主要内容是为了对比Tensorflow和Pytorch在动态图和静态图之间的区别,不用说,肯定Pytorch更好一些。

3.nn module(神经网络模块)

3.1 PyTorch: nn

计算图和autograd时很有用的范式,可以用来定义复杂运算符和自动求导。这时对于大型网络而言,原始的autograd就有些低级。
在构建神经网络时,会经常需要把计算安排在层(layers)中。某些层有可学习的参数,将会在学习中进行优化。
Pytorch提供的nn包就是类似Keras的高级抽象,其中定义了一系列Modules,相当于神经网络中的层,一个Module接收输入Variables,计算输出Variables,但是也可以保持一个内部状态,例如包含了可学习参数的Variables。nn 包还定义了一系列在训练神经网络时常用的损失函数。

接下来就是使用nn包来实现上面的两层神经网络

import torch

N, D_in, H, D_out = 64, 1000, 100, 10

x = torch.randn(N, D_in)
y = torch.randn(N, D_out)

model = torch.nn.Sequential(
    torch.nn.Linear(D_in, H),
    torch.nn.ReLU(),
    torch.nn.Linear(H, D_out),
)
loss_fn = torch.nn.MSELoss(size_average=False)

learning_rate = 1e-6
for t in range(500):
    y_pred = model(x)
    loss = loss_fn(y_pred, y)
    print(t, loss.data[0])

    model.zero_grad()

    loss.backward()
    with torch.no_grad():
        for param in model.parameters():
            param -= learning_rate * param.grad

3.2 PyTorch: optim(优化)

在前面更新权重,使用的是手动改变学习参数,这对于使用简单的优化算法(SGD)是可以的,但是在使用更加复杂的优化算法(ADAGrad,RMSProp,Adam)训练神经网络。
Pytorch提供了optim包对优化算法进行抽象。
同样是刚才的那个2层神经网络,这里使用optim来进行优化。

import torch
N, D_in, H, D_out = 64, 1000, 100, 10

x = torch.randn(N, D_in)
y = torch.randn(N, D_out)

model=torch.nn.Sequential(
    torch.nn.Linear(D_in,H),
    torch.nn.ReLU(),
    torch.nn.Linear(H,D_out),
)

loss_fn=torch.nn.MSELoss(size_average=False)
learning_rate=1e-4
optimizer=torch.optim.Adam(model.parameters(), lr=learning_rate)
for t in range(500):
    y_pred=model(x)
    loss=loss_fn(y_pred,y)
    print(t,loss.item())

    optimizer.zero_grad()

    loss.backward()
    optimizer.step()

对比前面的,你会发现越来越简化,就能生成一个神经网络。

3.3 PyTorch: Custom nn Modules (定制nn模块)

有时候,需要设定比现有模块序列更加复杂的模型。这时,你可以通过生成一个nn.Module的子类来定义一个forward。该forward可以使用其他的modules或者其他的自动梯度运算来接收输入Variables,产生输出Variables。
在这个例子中,我们实现两层神经网络作为一个定制的Module子类。

import torch


class TwoLayerNet(torch.nn.Module):
    def __init__(self, D_in, H, D_out):
        super(TwoLayerNet, self).__init__()
        self.linear1 = torch.nn.Linear(D_in, H)
        self.linear2 = torch.nn.Linear(H, D_out)

    def forward(self, x):
        h_relu = self.linear1(x).clamp(min=0)
        y_pred = self.linear2(h_relu)
        return y_pred


N, D_in, H, D_out = 64, 1000, 100, 10

x = torch.randn(N, D_in)
y = torch.randn(N, D_out)

model = TwoLayerNet(D_in, H, D_out)
criterion=torch.nn.MSELoss(size_average=False)
optimizer=torch.optim.SGD(model.parameters(),lr=1e-4)
for t in range(500):
    y_pred=model(x)
    loss=criterion(y_pred,y)

    print(t,loss.item())
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

3.4 PyTorch: Control Flow + Weight Sharing (控制流+权重分享)

我们实现一个非常奇怪的模型来作为动态图和权重分享的例子。这个模型是一个全连接的ReLU网络。每一个前向通道选择一个1至4之间的随机数,在很多隐含层中使用。多次使用相同的权重来计算最内层的隐含层。
这个模型我们使用正常的Python流控制来实现循环。在定义前向通道时,通过多次重复使用相同的Module来实现权重分享。
我们实现这个模型作为一个Module的子类。

# -*- coding: utf-8 -*-
import random
import torch


class DynamicNet(torch.nn.Module):
    def __init__(self, D_in, H, D_out):
        
        super(DynamicNet, self).__init__()
        self.input_linear = torch.nn.Linear(D_in, H)
        self.middle_linear = torch.nn.Linear(H, H)
        self.output_linear = torch.nn.Linear(H, D_out)

    def forward(self, x):
        
        h_relu = self.input_linear(x).clamp(min=0)
        for _ in range(random.randint(0, 3)):
            h_relu = self.middle_linear(h_relu).clamp(min=0)
        y_pred = self.output_linear(h_relu)
        return y_pred


# N is batch size; D_in is input dimension;
# H is hidden dimension; D_out is output dimension.
N, D_in, H, D_out = 64, 1000, 100, 10

# Create random Tensors to hold inputs and outputs
x = torch.randn(N, D_in)
y = torch.randn(N, D_out)

# Construct our model by instantiating the class defined above
model = DynamicNet(D_in, H, D_out)

# Construct our loss function and an Optimizer. Training this strange model with
# vanilla stochastic gradient descent is tough, so we use momentum
criterion = torch.nn.MSELoss(reduction='sum')
optimizer = torch.optim.SGD(model.parameters(), lr=1e-4, momentum=0.9)
for t in range(500):
    # Forward pass: Compute predicted y by passing x to the model
    y_pred = model(x)

    # Compute and print loss
    loss = criterion(y_pred, y)
    print(t, loss.item())

    # Zero gradients, perform a backward pass, and update the weights.
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

最后这个例子我没实现,照抄的。
这算是基本上的模型构建,主要包括模型、损失函数计算、优化、最后的迭代。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容