深度学习的补充

关于前面关于深度学习的学习我们介绍了深度学习的运行环境,以及使用食物识别的例子对于深度学习基于神经网络搭建的模型的优化。这次补充有助于更好地理解深度学习。

1.使用深度学习进行模型训练

  • 模型训练的目的:使得参数尽可能的与真实的模型逼近
  • 具体做法:1.首先给所有参数赋上随机值,使用随机参数值来预测训练数据的样本;2.其次计算预测值为yi,真实值为y,那么定义一个损失值loss,损失值用于判断预测的结果和真实值的误差,误差越小越好

神经网络中,单个神经元是用来模拟逻辑回归的,本质上就是逻辑回归。

神经网络可以做非线性映射------隐藏层

2.神经网络的构造(主要是看中间层的确定)

  • 输入层的节点数:与特征的维度匹配
  • 输出层的节点数:与目标的维度匹配
  • 中间层的节点数:没有什么特定的规则,就目前来说。一般根据经验设置,可以通过预先设定几个可选值,通过切换这几个值来看整个模型的预测效果,选择最为合适的

在深度学习中损失函数用的最多的就是交叉熵损失函数和均方差损失函数

3.损失函数都有哪些?

  • 0-1损失函数(二分类)
  • 均方差损失
  • 平均绝对值损失
  • 交叉熵损失
  • 合页损失

4.梯度下降

其实就是神经网络工作过程中,w不停更新的过程就是梯度下降。

各个w在什么情况下使得loss最小,一开始w的初始化随机给值,求损失函数loss关于权重w的偏导数,找到往loss最小的方向进行更新,学习率就是决定往这个方向走多少,这样的操作循环进行

求偏导过程中会出现一些连乘因子,梯度消失和梯度爆炸就和这些连乘因子有关:

  • 梯度消失:如果连乘因子大部分小于1,最后乘积的结果可能趋于0,也就是梯度消失,后面的网络层的参数不发生改变。
  • 梯度爆炸:如果连乘因子大部分大于1,最后乘积可能趋于无穷。

造成原因:梯度反向传播中的连乘效果,对于更普遍的梯度消失问题,可以使用relu,tanh等代替sigmoid函数。

  • 特征图个数就等于卷积核个数
  • cnn和nn不同的是,权重w的个数要考虑特征图的尺寸
  • 得到的特征图对应的每个数值都是他的特征,所以我们cnn转nn时,输入神经元是要乘上特征图尺寸的。

5.cnn神经网络的分析

前文:https://blog.csdn.net/2201_75573294/article/details/156615599?fromshare=blogdetail&sharetype=blogdetail&sharerId=156615599&sharerefer=PC&sharesource=2201_75573294&sharefrom=from_link

https://blog.csdn.net/2201_75573294/article/details/156643341?fromshare=blogdetail&sharetype=blogdetail&sharerId=156643341&sharerefer=PC&sharesource=2201_75573294&sharefrom=from_link

torch,其实就相当于pandas,都是用来处理数据的。

PIL库,完整名字为pillow,是图像处理库。Opencv包含大量的算法,pillow就类似于电脑中的画图。和opencv的区别就在于opnecv能看到对应的像素点,pillow就只进行简单的处理。

python 复制代码
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#随机垂直翻转,
  • RandomGrayscale(p=0.1)灰度率
python 复制代码
'''数据预处理'''
data_transforms = {#字典,两个键值对
    'train':
        transforms.Compose([  # 数据增强
            transforms.Resize([280, 280]),  # 先把图片缩放到280x280
            transforms.RandomCrop(256),  # 随机裁剪到256x256
            transforms.RandomHorizontalFlip(p=0.5),  # 50%概率水平翻转
            transforms.RandomVerticalFlip(p=0.5),
            transforms.ColorJitter(brightness=0.1, contrast=0.1),  # 调整亮度#,saturation=0.1,hue=0.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__这个方法实现可被索引的。

python 复制代码
# 数据集,读取食物图片
class food_dataset(Dataset):#继承父类Datase
    def __init__(self, file_path, transform=None): #类初始化,把需要的数据加载到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)#图像处理为张量

        label = self.labels[idx]#label还不是张量
        label = int(label)
        label = torch.from_numpy(np.array(label, dtype=np.int64))#label也转化为张量数据
        return image, label#元祖形式返回

dataloader,是一个类,对文件进行打包。

python 复制代码
#训练集和预测集的路径,把数据做好准备
training_data = food_dataset(file_path=r'.\trainda.txt', transform=data_transforms['train'])
test_data = food_dataset(file_path=r'.\testda.txt', transform=data_transforms['valid'])
#打包数据,dataloader是一个类,这里这里只是把包存在类中
train_dataloader = DataLoader(training_data, batch_size=64, shuffle=True)#64个批次
#打包,负责发给gpu,一个包64张,无gpu这个数值要写小一点,图片也不是按照顺序取的
test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True)

输入图片256x256

python 复制代码
# 自定义cnn模型
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(
                in_channels=3,#图像通道数,1表示为灰度图
                out_channels=16,#要得到多少个特征图,也就是卷积核的个数
                kernel_size=5,#卷积核大小,5X5
                stride=1,#步长为1
                padding=2,#填充为2,输出特征图16*256*256
            ),
            nn.ReLU(),#激活函数,矩阵中每个值做一个非线性映射,不改变还是16*256*256
            nn.MaxPool2d(kernel_size=2),
            #也有1d,3d的,对数据进行池化压缩,压缩一半,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)#全连接,定义一个神经网络层,把数据展开为一维

    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

这里我们卷积核大小,步长和填充设置为512是有原因的,512是一个很经典的设置组合

例如,输入数据为32x32x3的图像,用10个5x5x3的卷积核来进行操作,步长为1,边界0填充为2,最终输出结果为?

(32-5+2x2)/1+1=32,所以输出的特征图为10个32x32尺寸的(特征图个数就等于卷积核个数)

这里无论输入尺寸为多少,使用512设置,特征图的输出尺寸就和输入尺寸是一样的

python 复制代码
# 设备设置和模型初始化
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else 'cpu'
model = CNN().to(device)
print(model)
python 复制代码
# 训练函数
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 %1==0:
            print(f"loss:{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()  # test_loss是会自动累加每一个批次的损失值,不用累加,改一下!!!!!!!
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()  # 标量

    test_loss /= num_batchs
    correct /= size
    accuracy = 100 * correct
    print(f"Test result: \n Accuracy :{(accuracy)}%,Avg loss:{test_loss}")
    return accuracy
python 复制代码
# 损失函数
loss_fn = nn.CrossEntropyLoss()

# 优化器
# optimizer = torch.optim.SGD(model.parameters(),lr=0.001)#尝试不同的值可以确保最后的准确率
optimizer = torch.optim.Adam(model.parameters(), lr=0.0001)

# 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(f"Epoch{t + 1}\n------")
    train(train_dataloader, model, loss_fn, optimizer)
    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(f'cnn最佳模型:准确率{best_acc:.2f}%')
print("Dnoe!")
print(f'最佳模型:准确率{best_acc:.2f}%')

6.getitem的演示

python 复制代码
class USE_getitem():
    def __init__(self,text):
        self.text=text
    def __getitem__(self, index):
        result=self.text[index].upper()
        return result
    def __len__(self):
        return len(self.text)
p= USE_getitem("pytorch")
print(p[0],p[1])
print(len(p))
python 复制代码
class fun():
    def __init__(self,text):
        self.text=text
    def __getitem__(self,index):
        result=self.text[index]
        return result
    def __len__(self):
        return len(self.text)
a=fun('1,2,3,4,5,20,30,40,50,60')
print(a[5])
print(len(a))

相关推荐
_codemonster2 小时前
分布式深度学习训练框架Horovod
人工智能·分布式·深度学习
数智工坊2 小时前
【MobileVIT论文解读】打破 CNN 与 ViT 壁垒:MobileViT 如何重塑移动端视觉模型?
人工智能·神经网络·cnn
SaaS_Product2 小时前
企业网盘可以在局域网使用吗?
网络·人工智能·云计算·saas
落雨盛夏2 小时前
深度学习|李哥考研3
人工智能·深度学习
ZCXZ12385296a2 小时前
甲骨拓片智能识别与检测_YOLOv8_LQEHead优化实现_甲骨文图像目标检测
人工智能·yolo·目标检测
Coding茶水间2 小时前
基于深度学习的路面裂缝检测系统演示与介绍(YOLOv12/v11/v8/v5模型+Pyqt5界面+训练代码+数据集)
开发语言·人工智能·深度学习·yolo·目标检测·机器学习
q_35488851532 小时前
机器学习:python共享单车数据分析系统 可视化 Flask框架 单车数据 骑行数据 大数据 机器学习 计算机毕业设计✅
人工智能·python·机器学习·数据分析·flask·推荐算法·共享单车
2301_782129952 小时前
从消耗品到资产:构建你的“认知资本”与自我成长的AI系统
人工智能·chatgpt
人工智能AI技术2 小时前
【Agent从入门到实践】22 LLM的局限性:Agent开发中需要规避的坑
人工智能·python