首页人工智能Pytorch【深度学习(PyTorch...

【深度学习(PyTorch篇)】37.nn.Module

本系列文章配套代码获取有以下两种途径:

  • 通过百度网盘获取:
链接:https://pan.baidu.com/s/1XuxKa9_G00NznvSK0cr5qw?pwd=mnsj 提取码:mnsj
  • 前往GitHub获取
https://github.com/returu/PyTorch





nn.Module是一个Python类,在PyTorchtorch.nn包中定义。它是所有神经网络模块的基类,包括预定义的层(如nn.Linearnn.Conv2d等)以及用户自定义的模型。

01

定义自定义层


当用户需要实现PyTorch中没有的特定层时,可以通过继承nn.Module并定义自己的forward方法来实现。
例如,在PyTorch中,全连接层(也称为密集层或线性层)通常由nn.Linear类实现。但如果你想要实现自定义的全连接层,可以通过继承nn.Module类来完成。

以下是一个简单的示例,展示了如何创建一个自定义的全连接层(y=wx+b,其中wb是可学习参数):

  • 自定义层必须继承nn.Module,并在构造函数中调用nn.Module的构造函数(super().__init__());
  • 在构造函数__init__()中必须自行定义可学习的参数,并封装成nn.Parameter()。在PytorchParameter是一种特殊的Tensor,默认需要求导(即requires_grad=True);
  • 前向传播函数forward()的输入可以是一个或多个Tensor
  • nn.Module会利用autograd自动实现反向传播,无须手动编写。
class CustomLinearLayer(nn.Module):  
    # 继承nn.Module,需要重写构造函数__init__()以及前向传播函数forward()
    def __init__(self, input_features, output_features):  
        super().__init__()  
        # nn.Parameter()内的参数是网络中可学习的参数
        self.weight = nn.Parameter(torch.Tensor(output_features, input_features))  
        self.bias = nn.Parameter(torch.Tensor(output_features))  

    def forward(self, x):  
        # 执行线性变换并添加偏置:y=wx+b
        out = torch.mm(x, self.weight.t()) + self.bias  

        return out   

# 实例化自定义的全连接层  
custom_linear = CustomLinearLayer(input_features=10, output_features=5

# 假设输入是一个3x10的张量,即3个样本,每个样本10个特征  
input_tensor = torch.randn(310)
output_tensor = custom_linear(input_tensor)  
print(output_tensor)  # 输出应该是一个3x5的张量
nn.Module中定义的可学习参数,可以通过named_parameters()或者parameters()获取,两者都将返回一个迭代器,不过named_parameters()会给每个参数附上名字,更加清晰。
for name,parameter in custom_linear.named_parameters():
    print(name,parameter)

# 输出结果:
# weight Parameter containing:
# tensor([[7.1118e-04, 7.3017e+31, 2.8026e-45, 1.8672e+25, 0.0000e+00, 0.0000e+00,
#          5.3992e-14, 1.3556e-19, 2.8026e-45, 2.6354e+23],
#         [0.0000e+00, 0.0000e+00, 7.5338e+28, 7.1758e+22, 2.8026e-45, 6.8801e+16,
#          0.0000e+00, 0.0000e+00, 1.2415e+28, 2.7376e+20],
#         [2.8026e-45, 1.8524e+28, 0.0000e+00, 0.0000e+00, 1.8390e+25, 5.0714e-14,
#          2.8026e-45, 1.8888e+31, 0.0000e+00, 0.0000e+00],
#         [1.3419e+19, 1.7611e+19, 2.8026e-45, 1.3570e-14, 0.0000e+00, 0.0000e+00,
#          3.2745e-12, 7.5555e+31, 2.8026e-45, 1.4605e-19],
#         [0.0000e+00, 0.0000e+00, 3.0300e+35, 7.2251e+28, 2.8026e-45, 2.0027e-19,
#          0.0000e+00, 0.0000e+00, 2.4176e-12, 1.7743e+28]], requires_grad=True)
# bias Parameter containing:
# tensor([9.6429e-39, 8.4490e-39, 9.6429e-39, 9.2755e-39, 1.0286e-38],
#        requires_grad=True)
通过输出结果,可以看到输出的parameter名字为self.parameter_name=nn.Parameter()语句中的定义的名字parameter_name
  • nn.ParameterList:
nn.ParameterListPyTorch 中的一个类,它用于保存一组参数(通常是 nn.Parameter 的实例)。nn.ParameterList 允许你动态地管理一个参数列表,这些参数可以在模型的前向传播中使用,并会在训练过程中被优化
如果某些参数需要动态地管理或者这些参数的数量在模型定义时不是固定的,那么 nn.ParameterList 就非常有用。
以下是一个简单的使用示例:
class CustomLinearLayer_2(nn.Module):  
    # 继承nn.Module,需要重写构造函数__init__()以及前向传播函数forward()
    def __init__(self, input_features, output_features):  
        super().__init__()  
        # 创建一个nn.ParameterList,用于存储网络中的各个参数
        self.params = nn.ParameterList([
            nn.Parameter(torch.Tensor(output_features, input_features)) , # weight
            nn.Parameter(torch.Tensor(output_features)) # bias
        ])


    def forward(self, x):  
        # 执行线性变换并添加偏置:y=wx+b
        out = torch.mm(x, self.params[0].t()) + self.params[1]

        return out  

02

构建复杂模型


通过组合多个nn.Module实例(包括预定义的层和自定义层),用户可以构建复杂的神经网络模型。
  • 使用自定义层:

例如,使用上面创建的自定义全连接层创建一个多层感知机模型:

  • 在构造函数__init__()中将自定义的全连接层(module)作为当前module对象的一个子module
  • 前向传播函数forward()中加上各层之间的处理函数,例如激活函数。

class Perceptron(nn.Module):
    def __init__(self,in_features,hidden_features,out_features):
        super().__init__()
        # 使用前面自定义的全连接层CustomLinearLayer
        self.layer1 = CustomLinearLayer(in_features,hidden_features)
        self.layer2 = CustomLinearLayer(hidden_features,out_features)

    def forward(self,x):
        x = self.layer1(x)
        x = torch.sigmoid(x)
        x = self.layer2(x)
        return x

# 实例化自定义的多层感知机
Perceptron = Perceptron(in_features=10,hidden_features=50,out_features=5)  
# 假设输入是一个3x10的张量,即3个样本,每个样本10个特征  
input_tensor = torch.randint(low=0, high=100, size=(310),dtype=torch.float32)
output_tensor = Perceptron(input_tensor)  # 输出是一个3x5的张量
即使module中包含子moudlenn.Module也能够递归查找到子module中的Parameter,并将其作为学习参数。
# 主module能够递归查找子module中的Parameter
for name,parameter in Perceptron.named_parameters():
    print(name,parameter.shape)
# 输出结果:
layer1.weight torch.Size([50, 10])
layer1.bias torch.Size([50])
layer2.weight torch.Size([5, 50])
layer2.bias torch.Size([5])
从输出结果可以看出,对于子module中的Parameter,输出时会在parameter名字前加上当前module的名字。
  • 预定义的层和自定义层组合使用:

使用预定义的层和自定义层的组合来实现特定的模型架构

下面是一个简单的示例,展示了使用预定义层和前面定义的全连接层来构建一个卷积神经网络。
class CompleteConvNet(nn.Module):  
    def __init__(self,num_classes=10):  
        super().__init__()  

        # 第一个卷积层  
        self.conv1 = nn.Conv2d(332, kernel_size=3)  
        self.bn1 = nn.BatchNorm2d(32)  
        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)  

        # 第二个卷积层  
        self.conv2 = nn.Conv2d(3264, kernel_size=3)  
        self.bn2 = nn.BatchNorm2d(64)  
        self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)  

        # 第三个卷积层  
        self.conv3 = nn.Conv2d(64128, kernel_size=3)  
        self.bn3 = nn.BatchNorm2d(128)  

        # 预定义的全连接层
#         self.fc1 = nn.Linear(128 * 4 * 4, 512)
#         self.fc2 = nn.Linear(512,num_classes)

        # 自定义的全连接层  
        self.fc1 = CustomLinearLayer(128 * 4 * 4512)
        self.fc2 = CustomLinearLayer(512,num_classes)

    def forward(self, x):  
        # 第一个卷积层(卷积 -> 标准化 -> 激活 -> 池化)
        x = F.relu(self.bn1(self.conv1(x)))  
        x = self.pool1(x)  

        # 第二个卷积层(卷积 -> 标准化 -> 激活 -> 池化)
        x = F.relu(self.bn2(self.conv2(x)))  
        x = self.pool2(x)  

        # 第三个卷积层(卷积 -> 标准化 -> 激活)
        x = F.relu(self.bn3(self.conv3(x)))  

        # 将特征图展平  
        x = x.view(x.size(0), -1

        # 全连接层  
        x = F.relu(self.fc1(x))  
        x = self.fc2(x)  

        return x
通过named_parameters()获取各层参数信息:
# 主module能够递归查找子module中的Parameter
for name,parameter in net.named_parameters():
    print(name,parameter.shape)
    print('-----------')
输出结果为:
conv1.weight torch.Size([32, 3, 3, 3])
-----------
conv1.bias torch.Size([32])
-----------
bn1.weight torch.Size([32])
-----------
bn1.bias torch.Size([32])
-----------
conv2.weight torch.Size([64, 32, 3, 3])
-----------
conv2.bias torch.Size([64])
-----------
bn2.weight torch.Size([64])
-----------
bn2.bias torch.Size([64])
-----------
conv3.weight torch.Size([128, 64, 3, 3])
-----------
conv3.bias torch.Size([128])
-----------
bn3.weight torch.Size([128])
-----------
bn3.bias torch.Size([128])
-----------
fc1.weight torch.Size([512, 2048])
-----------
fc1.bias torch.Size([512])
-----------
fc2.weight torch.Size([10, 512])
-----------
fc2.bias torch.Size([10])
-----------

从输出结果可以看出,对于子module中的Parameter,输出时会在parameter名字前加上当前module的名字。


更多内容可以前往官网查看

https://pytorch.org/


本篇文章来源于微信公众号: 码农设计师

RELATED ARTICLES

欢迎留下您的宝贵建议

Please enter your comment!
Please enter your name here

- Advertisment -

Most Popular

Recent Comments