Pytorch实现自定义神经网络层

本文介绍了如何在PyTorch中使用Function类实现无参数的自定义神经网络层,如计算向量长度,并演示了如何通过Module类实现有参数的线性层,包括前向传播和反向传播的过程。
摘要由CSDN通过智能技术生成

1.Pytorch已经为我们提供了丰富的函数以及神经网络模块了,但是有的时候我们需要自定神经网络模块。

2.自定神经网络模块时候我们分为有参数和无参数定义。

3.如果是自定义的层没有可以需要学习的参数,直接用Function类就行,比如ReLu。

4.如果有参数,就使用Module类来实现。

我们在学习反向传播时,经常会有这么一个例子。

一个向量[1,1],将他*4,然后求取这个向量的长度。

我们通常时将其中的分量1作为x1,另外一个作为x2,然后y当作长度,y是x1,x2的结果,然后我们利用反向传播这个方法去求取y关于x1,x2的偏微分,然后得到这个向量的长度在这两个方向上的分量就可以得到,这里就是长度。当我们想要求长度关于某一个分量(比如对于(x1))的导数时,我们实际上是想要知道长度在(x1)方向变化的速率,微分理解一下^^

好了,我们来实现一个无参数的函数来计算y,并且可以反向传播求导。

import torch
from torch.autograd import Function
import torch.nn as nn
import numpy as np

class CustomizeNone(Function):
    # 自定义的类我们需要两个函数,前向传播,反向传播
    # 前向传播我们需要用到两个参数,ctx,input,ctx用于储存反向传播需要用到的对象

    # 这是Python中的装饰器语法,用于将下面的forward方法声明为一个静态方法(static method)。
    @staticmethod
    def forward(ctx, input):

        ctx.save_for_backward(input)

        # torch.detach()是PyTorch中的一个方法,用于创建一个新的张量,该张量与原始张量共享数据,但是与计算图分离。
        # 在深度学习中,计算图用于跟踪数据流和梯度计算,
        # detach()方法允许我们从计算图中分离张量,这意味着在将来的计算中不会再跟踪与原始张量相关的梯度信息。
        numpy_input = input.detach().numpy()
        result1 = numpy_input*4
        # np.linalg.norm()函数用于计算向量或矩阵的范数
        # 使用某层输出的范数作为后续计算的一部分。通过计算输出的范数,我们可以获得有关该层输出的一些信息,例如层中值的分布情况、大小等
        result2 = np.linalg.norm(result1, keepdims=True)

        # 创建一个新的与input具有相同数据类型的张量,并用result2的值初始化它
        return input.new(result2)


    @staticmethod
    def backward(ctx, grad_output):

        input, = ctx.saved_tensors
        # 这里是乘4后求微分
        # 即dy/dx1 = d(4(x1^2 + x2^2)^1/2)/dx1 = 4*1/2*(x1^2 + x2^2)^-1/2*2x1
        # (x1 ^ 2 + x2 ^ 2) ^ 1 / 2范数
        grad = 4*(1/2)*(1/input.norm().item())*(2*input)

        return grad


customize = CustomizeNone.apply

input = torch.Tensor([1, 1])
input.requires_grad = True
print("Input:", input)
result = customize(input)
print("result:", result)
result.backward()
print("input grad:", input.grad)





接下来实现有参数的层,需要用到Module类,我们来定义一个线性层。

# 下面是有参数的线性层的定义
# 定义了一个自定义的自动求导函数LinearFunction,用于执行线性操作的前向和反向计算。
class LinearFunction(Function):
    @staticmethod
    def forward(ctx, input, weight, bias=None):
        ctx.save_for_backward(input, weight, bias)
        # 对输入张量input和转置权重张量weight.t()进行矩阵乘法运算,以计算输出张量。
        output = input.mm(weight.t())
        if bias is not None:
            output += bias.unsqueeze(0).expand_as(output)
        return output

    @staticmethod
    def backward(ctx, grad_output):
        input, weight, bias = ctx.saved_tensors
        grad_input = grad_weight = grad_bias = None
        if ctx.needs_input_grad[0]:
            grad_input = grad_output.mm(weight)
        if ctx.needs_input_grad[1]:
            grad_weight = torch.matmul(grad_output.t(), input)
        if bias is not None and ctx.needs_input_grad[2]:
            grad_bias = grad_output.sum(0).squeeze(0)

        return grad_input, grad_weight, grad_bias


class Linear(nn.Module):
    def __init__(self, input_features, output_features, bias=True):
        super(Linear, self).__init__()
        self.input_features = input_features
        self.output_features = output_features
        self.weight = nn.Parameter(torch.Tensor(output_features, input_features))
        if bias:
            self.bias = nn.Parameter(torch.Tensor(output_features))
        else:
            self.register_parameter('bias', None)

        self.weight.data.uniform_(-0.1, 0.1)
        if bias is not None:
            self.bias.data.uniform_(-0.1, 0.1)

    def forward(self, input):
        return LinearFunction.apply(input, self.weight, self.bias)

    def extra_repr(self):
        return 'in_features={}, output_features={}, bias={}'.format(
            self.input_features, self.output_features, self.bias is not None
        )


linear = Linear(4,2)
input = torch.Tensor(3, 4)
input.requires_grad = True
#通过线性层对象linear进行前向传播操作,得到输出张量output。
output = linear(input)
output.backward(torch.ones(output.size()))
print(input.grad)

您可以使用PyTorch实现循环神经网络(RNN)。PyTorch提供了一个名为`nn.RNN`的类,它可以用于创建RNN模型。以下是一个使用PyTorch实现循环神经网络的示例代码: ```python import torch import torch.nn as nn # 定义RNN模型 class RNN(nn.Module): def __init__(self, input_size, hidden_size, num_layers, output_size): super(RNN, self).__init__() self.hidden_size = hidden_size self.num_layers = num_layers # 定义RNN self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True) # 定义全连接 self.fc = nn.Linear(hidden_size, output_size) def forward(self, x): # 初始化隐藏状态 h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device) # 前向传播RNN out, _ = self.rnn(x, h0) # 取最后一个时间步的输出作为输出结果 out = self.fc(out[:, -1, :]) return out # 设置超参数 input_size = 10 hidden_size = 32 num_layers = 2 output_size = 2 # 创建RNN模型实例 model = RNN(input_size, hidden_size, num_layers, output_size) # 创建输入数据 batch_size = 16 sequence_length = 5 input_data = torch.randn(batch_size, sequence_length, input_size) # 前向传播 output = model(input_data) print(output.shape) # 输出: torch.Size([16, 2]) ``` 在这个示例中,我们首先定义了一个名为`RNN`的自定义模型类,继承了`nn.Module`。在模型的构造函数中,我们定义了RNN和全连接,并在前向传播函数中使用它们。最后,我们创建了一个RNN模型实例,并将输入数据通过模型进行前向传播,得到输出结果。 请注意,这只是一个简单的示例,您可以根据您的需求进行修改和扩展。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值