赞
踩
.109cnn
import os import torch import torchvision import torchvision.transforms as transforms import matplotlib.pyplot as plt import numpy as np import sys import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from PIL import Image from torch.utils.data import Dataset import scipy.io as io import random from datetime import datetime
print(torch.cuda.is_available()) 确认版本是否匹配 os.environ["CUDA_VISIBLE_DEVICES"] = "0" device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 用cpu # print(torch.cuda.is_available())
class Net(nn.Module): 定义类(该类要继承nn.Module),在类中实现两个方法:1.初始化函数:实现在搭建网络过程中所需要实现的网络层结构。2.在forward函数中定义正向传播的过程。 def __init__(self): super(Net, self).__init__() super函数是继承父类的某个函数(理解为先执行父类的某个函数,再执行下面的语句) self.conv1 = nn.Conv2d(1, 32, 5, padding=2) 定义卷积层的函数为nn.Conv2d,参数顺序为:深度、卷积核的个数、卷积核的大小,通常情况下步距默认为1,此处运用了补0填充,保证前后图像尺寸相同,卷积处理的都是4维数据,批次处理,输入(4,1,64,64),意思是一次处理4组数据,通道为1,像素为64×64,第一次卷积就是(4,32,64,64),池化为(4,32,32,32),以此类推,4次卷积池化就是(4,256,4,4),卷积层的输出就是全连接层的输入。 self.conv2 = nn.Conv2d(32, 64, 3, padding=1) self.conv3 = nn.Conv2d(64, 128, 3, padding=1) self.conv4 = nn.Conv2d(128, 256, 3, padding=1) 一共定义四个卷积层 self.pool = nn.MaxPool2d(2) 定义下采样层的函数为nn.MaxPool2d,参数顺序为:卷积核大小,步距,padding self.fc1 = nn.Linear(4 * 4 * 256, 2560) 定义全连接层的函数为nn.Linear,全连接层的输入是一个一维的向量,因此需要将得到的特征矩阵给展平成一维向量 self.fc2 = nn.Linear(2560, 2) # self.fc2 = nn.Linear(2560, 4) 最后一个全连接层的输出是需要根据自己的分类类别进行更改的,这个2560是自己设置出来的
def forward(self, x): x代表输入的数据,就是一个tensor # print(x.size()) x = self.pool(F.relu(self.conv1(x))) 将输入经过第一个卷积层,再经过一个relu激活函数,再经过池化,每次的输入输出就是一次卷积池化得到的那个四维数组。 # print(x.size()) x = self.pool(F.relu(self.conv2(x))) # print(x.size()) x = self.pool(F.relu(self.conv3(x))) # print(x.size()) x = self.pool(F.relu(self.conv4(x))) # print(x.size()) x = x.view(-1, 4 * 4 * 256) output(4*4*256) view函数起到的作用是reshape,view的参数的是改变后的shape,-1代表第一个维度(batch)是自动推理的,第二个参数就是展平 # print(x.size()) x = F.relu(self.fc1(x)) output(2560) # print(x.size()) x = self.fc2(x) output(4) 没有接softmax的原因:理论上确实需要,但实际训练网络计算交叉熵时在其内部已经实现了一个更加高效的sofymax方法,所以不需要添加了(内置了) # print(x.size()) return x
下面是训练分类网络
PATH = "cnn_net.pth" net = Net() # net.load_state_dict(torch.load(PATH, map_location="cpu")) net = Net().to(device) 将所有最开始读取数据时的tensor变量copy一份到device所指定的CPU上去,之后的运算都在CPU上进行。 net.load_state_dict(torch.load(PATH)) print("load success")
criterion = nn.CrossEntropyLoss() 定义损失函数,其内部已经内置了softmax,多分类问题,用交叉熵损失函数 optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9) 定义优化器,参数一:所需要训练的参数(这里把网络中所有可训练的参数都进行训练);参数二:学习率
train_pics_dict = np.load("train_pics.npz") 加载上一个文件中已经保存的数据
train_labels_dict = np.load("train_labels.npz")
test_pics_dict = np.load("test_pics.npz")
test_labels_dict = np.load("test_labels.npz")
print(test_labels_dict["arr_" + str(3000)])
train_pics = [] 这里的空列表就是为了把前面储存再文件中的数据集拿出来,把数放进去
train_labels = []
test_pics = []
test_labels = []
for i in train_pics_dict.files: 增强数据,把数据变多
train_pics.append(train_pics_dict[i])
train_labels.append(int(train_labels_dict[i]))
for i in test_pics_dict.files: test_pics.append(test_pics_dict[i]) test_labels.append(int(test_labels_dict[i]))
print(test_labels) 结果全为0
class MyData(Dataset): 定义自己的数据集 def __init__(self, pics, labels): 初始化数据集 self.pics = pics self.labels = labels
def __getitem__(self, index): 返回编号index的数据
# print(index)
# print(len(self.pics))
assert index < len(self.pics)
return torch.Tensor([self.pics[index]]), self.labels[index]
def __len__(self):
return len(self.pics) 返回数据集总长度
def get_tensors(self): Tensors对模型以及模型参数的输入和输出进行编码 return torch.Tensor([self.pics]), torch.Tensor(self.labels)
def main(argv=None): classes = ["normal", "error"]
# 加载训练数据库 trainset = MyData(train_pics, train_labels) trainloader = torch.utils.data.DataLoader( trainset, batch_size=4, shuffle=True, num_workers=2 ) testset = MyData(test_pics, test_labels) testloader = torch.utils.data.DataLoader( testset, batch_size=4, shuffle=True, num_workers=2 )
batch_size:(数据类型 int)
每次输入数据的行数,默认为1。PyTorch训练模型时调用数据不是一行一行进行的(这样太没效率),而是一捆一捆来的。这里就是定义每次喂给神经网络多少行数据,如果设置成1,那就是一行一行进行(个人偏好,PyTorch默认设置是1)。
shuffle:(数据类型 bool)
洗牌。默认设置为False。在每次迭代训练时是否将数据洗牌,默认设置是False。将输入数据的顺序打乱,是为了使数据更有独立性,但如果数据是有序列特征的,就不要设置成True了。
num_workers:(数据类型 Int)
工作者数量,默认是0。使用多少个子进程来导入数据。设置为0,就是使用主进程来导入数据。注意:这个数字必须是大于等于0的,负数估计会出错。
for epoch in range(10): running_loss = 0 用来累加在训练过程中的损失 for i, data in enumerate(trainloader): 遍历训练集样本 enumerate() 函数返回数据和数据下标 inputs, labels = data 将数据分离成输入的图像和其所对应的标签 inputs = inputs.cuda() labels = labels.cuda() outputs = net(inputs) 正向传播得到输出 loss = criterion(outputs, labels) 用定义的函数计算损失,参数为:网络预测的值,输入图片对应的真实标签 optimizer.zero_grad() 梯度初始化为零,把loss关于weight的导数变成0 loss.backward() 将loss进行反向传播 optimizer.step() 进行参数的更新
#输出训练过程
running_loss += loss 每计算一个loss就将其追加到变量中 if i % 2000 == 1999: 每隔2000步打印一次数据 print( "epoch:", 输出第{}个epoch epoch, "[", i - 1999, ":", i, "] loss:", running_loss.item() / 2000, 输出目前的训练损失loss ) running_loss = 0 PATH = "cnn_net.pth" torch.save(net.state_dict(), PATH) print("save success")
训练分类网络代码结束,这就叫训练模型
下面是测试模型过程
correct = 0
total = 0
with torch.no_grad(): 在该模块下,所有计算得出的tensor的requires_grad都自动设置为False,当requires_grad设置为False时,反向传播时就不会自动求导了,因此大大节约了显存或者说内存
for inputs, labels in testloader:
inputs = inputs.cuda()
labels = labels.cuda()
outputs = net(inputs)
_, predicts = torch.max(outputs, 1)
total += 4
correct += (predicts == labels).sum().item()
print(correct / total * 100)
参考:
(1条消息) 深度学习之pytorch常用函数个人笔记_@会飞的毛毛虫的博客-CSDN博客(2条消息) 【PyTorch】从头搭建并训练一个神经网络模型(图像分类、CNN)_sin(豪)的博客-CSDN博客_搭建神经网络模型
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。