)
一、神经网路工作原理前面关于深度学习的学习我们介绍了深度学习的运行环境以及使用食物识别的例子对于深度学习基于神经网络搭建的模型的优化。但是之前的介绍比较浅显尤其是对模型搭建的介绍现在重新温故一遍1.使用深度学习进行模型训练模型训练的目的使得参数尽可能的与真实的模型逼近具体做法1.首先给所有参数赋上随机值使用随机参数值来预测训练数据的样本2.其次计算预测值为yi真实值为y那么定义一个损失值loss损失值用于判断预测的结果和真实值的误差误差越小越好神经网络中单个神经元是用来模拟逻辑回归的本质上就是逻辑回归。神经网络可以做非线性映射——隐藏层2.神经网络的构造主要是看中间层的确定输入层的节点数与特征的维度匹配输出层的节点数与目标的维度匹配中间层的节点数没有什么特定的规则就目前来说。一般根据经验设置可以通过预先设定几个可选值通过切换这几个值来看整个模型的预测效果选择最为合适的在深度学习中损失函数用的最多的就是交叉熵损失函数和均方差损失函数3.损失函数都有哪些0-1损失函数二分类均方差损失平均绝对值损失交叉熵损失合页损失4.梯度下降其实就是神经网络工作过程中w不停更新的过程就是梯度下降。各个w在什么情况下使得loss最小一开始w的初始化随机给值求损失函数loss关于权重w的偏导数找到往loss最小的方向进行更新学习率就是决定往这个方向走多少这样的操作循环进行求偏导过程中会出现一些连乘因子梯度消失和梯度爆炸就和这些连乘因子有关梯度消失如果连乘因子大部分小于1最后乘积的结果可能趋于0也就是梯度消失后面的网络层的参数不发生改变。梯度爆炸如果连乘因子大部分大于1最后乘积可能趋于无穷。造成原因梯度反向传播中的连乘效果对于更普遍的梯度消失问题可以使用relutanh等代替sigmoid函数。特征图个数就等于卷积核个数cnn和nn不同的是权重w的个数要考虑特征图的尺寸得到的特征图对应的每个数值都是他的特征所以我们cnn转nn时输入神经元是要乘上特征图尺寸的。二、搭建网络5.cnn神经网络的分析前文https://blog.csdn.net/2201_75573294/article/details/156615599?fromshareblogdetailsharetypeblogdetailsharerId156615599sharereferPCsharesource2201_75573294sharefromfrom_linkhttps://blog.csdn.net/2201_75573294/article/details/156643341?fromshareblogdetailsharetypeblogdetailsharerId156643341sharereferPCsharesource2201_75573294sharefromfrom_linktorch其实就相当于pandas都是用来处理数据的。PIL库完整名字为pillow是图像处理库。Opencv包含大量的算法pillow就类似于电脑中的画图。和opencv的区别就在于opnecv能看到对应的像素点pillow就只进行简单的处理。这里我们使用的dataloader方法这方法是用来加载自己的的数据集的。import torch#搭建网络 from torch.utils.data import Dataset, DataLoader#处理图片数据集之前我们的数据都是用pandas和numpy import numpy as np from PIL import Image#画图板 from torchvision import transforms#对数据进行处理工具尤其是图片 import torch.nn as nn #torchaudio是用来处理语音的如果我们在这里传入的图片大小是256x256那数据处理最后我们图片要保证是256x256否则我们后面神经网络一些数值也是需要修改的。关于数据增强缓解深度学习中数据不足的场景。此外训练集如果对图片进行标准化或归一化那测试集也必须进行标准化或者归一化Normalize[0.485,0.456,0.406][0.229,0.224,0.225]图片标准化第一个中括号里面是均值第二个是标准差标准化在tensor后 。标准化原因如果图片亮度不同像素矩阵值是差别很大的标准化就是让他们值在固定的值范围内真对rgb分别做归一化 #我们图片实际上是没有变多的但因为我们多轮训练每次图片随机改变是不一样的所以达到了图片变多的效果。数据增强方法还有RandomRotation(45)随机旋转45度RandomVerticalFlip 随机垂直翻转RandomGrayscalep0.1灰度率数据预处理 data_transforms {#字典两个键值对 train: transforms.Compose([ # 数据增强 transforms.Resize([280, 280]), # 先把图片缩放到280x280 transforms.RandomCrop(256), # 随机裁剪到256x256 transforms.RandomHorizontalFlip(p0.5), # 50%概率水平翻转 transforms.RandomVerticalFlip(p0.5), transforms.ColorJitter(brightness0.1, contrast0.1), # 调整亮度#,saturation0.1,hue0.1 transforms.ToTensor(), # 转成张量 transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])#标准化 ]), valid: transforms.Compose([ transforms.Resize([256, 256]), # 测试时就直接缩放到256x256 transforms.ToTensor(), # 转成张量 transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), }__getitem__内置的有特殊功能的函数它赋予了对象索引访问和切片访问的能力。其实列表和字典等这种可以迭代的数据类型本身就属于一种类他们利用的就是__getitem__这个方法实现可被索引的。# 数据集读取食物图片 class food_dataset(Dataset):#继承父类Datase def __init__(self, file_path, transformNone): #类初始化把需要的数据加载到self共享空间中 self.file_path file_path#创建共享空间 self.imgs []#存图片路径 self.labels []#存图片的标签结果 self.transform transform with open(self.file_path) as f: samples [x.strip().split() for x in f.readlines()] for img_path, label in samples: self.imgs.append(img_path) self.labels.append(label) def __len__(self): # 返回数据集大小 return len(self.imgs) def __getitem__(self, idx): #关键通过索引获取每一个图片数据和标签 image Image.open(self.imgs[idx])#读取到图片数据还不是张量形式 if self.transform:#判断是否是pil图像数据转化为张量 image self.transform(image)#图像处理为张量 #思考这里的transform是类还是对象 label self.labels[idx]#label还不是张量 label int(label) label torch.from_numpy(np.array(label, dtypenp.int64))#label也转化为张量数据 return image, label#元祖形式返回输入图片256x256nn开头的都是网络模型层关于神经网络的搭建具体项目参数都是不同的这是需要我们自己去尝试找到让模型最优的参数但是我们需要注意nn开头是调用了函数中的激活函数还是nn直接使用激活函数函数中的池化还是nn直接调用池化神经网络中我们需要的层所以如果使用函数中的激活函数或者函数中的池化就会报错。nn.ReLU()和nn.functional.Relu()是不一样的这里我们卷积核大小步长和填充设置为512是有原因的512是一个很经典的设置组合例如输入数据为32x32x3的图像用10个5x5x3的卷积核来进行操作步长为1边界0填充为2最终输出结果为32-52x2/1132所以输出的特征图为10个32x32尺寸的特征图个数就等于卷积核个数这里无论输入尺寸为多少使用512设置特征图的输出尺寸就和输入尺寸是一样的# 自定义cnn模型 class CNN(nn.Module): def __init__(self): super(CNN, self).__init__() self.conv1 nn.Sequential( nn.Conv2d( in_channels3,#图像通道数1表示为灰度图 out_channels16,#要得到多少个特征图也就是卷积核的个数 kernel_size5,#卷积核大小,5X5 stride1,#步长为1 padding2,#填充为2输出特征图16*256*256 ), nn.ReLU(),#激活函数层矩阵中每个值做一个非线性映射不改变还是16*256*256 nn.MaxPool2d(kernel_size2), #也有1d3d的对数据进行池化压缩压缩一半16*128*128 ) self.conv2 nn.Sequential(#输入16*128*128 nn.Conv2d(16, 32, 5, 1, 2),#32*128*128 nn.ReLU(), nn.Conv2d(32, 32, 5, 1, 2),#32*128*128 nn.ReLU(), nn.MaxPool2d(2),#32*64*64 ) self.conv3 nn.Sequential(#32*64*64 nn.Conv2d(32, 128, 5, 1, 2),#128*64*64 nn.ReLU(), ) self.dropout nn.Dropout(0.3) self.out nn.Linear(128 * 64 * 64, 20)#全连接定义一个神经网络层把数据展开为一维 #其实这里我们可以多写几层因为从128*64*64到20会很突然 def forward(self, x):#负责把模型串起来真正的数据 x self.conv1(x) x self.conv2(x) x self.conv3(x) x x.view(x.size(0), -1)#view改变维度这里x.size(0)64 output self.out(x)#64*20个结果 return output训练函数和测试函数# 训练函数 def train(dataloader, model, loss_fn, optimizer): model.train() batch_size_num 1 # 统计训练的batch数量 for X, y in dataloader: X, y X.to(device), y.to(device) # 把训练数据集和标签传入cpu或GPU pred model.forward(X) # 前向计算 loss loss_fn(pred, y) # 计算损失 optimizer.zero_grad() # 梯度清零 loss.backward() # 反向传播 optimizer.step() # 更新参数 loss_value loss.item() if batch_size_num %10: print(floss:{loss_value:7f} [number:{batch_size_num}]) batch_size_num 1 #with open () as f:上下文管理器 # 测试函数 def test(dataloader, model, loss_fn): size len(dataloader.dataset)#图片张数 num_batchs len(dataloader)#打包的批次 model.eval()#w进入测试模式没有再被修改的权限 test_loss, correct 0, 0 with torch.no_grad():#上下文管理器关闭梯度计算 for X, y in dataloader: X, y X.to(device), y.to(device) pred model.forward(X) test_loss loss_fn(pred, y).item() correct (pred.argmax(1) y).type(torch.float).sum().item() # 标量 test_loss / num_batchs correct / size accuracy 100 * correct print(fTest result: \n Accuracy :{(accuracy)}%,Avg loss:{test_loss}) return accuracy上面是我们训练模型需要准备的函数、类等……下面就是我们主要进行的过程dataloader是一个类对文件进行打包。和之前前文深度学习不同的是我用的是比较大的数据集数据多的情况下正确率也会提高不少。#训练集和预测集的路径,把数据做好准备 training_data food_dataset(file_pathr.\trainda.txt, transformdata_transforms[train]) test_data food_dataset(file_pathr.\testda.txt, transformdata_transforms[valid]) #打包数据dataloader是一个类这里这里只是把包存在类中 train_dataloader DataLoader(training_data, batch_size64, shuffleTrue)#64个批次 #打包负责发给gpu一个包64张无gpu这个数值要写小一点图片也不是按照顺序取的 test_dataloader DataLoader(test_data, batch_size64, shuffleTrue)这里我们定义deviceif语句识别系统设备也就是我们之前搭建深度学习学习环境下载的torch的版本cuda就是识别为gpucpu就识别为cpu这样一个规律mps是苹果系统的gpu。可以理解为这里device字符串是一个遥控器按钮虽然我们赋值给device的是一个字符串但由于torch底层有封装的代码所以这些字符串是能对应到具体设备的。CNN是一个类model CNN()是定义一个类的对象todevice就是把这个对象获得的数据等信息转移到device对应的设备上进行计算。# 设备设置和模型初始化 device cuda if torch.cuda.is_available() else mps if torch.backends.mps.is_available() else cpu model CNN().to(device) print(model)loss用来计算真实值和预测值之间的误差。优化器是用来提升我们模型正确率的参数中lr是学习率。调度器是用来调整学习率的没有调度器我们每一轮训练学习率都是在优化器中设置的那个值有调度器学习率就是动态的能更好的训练模型。然后就可以进行训练和测试也就是train(train_dataloader, model, loss_fn, optimizer)current_acc test(test_dataloader, model, loss_fn)这两句但因为训练一次效果不一定会很好所以我们就用epochs循环多进行几次训练并保存下最优模型。最优模型就是根据正确率最高这里预测testtest_dataloader,model,loss_fn放到循环里面测试函数中有一个with语句是上下文管理器上下文管理器会根据上下文灵活开关w修改权限。# 损失函数 loss_fn nn.CrossEntropyLoss()#用于计算真实值和预测值之间的误差 # 优化器 # optimizer torch.optim.SGD(model.parameters(),lr0.001)#尝试不同的值可以确保最后的准确率 optimizer torch.optim.Adam(model.parameters(), lr0.0001) #学习率调度器 schedulertorch.optim.lr_scheduler.StepLR(optimizer,step_size5,gamma0.5) # train(train_dataloader, model, loss_fn, optimizer) # current_acc test(test_dataloader, model, loss_fn) # 训练循环 best_acc 0 epochs 20 for t in range(epochs): print(fEpoch{t 1}\n------) train(train_dataloader, model, loss_fn, optimizer) scheduler.step()#使用调度器就要加上这个 current_acc test(test_dataloader, model, loss_fn) if current_acc best_acc: best_acc current_acc torch.save(model.state_dict(), cnn_best_model_da.pth) print(fcnn最佳模型准确率{best_acc:.2f}%) print(Dnoe!) print(f最佳模型准确率{best_acc:.2f}%)6.getitem的演示能对输入的内容进行索引class USE_getitem(): def __init__(self,text): self.texttext def __getitem__(self, index): resultself.text[index].upper() return result def __len__(self): return len(self.text) p USE_getitem(pytorch) print(p[0],p[1]) print(len(p))class fun(): def __init__(self,text): self.texttext def __getitem__(self,index): resultself.text[index] return result def __len__(self): return len(self.text) afun(1,2,3,4,5,20,30,40,50,60) print(a[5]) print(len(a))