【NLP 15、深度学习处理文本】
目录
一、反向传播
编辑
1.反向传播运算过程
2.前向传播和反向传播的作用
前向传播
反向传播
3.定义模型(torch包)
4.手动实现
① 线性层
② sigmoid激活函数
③ 手动实现MSE均方差损失函数
④ 前向传播
⑤ 手动实现梯度计算
⑤ 权重的更新:优化器函数
⑥ diy模型验证
⑦ 手动实现Adam优化器
二、优化器 Adam
Adam优化器的特点
Adam优化器的优点
手动实现Adam
SGD优化器调用:
Adam优化器调用:
三、NLP任务
步骤
step1 字符数值化
step2 矩阵转化为向量
step3 向量到数值
整体映射
四、Embedding 嵌入层
① 声明需要多少个向量
② 每个向量需要多少维
③ 初始化权重
④ 构造字符表
pad
unk
⑤ 根据位置将字符串转化为输出的数字序列
示例:Embedding层的处理
五、池化层 Pooling
Avg Pooling
Max Pooling
池化层的作用
六、网络结构 - RNN 循环神经网络
建立RNN模型
手动实现RNN循环神经网络
1.自定义RNN模型
2.forward 前向传播
3.对比试验 构建样本
4.对比实验结果
七、网络结构 - CNN 卷积神经网络
手动实现CNN卷积神经网络
1.自定义CNN模型
2.forward前向传播
3.对比试验 构建样本
4.对比试验结果
八、网络结构 - Normalization 归一化层
batch Normalization 批归一化
Layer Normalization 层归一化
Instance Normalization 实例化归一化
九、网络结构 - Dropout层
如何理解其作用:
测试代码
一切都在慢慢变好,而且会变得越来越好
—— 24.12.12
一、反向传播
反向传播是对链式求导法则的体现,先对外层求导再对内层函数求导
链式法则的体现叫做反向传播
sigmoid函数的导函数等于预测值 × (1 - 预测值)
1.反向传播运算过程
反向传播对模型函数的模型权重求梯度(求导)
反向传播:对模型函数链式法则求导
更新权重:w - lr * grad
2.前向传播和反向传播的作用
前向传播
前向传播是用来计算返回值的,前向传播是指输入一个值,经过模型计算返回一个预测值
反向传播
反向传播是用来计算导数(梯度)的,通过前向传播拿到预测值之后,通过预测值与真实值对比计算损失loss,反向传播再对模型权重 (参数)计算导数(梯度),然后才能知道模型优化的方向,调整模型的权重(参数)
3.定义模型(torch包)
class TorchModel(nn.Module):def __init__(self, hidden_size):super(TorchModel, self).__init__()# 线性层self.layer = nn.Linear(hidden_size, hidden_size, bias=False) #w = hidden_size * hidden_size wx+b -> wx# 激活层 sigmoidself.activation = torch.sigmoid# 损失函数 均方差损失函数self.loss = nn.functional.mse_loss #loss采用均方差损失#当输入真实标签,返回loss值;无真实标签,返回预测值def forward(self, x, y=None):# 线性层y_pred = self.layer(x)# 激活层y_pred = self.activation(y_pred)# 损失函数计算损失值if y is not None:return self.loss(y_pred, y)else:return self.activation(y_pred)
4.手动实现
① 线性层
特征提取
weignt:模型中初始化的参数
def __init__(self, weight):self.weight = weightdef forward(self, x, y=None):# 线性层激活函数x = np.dot(x, self.weight.T)
② sigmoid激活函数
# 手动实现sigmoid激活函数def diy_sigmoid(self, x):return 1 / (1 + np.exp(-x))
③ 手动实现MSE均方差损失函数
# 手动实现mse,均方差lossdef diy_mse_loss(self, y_pred, y_true):return np.sum(np.square(y_pred - y_true)) / len(y_pred)
④ 前向传播
前向传播用来计算预测值
反向传播通过前向传播得出的预测值,与标签真实值对比计算得出梯度,更新模型的权重(参数)
#自定义模型,接受一个参数矩阵作为入参
class DiyModel:def __init__(self, weight):self.weight = weightdef forward(self, x, y=None):x = np.dot(x, self.weight.T)y_pred = self.diy_sigmoid(x)if y is not None:return self.diy_mse_loss(y_pred, y)else:return y_pred
⑤ 手动实现梯度计算
# 手动实现梯度计算def calculate_grad(self, y_pred, y_true, x):#前向过程# wx = np.dot(self.weight, x)# sigmoid_wx = self.diy_sigmoid(wx)# loss = self.diy_mse_loss(sigmoid_wx, y_true)#反向过程# 均方差函数 (y_pred - y_true) ^ 2 / n 的导数 = 2 * (y_pred - y_true) / n , 结果为2维向量grad_mse = 2/len(x) * (y_pred - y_true)# sigmoid函数 y = 1/(1+e^(-x)) 导数 = y * (1 - y), 结果为2维向量grad_sigmoid = y_pred * (1 - y_pred)# wx矩阵运算,见ppt拆解, wx = [w11*x0 + w21*x1, w12*x0 + w22*x1]#导数链式相乘grad_w11 = grad_mse[0] * grad_sigmoid[0] * x[0]grad_w12 = grad_mse[1] * grad_sigmoid[1] * x[0]grad_w21 = grad_mse[0] * grad_sigmoid[0] * x[1]grad_w22 = grad_mse[1] * grad_sigmoid[1] * x[1]grad = np.array([[grad_w11, grad_w12],[grad_w21, grad_w22]])#由于pytorch存储做了转置,输出时也做转置处理return grad.T
⑤ 权重的更新:优化器函数
更新的过程:优化器函数
随机梯度下降(Stochastic Gradient Descent,SGD):随机梯度下降优化器是一种常用的优化算法,用于训练机器学习模型特别是神经网络。它通过迭代地更新模型参数来最小化损失函数。
公式:权重 - 学习率 * 上一轮迭代的梯度
#梯度更新
def diy_sgd(grad, weight, learning_rate):# 权重 - 学习率 * 梯度return weight - learning_rate * grad
⑥ diy模型验证
x = np.array([-0.5, 0.1]) #输入
y = np.array([0.1, 0.2]) #预期输出#torch计算梯度
torch_model = TorchModel(2)
# 取出torch模型权重的初始化
torch_model_w = torch_model.state_dict()["layer.weight"]
print(torch_model_w, "初始化权重")
numpy_model_w = copy.deepcopy(torch_model_w.numpy())
#numpy array -> torch tensor, unsqueeze的目的是增加一个batchsize维度
torch_x = torch.from_numpy(x).float().unsqueeze(0)
torch_y = torch.from_numpy(y).float().unsqueeze(0)
#torch的前向计算过程,得到loss
torch_loss = torch_model(torch_x, torch_y)
print("torch模型计算loss:", torch_loss)#手动实现loss计算
diy_model = DiyModel(numpy_model_w)
diy_loss = diy_model.forward(x, y)
print("diy模型计算loss:", diy_loss)
⑦ 手动实现Adam优化器
#adam梯度更新
def diy_adam(grad, weight):#参数应当放在外面,此处为保持后方代码整洁简单实现一步alpha = 1e-3 #学习率beta1 = 0.9 #超参数 β1beta2 = 0.999 #超参数 β2eps = 1e-8 #超参数 εt = 0 #初始化mt = 0 #初始化vt = 0 #初始化#开始计算t = t + 1gt = gradmt = beta1 * mt + (1 - beta1) * gtvt = beta2 * vt + (1 - beta2) * gt ** 2mth = mt / (1 - beta1 ** t)vth = vt / (1 - beta2 ** t)weight = weight - (alpha * mth/ (np.sqrt(vth) + eps))return weight
二、优化器 Adam
作用:在梯度计算完成后,通过优化器更新权重
Stepsize:α 学习率(步长)
β1,β2:(0,1)之间的两个数,一般β1设置为0.9,一般β2设置为0.999
f(θ):目标函数(模型)的参数θ
θ:初始化的模型参数
m0:第一轮梯度的指数衰减平均,初始值为0
v0:第一轮梯度平方的指数衰减,初始值为0
t:时间步,初始值为0
ε:防止分母为0,值很小
进入循环,收敛时停止:
① 时间步+1(记录训练样本轮次数)
② 计算获取梯度的过程
③ 将前一轮的梯度与本轮梯度合在一起,而前一轮梯度又是之前梯度的组合,所以mt就是前t轮梯度的组合
④ 将前轮梯度的平方与本轮梯度合在一起,而前一轮梯度又是之前梯度的带平方项的组合,所以vt就是前t轮带平方项梯度的组合
⑤ 前n轮的梯度累计 / (1 - β1^t)
⑥ 前n轮带平方项梯度累计 / (1 - β2^t),平衡梯度对学习率的影响
⑦ 上一轮的权重 - 学习率 * 【前n轮的梯度累计 / (1 - β1^t)】/ (【前n轮带平方项梯度 / (1 - β2^t)】^ 1/2 + ε)
Adam优化器的特点
1.考虑前n轮的梯度
2.随着训练时间的增加,放缓学习的频率
3.根据梯度绝对值的大小,调整学习率的大小
作用:在拿到梯度之后,如何更新模型的权重
Adam优化器将之前轮数都进行考虑,再来根据前n轮的结果综合考虑预测下一个值,优化的步长逐轮应该减小,通过公式中参数的变化,调整学习率的变化
Adam优化器的优点
① 实现简单,计算高效,对内存需求少
② 超参数具有很好的解释性,β1的大小决定了对历史数据的看重程度,β2同理,且通常无需调整或仅需很少的微调
③ 更新的步长能够被限制在大致的范围内(初始学习率)
④ 能够表现出自动调整学习率,通过公式中参数的变化,调整学习率的变化
⑤ 很适合应用于大规模的数据及参数的场景
⑥ 适用于不稳定目标函数
⑦ 适用于梯度稀疏或梯度存在很大噪声的问题
手动实现Adam
SGD优化器调用:
torch.optim.SGD(torch_model.parameters(), lr=learning_rate)
Adam优化器调用:
torch.optim.Adam(torch_model.parameters())
#adam梯度更新
def diy_adam(grad, weight):#参数应当放在外面,此处为保持后方代码整洁简单实现一步alpha = 1e-3 #学习率beta1 = 0.9 #超参数 β1beta2 = 0.999 #超参数 β2eps = 1e-8 #超参数 εt = 0 #初始化mt = 0 #初始化vt = 0 #初始化#开始计算t = t + 1gt = gradmt = beta1 * mt + (1 - beta1) * gtvt = beta2 * vt + (1 - beta2) * gt ** 2mth = mt / (1 - beta1 ** t)vth = vt / (1 - beta2 ** t)weight = weight - (alpha * mth/ (np.sqrt(vth) + eps))return weight
三、NLP任务
任务:字符串分类 – 判断字符串中是否出现了指定字符
当前输入:字符串 如:abcd
预期输出:概率值 正样本=1,负样本=0,以0.5为分界
X = “abcd” Y = 1
X = “bcde” Y = 0
建模目标:找到一个映射 f(x),使得 f(“abcd”) = 1, f(“bcde”) = 0
步骤
step1 字符数值化
将每个字符转化为同维度向量(embedding层)
矩阵形状 = 文本长度 * 向量长度
step2 矩阵转化为向量
对整句话做池化操作,求平均
由 4 * 5 矩阵 -> 1* 5 向量 形状 = 1 * 向量长度
step3 向量到数值
采取最简单的线性公式 y = w * x + b
w 维度为1 * 向量维度,b为实数
整体映射
“abcd” ---- 每个字符转化成向量 ----> 4 * 5矩阵
4 * 5矩阵 ---- 向量求平均 (池化层)----> 1 * 5向量
1 * 5向量 ---- w*x + b 线性公式 ---> 实数
实数 ---- sigmoid归一化函数 ---> 0-1之间实数,对应分类的类别
红色部分需要通过训练优化
四、Embedding 嵌入层
Embedding矩阵是可训练的参数,一般会在模型构建时随机初始化。也可以使用预训练的词向量来做初始化,此时也可以选择不训练Embedding层中的参数
输入的整数序列可以有重复,但取值不能超过Embedding矩阵的列数
核心价值:将离散值转化为向量 在nlp任务和各类特征工程中应用广泛
① 声明需要多少个向量
num_embeddings = 8 # 通常对于nlp任务,此参数为字符集字符总数,需要多少个随机向量
② 每个向量需要多少维
embedding_dim = 5 # 每个字符向量化后的向量维度
③ 初始化权重
# embedding参数:需要多少个向量,及向量的维度
embedding_layer = nn.Embedding(num_embeddings, embedding_dim, padding_idx=0)
print("随机初始化权重")
print(embedding_layer.weight)
④ 构造字符表
每个字符占第几个位置
pad
pad是占位补齐的功能,声明要补位的元素
在自然语言处理(NLP)任务中,由于不同句子长度可能不同,通常需要对句子进行填充(Padding)以确保它们具有相同的长度。pad 参数在嵌入层中用于处理这些填充的标记。
在NLP任务中,尽量少做截断,多做补0
def str_to_sequence(string,vocab):# 到长度为5截断seq = [vocab[s] for s in string][:5]# 长度不足5则补0if len(seq) < 5:seq += [vocab["pad"]] * (5 - len(seq))return seq
unk
在自然语言处理(NLP)任务中,词汇表(Vocabulary)通常是有限的,这意味着某些词汇可能不在词汇表中。为了处理这些未登录词(Out-of-Vocabulary,OOV),通常会引入一个特殊的标记<unk>(Unknown)。<unk>标记用于表示词汇表中未包含的词汇
构造字符表
# 每一维对应哪个字符
vocab = {"[pad]" : 0,"a" : 1,"b" : 2,"c" : 3,"d" : 4,"e" : 5,"f" : 6,"[unk]":7
}# 将字符转换为数字序列
def str_to_sequence(string, vocab):# 到长度为5截断seq = [vocab.get(s, 7) for s in string][:5]# 长度不足5则补0if len(seq) < 5:seq += [vocab["pad"]] * (5 - len(seq))return seq
⑤ 根据位置将字符串转化为输出的数字序列
对于同一个词表,同一个字符串而言,数字序列是固定的
# 将字符转换为数字序列
def str_to_sequence(string, vocab):# 到长度为5截断seq = [vocab.get(s, vocab["[unk]"]) for s in string][:5]# 长度不足5则补0if len(seq) < 5:seq += [vocab["pad"]] * (5 - len(seq))return seqstring1 = "abcde" # 12345
string2 = "ddccb" # 44332
string3 = "fedaz" # 65417sequence1 = str_to_sequence(string1, vocab)
sequence2 = str_to_sequence(string2, vocab)
sequence3 = str_to_sequence(string3, vocab)
示例:Embedding层的处理
#coding:utf8
import torch
import torch.nn as nn'''
embedding层的处理
'''num_embeddings = 8 # 通常对于nlp任务,此参数为字符集字符总数,需要多少个随机向量
embedding_dim = 5 # 每个字符向量化后的向量维度
# embedding参数:需要多少个向量,及向量的维度
embedding_layer = nn.Embedding(num_embeddings, embedding_dim, padding_idx=0)
print("随机初始化权重")
print(embedding_layer.weight)
print("——————————————————————————————————————————")# 构造字符表
# 每一维对应哪个字符
vocab = {"pad" : 0,"a" : 1,"b" : 2,"c" : 3,"d" : 4,"e" : 5,"f" : 6,"[unk]" : 7
}# 将字符转换为数字序列
def str_to_sequence(string, vocab):# 到长度为5截断seq = [vocab.get(s, vocab["[unk]"]) for s in string][:5]# 长度不足5则补0if len(seq) < 5:seq += [vocab["pad"]] * (5 - len(seq))return seqstring1 = "abcdea" # 12345
string2 = "ddcc" # 44332
string3 = "fedaz" # 65417sequence1 = str_to_sequence(string1, vocab)
sequence2 = str_to_sequence(string2, vocab)
sequence3 = str_to_sequence(string3, vocab)print(sequence1)
print(sequence2)
print(sequence3)x = torch.LongTensor([sequence1, sequence2, sequence3])
embedding_out = embedding_layer(x)
print(embedding_out)# 为了让不同长度的训练样本能够放在同一个batch中,需要将所有样本补齐或截断到相同长度
# padding 补齐
# [1,2,3,0,0]
# [1,2,3,4,0]
# [1,2,3,4,5]
# 截断
# [1,2,3,4,5,6,7] -> [1,2,3,4,5]
五、池化层 Pooling
将一个矩阵转化为向量时,常用到池化
处理文本问题时,文本长度为制定的最长文本长度
Avg Pooling
Avg Pooling 平均值池化
nn.AvgPool1d(4):几d就是池化几维的向量,这里是1d,则代表池化为1维的向量
torch.rand([3, 4, 5]):3条样本文本,每条样本文本长度为4,每个文本向量长度为5
池化的是第二个参数,即3条文本长度为4,每个文本长度为5的张量,经过池化后变为3条1 * 5的张量
nn.AvgPool() 网络层默认只会对输入张量的最后一维做池化,所以我们需要交换样本的顺序
x.transpose(1,2) # 交换第二、三维的顺序
squeeze() 会将3,5,1的样本转换为3,5的样本,去掉值为1的维度
#coding:utf8
import torch
import torch.nn as nn'''
pooling层的处理
'''#pooling操作默认对于输入张量的最后一维进行
#入参5,代表把五维池化为一维
# 池化有最大值max池化和average平均池化
# nn.maxPool1d(5) 最大池化
layer = nn.AvgPool1d(4) # 几d就是池化几维的向量
# 随机生成一个维度为3x4x5的张量
# 可以想象成3条样本,每条样本文本长度为4,一个文本向量长度为5
# 池化层是指对中间那维(文本长度层进行池化)进行求平均计算
# torch包中的pooling层默认是按照最后一维进行池化的
x = torch.rand([3, 4, 5])
print(x)
print(x.shape)
# 转置进行交换顺序
x = x.transpose(1,2)
print(x.shape, "交换后")
#经过pooling层
y = layer(x)
# 输入时是3,5,4;转换为3,5,1
print(y)
print(y.shape)
#squeeze方法去掉值为1的维度
# 最终转换为3 * 5的矩阵
y = y.squeeze()
print(y)
print(y.shape)
Max Pooling
Max Pooling 最大值池化,在图像任务上较为常见
nn.MaxPool1d(4):几d就是池化几维的向量,这里是1d,则代表池化为1维的向量
实际任务中,平均池化和最大值池化可以都进行实验,比较实验结果
池化层的作用
降低了后续网络层的输入维度,缩减模型大小,提高计算速度
减小不重要的输入对最终结果带来的影响
提高了特征的鲁棒性(泛化能力),防止过拟合
将一个矩阵转化为向量
六、网络结构 - RNN 循环神经网络
解决序列相关问题:预测某一步数的结果与前面n步预测的结果有关
主要思想:将整个序列划分成多个时间步,将每一个时间步的信息依次输入模型,同时将模型输出的结果传给下一个时间步
公式:逐渐把前面时间步的值通过记忆的方式不断传给下一个时间步(考虑顺序,本质也是由一系列矩阵乘得到)
每一个时间步都包含这个时间步的信息和之前所有序列的信息
网络层传出的矩阵可以再与其他层进行配合,搭建模型
缺点:输入序列越长,所存储的序列信息就越局限,RNN的效果会随着处理数据的长度增长而衰减
h一开始为0,其作用只是为了存储,将各个时间步的信息进行存储,保持序列的完整性
一般用最后一个词代表的向量代表整句话,因为最后一个字代表的向量(1 × h)包含了整句话的信息
建立RNN模型
nn.RNN():Pytorch库调用RNN激活函数
input_size:输入数据的维度
hidden_size:RNN内部的维度,两个值可以相等
bias:是否使用偏置项(b)
batch_first:默认输入数据第一维是batch_size(建议添加)
class TorchRNN(nn.Module):def __init__(self, input_size, hidden_size):super(TorchRNN, self).__init__()# batch_first层置batch_first=True,表示输入和输出的形状为(batch_size, seq_len, input_size)# 在NLP任务中加上batch_size = true# input_size 输入向量的维度 hidden_size 中间向量的维度 bias 是否使用偏置项 batch_first 是否将第一维设置成batch_size,一般都要加入self.layer = nn.RNN(input_size, hidden_size, bias=False, batch_first=True)def forward(self, x):return self.layer(x)
手动实现RNN循环神经网络
1.自定义RNN模型
w_ih:代表从输入层到隐藏层其中的权重
w_hh:代表从隐藏层到下一隐藏层其中的权重
ht:全零初始化,用来存储每一隐藏层的数据
#自定义RNN模型
class DiyModel:def __init__(self, w_ih, w_hh, hidden_size):# ih:输入层到隐藏层的权重矩阵,维度为(hidden_size, input_size)self.w_ih = w_ih# hh:隐藏层到隐藏层的权重矩阵,维度为(hidden_size, hidden_size)self.w_hh = w_hh# hidden_size:隐藏层的维度self.hidden_size = hidden_size
2.forward 前向传播
根据RNN的公式计算ux和wh,再将二者相加,作为下一轮的权重ht
def forward(self, x):# 全0初始化ht = np.zeros((self.hidden_size))output = []for xt in x:# 先做ux,再做whux = np.dot(self.w_ih, xt)wh = np.dot(self.w_hh, ht)# 将二者相加ht_next = np.tanh(ux + wh)output.append(ht_next)# 下一轮的ht用这一轮的ht_next,即ux和wh过tanh激活函数的和ht = ht_nextreturn np.array(output), ht
3.对比试验 构建样本
一个样本,由三个字构成,每个字都是一个三维向量
# 一个样本,三个字,三维向量
x = np.array([[1, 2, 3],[3, 4, 5],[5, 6, 7]]) #网络输入
4.对比实验结果
注:RNN输出时有两个输出,output列表中输出句子中每一个字对应的向量,h是句子中最后一个字对应的向量,可以用output[]当下一层输入的矩阵,也可以用h做下一层输入的向量
在NLP任务中,我们尽量保持中间张量的第一维的含义总是batch_size
#coding:utf8import torch
import torch.nn as nn
import numpy as np"""
手动实现简单的神经网络
使用pytorch实现RNN
手动实现RNN
对比
"""class TorchRNN(nn.Module):def __init__(self, input_size, hidden_size):super(TorchRNN, self).__init__()# batch_first层置batch_first=True,表示输入和输出的形状为(batch_size, seq_len, input_size)# 在NLP任务中加上batch_size = true# input_size 输入向量的维度 hidden_size 中间向量的维度 bias 是否使用偏置项 batch_first 是否将第一维设置成batch_size,一般都要加入self.layer = nn.RNN(input_size, hidden_size, bias=False, batch_first=True)def forward(self, x):return self.layer(x)#自定义RNN模型
class DiyModel:def __init__(self, w_ih, w_hh, hidden_size):# ih:输入层到隐藏层的权重矩阵,维度为(hidden_size, input_size)self.w_ih = w_ih# hh:隐藏层到隐藏层的权重矩阵,维度为(hidden_size, hidden_size)self.w_hh = w_hh# hidden_size:隐藏层的维度self.hidden_size = hidden_sizedef forward(self, x):# 全0初始化ht = np.zeros((self.hidden_size))output = []for xt in x:# 先做ux,再做whux = np.dot(self.w_ih, xt)wh = np.dot(self.w_hh, ht)# 将二者相加ht_next = np.tanh(ux + wh)output.append(ht_next)# 下一轮的ht用这一轮的ht_next,即ux和wh过tanh激活函数的和ht = ht_nextreturn np.array(output), ht# 一个样本,三个字,三维向量
x = np.array([[1, 2, 3],[3, 4, 5],[5, 6, 7]]) #网络输入#torch实验
hidden_size = 4
torch_model = TorchRNN(3, hidden_size)# print(torch_model.state_dict())
w_ih = torch_model.state_dict()["layer.weight_ih_l0"]
w_hh = torch_model.state_dict()["layer.weight_hh_l0"]
print(w_ih, w_ih.shape)
print(w_hh, w_hh.shape)
new_x = np.array(x)
# 再转换为torch.FloatTensor
torch_x = torch.FloatTensor(new_x)
output, h = torch_model.forward(torch_x)
print(h)
print(output.detach().numpy(), "torch模型预测结果")
print(h.detach().numpy(), "torch模型预测隐含层结果")
print("---------------")
diy_model = DiyModel(w_ih, w_hh, hidden_size)
output, h = diy_model.forward(x)
# output是每一个字对应的向量
print(output, "diy模型预测结果")
# h是最后一维的向量
print(h, "diy模型预测隐含层结果")
七、网络结构 - CNN 卷积神经网络
以卷积操作为基础的网络结构,每个卷积核可以看成一个特征提取器
例:
如图,输入其实是一个 5 × 5 的矩阵,卷积核是 3 × 3 的小方块,对位相乘再求和
NLP任务中流行一维一整行的卷积
卷积操作在图像任务上使用比较多,判断一个点没有意义,要需要从局部区域进行判断,从这个区域中获取特定的信息(每个模块的卷积核)
nn.Conv2d:卷积激活函数
in_channel:输入数据时图像的通道数量(RGB三通道矩阵)
out_channel:有多少卷积核,输出多少个卷积后的结果
kernel:卷积窗口的大小,可调节
bias:偏置b,加不加都行
每个卷积窗口先进行横向移动,再进行竖向移动
nn.Conv2d(in_channel, out_channel, kernel, bias=False)
卷积核包含可训练的参数,池化层不包含可训练参数
手动实现CNN卷积神经网络
1.自定义CNN模型
height:定义数据的高度
width:定义数据的宽度
weights:指卷积核的权重
kernel_size:卷积核的大小,卷积核在高度和宽度上的尺寸
#自定义CNN模型
class DiyModel:def __init__(self, input_height, input_width, weights, kernel_size):self.height = input_heightself.width = input_widthself.weights = weightsself.kernel_size = kernel_size
2.forward前向传播
squeeze():squeeze()是 numpy 库中用于减少数组维度的函数。它会移除数组形状中大小为1的维度
numpy():将其他数据结构(比如 PyTorch 中的张量等)转换为 numpy 数组的操作。但有时候需要将其转换为 numpy 数组,以便利用 numpy 库强大的数学运算、数组操作等功能进行后续处理,或者是为了遵循某些接口要求。
np.zeros():np.zeros()是numpy 库中的一个函数,用于创建一个指定形状的全零数组。这个数组的数据类型可以是默认的(通常是 float64 ),也可以通过参数指定为其他数据类型。
np.sum():它的主要功能是对给定的张量(Tensor)沿着指定的维度(或者对整个张量所有元素)进行求和计算。例如,对于一个二维张量(可以类比为一个矩阵),你可以选择沿着行维度或者列维度进行求和,得到相应的行和或者列和;也可以不指定维度,直接对整个张量中的所有元素进行求和,得到一个标量结果。
def forward(self, x):output = []for kernel_weight in self.weights:kernel_weight = kernel_weight.squeeze().numpy() #shape : 2x2kernel_output = np.zeros((self.height - kernel_size + 1, self.width - kernel_size + 1))for i in range(self.height - kernel_size + 1):for j in range(self.width - kernel_size + 1):window = x[i:i+kernel_size, j:j+kernel_size]kernel_output[i, j] = np.sum(kernel_weight * window) # np.dot(a, b) != a * b 对位相乘output.append(kernel_output)return np.array(output)
3.对比试验 构建样本
x = np.array([[0.1, 0.2, 0.3, 0.4],[-3, -4, -5, -6],[5.1, 6.2, 7.3, 8.4],[-0.7, -0.8, -0.9, -1]]) #网络输入
4.对比试验结果
#coding:utf8import torch
import torch.nn as nn
import numpy as np"""
手动实现简单的神经网络
使用pytorch实现CNN
手动实现CNN
对比
"""
#一个二维卷积
class TorchCNN(nn.Module):def __init__(self, in_channel, out_channel, kernel):super(TorchCNN, self).__init__()self.layer = nn.Conv2d(in_channel, out_channel, kernel, bias=False)def forward(self, x):return self.layer(x)#自定义CNN模型
class DiyModel:def __init__(self, input_height, input_width, weights, kernel_size):self.height = input_heightself.width = input_widthself.weights = weightsself.kernel_size = kernel_sizedef forward(self, x):output = []for kernel_weight in self.weights:kernel_weight = kernel_weight.squeeze().numpy() #shape : 2x2kernel_output = np.zeros((self.height - kernel_size + 1, self.width - kernel_size + 1))for i in range(self.height - kernel_size + 1):for j in range(self.width - kernel_size + 1):window = x[i:i+kernel_size, j:j+kernel_size]kernel_output[i, j] = np.sum(kernel_weight * window) # np.dot(a, b) != a * b 对位相乘output.append(kernel_output)return np.array(output)x = np.array([[0.1, 0.2, 0.3, 0.4],[-3, -4, -5, -6],[5.1, 6.2, 7.3, 8.4],[-0.7, -0.8, -0.9, -1]]) #网络输入#torch实验
in_channel = 1
out_channel = 3
kernel_size = 2
torch_model = TorchCNN(in_channel, out_channel, kernel_size)
print(torch_model.state_dict())
torch_w = torch_model.state_dict()["layer.weight"]
# print(torch_w.numpy().shape)
torch_x = torch.FloatTensor([[x]])
output = torch_model.forward(torch_x)
output = output.detach().numpy()
print(output, output.shape, "torch模型预测结果\n")
print("---------------")
diy_model = DiyModel(x.shape[0], x.shape[1], torch_w, kernel_size)
output = diy_model.forward(x)
print(output, "diy模型预测结果")
八、网络结构 - Normalization 归一化层
归一化(Normalization)层在神经网络中用于对输入数据或中间层的特征进行标准化处理,使得数据的分布更加稳定和合理。其主要目的是加速网络训练过程、提高模型的泛化能力和稳定性。
公式:数据减均值 除标准差,使数据进行归一化
bn层可以穿插在线性层或其他网络结构中
batch Normalization 批归一化
原理:在训练过程中,对一个小批次(batch)的数据进行归一化。
对于每个特征维度(比如卷积神经网络中的每个通道),计算该批次数据的均值和方差,然后将数据归一化到均值为 0、方差为1的分布。具体公式为其中Xi是输入数据,μ是批次均值,σ是批次方差,€是一个很小的数(如 1e - 5)用于防止除零错误,yi 是归一化后的输出。
最后,还会进行一个线性变换,其中 γ 和 β 是可学习的参数,用于恢复数据的表达能力,因为简单的归一化可能会改变数据的原始分布特性。
横向算均值,再除以其标准差(方差开二次根号)
图像相关任务中使用较多
Layer Normalization 层归一化
原理:是对每个样本的每个通道(在卷积神经网络中)或者每个特征维度(在一般网络中)独立地进行归一化。它计算每个样本内每个通道的均值和方差,与批归一化和层归一化的计算范围都不同。
纵向算均值,再除以其标准差(方差开二次根号)
NLP相关任务中使用较多
Instance Normalization 实例化归一化
原理:是对每个样本的每个通道(在卷积神经网络中)或者每个特征维度(在一般网络中)独立地进行归一化。它计算每个样本内每个通道的均值和方差,与批归一化和层归一化的计算范围都不
同。
生成对抗网络中,图像生成比较多
九、网络结构 - Dropout层
model.train():声明模型是在训练模式,dropout层才会起作用
dropout层只在训练过程起作用,在实际预测过程不起作用
作用:减少过拟合,按照指定概率,随机丢弃一些神经元(将其置为零)
其余元素乘以 1 / (1-p) 进行放大
如何理解其作用:
1)强迫一个神经单元,和随机挑选出来的其他神经单元共同工作,消除减弱了神经元节点间的联合适应性,增强了泛化能力
2)可以看做是一种模型平均,由于每次随机忽略的隐层节点都不同,这样就使每次训练的网络都是不一样的,每次训练都可以单做一个“新”的模型
3)启示:计算方式并不是越复杂就越好
测试代码
#coding:utf8import torch
import torch.nn as nn
import numpy as np"""
基于pytorch的网络编写
测试dropout层
"""import torchx = torch.Tensor([1,2,3,4,5,6,7,8,9])
# 50%的概率进行随机丢弃(置0),剩下的值有50%可能性进行翻倍用来训练
# 未被丢弃的神经元的输出会乘以一个缩放因子,通常是 1 / (1 - dropout_rate),其中 dropout_rate 是 Dropout 的概率
dp_layer = torch.nn.Dropout(0.4)
dp_x = dp_layer(x)
print(dp_x)
相关文章:
【NLP 15、深度学习处理文本】
目录 一、反向传播 编辑 1.反向传播运算过程 2.前向传播和反向传播的作用 前向传播 反向传播 3.定义模型(torch包) 4.手动实现 ① 线性层 ② sigmoid激活函数 ③ 手动实现MSE均方差损失函数 ④ 前向传播 ⑤ 手动实现梯度计算 ⑤ 权重的更新:…...
Android Studio创建新项目并引入第三方so外部aar库驱动NFC读写器读写IC卡
本示例使用设备:https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.52de2c1bbW3AUC&ftt&id615391857885 一、打开Android Studio,点击 File> New>New project 菜单,选择 要创建的项目模版,点击 Next 二、输入项目名称…...
3D视觉[一]3D计算机视觉
3D视觉[一]3D计算机视觉 3D计算机视觉概述 像机标定 文章目录 3D视觉[一]3D计算机视觉前言一、人类视觉二、计算机视觉2.1 计算机视觉的研究目的2.2 计算机视觉的研究任务2.3 计算机视觉的研究方法2.4 视觉计算理论2.5 马尔框架中计算机视觉表达的四个层次2.5.1 图像ÿ…...
Linux权限(超详细彻底搞懂Linux的权限)
🔥个人主页🔥:孤寂大仙V 🌈收录专栏🌈:Linux 🌹往期回顾🌹:Linux常见指令(初学者必看) 🔖流水不争,争的是滔滔不 一、Linux下的两种用户超级用户&…...
Ubuntu22.04安装docker desktop遇到的bug
1. 确认已启用 KVM 虚拟化 如果加载了模块,输出应该如下图。说明 Intel CPU 的 KVM 模块已开启。 否则在VMware开启宿主机虚拟化功能: 2. 下一步操作: Ubuntu | Docker Docs 3. 启动Docker桌面后发现账户登陆不上去: Sign in | …...
网新恒天八股总结
Java的基本数据类型 四类八种 整数类型:byte,short,int,long 浮点类型:float,double 字符类型:char 布尔类型:boolean char类型的范围 0 ~ 65535,可以表示16位无符号整数 equals和的区别 &,&&a…...
【AIGC】与模型对话:理解与预防ChatGPT中的常见误解
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AIGC | ChatGPT 文章目录 💯前言💯模型的工作原理和用户期望差异人工智能模型的基本工作原理认知上的局限与误解用户期望与模型实际能力的差距精确理解用户意图的重要性实际应用中的建议 &…...
09篇--图片的水印添加(掩膜的运用)
如何添加水印? 添加水印其实可以理解为将一张图片中的某个物体或者图案提取出来,然后叠加到另一张图片上。具体的操作思想是通过将原始图片转换成灰度图,并进行二值化处理,去除背景部分,得到一个类似掩膜的图像。然后…...
Qt 使用modbus协议
Qt 框架下 使用modbus协议 一,使用Qt原生的 QModbusClient ,比如QModbusTcpClient 1,因为modbus的读写 需要在同一个线程中,所以需要在主线程中利用moveToThread的方式,将业务逻辑封装到 子线程中。 2,m…...
pip离线安装一个github仓库
要使用pip安装一个本地Git仓库,你可以按照以下步骤操作: 确保你已经克隆了Git仓库到本地。 进入仓库所在的目录。 使用pip安装。 以下是具体的命令: 克隆Git仓库到本地(替换下面的URL为你的仓库URL) git clone https…...
【ETCD】【源码阅读】深入分析 storeTxnWrite.Put方法源码
该方法是 storeTxnWrite 类型中的核心方法,负责将键值对存储到数据库,同时处理键的元数据(如版本、修订号、租约)并管理租约关联。 目录 一、完整代码二、方法详解方法签名1. 计算修订号并初始化变量2. 检查键是否已存在3. 生成索…...
桥接模式的理解和实践
桥接模式(Bridge Pattern),又称桥梁模式,是一种结构型设计模式。它的核心思想是将抽象部分与实现部分分离,使它们可以独立地进行变化,从而提高系统的灵活性和可扩展性。本文将详细介绍桥接模式的概念、原理…...
【Rust自学】3.2. 数据类型:标量类型
3.2.0. 写在正文之前 欢迎来到Rust自学的第三章,一共有6个小节,分别是: 变量与可变性数据类型:标量类型(本文)数据类型:复合类型函数和注释控制流:if else控制流:循环 通过第二章…...
【Leetcode Top 100】199. 二叉树的右视图
问题背景 给定一个二叉树的 根节点 r o o t root root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。 数据约束 二叉树的节点个数的范围是 [ 0 , 100 ] [0,100] [0,100] − 100 ≤ N o d e . v a l ≤ 100…...
Java并发编程框架之其他并发工具
选错了就选错了,不要一遍一遍的后悔,总是一遍遍的想,当时怎么样就好了,不要欺负当时的自己,当时你一个人站在迷雾中,也很迷茫,就算重新来一遍,以你当时的阅历和心智,还是…...
MinerU:PDF文档提取工具
目录 docker一键启动本地配置下载模型权重文件demo.py使用命令行启动GPU使用情况 wget https://github.com/opendatalab/MinerU/raw/master/Dockerfile docker build -t mineru:latest .docker一键启动 有点问题,晚点更新 本地配置 就是在Python环境中配置依赖和…...
Unity性能优化---使用SpriteAtlas创建图集进行批次优化
在日常游戏开发中,UI是不可缺少的模块,而在UI中又使用着大量的图片,特别是2D游戏还有很多精灵图片存在,如果不加以处理,会导致很高的Batches,影响性能。 比如如下的例子: Batches是9࿰…...
wazuh-modules-sca-scan
sca模块主函数wm_sca_main -> wm_sca_start 检查policy文件中的每一个项目wm_sca_check_policy static int wm_sca_check_policy(const cJSON * const policy, const cJSON * const checks, OSHash *global_check_list) {if(!policy) {return 1;}const cJSON * const id c…...
力扣-图论-15【算法学习day.65】
前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程(例如想要掌握基础用法,该刷哪些题?)我的解析也不会做的非常详细,只会提供思路和一些关键点,力扣上的大佬们的题解质量是非…...
JS萤石云录像回放拖动进度条无法正常播放
问题描述: 本项目版本:vue2.6.12,webpack3.6.0,ezuikit-js0.7.2 在使用萤石云的JavaScript SDK做监控的直播、录像回放时,遇到部分设备的录像回放,无法根据控制面板的拖动进度条查看某时间段的录像。 官方…...
Spring Boot 启动时间优化全攻略
引言 随着 Spring Boot 的广泛应用,开发者享受到了快速开发和自动化配置的便利。然而,随着项目复杂度的增加,Spring Boot 项目启动时间也变得越来越长,这在开发、调试和部署阶段可能会成为效率瓶颈。如何优化 Spring Boot 的启动…...
ubuntu服务器木马类挖矿程序排查、及安全管理总结
版本 24.04 由于GPU多卡服务器多人使用,需要链接隧道ssh等,容易中招挖矿脚本。 总的思路是,顺着进程的PID回溯最终的程序运行起点,这里可以先看一下日志: journalctl -u PID 通过 PID 精确定位进程的信息,…...
redis 使用Lettuce 当redis挂掉重启之后 网络是怎么重新连接
Lettuce是一个高性能的Java Redis客户端,支持同步、异步和反应式编程模式 Lettuce的核心功能包括: 高性能:通过使用Netty作为底层网络通信框架,实现了非阻塞IO,提高了性能。丰富的API:提供了丰富…...
【PyTorch】实现在训练过程中自定义动态调整学习率
问题描述: 在使用 PyTorch 训练自定义神经网络时,我们希望能够动态地调整学习率,以便在训练过程中逐渐优化模型,避免过拟合并加速收敛。那么,如何在 PyTorch 中实现这一功能呢? 解决方案: 在训…...
【Flink-scala】DataStream编程模型总结
系列文章目录 1.【Flink-Scala】DataStream编程模型之数据源、数据转换、数据输出 2.【Flink-scala】DataStream编程模型之 窗口的划分-时间概念-窗口计算程序 3.【Flink-scala】DataStream编程模型之窗口计算-触发器-驱逐器 4.【Flink-scala】DataStream编程模型之水位线 5.【…...
语音芯片赋能可穿戴设备:开启个性化音频新体验
在科技日新月异的今天,语音芯片与可穿戴设备的携手合作,正引领我们步入一个前所未有的个性化音频时代。这一创新融合,用户可以享受到更加个性化、沉浸式的音频体验。下面将详细介绍语音芯片与可穿戴设备合作的优点和具体应用。 1. 定制化音效…...
JavaFX使用jfoenix的UI控件
jfoenix还是一个不错的样式,推荐使用,而且也可以支持scene builder中的拖拖拽拽 需要注意的是过高的javafx版本可能会使得某些样式或控件无法使用 比如alert控件,亲测javaFX 19版本可以正常使用 1.在pom.xml中引入依赖 GitHub地址https://gi…...
SpringBoot集成ENC对配置文件进行加密
在线MD5生成工具 配置文件加密,集成ENC 引入POM依赖 <!-- ENC配置文件加密 --><dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>2.1.2</ver…...
基于AI对话生成剧情AVG游戏
游戏开发这个领域,一直有较高的学习门槛。作为一个非专业的游戏爱好者,如果想要开发游戏,往往受制于游戏引擎的专业程度,难以完成复杂的游戏项目。 AI IDE的诞生,提供了另外的一种思路,即通过AI 生成项目及…...
MAVEN--Maven的生命周期,pom.xml详解,Maven的高级特性(模块化、聚合、依赖管理)
目录 (一)Maven的生命周期 1.Maven的三套生命周期 2.Maven常用命令 (二)pom.xml详解 (三)Maven的高级特性(模块化、聚合、依赖管理) 1.Maven的依赖范围 2.版本维护 3.依赖传…...
SpringBoot的事务钩子函数
如果需要在A方法执行完成之后做一个不影响主方法运行的动作B,我们需要判断这个A方法是否存在事务,并且使用异步执行动作B; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transa…...
uniapp滚动消息列表
两个相同的循环列表,循环滚动 <view class"winners_list uni-flex uni-column" :animation"animationData"><view v-for"(item, index) in winnersList" :key"index" class"li uni-flex uni-column"&g…...
基于python对pdf文件进行加密等操作
利用python对pdf文件进行操作 读取pdf-源码 import PyPDF2 # 读取pdf格式的文件 reader PyPDF2.PdfFileReader(示例文件/aaa.pdf) print(reader)# 读取指定页面的文件 page reader.getPage(0) # 输出当前页面的文本数据 print(page.extractText())读取pdf-源码解析 这段代…...
Three.js材质纹理扩散过渡
Three.js材质纹理扩散过渡 import * as THREE from "three"; import { ThreeHelper } from "/src/ThreeHelper"; import { LoadGLTF, MethodBaseSceneSet } from "/src/ThreeHelper/decorators"; import { MainScreen } from "/src/compone…...
【Leetcode 每日一题 - 扩展】45. 跳跃游戏 II
问题背景 给定一个长度为 n n n 的 0 0 0 索引 整数数组 n u m s nums nums。初始位置为 n u m s [ 0 ] nums[0] nums[0]。 每个元素 n u m s [ i ] nums[i] nums[i] 表示从索引 i i i 向前跳转的最大长度。换句话说,如果你在 n u m s [ i ] nums[i] nums[i…...
被裁20240927 --- YOLO 算法
背景 在云端部署ViSP,ViSP实现视觉伺服、yolo实现视觉跟踪。 开源的2d视觉跟踪算法有哪些? 开源的2D视觉跟踪算法有很多呢,这里给你推荐一些比较知名和常用的吧。 ByteTrackV2:这是一个通用2D跟踪算法,提出了分层的…...
AI技术架构:从基础设施到应用
人工智能(AI)的发展,正以前所未有的速度重塑我们的世界。了解AI技术架构,不仅能帮助我们看懂 AI 的底层逻辑,还能掌握其对各行业变革的潜力与方向。 一、基础设施层:AI 技术的坚实地基 基础设施层是 AI 技…...
植物大战僵尸辅助【控制台版本】
前面介绍了使用CE和OD的简单使用:CE和OD介绍和使用CE查找阳光的教学:阳光基地址和偏移地址,下面先使用最简单的控制台程序来实现修改阳光的功能。 项目地址 1.分析程序 我们的控制台程序想要修改植物大战僵尸游戏内的数据,它们…...
css中样式前加 css样式前面加个圆点
创建CSS样式,样式名称的前面需要加什么 1、我们只知道符号代表的意思是at,其翻译是 在... 例如media就是 在媒介上。没人规定本身具有什么意义,或者说就算规定了我们也改变不了,只需要知道其规定属性的用法即可。 2、px;}然后根据你自己索要…...
算法刷题Day18: BM41 输出二叉树的右视图
题目链接 描述 思路: 递归构造二叉树在Day15有讲到。复习一下,就是使用递归构建左右子树。将中序和前序一分为二。 接下来是找出每一层的最右边的节点,可以利用队列层次遍历。 利用队列长度记录当前层有多少个节点,每次从队列里…...
如何实现规范化LabVIEW编程
规范编写LabVIEW程序的目的是提高代码的可读性、可维护性、可扩展性,并确保团队成员能够高效地理解和修改代码。以下是一些关键建议,帮助您编写更专业的LabVIEW代码,并确保它易于后续的升级和维护: 1. 合理的项目结构 目录结构…...
TQ15EG开发板教程:使用SSH登录petalinux
本例程在上一章“创建运行petalinux2019.1”基础上进行,本例程将实现使用SSH登录petalinux。 将上一章生成的BOOT.BIN与imag.ub文件放入到SD卡中启动。给开发板插入电源与串口,注意串口插入后会识别出两个串口号,都需要打开,查看串…...
Springboot+vue实现大文件上传
背景:为了实现大文件上传的功能 1新建数据表sql file_chunk CREATE TABLE file_chunk (id bigint UNSIGNED NOT NULL AUTO_INCREMENT,file_name varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci NULL DEFAULT NULL COMMENT 文件名,chunk_nu…...
Linux笔记
常用的基本命令 查询某个安装包有没有安装某个软件 使用的命令是rpm -qa |grep 软件名字 卸载软件 rpm -e --nodeps 软件名称 查看已经启动的服务 netstat -tunlp 一般我们在Linux系统中上传文件一般上传到 /usr/local/src的目录下 查看防火墙的命令 firewall-cmd --sta…...
相机(Camera)成像原理详解
简介:个人学习分享,如有错误,欢迎批评指正。 成像流程 1、光学相机的定义 顾名思义,光学相机就是利用光学原理进行成像的相机,而且市面上的相机几乎都是光学相机,只不过随着时代的发展,胶卷式…...
计算机网络知识点全梳理(一.TCP/IP网络模型)
目录 TCP/IP网络模型概述 应用层 什么是应用层 应用层功能 应用层协议 传输层 什么是传输层 传输层功能 传输层协议 网络层 什么是网络层 网络层功能 网络层协议 数据链路层 什么是数据链路层 数据链路层功能 物理层 物理层的概念和功能 写在前面 本系列文…...
后端接受前端传递数组进行批量删除
问题描述:当我们需要做批量删除功能的时候,我们循环单次删除的接口也能进行批量删除,但要删除100条数据就要调用100次接口,或者执行100次sql,这样系统开销是比较大的,那么我们直接采用接收的数组格式数据sq…...
理解数据结构 hashtable的简易理解思路
结构图 为了方便演示,下图中分区算法为下标取模 private int hashFun(int id) {//使用 hash并取模return id % size;}Hashtable的结构如图所示:是一个数组(元素为各个链表的表头) 多个链表组成,也就是说 hashtable 结…...
大数据面试题--企业面试真题
大数据面试题--企业面试真题 PlanHub 点击访问获取: 大数据面试体系专栏_酷兜科技www.kudoumh.top/hlwai/85.html 点击访问获取: 大数据面试体系专栏_酷兜科技www.kudoumh.top/hlwai/85.html 大数据面试题汇总 HDFS 1、 HDFS 读写流程。 2、HDF…...
数据结构(C语言版)-6.查找
1. 查找的基本概念 2. 静态查找 2.1 顺序查找 typedef int KeyType; typedef int InfoType; typedef struct {KeyType key;InfoType otherdata; }SeqList; // 顺序表类型 // 顺序查找int SeqSearch(SeqList R[], int n, int k) {int i n;R[0].key k; // R[0].key为查找不成…...