1、numpy和pandas的比较?
NumPy和Pandas都是Python中用于数据处理的库,但它们的设计目的和功能特性有所不同。以下是NumPy和Pandas的比较:
- 设计目的:
- NumPy 主要是为了科学计算,提供高性能的多维数组对象和数学函数。
- Pandas 主要是为了数据分析和数据预处理,提供数据结构和数据分析工具。
- 数据结构:
- NumPy 使用
ndarray
(N维数组)来存储同一类型的数据,适合进行数学运算和矩阵操作。 - Pandas 使用
DataFrame
和Series
,可以存储异构数据(不同类型的数据),适合处理表格数据和时间序列数据。
- NumPy 使用
- 功能特性:
- NumPy 提供了广泛的数学函数和线性代数运算,以及傅里叶变换和随机数生成等功能。
- Pandas 提供了数据导入导出、数据清洗、数据合并、数据重塑、数据选择、数据分组、时间序列功能等。
- 性能:
- NumPy 通常性能更高,因为它底层是用C语言编写的,并且数组是固定类型的,减少了开销。
- Pandas 在处理异构数据时更加灵活,但可能会牺牲一些性能,因为它基于NumPy构建并在其之上添加了额外的功能。
- 使用场景:
- 当你需要进行数值计算、线性代数或科学计算时,通常会使用 NumPy。
- 当你需要处理和分析表格数据、执行数据预处理步骤时,通常会使用 Pandas。
- 集成:
- NumPy 可以与Pandas无缝集成,因为Pandas的
DataFrame
和Series
对象在底层使用NumPy数组。 - Pandas 提供了更高级的数据处理功能,但在需要时可以利用NumPy的性能优势。
在实际应用中,NumPy和Pandas经常一起使用。例如,在数据科学项目中,你可能会使用Pandas加载数据、清洗数据、转换数据,然后使用NumPy进行数学运算和建模。两者都是Python数据科学栈中不可或缺的部分。
- NumPy 可以与Pandas无缝集成,因为Pandas的
2、标准化,归一化,数值化的目的,应用场景,并进行比较
目的:
-
标准化(Standardization):
- 目的: 将数据转换成具有零均值和单位标准差的正态分布。
- 公式:
z = x − μ σ ,其中 x 是原始值, μ 是均值, σ 是标准差。 z = \frac{x - \mu}{\sigma} ,其中 x 是原始值, \mu 是均值,\sigma 是标准差。 z=σx−μ,其中x是原始值,μ是均值,σ是标准差。
- 应用场景: 当数据分布近似正态分布时,特别是使用基于梯度下降的算法时。
-
归一化(Normalization):
- 目的: 将数据缩放到一个固定的范围,通常是0到1。
- 公式:
x norm = x − x min x max − x min ,其中 x 是原始值, x min 和 x max 分别是数据的最小值和最大值。 x_{\text{norm}} = \frac{x - x_{\text{min}}}{x_{\text{max}} - x_{\text{min}}},其中 x 是原始值,x_{\text{min}} 和 x_{\text{max}} 分别是数据的最小值和最大值。 xnorm=xmax−xminx−xmin,其中x是原始值,xmin和xmax分别是数据的最小值和最大值。 - 应用场景: 当数据特征的量级相差很大,或者不确定数据的分布时。
-
数值化(Encoding):
- 目的: 将非数值数据(如分类数据)转换为数值形式,以便机器学习模型可以处理。
- 方法: 常见的数值化方法包括独热编码(One-Hot Encoding)、标签编码(Label Encoding)等。
- 应用场景: 处理分类特征或标签时。
应用场景:
- 标准化(Standardization):
- 应用场景: 在机器学习算法中,标准化可以加快学习速度,特别是对于基于梯度下降的算法,如线性回归、逻辑回归、支持向量机等。
- 归一化(Normalization):
- 应用场景: 归一化特别适用于数据特征的量级相差很大时,或者当你不确定数据的分布时。它可以帮助保持不同特征之间的相对重要性。
- 数值化(Encoding):
- 应用场景: 当数据包含分类特征时,数值化是必要的。例如,在处理性别、颜色、国家等分类数据时,需要将它们转换为数值形式。
比较:
类型 | 目的 | 应用场景 | 数据转换后的范围 | 对数据分布的假设 |
---|---|---|---|---|
标准化 | 零均值,单位标准差 | 适用于数据分布近似正态分布,特别是基于梯度下降的算法 | 不固定,依赖于原始数据 | 正态分布 |
归一化 | 缩放到固定范围(通常是0到1) | 特征量级相差很大,或不确定数据的分布 | 0到1之间 | 无 |
数值化 | 将非数值数据转换为数值形式 | 处理分类特征或标签 | 依赖于转换方法 | 无 |
在选择使用哪种预处理技术时,需要根据数据的特点和机器学习算法的要求来决定。通常,标准化和归一化用于数值特征,而数值化用于分类特征。在实际应用中,可能需要结合使用这些技术来获得最佳的性能。
3、Relu
RELU函数,即修正线性单元(Rectified Linear Unit),是深度学习中应用非常广泛的一种激活函数。它的数学表达式简单直观:
f
(
x
)
=
max
(
0
,
x
)
f(x) = \max(0, x)
f(x)=max(0,x)
这意味着,对于任何输入值( x ),如果( x )为正,则输出为( x )本身;如果( x )为负,则输出为0。
RELU函数的特点和优势:
- 计算效率高:由于RELU函数的简单性,它在前向传播时的计算速度非常快。特别是与Sigmoid和Tanh函数相比,RELU避免了复杂的指数运算和浮点运算,只需要简单的条件判断(if-else)即可完成计算。
- 减少梯度消失问题:在反向传播过程中,RELU函数的导数(即斜率)在输入为正时为1,而在输入为负时为0。这使得在输入为正的区域,梯度不会随着层数的增加而消失,有助于深层网络的训练。
- 增加网络的稀疏性:由于RELU函数的性质,只有一部分神经元的输出会是非零值,这导致网络中的权重参数有更多的机会变为0,从而减少了参数之间的相互依赖,提高了模型训练的效率,并有助于缓解过拟合问题。
- 非线性特性:RELU函数为神经网络引入了非线性特性,使得网络能够捕捉到更加复杂的数据结构和模式。
使用RELU的注意事项:
- Dead ReLU问题:如果网络中存在始终为负的输入,那么对应的神经元将永远不会激活,这个问题被称为“Dead ReLU”。为了解决这个问题,可以考虑使用Leaky ReLU或其他变体,如Parametric ReLU(PReLU),这些变体在输入为负时提供了一个小的正斜率。
- 输出范围:RELU函数的输出范围始终为非负数,这可能会导致网络的输出无法直接用于后续的比较操作,如分类问题中的softmax层。然而,这可以通过在输出层之前添加一个恒等映射来解决。
总的来说,RELU及其变体由于其简单性、效率和效果,在深度学习领域得到了广泛的应用。尽管存在一些局限性,但它仍然是设计和训练深度神经网络时最受欢迎的激活函数之一。
4、梯度下降和反向传播
梯度:是一个向量,可以理解为导数+(参数/学习)变化最快的方向
梯度下降是一种优化算法,用于通过迭代的方式找到一个函数的局部最小值。在机器学习中,这个函数通常是损失函数,它衡量的是模型的预测值与真实值之间的差异。梯度下降的基本思想是沿着函数梯度的反方向逐步调整参数,以减少损失函数的值。
梯度下降的计算步骤如下:
-
初始化参数:
选择一个初始的参数值 θ 选择一个初始的参数值 \theta 选择一个初始的参数值θ -
计算梯度:
计算当前参数下损失函数的梯度 ∇ θ J ( θ ) ,梯度表示损失函数对每个参数的偏导数。 计算当前参数下损失函数的梯度 \nabla \theta J(\theta) ,梯度表示损失函数对每个参数的偏导数。 计算当前参数下损失函数的梯度∇θJ(θ),梯度表示损失函数对每个参数的偏导数。 -
更新参数:
根据梯度和学习率(步长)来更新参数值。更新公式为: θ = θ − α ∇ θ J ( θ ) 其中, α 是学习率,控制着每一步更新的幅度。 根据梯度和学习率(步长)来更新参数值。更新公式为: \theta = \theta - \alpha \nabla \theta J(\theta) 其中,\alpha 是学习率,控制着每一步更新的幅度。 根据梯度和学习率(步长)来更新参数值。更新公式为:θ=θ−α∇θJ(θ)其中,α是学习率,控制着每一步更新的幅度。 -
重复迭代:重复步骤2和3,直到满足停止条件,比如梯度的变化非常小(接近0),或者达到预设的迭代次数。
在实际应用中,梯度下降的实现可以根据数据的特点和问题的复杂性有所不同。以下是一些梯度下降的变体:
- 批量梯度下降(Batch Gradient Descent):每次更新参数时使用全部的训练数据来计算梯度。这种方法在数据量不大时效果很好,但当数据量大时计算量也会很大。
- 随机梯度下降(Stochastic Gradient Descent,SGD):每次更新参数时只使用一个随机样本来计算梯度。这种方法计算效率高,但可能收敛速度较慢,且路径更曲折。
- 小批量梯度下降(Mini-batch Gradient Descent):每次更新参数时使用部分(小批量)训练数据来计算梯度。这种方法结合了批量梯度下降和随机梯度下降的优点,是实际应用中最常用的方法。
梯度下降是一种简单而强大的优化算法,但它的收敛速度和最终结果很大程度上取决于学习率和初始参数值的选择。因此,通常需要通过实验来调整这些超参数。
注:loss.backward()就是根据损失函数,对参数(required_grad=True)去计算它的梯度,并且把它累加保存到x.grad,此时还并未更新其梯度
- tensor.data:
- required_grad=False,tensor.data和tensor等价
- require_grad=True,tensor.data仅获取tensor中的数据
- tensor.numpy():
- require_grad=True不能够直接转化,需要使用tensor.detach().numpy()
5、nn.Module
和nn.functional
和Sequential
torch.nn.Module
torch.nn.Module
是所有神经网络模块的基类。当你创建一个模型时,通常需要继承这个类。它提供了一种组织构建块的方法,允许你定义一个包含多个层和操作的网络。Module
类还提供了许多有用的功能,如.parameters()
、.zero_grad()
、.to(device)
等,这些方法可以方便地访问和管理模型的参数,以及将模型移动到不同的设备(如CPU或GPU)。
当我们在自定义网络时,有两个方法需要特别注意:
- __init__需要调用super方法,继承父类的属性和方法
- forward方法必须实现,用定义我们的网络向前计算的过程
示例代码:
import torch.nn as nn
import torch.nn.functional as F
class SimpleModel(nn.Module):
def __init__(self):
super(SimpleModel, self).__init__()
self.conv1 = nn.Conv2d(1, 20, 5)
self.fc1 = nn.Linear(320, 50)
self.fc2 = nn.Linear(50, 10)
def forward(self, x):
x = F.relu(self.conv1(x))
x = F.max_pool2d(x, 2, 2)
x = x.view(-1, 320)
x = F.relu(self.fc1(x))
x = self.fc2(x)
return F.log_softmax(x, dim=1)
注意:nn.Model定义了__call__方法,实现的就是调用forward方法。即SimpleModel的实例,能够直接被传入参数调用,实际调用的是forward方法并传入参数*
# 实例化模型
model=SimpleModel()
# 传入数据,计算结果
predict=model(x)
torch.nn.functional
torch.nn.functional
提供了一系列激活函数、池化层、损失函数等,这些都是不需要参数的层或操作。使用torch.nn.functional
而不是torch.nn.Module
的优点是,你的模型会更加灵活,尤其是在定义复杂的层操作时。然而,这也意味着你需要手动管理更多的细节,如输入数据的形状。
示例代码:
import torch.nn as nn
import torch.nn.functional as F
class FunctionalModel(nn.Module):
def __init__(self):
super(FunctionalModel, self).__init__()
self.conv1 = nn.Conv2d(1, 20, 5)
self.fc1 = nn.Linear(320, 50)
self.fc2 = nn.Linear(50, 10)
def forward(self, x):
x = F.relu(F.max_pool2d(self.conv1(x), 2, 2))
x = x.view(-1, 320)
x = F.relu(self.fc1(x))
x = self.fc2(x)
return F.log_softmax(x, dim=1)
比较
- 构造函数:
Module
通常在构造函数中定义层,而functional
直接在forward
函数中使用。 - 参数管理:
Module
类自动处理参数的初始化、更新和序列化。functional
需要手动处理这些。 - 灵活性:
functional
提供更大的灵活性,尤其是在定义动态模型时。 - 代码组织:
Module
提供了更好的代码组织方式,特别是在大型项目中。
总结
选择Module
还是functional
取决于你的具体需求。如果你在构建一个标准的、层次结构清晰的模型,Module
可能是更好的选择。如果你需要更多的灵活性,或者你的模型比较简单,functional
可能更适合。在实际应用中,Module
和functional
经常一起使用,以达到最佳的灵活性和组织性。
Sequential
在PyTorch中,torch.nn.Sequential
是一个顺序容器。模块将按照它们在构造器中传递的顺序添加到它里面。也可以通过索引来访问Sequential
中的模块。
Sequential
的特点是简化了神经网络的构建过程,使得构建神经网络更加直观和方便。
下面是一个使用torch.nn.Sequential
构建简单神经网络的例子:
import torch
import torch.nn as nn
# 定义一个简单的神经网络
class SimpleNet(nn.Module):
def __init__(self):
super(SimpleNet, self).__init__()
# 使用Sequential定义网络的层
self.layers = nn.Sequential(
nn.Linear(10, 20), # 第一层,10个输入,20个输出
nn.ReLU(), # 激活函数
nn.Linear(20, 10), # 第二层,20个输入,10个输出
nn.ReLU(), # 激活函数
nn.Linear(10, 1) # 输出层,10个输入,1个输出
)
def forward(self, x):
# 直接使用Sequential的前向传播
x = self.layers(x)
return x
# 创建网络实例
net = SimpleNet()
# 创建一个随机输入张量
input_tensor = torch.randn(1, 10)
# 前向传播
output = net(input_tensor)
print(output)
在这个例子中,我们首先定义了一个名为SimpleNet
的神经网络类,它继承自nn.Module
。在构造函数中,我们使用nn.Sequential
来定义网络的层。在前向传播函数forward
中,我们直接调用self.layers
(即Sequential
容器)来进行前向传播。
使用Sequential
的好处是代码更加简洁,层与层之间的连接自动处理,不需要手动定义每一层的输入和输出。这使得网络构建更加直观,特别是对于具有大量层的深层网络。
6、优化器类
优化器(optimizer)可以理解为torch为我们封装的用来更新参数的方法,比如常见的随机梯度下降(SGD)
优化器都是由torch.optim提供的,如:
- torch.optim.SGD(参数,学习率)
- torch.optim.Adam(参数,学习率)
注意:
- 参数可以使用model.parameters()来获取,获取模型中所有required_gard=True的参数
- 优化器类的使用方法
- 实例化
- 所有参数梯度置0
- 反向传播计算梯度
- 跟新参数值
示例如下:
import torch.optim as optim
optimizer = optim.SGD(Model.parameters(),lr=1e-3) #1.实例化
optimizer.zero_gard() #2.梯度置0
loss.backward() #3.反向传播计算梯度
optimizer.step() #4.更新参数值
7、损失函数
- 均方误差:nn.MESLoss(),常用于回归问题
import torch.nn as nn
model = SimpleModel()
crition = nn.MSELoss()
optimizer = optim.SGD(Model.parameters(),lr=1e-3)
for i in range(100):
y_predict = model(x_true)
loss = crition(y_true,y_predict)
optimizer.zero_gard()
loss.backward()
optimizer.step()
- 交叉熵损失:nn.CrossEntropyLoss(),常用于分类问题
crition = nn.CrossEntropyLoss()
loss = crition(output,target)
output = F.log_softmax(x,dim=-1) #1.对输出值计算softmax和取对数
loss = F.nll_loss(output,target) #2.使用torch中的带权损失
带权损失定义为: l n = − ∑ w i x i l_n=-\sum w_ix_i ln=−∑wixi, 其中把 l o g ( P ) 作为 x i , 把真实值 Y 作为权重 其中把log(P)作为x_i,把真实值Y作为权重 其中把log(P)作为xi,把真实值Y作为权重
8、Pytorch中数据的加载
在深度学习中,数据量通常比较大,面对如此大量的数据,不可能一次性的在模型中进行前向传播和反向传播。所以我们会对整个数据进行随机的打乱顺序,把数据整理成一个个batch,同时还对数据进行预处理。
数据集类
数据集类的主要目的是为了提供一种方便的方式来加载、访问和处理数据。在PyTorch中,通常使用Dataset类来定义数据集,并使用DataLoader类来加载数据。
示例如下
import torch
from torch.utils.data import Dataset
class MyDataset(Dataset):
def __init__(self, data, labels):
self.data = data
self.labels = labels
def __len__(self):
return len(self.data)
def __getitem__(self, index):
data_point = self.data[index]
label = self.labels[index]
return data_point, label
我们需要在自定义的数据集中继承Dataset类,同时还需要实现两个方法
- __len__方法,能够实现通过全局的len()方法获取其中的元数个数
- __getitem__方法,能够通过传入索引的方式获取数据,如通过dataset[i]获取其中第i个数据
迭代数据集
使用上述方法能够对数据进行读取,但其中还有很多内容没有实现:
- 批处理数据
- 打乱数据
- 使用多线程multiprocessing并行加载数据
示例如下
from torch.utils.data import DataLoader
dataset = MyDataset()
data_loader = DataLoader(dataset = dataset,batch_size = 10,shuffle = True,num_workers = 2)
# 遍历获得每一个batch的结果
for index,(label,contxet) in enumerate(data_loader):
print(index,label,context)
其中参数含义:
- dataset:提前定义的dataset实例
- batch_size:传入数据的batch大小
- shuffle:表示是否在每一次获取数据的时候提前打乱数据
- num_workers:加载数据的线程数
9、模型的保存和加载
# 保存模型
torch.save(model.state_dict(), 'model.pth')
# 加载模型
model = SimpleModel()
model.load_state_dict(torch.load('model.pth'))
标签:__,nn,梯度,self,torch,基础,学习,深度,数据
From: https://blog.csdn.net/qq_56547436/article/details/139575738