学习笔记3

学习笔记3

关于训练神经网路的诸多技巧Tricks(完全总结版)-腾讯云开发者社区-腾讯云 (tencent.com)

(1)关于用gpu跑程序的步骤


有英伟达的驱动的前提下:

1)创建虚拟环境:2023最新pytorch安装教程,简单易懂,面向初学者(Anaconda+GPU)-优快云博客

2)nvidia-smi查看自己的电脑配置选择合适的CUDA版本

3)下载cuda版本的pytorch:https://pytorch.org/

4)检查

import torch
torch.cuda.is_available()

5)代码部分的实现:

1.申明用GPU

device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)

2.把model放到GPU上

net= Net ()
net.to(device)

3.把数据和标签放到GPU上

inputs, labels= inputs.to(device),labels.to(device)

(2)图像的数据预处理


1)类型:

  • 爬取或搜索引擎采集:图像进行去重、删除无效样本等操作,

  • 自行拍摄、实验提取:可能需要根据实验要求进行一些删除、增加的处理

2)确保:

1)全部样本的尺寸和通道是一致的

2)图像最终以Tensor形式被输入卷积网络

3)图像被恰当地归一化,即让像素值减去一个数(默认为均值)、再除以另一个数(默认是标准差)

4)方法:

  • Compose transforms专用的,类似于nn.Sequential的打包功能,可以将数个transforms下的类打包

  • CenterCrop 中心裁剪

  • Resize 尺寸调整,注意和裁剪区分开,这个与原图较为相似的信息,但图片尺寸会得到缩放。

  • Normalize 归一化,有两个参数,一个是mean,另一个是std,分别代表需要减去的值和需要除以的值

  • ToTensor 转化为张量

代码实现的例子:

from torchvision import transforms

# 定义图像预处理的组合方法
transform = transforms.Compose([
    transforms.CenterCrop(100),  # 中心裁剪到100x100大小
    transforms.Resize((64, 64)),  # 将图像调整为64x64大小
    transforms.ToTensor(),  # 转换为张量,并归一化到[0, 1]
    transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])  # 归一化,将张量的值从 [0, 1] 缩放到 [-1, 1]
])

5)区分:

  • 表格数据而言,归一化是以特征为单位进行的,每个特征会单独减去自己这个特征的均值,再除以这个特征的标准差。

​ 类transforms.ToTensor()已经带有归一化的功能:这个类会按照最大值255,最小值0对图片数据进行归一化,将所有图像的像素值压缩到[0,1]之间

  • 任意图像而言,归一化都是以通道为单位进行的,每个通道上的全部样本的全部像素点会减去通道像素的均值,再除以通道像素的标准差图像,在被归一化前必须被转化为Tensor。

​ 如果输入transforms.ToTensor() 的数据原本是二维表,那其最大值可能会远远超出255,那经过归一化后数字范围也不会在[0,1]之间。为了避免这种情况的出现,我们可以提前将二维表的数据压缩到[0,255]之间

(3)数据增强


代码实现:

from torchvision import transforms

scale_range = (0.9, 1.1)
rotation_range = 10
translation_range = (0.1, 0.1)

transform = transforms.Compose([
    transforms.ToTensor(),  # 转换为张量,并归一化到[0, 1]
    transforms.Normalize((0.5,),(0.5,))
     transforms.RandomHorizontalFlip(), # 随机水平翻转
    transforms.RandomRotation(degrees=rotation_range), # 随机旋转
    transforms.RandomAffine(0, scale=scale_range), # 数据随机缩放
    transforms.RandomAffine(0, translate=translation_range), # 随机平移
])

(4)利用train_test_split进行训练集、验证集、测试集的随机划分


例子:

数据形式为文本,且形式为数据和标签在一起

# 从总的数据集中(有规律)选取固定大小部分作为训练集验证集测试集的总和。如此处选取总数据集的前10000句作为需要使用的数据集。
# 两次使用train_test_split()将选取的固定大小的数据集,按照一定的比例,如8:1:1随机划分为训练集,验证集,测试集。
# 并分别将划分好的数据集进行写入到固定目录下
 
from sklearn.model_selection import train_test_split
 
 
def write_data(datapath, line_sen_list):
    '''
    datapath: 需要写入的文件地址
    line_sen_list: 需要写入的文件内容行列表
    '''
    with open(datapath, 'w', encoding = 'utf-8') as o:
        o.write(''.join(line_sen_list))
        o.close()
 
 
def main():
 
    raw_data_path = './output_s044_final_final_final.txt'
    train_data_path = './train_80000.txt'
    validate_data_path = './validate_10000.txt'
    test_data_path = './test_10000.txt'
 
    line_sen_list = []
    
    with open(raw_data_path, 'r', encoding = 'utf-8') as f:
        lines = f.readlines()
        # 按某种规律选取固定大小的数据集
        for line in lines[0:100000]:
            line_sen_list.append(''.join(line))
        f.close()
 
    label_list = [0] * 100000  # 由于该数据形式为文本,且形式为数据和标签在一起,所以train_test_split()中标签可以给一个相同大小的0值列表,无影响。
 
    # 先将1.训练集,2.验证集+测试集,按照8:2进行随机划分
    X_train, X_validate_test, _, y_validate_test = train_test_split(line_sen_list, label_list, test_size = 0.2, random_state = 42)
    # 再将1.验证集,2.测试集,按照1:1进行随机划分
    X_validate, X_test, _, _ = train_test_split(X_validate_test, y_validate_test, test_size = 0.5, random_state = 42)
    
    # 分别将划分好的训练集,验证集,测试集写入到指定目录
    write_data(train_data_path, X_train)
    write_data(validate_data_path, X_validate)
    write_data(test_data_path, X_test)
 
if __name__ == '__main__':
    main()

(5)shutil.copyfile复制文件到另一个文件夹中


1)shutil.copyfile(file1,file2)

file1为需要复制的源文件的文件路径,file2为目标文件的文件路径+文件名

src_file = 'C:\\A\\0.png'
dst_file = 'D:\\B\\1.png'
shutil.copyfile(src_file,dst_file)

2)shutil.copy(file,folder)

和上面的区别就是这个复制完后文件的名字可以一样

dst_file = './test_copy2'
src_file = './test_copy1'
current_list = glob.glob(os.path.join(src_file,'*'))
# 使用 glob.glob() 函数获取源文件夹中所有文件的路径,并将它们存储在 current_list 列表中
for x in current_list:
    shutil.copy(x,dst_file)

补充

巧用Python:用Python批量复制文件,方法有9种,方便快捷-优快云博客

(6)loss曲线诊断神经网络模型


1)相关的资料:


通过loss曲线诊断神经网络模型-优快云博客

如何根据训练/验证损失曲线诊断我们的CNN-腾讯云开发者社区-腾讯云 (tencent.com)


2)情况出现:


过拟合的情况:

  • 训练损失持续下降,验证损失开始上升
  • 训练损失和验证损失均下降,但两者之间的差距越来越大

理想情况:

  • 训练损失和验证损失均下降,且两者趋于平稳且差距较小

3)可能会出现的问题(图像分析):


img

分析(从左到右):

  • 图1 :显然的学习不到任何东西(可以适当smooth一下看的清楚一点);
  • 图2:是典型的过拟合现象;
  • 图三:更严重的过拟合;
  • 图四:等训练的epoch结束的时候,最右边的损失值还是下降的趋势,说明还没训练足够;
  • 图五:开头经历了比较长的iterate才慢慢收敛,可能初始化权重太小,或者数据集中含有不正确的数据
  • 图六:越学习损失值越大,很有可能是“梯度向上”了

img

补充

左上一和二:没有对数据集进行洗牌,也就是每次训练都是采用同一个顺序对数据集进行读取;

右上一:训练的过程曲线消失,遇到了nan值,很有可能是模型设置的缘故;

最后一个图显示较小比例的val集设置会导致统计不准确,比较好的val设置比例是0.2。


(7)dataset和dataloader


【pytorch】shuffle,dataloader和enumerate - 知乎 (zhihu.com)

PyTorch学习笔记(4)–DataLoader的使用-优快云博客

(8)Batch Normalization


1)参考介绍:


什么是批标准化 (Batch Normalization) - 知乎 (zhihu.com)

Batch Normalization:批标准化, 和普通的数据标准化类似, 是将分散的数据统一的一种做法


2)背景:


举一个例子理解:比如x1=1,x2=20,w=0.1,那么输出x1 * w=0.1,x2 * w=2,当经过激活函数比如tanh之后会变成接近1和0.1, 接近于 1 的部分已经处在饱和阶段,BN就可以来解决问题。


3)原理:


把数据分成小批小批进行随机梯度下降, 而且在每批数据进行前向传递的时候, 对每一层都进行 normalization 的处理,它被添加在每一个全连接和激励函数之间。


4)效果:


img

没有 normalize 的数据 使用 tanh 激活以后, 激活值大部分都分布到了饱和阶段, 也就是大部分的激活值不是-1, 就是1, 而 normalize 以后, 大部分的激活值在每个分布区间都还有存在. 再将这个激活后的分布传递到下一层神经网络进行后续计算, 每个区间都有分布的这一种对于神经网络就会更加有价值. Batch normalization 不仅仅 normalize 了一下数据, 还进行了反 normalize 的手续.

(9)经典网络


——> lenet-5


参数大约有6万 5层

详细和代码见:

卷积神经网络:LeNet-5_lenet5卷积神经网络结构-优快云博客

LeNet-5卷积神经网络的整体框架


——> Alexnet


使用了8层卷积神经网络,前5层是卷积层,剩下的3层是全连接层

特点:

  • 和letnet-5相比,它的参数要大得多,大约有6000万,而且它里面还用到了relu激活函数,采用修正线性单元(ReLU)的深度卷积神经网络训练时间比等价的tanh单元要快几倍
  • 以往池化的大小PoolingSize与步长stride一般是相等的,这里反而重叠,类似于卷积,此操作可以有效防止过拟合的发生
  • Dropout:全连接层中去掉了一些神经节点,将概率小于0.5的每个隐层神经元的输出设为0,即去掉了一些神经节点,达到防止过拟合
  • 对比letnet,有更深的网络深度,有利于性能的提高

在这里插入图片描述

c1 卷积–>ReLU–>池化 –> c2 卷积–>ReLU–>池化–> c3卷积–>ReLU–> c4 卷积–>ReLU–> c5 卷积–>ReLU–>池化–>

Fc6全连接–>>ReLU–>Dropout–> Fc7全连接–>>ReLU–>Dropout


——> VGG -16


介绍:层与层之间使用max-pooling(最大化池)分开,所有隐层的激活单元都采用ReLU函数。13个卷积层和5个池化层,3个全连接层。它没有很多的参数,是专注于构建卷积层的简单网络

  • 卷积-卷积-池化-卷积-卷积-池化-卷积-卷积-卷积-池化-卷积-卷积-卷积-池化-卷积-卷积-卷积-池化-全连接-全连接-全连接
  • 通道数分别为64,128,512,512,512,4096,4096,1000。卷积层通道数翻倍,直到512时不再增加。通道数的增加,使更多的信息被提取出来。全连接的4096是经验值,当然也可以是别的数,但是不要小于最后的类别。1000表示要分类的类别数。

使用多个较小卷积核(3x3)的卷积层代替一个卷积核较大的卷积层,一方面可以减少参数,另一方面相当于进行了更多的非线性映射,可以增加网络的拟合/表达能力,池化层的池化核为2*2

特点 :图像缩小的比例和信道数量增加的比例是有规律的

​ 卷积可以代替全连接,适用各种尺寸的图片

​ 只用到3x3的卷积层和2x2的池化层,比较简洁美观

缺点: 即训练时间过长,调参难度大。 需要的存储容量大,不利于部署(就是将训练好的VGG16模型应用到实际场景中


(10)残差网络


背景:

  • 梯度消失:

很深的网络层,由于参数初始化一般更靠近0,这样在训练的过程中更新浅层网络的参数时,很容易随着网络的深入而导致梯度消失,浅层的参数无法更新。

  • 网络退化

假设一个只需要18层就能达到最优性能的模型有34层,我们希望模型能够自动将多余的16层学习成恒等映射,即这些层的输出与输入相同。但模型很难学习将这些层学习成恒等映射的参数,而可能会学习到与恒等映射不相符的参数,导致性能下降。这就是所谓的网络退化现象,而不是过拟合所导致的。


残差网络Resnets

思想就是背景所说的,希望冗杂多余的层学习恒等映射

img

增加了 x 项,那么该网络求 x 的偏导的时候,多了一项常数 1(对x的求导为1)

在第二层进行线性变化激活之前对F(x)添加了x的输入值,这条路径叫做shortcut



(10)残差网络


背景:

  • 梯度消失:

很深的网络层,由于参数初始化一般更靠近0,这样在训练的过程中更新浅层网络的参数时,很容易随着网络的深入而导致梯度消失,浅层的参数无法更新。

  • 网络退化

假设一个只需要18层就能达到最优性能的模型有34层,我们希望模型能够自动将多余的16层学习成恒等映射,即这些层的输出与输入相同。但模型很难学习将这些层学习成恒等映射的参数,而可能会学习到与恒等映射不相符的参数,导致性能下降。这就是所谓的网络退化现象,而不是过拟合所导致的。


残差网络Resnets

思想就是背景所说的,希望冗杂多余的层学习恒等映射

img

增加了 x 项,那么该网络求 x 的偏导的时候,多了一项常数 1(对x的求导为1)

在第二层进行线性变化激活之前对F(x)添加了x的输入值,这条路径叫做shortcut


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值