系列文章目录
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、认识PyTorch的总体架构
提示:首先,PyTorch的设计哲学很像是一个高度模块化和可插拔的系统。
主要划分为四个模块:
- 模型(Model)
- 数据处理(Data Handling)
- 训练控制(Training Control)
- 优化器(Optimizer)
以下我分别介绍这些模块,作用以及调用方式和调用逻辑。
1.1 模型(Model)
在PyTorch中,所有的模型都是从nn.Module基类继承而来。这个基类让用户可以定义自己的前向传播逻辑。每个模型可以有多个子模块,这些子模块也是继承自nn.Module,这就形成了一个可以任意扩展的层次结构。
- 调用机制:
当你调用一个模型的时候,实际上你是在调用它的forward方法。
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.layer1 = nn.Linear(10, 20)
self.layer2 = nn.Linear(20, 10)
def forward(self, x):
x = torch.relu(self.layer1(x))
return torch.relu(self.layer2(x))
model = Net()
output = model(input_data) # 实际上调用 model.forward(input_data)
1.2 数据处理(Data Handling)
数据处理在PyTorch中通过Dataset和DataLoader进行。Dataset负责管理数据集的加载和预处理,DataLoader负责以一个可迭代的方式提供批量的数据。
- 调用机制:
DataLoader 内部使用了 Python 的迭代器,每次迭代提供一个批次的数据,这一点和 Java 的迭代器非常类似。
dataset = CustomDataset()
dataloader = DataLoader(dataset, batch_size=10, shuffle=True)
for data in dataloader:
inputs, labels = data
outputs = model(inputs)
1.3 训练控制(Training Control)
这一部分通常包括设置训练循环,监控训练过程中的损失等。它可以比作是业务逻辑层,控制着模型的训练过程。
调用机制:
使用显式的循环来迭代数据集,对每个批次的数据调用模型的前向传播和后向传播方法。
for epoch in range(total_epochs):
for inputs, labels in dataloader:
optimizer.zero_grad()
outputs = model(inputs)
loss = loss_function(outputs, labels)
loss.backward()
optimizer.step()
1.4 优化器(Optimizer)
优化器负责更新模型的权重,以优化模型的性能。这个概念在Java中没有直接的对应,但可以理解为后台管理或维护任务,例如垃圾收集器或者数据库的优化操作。
调用机制:
优化器在训练循环中被调用,使用模型的loss.backward()生成的梯度来更新模型参数。
optimizer = optim.SGD(model.parameters(), lr=0.01)
for inputs, labels in dataloader:
optimizer.zero_grad()
outputs = model(inputs)
loss = loss_function(outputs, labels)
loss.backward()
optimizer.step()
1.5 小总结
在PyTorch中,每个组件都有其专责,通过组合使用这些组件,你可以构建出功能强大且灵活的深度学习应用。模型定义了计算的结构,数据加载器提供了输入数据,训练控制管理了学习过程,优化器负责改进学习效果。这种设计使得PyTorch在科研和工业界都非常受欢迎。
二、知识补充 什么是继承 以及python中继承的表现形式
2.1 简介
在Python中,继承是面向对象编程的一个基本概念,其作用是允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。这样做的主要目的是代码的重用,以及实现接口的一致性。
2.2 继承的作用
-
代码重用:
继承允许我们定义一个通用的基类,它实现了在多个地方需要的功能。然后,我们可以创建多个派生类,这些派生类继承基类的功能,并添加特定于派生类的功能。 -
实现接口的一致性:
通过继承,所有的派生类都可以拥有相同的接口(即方法和属性)。这使得使用任何派生类的对象都非常方便,因为他们有共同的操作方式,这是面向对象设计的一个重要方面。 -
多态:
继承允许实现多态,即同一个接口可以有不同的实现。这意味着一个函数可以使用多个类型的对象,只要这些对象来自同一个基类。
# 定义一个基类 Animal
class Animal:
def __init__(self, name):
self.name = name # 每个动物都有一个名字
def speak(self):
raise NotImplementedError("Subclass must implement abstract method")
# 定义一个派生自Animal的类 Dog
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
# 定义另一个派生自Animal的类 Cat
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
# 使用基类和派生类
animals = [Dog("Buddy"), Cat("Whiskers"), Dog("Fido")]
for animal in animals:
print(animal.speak())
三、通过上述框架分析 vision_text_display_model.py 代码结构
-
模型(Model)
这个类定义了你的神经网络架构,其中包括前向传播的逻辑。它从nn.Module基类继承,这是所有PyTorch模型的基础。
主要组件:
多个神经网络层(例如:nn.Linear, nn.Conv2d, nn.ReLU等) forward方法定义了数据如何通过这些层流动。
class MSD_Net(nn.Module):
def __init__(self, args):
# 初始化各种层
def forward(self, vision_embeddings, text_embeddings, text_sentiment):
# 定义前向传播
return fuse_final_cls
作用:在调用model(input)时,自动调用forward方法
- 数据处理(Data Handling)
这个类处理数据的加载和预处理,使其适合模型使用。
主要方法:
__init__:设置基本参数,加载数据。
__getitem__:返回一条数据,供DataLoader使用。
__len__:返回数据集的总大小。
class MultiModalDataset(Dataset):
def __init__(self, text_tools, vision_transforms, args, mode):
# 初始化,加载数据
def __getitem__(self, idx):
# 返回单个数据项
def __len__(self):
# 返回数据集大小
作用:这个类通过提供标准接口简化了数据操作,并且使得数据加载更加模块化。
- 数据处理(Data Handling)
这部分通常是指训练脚本,其中可能包括模型的实例化、训练循环等。
训练循环可能包括:
加载数据
执行前向传播
计算损失
执行后向传播(通过.backward())
更新模型参数(通过调用优化器)
-
优化器配置(Optimizer Configuration)
这个函数负责创建和配置优化器,它定义了如何更新模型的权重。
主要组件:optim.Adam: 定义了优化算法。 学习率调度器(如get_linear_schedule_with_warmup)
def get_multimodal_configuration(args, model):
optimizer = optim.Adam(model.parameters(), lr=args.multimodal_lr)
scheduler = get_linear_schedule_with_warmup(optimizer, ...)
criterion = nn.BCEWithLogitsLoss()
return optimizer, scheduler, criterion
作用:配置如何根据损失函数来调整网络参数,这对学习过程至关重要。
四、重点分析 vision_text_display_model.py 模型
- 类定义和初始化
这段代码初始化了一个神经网络模型,它继承自 nn.Module —— PyTorch中所有神经网络模块的基类。
class MSD_Net(nn.Module):
def __init__(self, args):
super().__init__()
self.args = args # 存储传入的参数,可能包括配置选项如模式选择等
- 网络层的定义
这些是模型中使用的神经网络层,包括线性层(全连接层)、ReLU激活函数、丢弃层用于防止过拟合,以及损失函数的选择。
# 定义多个全连接层和卷积层以及激活函数和丢弃层
self.sentiment_fc1 = nn.Linear(768, 768, bias=True)
self.ReLu = nn.ReLU()
self.dropout = nn.Dropout(p=0.1, inplace=False)
self.sentiment_fc2 = nn.Linear(768, 1, bias=True)
self.sentiment_criterion = nn.MSELoss() # 定义损失函数
- 前向传播定义
forward 方法定义了数据通过网络的流程,这是执行网络计算的核心。
def forward(self, vision_embeddings, text_embeddings, text_sentiment, TFlagNow=None, label=None):
# 进行前向传播,处理视觉和文本嵌入
...
return fuse_final_cls # 返回最终的融合结果
- 数据处理与特征融合
这部分代码通过生成和应用注意力图来处理和融合视觉和文本数据。这包括矩阵乘法、应用卷积层和计算融合后的嵌入。
# 处理视觉和文本数据,生成注意力图并应用卷积层
text_embedd = text_embeddings.transpose(1, 2)
vision_embedd = vision_embeddings
attention_map = torch.bmm(vision_embedd, text_embedd)
...
aligned_vision_embeddings = vision_attention_unsqueeze_minus1 * vision_embedd
- 新增功能与计算
这里添加了新的计算层和进行了额外的语义相关的计算,用于增强模型对特定特征的理解和处理。
# 新增的卷积层处理和语义计算
attention_map_new = attention_map * TFlagNow
...
semantic_vision_embeddings = vision_CLS + vision_CLS * variance_vision.unsqueeze(0).repeat(batch_size,1)
- 结果融合和输出
这一部分代码进行了多层次的特征和结果融合,使用自定义的融合函数和配置参数来调整融合过程。
# 结果融合
semantic_cls = self.fusion(semantic_vision_embeddings, semantic_text_embeddings, self.multimodal_fusion)
final_cls = self.fusion(semantic_cls, sentiment_cls, self.multilevel_fusion)
final_cls = self.final_fc(final_cls).squeeze()
fuse_final_cls = final_cls + self.args.lambda_sentiment * lamda_sentiment + self.args.lambda_semantic * lamda_semantic - self.args.constant
4.1 网络层的定义
这段代码是一个深度神经网络模型的定义部分,使用的是PyTorch框架。代码详细定义了多个网络层、损失函数、以及一些用于数据处理和决策支持的队列。下面是对每个部分的详细中文注解:
- 网络层的定义与功能
# 定义情感分析的全连接层,输入和输出都是768维,使用偏置
self.sentiment_fc1 = nn.Linear(768, 768, bias=True)
# 激活函数ReLU,用于添加非线性,帮助网络学习复杂的功能
self.ReLu = nn.ReLU()
# Dropout层,概率为0.1,用于防止过拟合,随机丢弃一部分网络连接
self.dropout = nn.Dropout(p=0.1, inplace=False)
# 第二个全连接层,将768维数据压缩到1维
self.sentiment_fc2 = nn.Linear(768, 1, bias=True)
# 均方误差损失函数,用于在训练过程中评估模型的预测结果与实际结果的误差
self.sentiment_criterion = nn.MSELoss()
# 用于处理相关性的卷积层序列,第一个卷积层将1通道扩展到64通道,第二个卷积层将64通道压缩回1通道
self.correlation_conv = nn.Sequential(
nn.Conv2d(1, 64, 3, stride=1, padding=1),
nn.Conv2d(64, 1, 3, stride=1, padding=1),
nn.ReLU()
)
# 另一个卷积层序列,处理流程与上面相似,但通道数较少
self.my_conv_1 = nn.Sequential(
nn.Conv2d(1, 32, 3, stride=1, padding=1),
nn.Conv2d(32, 1, 3, stride=1, padding=1),
nn.ReLU()
)
- 融合策略与最终决策层
# 根据参数选择融合策略
self.multimodal_fusion = args.multimodal_fusion
self.multilevel_fusion = args.multilevel_fusion
# 根据融合策略选择最终的全连接层结构
if self.multilevel_fusion != 'concat' and self.multimodal_fusion != 'concat':
self.final_fc = nn.Linear(768, 1, bias=True)
elif self.multilevel_fusion == 'concat' and self.multimodal_fusion == 'concat':
self.final_fc = nn.Linear(4*768, 1, bias=True)
else:
self.final_fc = nn.Linear(3*768, 1, bias=True) # 如果是其他情况,默认使用3倍768维的输入
- 内存队列用于存储历史信息
# 定义内存长度参数
self.memory_length = args.memory_length
# 使用队列存储历史中的讽刺性和非讽刺性信息,用于后续处理
self.sarcasm_bank = Queue(maxsize=self.memory_length)
self.non_sarcasm_bank = Queue(maxsize=self.memory_length)
这段代码中,网络通过多个卷积层和全连接层处理输入数据,使用ReLU激活函数增加非线性,Dropout防止过拟合。通过特定的融合策略和决策层输出最终结果。同时,通过队列记录历史信息,可能用于动态调整模型策略或进行时间序列分析。