1.数据集载入
网上许多的搭建网络的历程中都是使用已经组织好的数据集,当使用自定义的数据集需要以下操作
1.1 假设新建一个myDataset.py
from torch.utils.data import Dataset,DataLoader
import torchvision
import torch
import os
import h5py
import numpy as np
class myDataset(torch.utils.data.Dataset):#需要继承torch.utils.data.Dataset
def __init__(self,fileset):#可以添加一些参数
# 初始化文件路径或文件名列表。
# 初始化该类的一些基本参数。
'''
例如:
self.set=set
self.len=np.sum(np.array( [set_num[key] for key in set_num] ))
'''
pass
def __getitem__(self, index):
#1 从文件中读取一个数据(例如,plt.imread)。
#2 预处理数据(例如torchvision.Transform)。
#3 返回数据对(例如图像和标签)。
# 这里需要注意的是,第一步:read one data,是一个data
'''
例如:
path=root+'{}.npy'.format(index)
data,label=read(path)
return data,label
'''
pass
def __len__(self):
# 返回数据集的总大小。
'''
例如:
return self.len
'''
pass
- 注意
__getitem__
返回的data,label
转化成tensor
不一定是什么数据类型,很可能会在网络中tensor
运算中出错,例如提示
Expected object of scalar type Long but got scalar type Float for sequence element #2
- 可以在
__getitem__
就转化成指定数据类型的tensor
def __getitem__(self, index):
'''
'''
label=torch.from_numpy(label).int()#可以是.long() .float()
sample=torch.from_numpy(sample)
return sample,label
1.2 引入
在训练或者测试的文件里引入myDataset.py
from myDataset import myDataset
from torch.utils.data import Dataset,DataLoader,WeightedRandomSampler
batch_size=128
train_dataset=heartDataset()
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size)
#每次回返回batch_size个样本和数据
for index,data in enumerate(tqdm(train_loader)):
samples,labels=data
1.3 采样策略
需要打乱训练顺序或者,
样本不均衡
的时候需要采用不同的策略
- 顺序采样
from torch.utils.data import Dataset,DataLoader,WeightedRandomSampler
train_set=['a_set','b_set']
train_dataset=myDataset(fileset=train_set)
train_loader = DataLoader(dataset=train_dataset, batch_size=32, shuffle=False)
- 随机采样
from torch.utils.data import Dataset,DataLoader,WeightedRandomSampler
train_set=['a_set','b_set']
train_dataset=heartDataset(fileset=train_set)
train_loader = DataLoader(dataset=train_dataset, batch_size=32, shuffle=True)
- 加权采样
from torch.utils.data import Dataset,DataLoader,WeightedRandomSampler
train_set=['a_set','b_set']
train_dataset=heartDataset(fileset=train_set)
sampler=WeightedRandomSampler(samples_weight,num_samples=set_nums,replacement=True)
#replacement表示可不可以重新采
#samples_weight表示采样的权重,越大越可能采到,加起来不一定要是1,比如samples_weight=[1,2,1,3]
train_loader = DataLoader(dataset=train_dataset, batch_size=128, sampler=sampler)
- ps: samples_weight是
每一个样本的权重,不是每一个类别
,- 由于类别不均衡,想改更改每个样本的采样权重可以采用以下方式
from torch.utils.data import Dataset,DataLoader,WeightedRandomSampler
train_set=['a_set','b_set']
train_dataset=heartDataset(train_set)
train_loader = DataLoader(dataset=train_dataset, batch_size=1)
samples_weight=[]
samples_weight.extend( samples_w[label.item()] for [_,label] in train_loader)
sampler = WeightedRandomSampler(samples_weight,num_samples=set_nums,replacement=True)
train_loader = DataLoader(dataset=train_dataset, batch_size=128, sampler=sampler)
2 搭建网络
2.1 假设新建一个myModel.py
import torch
import torchvision
import torchvision.transforms as transforms
import torch.nn as nn
class Net(nn.Module):
def __init__(self):
super(Net1, self).__init__()
self.conv1=nn.Sequential(
#
)
self.conv2=nn.Sequential(
#
)
self.mpl3=nn.Sequential(
#
)
self.out4=nn.Sequential(
#
)
def forward(self,x):
#卷积提特征
x=self.conv1(x)
x=self.conv2(x)
#过度全连接层
x=x.flatten(start_dim=1)#阻止批次扁平化
#全连接层分类
x=self.mpl3(x)
x=self.out4(x)
return x
在
Sequential
可以添加一些序列操作
#例如
self.conv1=nn.Sequential(
nn.Conv2d(in_channels=64,out_channels=128,kernel_size=5),
nn.BatchNorm1d(128),
nn.ReLU(),
nn.MaxPool1d(kernel_size=2),
)
2.2 训练
在训练或者测试的文件里引入myModel.py
import torchvision
import torch
import torch.optim as optim
import torch.nn as nn
from tqdm import tqdm
from myModel import Net
gpu_id=0
epoches=10
root='/data'
train_set=[<setname>,<setname>]
try:
if torch.cuda.is_available():
device = torch.device('cuda:{}'.format(gpu_id))
else:
device = torch.device('cpu')
print("device{ }".format(device))
except:
device = torch.device('cpu')
#载入数据
train_dataset=heartDataset(tarin_set)
train_loader = DataLoader(dataset=test_dataset, batch_size=32, shuffle=False)
model=Net().to(device)
optimizer = optim.Adam(model.parameters(),weight_decay=0.01)#weight_decay=0.01引入正则化
criterion = nn.BCELoss()#设置损失函数
for epoch in range(epoches):
print("ecpoch:{}/{}".format(epoch+1,epoches))
for index,data in enumerate(tqdm(train_loader)):
samples,labels=data
labels = Variable(labels.float()).to(device)#根据网络或者报错更改数据类型
samples =Variable(samples.float()).to(device)
optimizer.zero_grad()
output=model(samples)
loss = criterion(output, labels)
loss.backward()
optimizer.step()
savepath=root+'/model'+'/m_e{}'.format(epoches)+'.pt'
torch.save(model.state_dict(), savepath)
2.3测试
即使没有backward,输入也会对模型的参数造成影响,作为测试需要使用:
- 1 设置
model.eval()
,和model.train()主要是BN
和Dropout
的差别
在
with torch.no_grad():
下输入主要是为了不计算梯度,减少gpu内存消耗,不能更新权值
loadpath=root+'/model'+'/m_e{}'.format(epoches)+'.pt'
model=Net()
model.load_state_dict(torch.load(loadpath, map_location=device if device =='cpu' else "{}".format(device)))
model.eval()
for index,data in enumerate(tqdm(test_loader)):
samples,labels,names=data
labels = labels.float().to(device)
samples = samples.float().to(device)
with torch.no_grad():
output=model(samples)