#TASK2

import torch
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
#N是批次大小,D_in是输入维度
#H是隐藏维度,D_out是输出维度
N,D_in,H,D_out=64,1000,100,10

#产生随机的输入和输出数据
x = torch.randn(N,D_in,device=device)
y = torch.randn(N,D_out,device=device)

#随机初始化权重
w1 = torch.randn(D_in,H,device=device)
w2 = torch.randn(H,D_out,device=device)

learn_rate = 1e-6
for t in range(500):
    #前向传播计算预测值y
    h = x.mm(w1)
    h_relu = h.clamp(min=0)
    y_pred = h_relu.mm(w2)
    
    #计算并输出loss,loss是存储在pytorch的tensor中的标量维度是()(零维标量)
    #我们计算loss.item()得到tensor中的纯python数值
    loss = (y_pred-y).pow(2).sum()
    print(t,loss.item())
    
    #反向传播,计算w1、w2对loss的梯度
    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 -= learn_rate*grad_w1
    w2 -= learn_rate*grad_w2

Pytorch 张量和自动求导

import torch

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

#N为批次大小,D_in为输入维度
#H为隐层维度,D_out为输出维度
N,D_in,H,D_out = 64,1000,100,10

#产生随机输入和输出数据
x = torch.randn(N,D_in,device=device)
y = torch.randn(N,D_out,device=device)

#产生随机变量tensor,将requires_grad设置为True意为着我们希望在反向传播时计算这些值的梯度
w1 = torch.randn(D_in,H,device = device,requires_grad = True)
w2 = torch.randn(H,D_out,device = device,requires_grad = True)

learning_rate = 1e-6
for t in range(500):
    y_pred = x.mm(w1).clamp(min=0).mm(w2)
    #计算loss
    loss = (y-y_pred).pow(2).sum()
    print(t,loss.item())
    #使用autograd计算反向传播,这个调用将计算loss对所有的requires_grad=True的tensor的梯度
    #这次调用后,w1.grad和w2.grad将分别是loss对w1的梯度张量和w2的梯度张量
    loss.backward()
    
    #使用autograd计算反向传播
    with torch.no_grad():
        #用梯度下降更新权重
        w1 -= learning_rate*w1.grad
        w2 -= learning_rate*w2.grad
        
        #在反向传播后手动清零梯度
        w1.grad.zero_()
        w2.grad.zero_()

定义新的自动求导函数

# 可运行代码见本文件夹中的 two_layer_net_custom_function.py
import torch

class MyReLU(torch.autograd.Function):
    """
    我们可以通过建立torch.autograd的子类来实现我们自定义的autograd函数,
    并完成张量的正向和反向传播。
    """
    @staticmethod
    def forward(ctx, x):
        """
        在正向传播中,我们接收到一个上下文对象和一个包含输入的张量;
        我们必须返回一个包含输出的张量,
        并且我们可以使用上下文对象来缓存对象,以便在反向传播中使用。
        """
        ctx.save_for_backward(x)
        return x.clamp(min=0)

    @staticmethod
    def backward(ctx, grad_output):
        """
        在反向传播中,我们接收到上下文对象和一个张量,
        其包含了相对于正向传播过程中产生的输出的损失的梯度。
        我们可以从上下文对象中检索缓存的数据,
        并且必须计算并返回与正向传播的输入相关的损失的梯度。
        """
        x, = ctx.saved_tensors
        grad_x = grad_output.clone()
        grad_x[x < 0] = 0
        return grad_x


device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# N是批大小; D_in 是输入维度;
# H 是隐藏层维度; D_out 是输出维度
N, D_in, H, D_out = 64, 1000, 100, 10

# 产生输入和输出的随机张量
x = torch.randn(N, D_in, device=device)
y = torch.randn(N, D_out, device=device)

# 产生随机权重的张量
w1 = torch.randn(D_in, H, device=device, requires_grad=True)
w2 = torch.randn(H, D_out, device=device, requires_grad=True)

learning_rate = 1e-6
for t in range(500):
    # 正向传播:使用张量上的操作来计算输出值y;
    # 我们通过调用 MyReLU.apply 函数来使用自定义的ReLU
    y_pred = MyReLU.apply(x.mm(w1)).mm(w2)

    # 计算并输出loss
    loss = (y_pred - y).pow(2).sum()
#     print(t, loss.item())

    # 使用autograd计算反向传播过程。
    loss.backward()

    with torch.no_grad():
        # 用梯度下降更新权重
        w1 -= learning_rate * w1.grad
        w2 -= learning_rate * w2.grad

        # 在反向传播之后手动清零梯度
        w1.grad.zero_()
        w2.grad.zero_()

Pytorch nn

import torch

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

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

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

#使用nn包将我们的模型定义为一系列的层
#nn.Sequential是包含其他模块的模块,并按顺序应用这些模块进行输出
#每个线性模块使用线性函数从输入计算输出,并保存其内部的权重和张量偏差
#在构造模型之后我们使用.to()方法将其移动到所需的设备
model = torch.nn.Sequential(
            torch.nn.Linear(D_in,H),
            torch.nn.ReLU(),
            torch.nn.Linear(H,D_out)
            ).to(device)
#nn包还包含常用损失函数的定义
#在这种情况下,我们将使用平均方误差(MSE)作为我们的损失函数
#设置reduction='sum',表示我们的计算的是平均误差的“和”,而不是平均值
#这是为了与前面我们手工计算损失函数的例子保持一致
#但是在实践中,通过设置reduction='elementwise_mean'来使用均方误差更为常见

loss_fn = torch.nn.MSELoss(reduction='sum')

learning_rate = 1e-4

for t in range(500):
    y_pred = model(x)
    
    loss = loss_fn(y_pred,y)
    print(t,loss.item())
    
    loss.backward()
    
    with torch.no_grad():
        for param in model.parameters():
            param.data -= learning_rate*param.grad

Pytorch optim

到目前为止,我们已经通过手动改变包含可以学习参数来更新新模型的权重。对于随机梯度下降(SGD/dtochastic gradient descent)等简单的优化算法来说不是一个很大的负担,但实践中,我们常常使用AdaGrad、RMSProp、Adam等更复杂的优化器来训练神经网络

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(reduction='sum')
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将它要更新的张量的梯度清零
    optimizer.zero_grad()
    
    loss.backward()
    
    #用step函数使所有的参数更新
    optimizer.step()

Pytorch 自定义nn模块

有时候需要指定比现有模块更复杂的模型,对于这种情况,可以通过继承nn.Module并定义forward函数,这个forward函数可以使用其他模块或者其他的自动求导运算来接受输入tensor产生输出的tensor

import torch

class TwoLayerNet(torch.nn.Module):
    def __init__(self, D_in, H, D_out):
        """
        在构造函数中,我们实例化了两个nn.Linear模块,并将它们作为成员变量。
        """
        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)

#构造损失函数和优化器
#SGD构造函数中对model.parameters()的调用
#将包含模型的一部分,即两个nn.Linear模块可学习参数
loss_fn = torch.nn.MSELoss(reduction='sum')
optimizer = torch.optim.SGD(model.parameters(),lr = 1e-4)
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()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值