一维CNN拉曼光谱多分类(Python实现)

 本贴需要有一定的基础,具体需要预先学习的工具包如下:

  1. python的基本语法
  2. numpy
  3. 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))

将测试集的数据用来测试模型的准确率,测试的是训练过程中保存的最佳状态。

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值