pytorch基本文档以及处理

1.常用代码

1. 关于数据的格式以及数据的处理

在这里主要介绍关于数据的常见存储格式,以及这些数据如何做处理

1.0 pandas包的使用

在进行数据清理之前,一般是要使用pandas包对数据进行一些处理,将数据转化为dataFrame再进行一些数据清洗操作是我们一贯的流程. pandas的下载就是使用简单的指令

1
pip install pandas(视系统而定)
下载以后可以再文件头部引入即可

1.0.1 读取数据的常用函数
数据读取函数 说明
pandas.read_csv() 读取csv文件中的数据并且转化为dataframe
pandas.read_excel() 读取excel文件中的数据并且转化为dataframe
以此类推 差不多

以下为代码的展示用例:

1
2
3
4
5
6
7
import pandas as pd

# 从 CSV 文件中读取数据
df = pd.read_csv('data.csv')

# 从 Excel 文件中读取数据
df = pd.read_excel('data.xlsx')
1.0.2 pandas中两种常用的数据结构

pandas中有两种常用的数据结构,series以及dataframe,分别对应一维数组和二维数组,大概可以这样子理解(其中dataframe还可以理解为多个series的组合,怪怪的),pandas提供了很多奇奇怪怪的api用来清洗数据.

和张量很像,但是有一点和张量不是很一样,series和dataframe虽然是一维和二维的关系,但是实际上series并不是dataFrame中的每一个行,而是每一个列

比如这个样子

1
arr = square["name"]

实际上获取到的是某个索引为name的列,因为dataframe的大致结构是这样子的

name .....
0 张三
1 李四
2 王五

对于series,需要注意的事情大概只有以下几个 1. Series 中的数据是有序的。 2. 可以将 Series 视为带有索引的一维数组。 3. 索引可以是唯一的,但不是必须的。 4. 数据可以是标量、列表、NumPy 数组等。

此外 series和一维数组也是有一定区别的,其实是个双层结构,包含"索引"和"数值",其他的api请自行查阅文档获取

不过另外有一个值得注意的点,对于这两种pandas的数据结构,[]的用法很灵活

Series:

对于 Series,可以通过布尔索引进行元素的筛选。

1
arr=arr[0,1,0,1] # 这样子是获取整个series的第一个和第三个元素

布尔索引是一种利用布尔条件来选择元素的方法。 当使用 [] 内部加上判断语句时,实际上是在进行布尔索引操作,返回的是满足条件的元素构成的新 Series。

1
2
3
arr = arr[arr>0] # 这一列中所有大于0的元素都会进入新的series

# 实际上底层是根据张量运算得到了一共布尔数组,再根据布尔数组选取元素形成新的series

也可以加上另一个索引序列,用来选择对应位置的元素。这两个索引序列可以是布尔值,也可以是整数索引,比如下面整个例子

1
2
3
4
5
6
7
all_features.dtypes[all_features.dtypes != 'object'].index  # 不等于object的列的索引
all_features[numeric_features] = all_features[numeric_features].apply(lambda x: (x - x.mean()) / (x.std())) # 对于每个数字的列都进行放缩
"""
这是一段比较复杂的应用了
获取所有属性中不是object的属性,然后使用index函数进行获取这些索引号
根据索引号就能找到所有为数字的列,然后使用apply函数对列中每个元素进行操作
"""

DataFrame:

对于 DataFrame,[] 的用法更加灵活。

可以在 [] 内部使用判断语句,返回满足条件的行(或列)构成的新 DataFrame。 还可以使用另一个索引序列,可以是布尔值、整数索引、切片等,用来选择对应的行和列。

1.0.3 dataframe数据清洗的常用函数

实现对于缺失的处理

1
2
3
4
5
6
7
8
# 删除包含缺失值的行或列(需要添加参数)
df.dropna()

# 将缺失值替换为指定的值
df.fillna(0)

# 将指定值替换为新值
df.replace('old_value', 'new_value')

数据切片

1
2
3
4
5
6
7
8
9
 选择指定的列
df['column_name']

# 通过标签选择数据
df.loc[row_index, column_name]

# 通过位置选择数据
df.iloc[row_index, column_index]

一些计算

1
2
3
4
df.mean()	计算每列的平均值。
df.median() 计算每列的中位数。
df.mode() 计算每列的众数。
df.count() 计算每列非缺失值的数量。
热编码操作以及强制类型转换
1
2
3
pandas.get_dummies(df, dummy_na=True)

df.atypes(int) # 强制转化为int

下方为一共房价数据的清洗的详细操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
with open('./train.csv','r') as file:
all_features=pandas.read_csv(file)

all_features=all_features.iloc[:, 1:-1] # 去掉第一列:id

numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index # 寻找所有是数字的列的索引

all_features[numeric_features] = all_features[numeric_features].apply(lambda x: (x - x.mean()) / (x.std())) # 对于每个数字的列都进行放缩

all_features[numeric_features] = all_features[numeric_features].fillna(0) # 对于所有缺失数值都设为0(按列)

all_features = pandas.get_dummies(all_features, dummy_na=True) # 对于所有的数值进行独立热编码

boolic_features = all_features.dtypes[all_features.dtypes == 'bool'].index # 找到所有类型为布尔列

all_features[boolic_features] = all_features[boolic_features].astype(int) # 对这些类进行强制的类型转化

all_features=torch.tensor(all_features.values,dtype=torch.float32)

1.1 对于数据的保存和读取

1.1.1 pt格式的数据保存以及读取

pt格式是pytorch的缩写,也是不需要进行数据转化的默认保存方式

对于张量都可以使用该种格式进行保存和读取

代码示例如下,对于单一张量,可以直接使用save和load函数进行读取

1
2
3
4
5
import torch
# 将x2从文件中读取
x2 = torch.load('pt文件地址')
# 将x2存为某文件
torch.save(x2,"pt文件地址")

通过这种文件存取的方式可以将数据进行一个简单的存储,值得一提的是,这种方法同样可以存储张量列表并且按照顺序进行读取

1
2
torch.save([x2,y2],'目标地址')
A,B = torch.load('刚才存的地址')
1.1.2 对于csv的数据保存和处理

ps: 对于csv文件的创建需要另一个包os的参与,这里不做解释

csv文件指的是"逗号分隔符",某种意义上来说和excel处理数据的方式是一样的,按顺序存取,一般来说都是用这个文件格式去存储数据的

对于csv文件,需要使用pandas库中的read_csv函数进行文件读取

1
2
with open('./xxx.csv','r') as file:
data=pandas.read_csv(file)

注意一下,这里的data并不是常规的数据,而是被称之为dataframe的数据结构,是pandas整个包所规定的

我们可以通过某种手段来进行dataFrame到tensor或者dataset这种便于训练的数据结构的转变

对于DataFrame形式的数据来说, 对于一些奇奇怪怪的数据,很多都是在整个阶段使用pandas中的函数完成处理的

1.2 对于模型的保存和处理

1.2.1 对于模型的参数处理

后面会加以解释,对于一个模型net,我们可以使用state_dict()函数获取参数

获取参数

1
2
//使用save函数进行读取,这一点和正常的张量保存是一样的
torch.save(net.state_dict(), 'mlp.params')

读取参数

1
2
//加载参数可以使用load_state_dict函数,参数为一个张量
net.load_state_dict(torch.load('mlp.params'))
对于模型的数据加载需要注意的一点就是,给模型加载参数的时候必须保证两个模型是完全一致的结构

1.2.2 对于模型的保存实例

这段代码来自于一个具体的实验项目,我们根据预训练的地址获取模型的参数

再根据自己创建的函数,构建一个空白的模型对象(空白指的是模型参数是空白的)

类比一下就是枪和弹夹的关系

1
2
3
4
5
6
7
8
9
10
# 加载预训练模型
RNN_path = '/mnt/sde/ycl/NanoCon/code/lightning_logs/version_163/checkpoints/RNN-mnist-epoch=49-avg_val_ACC=0.86791-avg_val_AUPRC=0.95966-avg_val_AUROC=0.93144-avg_val_Precision=0.89477-avg_val_Recall=0.90262-avg_val_F1Score=0.89864.ckpt'
# 创建一个模型类,这里是模型对象,数据还没初始化
RNN = biRNN_basic()
# 读取为张量
checkpoint = torch.load(RNN_path)
# 对张量进行操作加载
checkpoint['state_dict'] = {k: v for k, v in checkpoint['state_dict'].items() if 'fc' not in k}
# 加载模型
RNN.load_state_dict(checkpoint['state_dict'], strict=False)

1.3 如何对数据进行训练读取

这里将按照一个csv格式数据的读取,梳理一下大致数据读取以及创建训练加载器的流程

主要的数据读取可以为以下几个步骤来实现

  • csv使用pandas读取为DataFrame对象
  • (根据需求处理DataFrame对象中的数据)
  • DataFrame对象转化为tensor
  • tensor转化为dataset对象
  • 根据dataset对象创建dataloader

获得了dataloader以后,就可以进行小批量梯度训练了

下面会根据一个完整的整理过程,创建一个可用的数据读取器,假设我们现在在某个位置存在一个csv数据集合

首先,先使用read_csv函数,将csv文件对象读取为dataFrame数据

1
2
with open('目标文件地址','r') as file:
csvreader=pandas.read_csv(file)
对于dataFrame对象,可以对数据进行一些处理,pandas提供了很多函数方便处理张量无法转化的数据 比如独立热编码等等工作,不过在这里不解释了

dataFrame函数可以直接转化为张量, 张量可以足够大, 上百万条数据都可以整合到一起都可以用tensor进行接收

1
tensor_from_df = torch.tensor(csvreader.values)

在这里首先使用values函数,将dataFrame转化为数组,然后再根据整个的基础上创建tensor即可

接下来就是根据tensor创建dataset数据集合

(dataset的作用是可以把任意size相同的张量打包成一个整体,并且可以再建立dataloader以后进行进行分别读取)

使用data包下的TensorDataset函数实现张量和dataset的转换,dataset是比较常用的一种对象,一些pytorch内置的数据集就是用这种方式作为存储的

1
2
3
4
5
6
7
from torch.utils.data import TensorDataset

# 在这里实现对于data和labels两个张量的数据绑定
datas = torch.tensor([[1,1], [2,2], [3,3], [4,4], [5,5]])
labels = torch.tensor([2, 4, 6, 8, 10])

dataset = TensorDataset(data, labels)
dataset并非是数组,但是令人意外的是,dataset仍然是以二维的数据结构实现对于多个绑定数据的保存和访问,可以使用类似二维数组的形式实现对于数据的绑定

1
print('data_n',dataset[0][0]) # 读取到了第0个张量的第0个数据

顺利得到了dataset以后,就可以创建dataloader来进行数据的迭代

1
2
3
4
5
batch_size=256
train_iter=data.DataLoader(mnist_train,batch_size=256,shuffle=True,num_workers=4)
#将这个数据集划分为256一打,洗牌模式随机抽取,四个线程进行读取
test_iter=data.DataLoader(mnist_test,batch_size=256,shuffle=True,num_workers=4)
# 这样就生成一个类似迭代器的东西了,使用for循环可以进行读取
然后执行迭代,即可读取到特定大小的张量
1
2
for features,labels in train_iter:
..........................

2. 模型的构建,初始化

2.1 模型的两种创建方式

模型存在两种创建方式,第一种是直接根据运算顺序,用sequential容器进行创建

1
2
3
4
5
6
7
net=nn.Sequential(
nn.Flatten(),
nn.Linear(784,256),
nn.ReLU(),
nn.Linear(256,10),
nn.Softmax(dim=1)
)

另一种比较常见的创建方式,是使用继承自module的类进行构建,如图所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
class Net(nn.Module):
#初始化函数,在这个部分里面我们负责把这些东西都进行一个输入
def __init__(self):
super().__init__()
#初始化参数的方法:
self.flatten=nn.Flatten()
#初始化参数
self.init_para()
# 向前传播,这是一个具体的计算逻辑
def forward(self,X):
X=self.flatten(X)
return X
# 封装一个初始化参数方法
def init_para(self):
def init(m):
if(type(m)==nn.Linear):
nn.init.normal_(m.weight,std=0.1)
nn.init.constant_(m.bias,0.1)
self.apply(init)

net=Net()

至于模型参数的读取,可以直接使用函数

1
net.state_dict()

2.整体的训练流程

整体的训练流程也可以划分为几个步骤

  • 获取数据集合并且转化为可以用于训练的形式
  • 观察数据结构,制造神经网络
  • 定制优化器以及损失函数
  • 训练并且迭代(计算梯度,梯度清空,反向传播,迭代)

以Fashion为简单案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import torch
import torchvision
from torch.utils import data
from torchvision import transforms
from torchvision import transforms

import pandas
from torch import nn

#这个就是下载数据集合了,这里获取到了数据集合并且放到内存里面


# 通过ToTensor实例将图像数据从PIL类型变换成32位浮点数格式,
# 并除以255使得所有像素的数值均在0~1之间
trans = transforms.ToTensor() # 数据转换机制不知道是干啥的
mnist_train = torchvision.datasets.FashionMNIST(
root="./data", train=True, transform=trans, download=True)
mnist_test = torchvision.datasets.FashionMNIST(
root="./data", train=False, transform=trans, download=True)

# 检验一下数据的形式
print(mnist_train[0][0].shape) #1,28,28
print(len(mnist_train)) #60000

# 获取到的两个对象都是dataset,在这里直接使用类加载器
batch_size=256
train_iter=data.DataLoader(mnist_train,batch_size=256,shuffle=True,num_workers=0) #将这个数据集划分为256一打,洗牌模式随机抽取,四个线程进行读取
test_iter=data.DataLoader(mnist_test,batch_size=256,shuffle=True,num_workers=0) # 这样就生成一个类似迭代器的东西了,使用for循环可以进行读取

# 设置一个神经网络,先这么放着后面再说计算

class MyNet(nn.Module):
def __init__(self):
super().__init__()
self.flatten=nn.Flatten()
self.linear1=nn.Linear(784,256)
self.linear2=nn.Linear(256,10)
self.relu=nn.ReLU()
self.softmax=nn.Softmax(dim=1)
self.initPara()
def forward(self,X):
X=self.flatten(X)
X=self.linear1(X)
X=self.relu(X)
X=self.linear2(X)
X=self.softmax(X)
return X
def initPara(self):
def init(m):
if(type(m)==nn.Linear): # 对线性层进行权重的初始化
nn.init.normal_(m.weight,std=0.1)
nn.init.constant_(m.bias,0.1)
self.apply(init)

# 输入数据
net=MyNet()

sum=len(mnist_train)

#训练函数,小批量梯度下降
train = torch.optim.SGD(net.parameters(), lr=0.03)

#交叉熵损失函数
loss = nn.CrossEntropyLoss(reduction='none')


epoch_num=10
for epoch in range(epoch_num):
i=0
for X,y in train_iter:
# 计算损失然后求平均
l=loss(net(X),y).mean()
train.zero_grad()
l.backward()
train.step()
i+= l.mean() * (X.shape[3]/sum)
# l=loss(net(inputs),outputs)
print(f'epoch {epoch + 1}, loss {i:f}')

i=0
for X,y in test_iter:
# 计算损失然后求平均
l=loss(net(X),y).mean() # 计算损失
train.zero_grad() # 清空训练器梯度
l.backward() # 反向传播计算梯度
train.step() # 训练迭代
i+= l.mean() * (X.shape[3]/sum)
# l=loss(net(inputs),outputs)
print(f'finall test, loss {i:f}')

## 保存模型

3.一些其他需要注意的事项

3.1 维度的划分

在pytorch的许多函数中都存在一个东西dim,代表了张量的维度,熟悉了其他语言中向量的操作以后,肯定很容易可以将其和空间联想起来,但是实际上pytorch组织维度的方式和其他语言有些不一样,在这里将会通过cat,split,softmax三个函数来演示dim的具体划分形式

按照正常来说,张量维度的安排顺序和shape的顺序是一致的,也就是从左到右,从0开始

举例:

1
2
3
4
a=torch.ones((1,2,3))
a.size(dim=0) #第0个维度的长度为1
a.size(dim=1) #2
a.size(dim=2) #3

以cat函数为例子

1
2
3
4
5
6
7
8
9
# 两个示例张量
x1 = torch.ones((3,2))
x2 = torch.ones((3,2))

# 拼接
concatenated_tensor = torch.cat((x1, x2), dim=1) #(3,4)

# 果然拼接顺序不能按照空间想象...而是直接在第几个维度合并...
# 顺序自然是从shape的从左往右数

以split函数为例子

1
2
3
4
print(concatenated_tensor.split(2,dim=1))   

# 而split函数也是,在某个维度方向上,按照规定步长进行拆分
# 比如(3,4),按照上面函数的拆分效果就是(3,2),(3,2)

以F包下的softmax为例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 对第一个维度的延伸方向构建softmax
print(F.softmax(concatenated_tensor,dim=0))
"""
tensor([[0.3333, 0.3333, 0.3333, 0.3333],
[0.3333, 0.3333, 0.3333, 0.3333],
[0.3333, 0.3333, 0.3333, 0.3333]])
"""

# 对第二个维度的延伸方向构建softmax
print(F.softmax(concatenated_tensor,dim=1))
"""
tensor([[0.2500, 0.2500, 0.2500, 0.2500],
[0.2500, 0.2500, 0.2500, 0.2500],
[0.2500, 0.2500, 0.2500, 0.2500]])
"""


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 xranudvilas@gmail.com

💰

×

Help us with donation