深度学习模型:Pytorch搭建ResNet、DenseNet网络,完成一维数据分类任务

2023.7.17

DenseNet和ResNet都是深度学习中常用的网络结构,它们各有优缺点。

DenseNet的优点是可以充分利用网络中的信息,因为每个层都可以接收来自前面所有层的信息。这种密集连接的结构可以提高网络的准确性,减少过拟合的风险。此外,DenseNet的参数量比ResNet少,训练速度更快。

ResNet的优点是可以解决深度网络中的梯度消失问题,使得网络可以更深更复杂。ResNet的残差结构可以让信息直接从前面的层传递到后面的层,避免了信息的丢失,提高了网络的准确性。此外,ResNet的结构简单,易于理解和实现。

DenseNet和ResNet的缺点也有所不同。DenseNet的缺点是需要更多的内存和计算资源,因为每个层都需要接收来自前面所有层的信息。此外,DenseNet的结构较为复杂,不易于理解和实现。

ResNet的缺点是在某些情况下可能会出现过拟合的问题,因为残差结构可以让信息直接从前面的层传递到后面的层,可能会导致网络过于复杂,难以泛化。

一、数据集的处理:

训练集、验证集、测试集的划分:

数据会被整理为.txt:(例如形成的trian.txt)

                最后会分割为trian_data.txt和train_labels.txt两个文件 

import os
import numpy as np
import random
import math



def normalization(data):  # 归一化:均值0,方差1
    data = (data - data.mean()) / data.std()
    return data


def random_rowl(data):  # 把行的顺序随机排列
    idx = np.arange(data.shape[0])
    np.random.shuffle(idx)
    data = data[idx[0:]]
    return data


def getfilelist(path):  # 读取文件夹下所有txt文件
    filelist = []
    for filename in os.listdir(path):
        if os.path.splitext(filename)[1] == '.txt':
            filelist.append(filename)
    random.shuffle(filelist)  # 随机打乱文件列表里的顺序
    return filelist


path = '第一类数据的文件夹子路径','第二类数据的文件夹子路径','第三类数据的文件夹子路径'

sort_num = 3  # 一共多少类?

for i in range(sort_num):  # 个数修改为路径的数目,与文件夹个数相同
    fileName = "{}/".format(path[i])
    files = getfilelist(fileName)
    # files=getfilelist(path[i]+'/')
    a = len(files)
    print(path[i], a)
    data = np.loadtxt(fileName + files[0])[:, 1]
    data = normalization(data)
    for j in range(1, a):
        data1 = np.loadtxt(fileName + '/' + files[j])[:, 1]
        data1 = normalization(data1)
        data = np.c_[data, data1]
    data = data.T

    # 加标签
    label = np.zeros((len(data), sort_num))  # 标签也改为分类的数目,与文件夹个数相同

    for m in range(len(label)):
        label[m, i] = 1
    data = np.c_[data, label]
    data = random_rowl(data)

    t = math.floor(len(data) * 0.7)

    v = math.floor(len(data) * 0.2)
    train = data[:t, :]
    val = data[t:(t + v), :]
    test = data[(t + v):, :]

    np.savetxt(path[i] + '_train.txt', train, fmt='%.6f')
    np.savetxt(path[i] + '_val.txt', val, fmt='%.6f')
    np.savetxt(path[i] + '_test.txt', test, fmt='%.6f')

train = np.loadtxt(path[0] + '_train.txt')
val = np.loadtxt(path[0] + '_val.txt')
test = np.loadtxt(path[0] + '_test.txt')

for i in range(1, sort_num):  # 需要修改为与分类个数相同,最后一个数与文件夹
    train1 = np.loadtxt(path[i] + '_train.txt')
    val1 = np.loadtxt(path[i] + '_val.txt')
    test1 = np.loadtxt(path[i] + '_test.txt')

    train = random_rowl(np.r_[train, train1])
    val = random_rowl(np.r_[val, val1])
    test = random_rowl(np.r_[test, test1])

np.savetxt('train.txt', train, fmt='%.6f') # 划分训练集
np.savetxt('val.txt', val, fmt='%.6f')  # 划分验证集
np.savetxt('test.txt', test, fmt='%.6f')  # 划分测试集


# 从train.txt、val.txt、test.txt中分别获取数据和标签

class_num = sort_num  # 分类的类数 

train_labels = np.loadtxt('./train.txt')[:, -class_num:]
test_labels = np.loadtxt('./test.txt')[:, -class_num:]
val_labels = np.loadtxt('./val.txt')[:, -class_num:]

train_data = np.loadtxt('./train.txt')[:, :-class_num]
test_data = np.loadtxt('./test.txt')[:, :-class_num]
val_data = np.loadtxt('./val.txt')[:, :-class_num]

np.savetxt('train_data.txt', train_data, fmt='%.6f')
np.savetxt('val_data.txt', val_data, fmt='%.6f')
np.savetxt('test_data.txt', test_data, fmt='%.6f')

np.savetxt('train_labels.txt', train_labels, fmt='%d')
np.savetxt('val_labels.txt', val_labels, fmt='%d')
np.savetxt('test_labels.txt', test_labels, fmt='%d')

二、数据的训练:

ResNet:

import numpy as np
import torch.optim as optim
import torch.nn as nn

import torch
from torch.utils.data import DataLoader, Dataset


class Bottlrneck(torch.nn.Module):
    def __init__(self, In_channel, Med_channel, Out_channel, downsample=False):
        super(Bottlrneck, self).__init__()
        self.stride = 1
        if downsample == True:
            self.stride = 2

        self.layer = torch.nn.Sequential(
            torch.nn.Conv1d(In_channel, Med_channel, 1, self.stride),
            torch.nn.BatchNorm1d(Med_channel),
            torch.nn.ReLU(),
            torch.nn.Conv1d(Med_channel, Med_channel, 3, padding=1),
            torch.nn.BatchNorm1d(Med_channel),
            torch.nn.ReLU(),
            torch.nn.Conv1d(Med_channel, Out_channel, 1),
            torch.nn.BatchNorm1d(Out_channel),
            torch.nn.ReLU(),
        )

        if In_channel != Out_channel:
            self.res_layer = torch.nn.Conv1d(In_channel, Out_channel, 1, self.stride)
        else:
            self.res_layer = None

    def forward(self, x):
        if self.res_layer is not None:
            residual = self.res_layer(x)
        else:
            residual = x
        return self.layer(x) + residual


class ResNet(torch.nn.Module):
    def __init__(self, in_channels=2, classes=6):
        super(ResNet, self).__init__()
        self.features = torch.nn.Sequential(
            torch.nn.Conv1d(in_channels, 64, kernel_size=7, stride=2, padding=3),
            torch.nn.MaxPool1d(3, 2, 1),

            Bottlrneck(64, 64, 256, False),
            Bottlrneck(256, 64, 256, False),
            Bottlrneck(256, 64, 256, False),
            #
            Bottlrneck(256, 128, 512, True),
            Bottlrneck(512, 128, 512, False),
            Bottlrneck(512, 128, 512, False),
            Bottlrneck(512, 128, 512, False),
            #
            Bottlrneck(512, 256, 1024, True),
            Bottlrneck(1024, 256, 1024, False),
            Bottlrneck(1024, 256, 1024, False),
            Bottlrneck(1024, 256, 1024, False),
            Bottlrneck(1024, 256, 1024, False),
            Bottlrneck(1024, 256, 1024, False),
            #
            Bottlrneck(1024, 512, 2048, True),
            Bottlrneck(2048, 512, 2048, False),
            Bottlrneck(2048, 512, 2048, False),

            torch.nn.AdaptiveAvgPool1d(1)
        )
        self.classifer = torch.nn.Sequential(
            torch.nn.Linear(2048, classes)
        )

    def forward(self, x):
        x = torch.Tensor.view(x, (-1, 2, 511))
        x = self.features(x)
        x = x.view(-1, 2048)
        x = self.classifer(x)
        return x


class MyDataset(Dataset):
    def __init__(self, raman_dir, label_file):
        self.raman_dir = np.loadtxt(raman_dir)
        self.label_file = np.loadtxt(label_file)
        self.raman_data = []
        self.label_list = []
        for index in self.raman_dir:
            self.raman_data.append(index)

        for index in self.label_file:
            self.label_list.append(index)

    def __getitem__(self, idx):
        raman = torch.Tensor(self.raman_data[idx])
        label = torch.Tensor(self.label_list[idx])
        label = np.argmax(label)

        return raman, label

    def __len__(self):
        # 获取数据集的长度
        return len(self.label_list)


if __name__ == '__main__':
    # 准备数据集
    train_data = './train_data.txt'
    val_data = './val_data.txt'
    
    # 标签
    train_label = './train_labels.txt'
    val_label = './val_labels.txt'

    # 创建数据加载器
    batch_size = 128
    # 训练集输入
    train_dataset = MyDataset(train_data, train_label)
    train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
    # 测试集输入
    test_dataset = MyDataset(test_data, test_label)
    test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=True)
    # 验证集输入
    val_dataset = MyDataset(val_data, val_label)
    val_dataloader = DataLoader(val_dataset, batch_size=batch_size, shuffle=True)

    train_data_size = len(train_dataset)
    val_data_size = len(val_dataset)

    # 创建网络模型
    class_num = 6
    test_data_length = 600
    ResNetOutput = ResNet(in_channels=2, classes=class_num).cuda()

    # 定义损失函数
    loss_fn = nn.CrossEntropyLoss().cuda()

    # 定义优化器
    learning_rate = 0.00001
    optimizer = optim.Adam(ResNetOutput.parameters(), lr=learning_rate)

    # 记录验证的次数
    total_train_step = 0
    total_val_step = 0

    # 训练
    epoch = 100
    acc_list = np.zeros(epoch)
    print("{0:-^27}".format('Train_Model'))
    for i in range(epoch):
        print("----------epoch={}----------".format(i + 1))
        ResNetOutput.train()
        for data in train_dataloader:  # data 是batch大小
            raman_train_data, t_labels = data
            raman_train_data = raman_train_data.cuda()
            t_labels = t_labels.cuda()
            output = ResNetOutput(raman_train_data)
            loss = loss_fn(output, t_labels)

            # 优化器优化模型
            optimizer.zero_grad()  # 梯度清零
            loss.backward()  # 反向传播
            optimizer.step()  # 优化更新参数

            total_train_step = total_train_step + 1
            print("train_times:{},Loss:{}".format(total_train_step, loss.item()))

        # 测试步骤开始
        ResNetOutput.eval()
        total_val_loss = 0
        total_accuracy = 0
        with torch.no_grad():  # 测试的时候不需要对梯度进行调整,所以梯度设置不调整
            for data in val_dataloader:
                raman_val_data, v_labels = data
                raman_val_data = raman_val_data.cuda()
                v_labels = v_labels.cuda()
                outputs = ResNetOutput(raman_val_data)
                loss = loss_fn(outputs, v_labels)
                total_val_loss = total_val_loss + loss.item()  # 计算损失值的和
                accuracy = 0

                for j in v_labels:

                    if outputs.argmax(1)[j] == v_labels[j]:
                        accuracy = accuracy + 1

                # accuracy = (outputs.argmax(1) == v_labels).sum()  # 计算一个数据的精确度
                total_accuracy = total_accuracy + accuracy

        val_acc = float(total_accuracy / 1440) * 100
        acc_list[i] = val_acc
        print('the_classification_is_correct :', total_accuracy)  # 正确分类的个数
        print("val_Loss:{}".format(total_val_loss))
        print("val_acc:{}".format(float(total_accuracy / 1440) * 100), '%')

        total_val_step += 1
        torch.save(ResNetOutput, "ResNet_{}.pth".format(i))
        # torch.save(ResNetOutput.state_dict(), "ResNet_{}.pth".format(i))
        print("{0:-^24}".format('Model_Save'), '\n')
        print('val_max=', max(acc_list), '%')

注意!在代码的75行:

x = torch.Tensor.view(x, (-1, 2, 511))  # 511的位置要根据自己的数据集形状调整

DenseNet:

import numpy as np
import torch.optim as optim
import torch.nn as nn

import torch
from torch.utils.data import DataLoader, Dataset


class DenseLayer(torch.nn.Module):
    def __init__(self, in_channels, middle_channels=128, out_channels=32):
        super(DenseLayer, self).__init__()
        self.layer = torch.nn.Sequential(
            torch.nn.BatchNorm1d(in_channels),
            torch.nn.ReLU(inplace=True),
            torch.nn.Conv1d(in_channels, middle_channels, 1),
            torch.nn.BatchNorm1d(middle_channels),
            torch.nn.ReLU(inplace=True),
            torch.nn.Conv1d(middle_channels, out_channels, 3, padding=1)
        )

    def forward(self, x):
        return torch.cat([x, self.layer(x)], dim=1)


class DenseBlock(torch.nn.Sequential):
    def __init__(self, layer_num, growth_rate, in_channels, middele_channels=128):
        super(DenseBlock, self).__init__()
        for i in range(layer_num):
            layer = DenseLayer(in_channels + i * growth_rate, middele_channels, growth_rate)
            self.add_module('denselayer%d' % (i), layer)


class Transition(torch.nn.Sequential):
    def __init__(self, channels):
        super(Transition, self).__init__()
        self.add_module('norm', torch.nn.BatchNorm1d(channels))
        self.add_module('relu', torch.nn.ReLU(inplace=True))
        self.add_module('conv', torch.nn.Conv1d(channels, channels // 2, 3, padding=1))
        self.add_module('Avgpool', torch.nn.AvgPool1d(2))


class DenseNet(torch.nn.Module):
    def __init__(self, layer_num=(6, 12, 24, 16), growth_rate=32, init_features=64, in_channels=1, middele_channels=128,
                 classes=6):
        super(DenseNet, self).__init__()
        self.feature_channel_num = init_features
        self.conv = torch.nn.Conv1d(in_channels, self.feature_channel_num, 7, 2, 3)
        self.norm = torch.nn.BatchNorm1d(self.feature_channel_num)
        self.relu = torch.nn.ReLU()
        self.maxpool = torch.nn.MaxPool1d(3, 2, 1)
        # self.attention = SpatialAttention(64)  # 空间注意力机制

        self.DenseBlock1 = DenseBlock(layer_num[0], growth_rate, self.feature_channel_num, middele_channels)
        self.feature_channel_num = self.feature_channel_num + layer_num[0] * growth_rate
        self.Transition1 = Transition(self.feature_channel_num)

        self.DenseBlock2 = DenseBlock(layer_num[1], growth_rate, self.feature_channel_num // 2, middele_channels)
        self.feature_channel_num = self.feature_channel_num // 2 + layer_num[1] * growth_rate
        self.Transition2 = Transition(self.feature_channel_num)

        self.DenseBlock3 = DenseBlock(layer_num[2], growth_rate, self.feature_channel_num // 2, middele_channels)
        self.feature_channel_num = self.feature_channel_num // 2 + layer_num[2] * growth_rate
        self.Transition3 = Transition(self.feature_channel_num)

        self.DenseBlock4 = DenseBlock(layer_num[3], growth_rate, self.feature_channel_num // 2, middele_channels)
        self.feature_channel_num = self.feature_channel_num // 2 + layer_num[3] * growth_rate

        self.avgpool = torch.nn.AdaptiveAvgPool1d(1)

        self.classifer = torch.nn.Sequential(
            torch.nn.Linear(self.feature_channel_num, self.feature_channel_num // 2),
            torch.nn.ReLU(),
            torch.nn.Dropout(0.5),
            torch.nn.Linear(self.feature_channel_num // 2, classes),

        )

    def forward(self, x):
        x = torch.Tensor.view(x, (-1, 1, 1022))  # 第一个参数是batch_size
        x = x.resize_as_(x.to(torch.float32))
        x = self.conv(x)
        x = self.norm(x)  # 正则化
        x = self.relu(x)
        x = self.maxpool(x)
        x = self.DenseBlock1(x)
        x = self.Transition1(x)
        x = self.DenseBlock2(x)
        x = self.Transition2(x)
        x = self.DenseBlock3(x)
        x = self.Transition3(x)
        x = self.DenseBlock4(x)
        x = self.avgpool(x)
        x = x.view(-1, self.feature_channel_num)
        x = self.classifer(x)

        return x


class MyDataset(Dataset):  # 利用Pytorch的内置函数加载数据
    def __init__(self, raman_dir, label_file):
        self.raman_dir = np.loadtxt(raman_dir)
        self.label_file = np.loadtxt(label_file)
        self.raman_data = []
        self.label_list = []
        for index in self.raman_dir:
            self.raman_data.append(index)

        for index in self.label_file:
            self.label_list.append(index)

    def __getitem__(self, idx):
        raman = torch.Tensor(self.raman_data[idx])
        label = torch.Tensor(self.label_list[idx])
        label = np.argmax(label)

        return raman, label

    def __len__(self):
        # 获取数据集的长度
        return len(self.label_list)


if __name__ == '__main__':
    # 准备数据集
    train_data = './train_data.txt'
    val_data = './val_data.txt'
    

    # 标签
    train_label = './train_labels.txt'

    val_label = './val_labels.txt'

    # 数据长度
    test_data_length = 600
    val_data_length = 1440

    # 分类的类别
    class_num = 6  # 注意调整58行的函数中的class(分类类别)

    # 学习率
    learning_rate = 0.00001
    # 批处理大小
    batch_size = 128

    # 数据加载器
    train_dataset = MyDataset(train_data, train_label)
    train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)

    test_dataset = MyDataset(test_data, test_label)
    test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=True)

    val_dataset = MyDataset(val_data, val_label)
    val_dataloader = DataLoader(val_dataset, batch_size=batch_size, shuffle=True)

    train_data_size = len(train_dataset)
    val_data_size = len(val_dataset)

    # 创建网络模型
    DenseNetOutput = DenseNet().cuda()  # .Cuda()数据是指放到GPU上

    # 定义损失函数
    loss_fn = nn.CrossEntropyLoss().cuda()  # 交叉熵函数

    # 定义优化器
    optimizer = optim.Adam(DenseNetOutput.parameters(), lr=learning_rate)

    # 记录验证的次数
    total_train_step = 0
    total_val_step = 0
    writer = SummaryWriter("logs_train")  # 记录训练的权重

    # 训练
    epoch = 30  #
    acc_list = np.zeros(epoch)
    print("{0:-^27}".format('Train_Model'))
    for i in range(epoch):
        print("----------epoch={}----------".format(i + 1))
        DenseNetOutput.train()
        for data in train_dataloader:  # data 是batch大小
            raman_train_data, t_labels = data
            raman_train_data = raman_train_data.cuda()
            t_labels = t_labels.cuda()
            output = DenseNetOutput(raman_train_data)
            loss = loss_fn(output, t_labels)

            # 优化器优化模型
            optimizer.zero_grad()  # 梯度清零
            loss.backward()  # 反向传播
            optimizer.step()  # 优化更新参数

            total_train_step = total_train_step + 1
            print("train_times:{},Loss:{}".format(total_train_step, loss.item()))

        # 测试步骤开始
        DenseNetOutput.eval()
        total_val_loss = 0
        total_accuracy = 0
        with torch.no_grad():  # 测试的时候不需要对梯度进行调整,所以梯度设置不调整
            for data in val_dataloader:
                raman_val_data, v_labels = data
                raman_val_data = raman_val_data.cuda()
                v_labels = v_labels.cuda()
                outputs = DenseNetOutput(raman_val_data)
                loss = loss_fn(outputs, v_labels)
                total_val_loss = total_val_loss + loss.item()  # 计算损失值的和
                accuracy = 0

                for j in v_labels:  # 计算精确度的和

                    if outputs.argmax(1)[j] == v_labels[j]:
                        accuracy = accuracy + 1

                # accuracy = (outputs.argmax(1) == v_labels).sum()  # 计算一个数据的精确度
                total_accuracy = total_accuracy + accuracy

        val_acc = float(total_accuracy / val_data_size) * 100
        acc_list[i] = val_acc  # 记录验证集的正确率
        print('the_classification_is_correct :', total_accuracy, val_data_length)
        print("val_Loss:{}".format(total_val_loss))
        print("val_acc:{}".format(val_acc), '%')
        
        total_val_step += 1
        torch.save(DenseNetOutput, "DenseNet_{}.pth".format(i + 1))
        print("{0:-^24}".format('Model_Saved'), '\n')

        print('val_max=', max(acc_list), '%')  # 验证集的最高正确率

注意!在代码的93行:

x = torch.Tensor.view(x, (-1, 1, 1022))  # 1022的位置要根据自己的数据集大小取调整 

测试代码:

import torch
import numpy as np
from ResNet import Bottlrneck, ResNet

# from DenseNet_SpatialAttention import DenseNet, DenseLayer, DenseBlock

device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')  # 判断是否有GPU

test_data = np.loadtxt('./test_data.txt')  # 测试集的路径

model = ResNet().to(device)
model.load_state_dict(torch.load('ResNet_100.pth'))  # 加载模型

# model = DenseNet().to(device)
# model.load_state_dict(torch.load('DenseNet_100.pth'))  # 加载模型

test_length = test_data.shape[0]

for i in range(test_length):
    td = torch.from_numpy(test_data[i]).float().to(device)
    Predict_output = model(td).to(device)

    _, predicted = Predict_output.max(1)
    pred_type = predicted.item()
    print('pred_type:', pred_type)

  • 7
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 16
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值