(三)构建网络模型


————————————————————————————————————————————
Pytorch构建模型大致可分为三部分:

1.构建网络层,在 继承于 torch.nn.Module 的类对象的构造器 init 方法中定义卷积、池化、线性、激活函数等;

2.定义前向传播,重写 forward 实例方法;

3.定义初始化方式,使用 torch.nn.init 中的函数。

PyTorch 中组装模型需要用到容器Containers,Containers包括Module、 Sequential、ModuleList、ModuleDict。

Module 是所有模型的基类,此外构建block一般用 Sequential,整体模型构建用Module

1. Module 类

torch.nn.Module 为所有模型的基类,它自定义层的步骤:

1.自定义一个Module的子类,实现两个基本的函数: (1)构造 init 函数 (2)层的逻辑运算函数,即正向传播的forward函数

2.在构造 init 函数中实现层的参数定义。 比如Linear层的权重和偏置,Conv2d层的in_channels, out_channels, kernel_size, stride=1,padding=0, dilation=1, groups=1,bias=True, padding_mode='zeros’这一系列参数;

3.在forward函数里实现前向运算。 一般都是通过torch.nn.functional.xx()函数来实现,如果该层含有权重,那么权重必须是nn.Parameter类型。

4.补充:一般情况下,我们定义的参数是可以求导的,但是自定义操作如不可导,需要实现backward函数。

下面是lenet模型的两种写法
区别在于是否将relu,maxpool操作创建为网络的成员对象组件:

如果将其创建为对象,使用torch.nn,则需要在__init__函数中进行创建加入self.
如果不将其创建为对象,使用torch.nn.functional,则需要在forward中直接调用.

from torch.nn import Module
from torch.nn import Conv2d, ReLU, MaxPool2d, Linear

class LeNet5(Module):  # 继承
    def __init__(self, num_classes=10):
        super(LeNet5, self).__init__()
        self.conv1 = Conv2d(in_channels=1, out_channels=6, kernel_size=5, stride=1, padding=2)
        self.conv2 = Conv2d(6, 16, 5)
        self.linear1 = Linear(in_features=16 * 5 * 5, out_features=120)
        self.linear2 = Linear(120, 84)
        self.linear3 = Linear(84, num_classes)
        self.relu = ReLU()
        self.maxpool = MaxPool2d(kernel_size=2)

    def forward(self, x):  # 一个 module 相当于一个运算,必须实现 forward 函数
        x = self.conv1(x)  # 1 x 28 x 28 -> 6 x 28 x 28
        x = self.relu(x)
        x = self.maxpool(x)  # 6 x 28 x 28 -> 6 x 14 x 14
        x = self.conv2(x)  # 6 x 14 x 14 -> 16 x 10 x 10
        x = self.relu(x)
        x = self.maxpool(x)  # 16 x 10 x 10 -> 16 x 5 x 5

        x = torch.flatten(x, 1)

        x = self.linear1(x)  # 400 -> 120
        x = self.relu(x)
        x = self.linear2(x)  # 120 -> 84
        x = self.relu(x)
        x = self.linear3(x)  # 84 -> num_classes

        return x
import torch.nn as nn
import torch.nn.functional as F

class LeNet(nn.Module):
    def __init__(self, classes):  # 构建网络层组件(用torch.nn创建组件)
        super(LeNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, classes)

    def forward(self, x):  # 拼接网络层组件(用torch.nn.functional创建组件)
        out = F.relu(self.conv1(x))
        out = F.max_pool2d(out, 2)
        out = F.relu(self.conv2(out))
        out = F.max_pool2d(out, 2)
        out = out.view(out.size(0), -1)
        out = F.relu(self.fc1(out))
        out = F.relu(self.fc2(out))
        out = self.fc3(out)
        return out

2. Sequential 类

torch.nn.Sequential 类能够按顺序组装网络层,nn.Sequential 通用继承于 nn.Module 类,与Module不同的是,Sequential 已经默认定义了forward函数,按照顺序依次输入输出。模块将按照构造函数中传递的顺序添加到模块中。
nn.Module相同,nn.Sequential也是用来构建网络block的,但nn.Sequential不需要像nn.Module那么多过程,可以快速构建神经网络。

一般向 Sequential 中传入网络层有两种格式:

1.向 Sequential 中直接传入各网络层,实例化后以数字为索引 (用的较多)
这个LeNetModule由两个Sequential组成(features 和classifier )

import torch
import torchvision
import torch.nn as nn
from collections import OrderedDict
# ============================ Sequential
class LeNetSequential(nn.Module):
    def __init__(self, classes):  # 此LeNetModule由两个Sequential组成
        super(LeNetSequential, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 6, 5),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(6, 16, 5),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),)

        self.classifier = nn.Sequential(
            nn.Linear(16*5*5, 120),
            nn.ReLU(),
            nn.Linear(120, 84),
            nn.ReLU(),
            nn.Linear(84, classes),)

    def forward(self, x):  # 只需执行features(卷积池化)和classifier(全连接)
        x = self.features(x)
        x = x.view(x.size()[0], -1)
        x = self.classifier(x)
        return x

2.向 Sequential 中传入 OrderedDict 对象,实例化后可以自定义的名字为索引

import torch
import torchvision
import torch.nn as nn
from collections import OrderedDict
# ============================ Sequential
class LeNetSequentialOrderDict(nn.Module):
    def __init__(self, classes):
        super(LeNetSequentialOrderDict, self).__init__()

        self.features = nn.Sequential(OrderedDict({ #通过有序字典对网络中的操作进行命名,这样可以很容易的索引到
            'conv1': nn.Conv2d(3, 6, 5),
            'relu1': nn.ReLU(inplace=True),
            'pool1': nn.MaxPool2d(kernel_size=2, stride=2),

            'conv2': nn.Conv2d(6, 16, 5),
            'relu2': nn.ReLU(inplace=True),
            'pool2': nn.MaxPool2d(kernel_size=2, stride=2),
        }))

        self.classifier = nn.Sequential(OrderedDict({
            'fc1': nn.Linear(16*5*5, 120),
            'relu3': nn.ReLU(),

            'fc2': nn.Linear(120, 84),
            'relu4': nn.ReLU(inplace=True),

            'fc3': nn.Linear(84, classes),
        }))

    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size()[0], -1)
        x = self.classifier(x)
        return x

3. Parameter类

torch.nn.Parameter是继承自torch.Tensor的子类,其主要作用是作为nn.Module中的可训练参数使用。它与torch.Tensor的区别就是nn.Parameter会自动被认为是module的可训练参数,即加入到parameter()这个迭代器中去;而module中非nn.Parameter()的普通tensor是不在parameter中的。

nn.Parameter的对象的requires_grad属性的默认值是True,即是可被训练的,这与torh.Tensor对象的默认值相反。在nn.Module类中,pytorch也是使用nn.Parameter来对每一个module的参数进行初始化的。

4. 常见网络层

卷积层

nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, 
		dilation=1, groups=1, bias=True, padding_mode='zeros')

dilation:空洞卷积,当大于1的时候可以增大感受野,同时保持特征图的尺寸
groups:可实现组卷积,即在卷积操作时不是逐点卷积,而是将输入通道范围分为多个组,稀疏连接达到降低计算量的目的

输入特征图必须写为( B , C , H , W ) 的形式

池化层

最大下采样池化层

nn.MaxPool2d(kernel_size, stride=None, padding=0, 
			dilation=1, return_indices=False, ceil_mode=False)

stride – 注意:stride 默认值= kernel_size,而非1
return_indices – 是否返回最大下采样的像素索引位置
ceil_mode – when True, will use ceil instead of floor to compute the output shape

平均池化层

nn.AvgPool2d(kernel_size, stride=None, padding=0, 
			ceil_mode=False, count_include_pad=True, divisor_override=None)

count_include_pad – 边界padding填充是否用于计算平均值
divisor_override – 除法因子

最大上采样池化层

nn.MaxUnpool2d(kernel_size, stride=None, padding=0)
forward(self,input,indeces)

使用时,不仅要传入input,还要传入indeces最大下采样时得到的像素索引位置
在这里插入图片描述

全连接层(线性层)

nn.Linear(in_features, out_features, bias=True)

一维向量进行线性组合
in_features:输入向量长度(输入层结点数)
out_features:输出向量长度(输出层结点数)

>>> linear = nn.Linear(784, 10)
>>> input = torch.randn(4, 784)
>>> output = linear(input)
>>> output.shape
torch.Size([4, 10])

RNN层

nn.RNN(input_size, hidden_size, num_layers=1, nonlinearity=tanh, 
		bias=True, batch_first=False, dropout=0, bidirectional=False)

input_size输入特征的维度, 一般rnn中输入的是词向量,那么 input_size 就等于一个词向量的维度
hidden_size隐藏层神经元个数,或者也叫输出的维度(因为rnn输出为各个时间步上的隐藏状态)
num_layers网络的层数
nonlinearity激活函数
bias是否使用偏置
batch_first输入数据的形式,默认是 False,就是这样形式,(seq(num_step), batch, input_dim),也就是将序列长度放在第一位,batch 放在第二位
dropout是否应用dropout, 默认不使用,如若使用将其设置成一个0-1的数字即可
birdirectional是否使用双向的 rnn,默认是 False
注意某些参数的默认值在标题中已注明

具体计算过程:
在这里插入图片描述

[batch_size, input_dim] * [input_dim, num_hiddens] + [batch_size, num_hiddens] *[num_hiddens, num_hiddens] +bias

GRU层

nn.GRU(input_size, hidden_size,num_layers=1) 

LSTM 层

nn.LSTM(input_size=embedding_dim,hidden_size=hidden_size,num_layers=num_layers,
         bias=True,batch_first=False,dropout=0.5,bidirectional=False)

激活函数层

激活函数层也可以用torch.nn.functional中的函数替代
在这里插入图片描述

Sigmoid层

导数<1,易梯度消失

nn.Sigmoid()
>>> sigmoid = nn.Sigmoid()
>>> sigmoid(torch.Tensor([1, 1, 2, 2]))
tensor([0.7311, 0.7311, 0.8808, 0.8808])

ReLU层

导数=1,但易梯度爆炸

nn.ReLU(inplace=False)
>>> relu = nn.ReLU(inplace=True)
>>> input = torch.randn(2, 2)
>>> input
tensor([[-0.4853,  2.3864],
        [ 0.7122, -0.6493]])
>>> relu(input)
tensor([[0.0000, 2.3864],
        [0.7122, 0.0000]])
>>> input
tensor([[0.0000, 2.3864],
        [0.7122, 0.0000]])

Tanh层

导数<1,易梯度消失

nn.Tanh()
>>>m = nn.Tanh()
>>>input = torch.randn(2)
>>>output = m(input)
>>>print(output)
>tensor([0.5793, 0.2608])

Softplus层

nn.Softplus()

Softmax层

将一/二维数据变成符合概率分布的形式(非负,行和为1),常用于分类输出,放在FC层之后
在这里插入图片描述

nn.Softmax(dim=None)
>>> softmax = nn.Softmax(dim=1)
>>> score = torch.randn(1, 4)
>>> score
tensor([[ 0.3101,  3.5648,  1.0988, -1.5856]])
>>> softmax(score)
tensor([[0.0342, 0.8855, 0.0752, 0.0051]])

损失函数

衡量模型输出真实标签的差异

CrossEntropyLoss交叉熵损失函数

nn.CrossEntropyLoss(weight=None, ignore_index=-100, reduction='mean')

Softmax + CrossEntropyLoss,它们两个结合在一起时梯度反向传播的时候结果就会很好
weight:各个类别loss的权重
ignore_index:忽略某个类别
reduction:计算模式(none/some/mean)

 forward(self, input: Tensor, target: Tensor)
 # input输入(模型输出),target目标(真实标签)
loss = nn.CrossEntropyLoss()
input = torch.randn(3, 5, requires_grad=True)
target = torch.empty(3, dtype=torch.long).random_(5)

output = loss(input, target)
output.backward()

NLLLoss

负对数似然函数的负号功能

nn.NLLLoss(weight=None, size_average=None, 
			ignore_index=-100, reduce=None, reduction='mean')

weight:各个类别loss的权重
ignore_index:忽略某个类别
reduction:计算模式(none/some/mean)

BCELoss

torch.nn.BCELoss(weight=None,size_average=None,reduce=None,reduction='elementwise_mean')

二分类交叉熵,是nn.CrossEntropyLoss函数的特例。

其分类限定为二分类,输入必须在[0,1]

TripletMarginLoss

class torch.nn.TripletMarginLoss(margin=1.0, p=2, eps=1e-06, swap=False, size_average=None,
									reduce=None, reduction='elementwise_mean')

功能: 计算三元组损失,人脸验证中常用。 如下图Anchor、Negative、Positive,目标是让Positive元和Anchor元之间的距离尽可能的小,Positive元和Negative元之间的距离尽可能的大。
在这里插入图片描述
从公式上看,Anchor元和Positive元之间的距离加上一个threshold之后,要小于Anch
在这里插入图片描述
margin(float)- 默认值为1

p(int)- The norm degree ,默认值为2

swap(float)– The distance swap is described in detail in the paper Learning shallow convolutional feature descriptors with triplet losses by V. Balntas, E. Riba et al. Default: False

size_average(bool)- 当reduce=True时有效。为True时,返回的loss为平均值;为False时,返回的各样本的loss之和。 reduce(bool)- 返回值是否为标量,默认为True。

Optimizer优化器

管理并更新模型中可学习参数的值,使得模型输出更接近真实标签。通俗一点,就是采样梯度更新模型的可学习参数,使得损失减小。

class Optimizer(object):
	def __init__(self, params, defaults):
		self.defaults = defaults
		self.state = defaultdict(dict)
		self.param_groups = []
		...
		param_groups = [{'params': param_groups}]

optimizer的基本属性
defaults:优化器超参数
state:参数的缓存,如momentum的缓存
params_groups:管理的参数组
_step_count:记录更新次数,学习率调整中使用

optimizer的基本方法
zero_grad():清空所管理参数的梯度,pytorch特性:张量梯度不自动清零,会将张量梯度累加;因此,需要在使用完梯度之后,或者在反向传播前,将梯度自动清零

step():执行一步更新
在这里插入图片描述

add_param_group():以字典的形式,添加参数组,不同参数组可以设置不同的学习率 lr,例如:可以为特征提取层与全连接层设置不同的学习率或者别的超参数

state_dict():获取优化器当前状态信息字典,长时间的训练,会隔一段时间保存当前的状态信息,用来在断点的时候恢复训练,避免由于意外的原因导致模型的终止

load_state_dict() :加载状态信息字典,用于周期性保存参数

优化器中的常用参数
params:管理的参数
learning rate 学习率
梯度下降:学习率(learning rate)控制更新的步伐
在这里插入图片描述
momentum 动量:结合当前梯度与上一次更新信息,用于当前更新,越往前梯度信息的作用就越小。
在这里插入图片描述
weight_decay:L2正则化系数
nesterov:是否采用NAG

十种优化器实例

optim.SGD:随机梯度下降法

optim.SGD(params, lr=<object object>, 
		momentum=0, dampening=0, 
		weight_decay=0, nesterov=False)

主要参数:
params:管理的参数组
lr:初始学习率
momentum:动量系数0.9
weight_decay:L2正则化系数
nesterov:是否采用NAG

其他优化器:
optim.Adagrad:自适应学习率梯度下降法
optim.RMSprop: Adagrad的改进
optim.Adadelta: Adagrad的改进
optim.Adam:RMSprop结合Momentum
optim.Adamax:Adam增加学习率上限
optim.SparseAdam:稀疏版的Adam
optim.ASGD:随机平均梯度下降
optim.Rprop:弹性反向传播
optim.LBFGS:BFGS的改进

SGD与Adam是两种最常用的方式。

正则化网络层

正则化:减少方差的方法,方差表示数据扰动造成的影响,即减少数据扰动造成的过拟合。

Dropout层
按p概率,随机失活神经元(通过设置weight=0实现)

nn.Dropout(p=0.5, inplace=False)
>>> dropout = nn.Dropout(0.5, inplace=False)
>>> input = torch.randn(1, 20)
>>> output = dropout(input)
>>> output
tensor([[-2.9413,  0.0000,  1.8461,  1.9605,  0.2774, -0.0000, -2.5381, -2.0313,
         -0.1914,  0.0000,  0.5346, -0.0000,  0.0000,  4.4960, -3.8345, -1.0938,
          4.3297,  2.1258, -4.1431,  0.0000]])
>>> input
tensor([[-1.4707,  0.5105,  0.9231,  0.9802,  0.1387, -0.4195, -1.2690, -1.0156,
         -0.0957,  0.8108,  0.2673, -2.0898,  0.6666,  2.2480, -1.9173, -0.5469,
          2.1648,  1.0629, -2.0716,  0.9974]])

Batch Normalization(BN)
Batch Normalization:批标准化,不同样本在同一特征上的标准化
批:一批数据,通常为mini-batch
标准化:0均值,1标准差
在这里插入图片描述

torch.nn.BatchNorm2d(num_features, eps=1e-05, momentum=0.1, 
					affine=True, track_running_stats=True)

num_features:一个样本特征数量(最重要),也就是输出特征图的通道channal数
eps:分母修正项,一般设置比较小的数,防止除以0导致错误
momentum:指数加权平均估计当前mean/var
affine:是否需要affine transform
track_running_states:是训练状态,还是测试状态,训练:均值和方差采用指数加权平均计算,测试:当前统计值

主要属性:
running_mean:均值
running_var:方差
weight:affine transform中的gamma
bias:affine transform中的beta

>>> bn = nn.BatchNorm2d(64)
>>> input = torch.randn(4, 64, 28, 28)
>>> output = bn(input)
>>> output.shape
torch.Size([4, 64, 28, 28])

Layer Normalization(LN)
Layer Normalization:由于BN不适用于长网络,LN逐层求均值和方差

torch.nn.LayerNorm(normalized_shape, eps: float = 1e-5, elementwise_affine: bool = True)

主要参数:
normalized_shape:该层特征形状
eps:分母修正项
elementwise_affine:是否需要affine transform(逐元素)

Instance Normalization(IN)
Instance Normalization:BN在图像生成(Image Generation)中不适用,逐Instance(channel)计算均值和方差

torch.nn.InstanceNorm2d(num_features, eps=1e-05, momentum=0.1, 
					affine=True, track_running_stats=True)

主要参数:
num_features:一个样本特征数量(最重要)
eps:分母修正项
momentum:指数加权平均估计当前mean/var
affine:是否需要affine transform
track_running_states:是训练状态,还是测试状态

Group Normalization(GN)
起因:小batch样本中,BN估计的值不准
思路:数据不够,通道来凑

注意事项:
不再有running_mean和running_var
gamma和beta为逐通道(channel)的
应用场景:大模型(小batch size)任务

torch.nn.GroupNorm(num_groups, num_channels, eps=1e-05, momentum=0.1, affine=True)

主要参数:
num_groups:分组数
num_channels:通道数(特征数)
eps:分母修正项
affine:是否需要affine transform
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Python可以使用各种深度学习框架来构建典型的神经网络模型。以下是一些常见的深度学习框架以及它们用于构建网络模型的示例: 1. TensorFlow:TensorFlow是一个广泛使用的开源深度学习框架,可以用于构建各种类型的神经网络模型。以下是一个使用TensorFlow构建典型的卷积神经网络(CNN)的示例: ```python import tensorflow as tf # 构建卷积神经网络模型 model = tf.keras.models.Sequential([ tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)), tf.keras.layers.MaxPooling2D(pool_size=(2, 2)), tf.keras.layers.Flatten(), tf.keras.layers.Dense(64, activation='relu'), tf.keras.layers.Dense(10, activation='softmax') ]) # 编译模型 model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy']) # 训练模型 model.fit(x_train, y_train, epochs=10, validation_data=(x_test, y_test)) ``` 2. PyTorchPyTorch也是一个广泛使用的深度学习框架,它具有动态图形的特性,使得构建和调试模型更加灵活。以下是一个使用PyTorch构建典型的循环神经网络(RNN)的示例: ```python import torch import torch.nn as nn # 构建循环神经网络模型 class RNN(nn.Module): def __init__(self, input_size, hidden_size, output_size): super(RNN, self).__init__() self.hidden_size = hidden_size self.rnn = nn.RNN(input_size, hidden_size) self.fc = nn.Linear(hidden_size, output_size) def forward(self, x): hidden = torch.zeros(1, x.size(0), self.hidden_size) out, _ = self.rnn(x, hidden) out = self.fc(out[-1]) return out # 实例化模型 model = RNN(input_size, hidden_size, output_size) # 定义损失函数和优化器 criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate) # 训练模型 for epoch in range(num_epochs): outputs = model(inputs) loss = criterion(outputs, labels) optimizer.zero_grad() loss.backward() optimizer.step() ``` 这只是两个深度学习框架的简单示例,实际上还有很多其他的框架可以用于构建典型的神经网络模型,例如Keras、MXNet等。选择深度学习框架取决于你的需求和个人偏好。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yuezero_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值