模型泛化、残差模块算子融合、遗传算法

摘要

本周学习了模型泛化、自动微分、PyTorch中模型保存与加载、Dropout的实现及其变体R-Dropout,以及遗传算法的基础知识。通过具体示例介绍了自动微分的前向和反向传播过程、PyTorch中模型保存的不同方式、Dropout在神经网络中的应用及其实现,还展示了如何在PyTorch中实现卷积残差模块的算子融合,并给出了MATLAB中遗传算法的基本操作及函数解释。

abstract

This week you learned about model generalization, automatic differentiation, model saving and loading in PyTorch, the implementation of Dropout and its variant R-Dropout, and the basics of genetic algorithms. This paper introduces the forward and back propagation process of automatic differentiation, the different ways of model saving in PyTorch, the application of Dropout in neural networks and its implementation. It also shows how to realize the operator fusion of convolutional residual module in PyTorch, and gives the basic operation and function explanation of genetic algorithm in MATLAB.

1. 模型泛化以及代码实现原理

1.1 自动微分

在这里插入图片描述
Forward pass:基于输入以及当前参数算出输出
Backward pass:基于当前预测输出和正确标签算出误差关于所有参数的梯度,在规则下更新所有网络的参数。

在这里插入图片描述
自动微分的优点:以每个节点为单位算,占用的内存小,使用链式法则进行推导较准确(理解为前向传播)
下面是一个对于Forward pass使用链式法则的一个求导例子:
有一函数为:
y = f ( x 1 , x 2 ) = ln ⁡ ( x 1 ) + x 1 x 2 − sin ⁡ ( x 2 ) y=f(x_{1},x_{2})=\ln(x_{1})+x_{1}x_{2}-\sin(x_{2}) y=f(x1,x2)=ln(x1)+x1x2sin(x2)

在这里插入图片描述
也可以使用给对偶数的方法:
约定eps≠0,而eps^2=0;
假设f(x) = x^2 + 2*x
求f(x)在x=2处的导数

f(2 + eps) = (2 + eps)^2 + 2*(2 + eps) = 8 + 6*eps
f(2) = 8;f’(x) = 6;

以下是Reverse pass的一个例子:
在这里插入图片描述
先算前向节点,然后进行reverse mode计算。(在pytorch)需要梯度累加。

2.保存与加载PyTorch训练的模型和超参数

有两种方法保存和加载模型以进行推理PyTorch的Torch中。

  • 保存和加载使用state_dict(仅保存有用参数)
  • 保存和加载整个模型(使用pickle module)

后者的缺点是,序列化的数据绑定到保存模型时使用的特定类和确切的目录结构。pickle并不保存模型类本身。相反,它保存包含类的文件的路径,该路径将在加载时使用。

保存多个模型如下:

PATH = "model.pt"

torch.save({
	'modelA_state_dict':netA.state_dict(),
	'modelB_state_dict':netB.state_dict(),
	'optimizerA_state_dict':optimezerA.state_dict(),
	'optimizerB_state_dict':optimezerB.state_dict(),
},PATH)

# 模型推理
 modelA.eval()
 
# 模型训练
 modelA.train()

下面是一个很标准的人工智能学习图:
在这里插入图片描述
以下是机器学习中需要使用到的库:
在这里插入图片描述

3.Dropout实现

3.1使用numpy 实现Dropout

def train(rate, x, w1, b1, w2, b2):
    layer1 = np.maximum(0, np.dot(w1, x) + b1)
    mask1 = np.random.binomial(1, 1-rate, layer1.shape)
    layer1 = layer1 * mask1

    layer2 = np.maximum(0, np.dot(w2, layer1) + b2)
    mask2 = np.random.binomial(1, 1-rate, layer2.shape)
    layer2 = layer2 * mask2

    return layer2

def another_train(rate, x, w1, b1, w2, b2):
    layer1 = np.maximum(0, np.dot(w1, x) + b1)
    mask1 = np.random.binomial(1, 1-rate, layer1.shape)
    layer1 = layer1 * mask1
    layer1 = layer1 / (1-rate)

    layer2 = np.maximum(0, np.dot(w2, layer1) + b2)
    mask2 = np.random.binomial(1, 1-rate, layer2.shape)
    layer2 = layer2 * mask2
    layer2 = layer2 / (1-rate)
    return layer2
    
def test(rate, x, w1, b1, w2, b2):
	layer1 = np.maximum(0, np.dot(w1, x) + b1)
	layer1 = layer1*(1-rate)
	layer2 = np.maximum(0, np.dot(w2, layer1) + b2)
	return layer2
	
def another_test(x, w1, b1, w2, b2):
	layer1 = np.maximum(0, np.dot(w1, x) + b1)
	layer2 = np.maximum(0, np.dot(w2, layer1) + b2)
	return layer2

在test()函数中,rate参数表示学习速率,x表示输入向量,w1和b1分别表示第一层的权重和偏置,w2和b2则分别是第二层的权重和偏置。首先,通过np.dot()函数计算第一层的激活值,然后将其传递给ReLU激活函数(即np.maximum(0, x))。接着,将ReLU激活后的第一层输出乘以(1-rate),再与w2相乘加上b2,得到第二层的激活值,同样经过ReLU激活后返回。

4.PyTorch中进行卷积残差模块算子融合

Dropout 和R-Droupout的区别
Dropout的工作原理:

  • 在训练期间,每个神经元(除了输出层)都有一定概率被临时从网络中移除,即其输出被设置为0.
  • Dropout 会通过一个固定的比率(如0.5)来确定哪个神经元会被丢弃。
  • 在推理(测试)阶段,所有神经元都被保留,但它们的权重需要按丢弃率进行缩放,来保持期望的输出不变。

R-Dropout的工作原理:

  • R-Dropout不是简单地根据一个固定地概率来决定是否丢弃某个神经元,而是根据每个神经元的实际激活值来动态调整丢弃的概率。
  • 对于某个神经元,如果其激活值较小,则被丢弃的概率较大;反之,如果激活值较大,则被保留的概率较大。
  • 这种动态调整的机制可以让网络更加关注那些重要的特征,而忽略那些不太相关的特征。

在这里插入图片描述

下面是两种方法实现上面图片中一个resnet网络的block块

import torch
import torch.nn.functional as F
import torch.nn as nn
in_channels = 2
out_channels = 2
kernel_size = 3
w = 9
h = 9

# res_block = 3*3 conv + 1*1 conv + input

# 方法一 :原生写法
conv_2d = nn.Conv2d(in_channels,out_channels,kernel_size,padding="same")
conv_2d_pointwise = nn.Conv2d(in_channels,out_channels,1)
result1 = conv_2d(x) + conv_2d_pointwise(x) + x

 # 方法二:算子融合
 # 把point-wise 卷积和 x 本身写成 3*3 的卷积
 # 最终把三个卷积写成一个卷积
 pointwise_to_conv_weight = F.pad(conv_2d_pointwise.weight,[1,1,1,1,0,0,0,0]) #2*2*1*1---->2*2*3*3
 conv_2d_for_pointwise = nn.Conv2d(in_channels,out_channels,kernel_size,padding="same")
conv_2d_for_pointwise.weight = nn.Parameter(pointwise_to_conv_weight)
conv_2d_for_pointwise.bias = conv_2d_pointwise .bias
# 创建恒等映射的卷积权重
zeros = torch.unsqueeze(torch.zeros(kernel_size, kernel_size), 0) # 形状为kernel_size * kernel_size *1
stars = torch.unsqueeze(F.pad(torch.ones(1, 1), [1, 1, 1, 1]), 0)  # 创建一个中心为1的3*3的张量
stars_zeros = torch.unsqueeze(torch.cat([stars, zeros], 0), 0) # 实现拼接功能 其形状为2*kernel_size * kernel_size *1
zeros_stars = torch.unsqueeze(torch.cat([zeros, stars], 0), 0) 
identity_to_conv_weight = torch.cat([stars_zeros, zeros_stars], 0) # 沿着第一个维度拼接,成为4*kernel_size*kernel_size*1
# 创建恒等映射的卷积层
conv_2d_for_identity = nn.Conv2d(in_channels, ou_channels, kernel_size, padding="same")
conv_2d_for_identity.weight = nn.Parameter(identity_to_conv_weight)
conv_2d_for_identity.bias = nn.Parameter(torch.zeros(ou_channels))
# 计算融合后的结果
result2 = conv_2d(x) + conv_2d_for_pointwise(x) + conv_2d_for_identity(x)
print(torch.all(torch.isclose(result1, result2))) # 比较融合后的结果是否接近

5. 遗传算法(部分学习)

遗传算法三个基本操作:选择、交叉、变异
重点函数解读(matlab)
initializega
pop = initializega(populationSize,variableBounds,evalFN,evalOps,options)

参数意义
pop随机生成的初始种群
populationSize种群中个体的数目
variableBounds变量边界的矩阵
evalFN适应度函数的名称
evalOps适应度函数的参数
options精度以及编码形式,1为浮点编码,0为二进制编码
ga

[x,endPop,bPop,traceInfo] = ga(bounds,evalFN,evalOps,startOps,opts,termFN,termOps,selectFN,selectps,xOverFNs,xOverOps,mutFNs,mutOps)

参数意义
x优化计算得到的最优个体
endPop优化终止时的最终算法
bPop最优种群的进化轨迹
traceInfo每代的最优适应度函数值和平均适度函数值矩阵

6.总结

本周围绕深度学习中的关键概念和技术进行了详细阐述,包括模型泛化的重要性、自动微分机制的运作原理、PyTorch中模型保存与加载的最佳实践、Dropout及其变体R-Dropout的使用方法。此外,还学习了在PyTorch中如何实现卷积残差模块的算子融合以提升模型性能,并介绍了遗传算法这一优化方法的基础知识及其在MATLAB中的重要函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值