本贴需要有一定的基础,具体需要预先学习的工具包如下:
- python的基本语法
- numpy
- pytorch
数据导入
工具包:Dataloader
首先将数据分类放在不同的文件夹里,像这样,csv格式
导入代码:
import torch
import numpy as np
import csv,os
from torch.utils.data import Dataset,DataLoader
class Raman_spectra(Dataset):
#这里是为了方便将precessed这个文件夹放在同一个根目录下,root就是存放数据的路径
def __init__(self, root='processed' ,mode='train'):
super(Raman_spectra, self).__init__()
self.root=root
self.namelabel = {}
for name in sorted(os.listdir(os.path.join(root))):
if not os.path.isdir(os.path.join(root, name)):
continue
self.namelabel[name] = len(self.namelabel.keys())
self.datas, self.labels = self.load_csv()
if mode == 'train':
self.datas = self.datas[:int(0.7 * len(self.datas))]
self.labels = self.labels[:int(0.7 * len(self.labels))]
elif mode == 'val':
self.datas = self.datas[int(0.7 * len(self.datas)):int(0.8 * len(self.datas))]
self.labels = self.labels[int(0.7 * len(self.datas)):int(0.8 * len(self.labels))]
else:
self.datas = self.datas[int(0.8 * len(self.datas)):]
self.labels = self.labels[int(0.8 * len(self.labels)):]
def load_csv(self):
data=[]
label=[]
for name in self.namelabel.keys():
for name2 in sorted(os.listdir(os.path.join(self.root, name))):
with open(os.path.join(self.root, name, name2)) as f:
reader = csv.reader(f)
for row in reader:
data.append(row)
label.append(self.namelabel[name])
data=np.array(data).astype(float)
label=np.array(label)
#这里我的数据是要分为10类,每一类有300组光谱,光谱的长度为623
data = data.reshape(10, 300,1, 623).swapaxes(0, 1).reshape(3000, 1, 623)
label = label.reshape(10, 300).swapaxes(0, 1).flatten()
label=list(label)
return data, label
def __len__(self):
return len(self.datas)
def __getitem__(self, idx):
data, label = self.datas[idx], self.labels[idx]
data=torch.Tensor(data)
label=torch.Tensor([label])
return data,label
if __name__=='__main__':
db=Raman_spectra()
loader=DataLoader(db,batch_size=128)
for data,label in loader:
print(data.shape,label.shape)
这里将数据按照7:1:2分为训练集,验证集和测试集。
运行效果:
128是批量大小,623是光谱长度。
模型搭建
这里神经网络的搭建可以随意搭建,只需要注意最终输出的节点数目和你的
两层卷积神经网络,第一层6个卷积核,第二层32个,卷积核大小为5,卷积步长是2。
一个全连接层。
import torch
from torch import nn
class cnn(nn.Module):
def __init__(self):
super(cnn, self).__init__()
#1X623
self.sq1=nn.Sequential(
nn.Conv1d(in_channels=1,out_channels=6,kernel_size=5,stride=2),
#4X623
nn.ReLU(),
)
self.sq2=nn.Sequential(
nn.Conv1d(in_channels=6,out_channels=32,kernel_size=5,stride=2),
nn.ReLU(),
#16X311
)
self.sq3=nn.Sequential(
#10对应分10类,这个4896需要计算一下,简单做法可以在forword里面print一下
nn.Linear(4896,10),
#交叉熵损失函数自带softmax,也可以不带
nn.Softmax()
)
def forward(self,X):
X=self.sq1(X)
X=self.sq2(X)
#将数据展平
X = X.view(X.size(0), -1)
#print(X.size())
X=self.sq3(X)
return X
if __name__=='__main__':
model=cnn()
tmp=torch.randn(6,1,623)
out=model(tmp)
print(out.shape)
运行效果:
模型训练
这个过程需要调节学习率和最大迭代次数来优化模型,也可以改变损失函数和优化器等。
from DataLoad import Raman_spectra
from torch.utils.data import DataLoader
import torch
from torch import nn,optim
from NN import cnn
#设置超参数方便调参
batch_size=100
learn_rate=0.0001
max_interation=1000
#利用dataloader导入数据
db=Raman_spectra()
loader=DataLoader(db,batch_size=batch_size,shuffle=True)
db_test=Raman_spectra(mode='val')
loader2=DataLoader(db_test,batch_size=128,shuffle=False)
#可以将数据放在GPU上训练,数据量小的话在CPU上训练也可以
device = torch.device( 'cuda:0' if torch.cuda.is_available() else"cpu")#"
model=cnn().to(device)
#weight_decay是防止过拟合的
optimizer=optim.Adam(model.parameters(),lr=learn_rate,weight_decay=0.002)
loss_fn=nn.CrossEntropyLoss().to(device)
def evluate_acc(model,loader):
total_crocret = 0
total_num = 0
for data2, label2 in loader:
data2, label2 = data2.to(device), label2.to(device)
pre = model(data2)
out = torch.argmax(pre,dim=1)
total_crocret +=torch.eq(out, label2.long().squeeze()).float().sum()
total_num += data2.size(0)
acc=total_crocret/total_num
return acc.item()
#best_epoch,best_acc来记录训练最好的批次和准确率
best_epoch,best_acc=0,0
for epoch in range(max_interation):
for data,label in loader:
data,label=data.to(device),label.to(device)
pred=model(data)
loss=loss_fn(pred,label.long().squeeze())
optimizer.zero_grad()
loss.backward()
optimizer.step()
val_acc=evluate_acc(model,loader2)
#early stop来保存最好的状态
if val_acc > best_acc:
best_epoch=epoch
best_acc=val_acc
torch.save(model.state_dict(),'best.mdl')
print('epoch:',epoch,'loss value:', loss.item(),'accuracy:',val_acc,'best epoch:',best_epoch,'best accuracy:',best_acc)
运行效果:
可以看出损失在降低,准确率在提升。
模型测试
from DataLoad import Raman_spectra
from torch.utils.data import DataLoader
import torch
from NN import cnn
db=Raman_spectra(mode='test')
loader=DataLoader(db,batch_size=128,shuffle=True)
def evluate_acc(model,loader):
total_crocret = 0
total_num = 0
for data2, label2 in loader:
data2, label2 = data2, label2
pre = model(data2)
out = torch.argmax(pre,dim=1)
total_crocret +=torch.eq(out, label2.long().squeeze()).float().sum()
total_num += data2.size(0)
acc=total_crocret/total_num
return acc.item()
model=cnn()
model.load_state_dict(torch.load('best.mdl'))
print('test accuracy:',evluate_acc(model,loader))
将测试集的数据用来测试模型的准确率,测试的是训练过程中保存的最佳状态。