|
主体:卷积+池化
数据集[批次,特征数,特征shape]
卷积变换特征数,先少后多
池化层 对特征shape降维,舍弃 次要/部分 信息
- 既然卷积没有减少特征的shape,还将特征由少变多了,
- 这导致网络的参数量爆增
- 因此就需要一个组件去降低参数量,选择了池化层来解决这个问题
- 卷积当然也可以将参数由多变少,但卷积的计算量大
- 并且参数由少变多,重复数据及无效信息也是爆增
- 这种情况下,用池化这种直接按相对大小舍弃信息的做法显得高效有用
- 实际上是将原信息图(即原特征图)划分成等分的区间
- 每个区间都取出一个
- 特征图的整体架构还在,只是每张特征图变得稀疏了
- 个人认为:可以一个维度取一个最大池化,另外一个维度取一个最小池化
- 仅是想法,尚未验证...
- 按理论来说,这种做法不会取得更好效果,因为如果交易好,早就流行了
- 但至今未见过有人这么做
- 但有时间有条件的话,本人还会尝试验证一下
优化 BN加速收敛 激活函数Rule增加 神经网络 的非线性能力 健壮性 dropout 全连接分类 不管数据原来多少维,最后还是要放到一个维度上,做全连接分类 损失函数与优化器 损失函数用于衡量模型与样本两个分布的差异 分类问题:交叉熵 CE 回归问题:均方误差 MSE 优化器 - 梯度下降法修改参数 - w = w - w*w.grad - adam - sgd 论文 重在思想及转化 抓住论文的核心思想,结合实际问题进行转化 |
设计一个网络,是有原因的,是要去解决一个问题 这就是网络应该具备的能力,要验证以确定网络具备该能力 |
卷积的参数分为两类: 一类控制特征的维度变换 一类控制如何滑动取窗,每个窗口得到一个数值
in_channels: int,
out_channels: int,
kernel_size: Union[int, Tuple[int]],
stride: Union[int, Tuple[int]] = 1,
padding: Union[str, int, Tuple[int]] = 0,
二维卷积
- 输入:
- 类--对象:
- in_channels:代表输入的图像是几个通道的
- out_channels:代表输出的特征图是几个通道的
- kernel_size:代表卷积核的大小
- stride:代表卷积移动时的步长
- padding:代表补零的个数(上下对称,左右对称)
- 对象 -- 函数:
- [N, 输入特征数, H_in, W_in]
- [N, 输出特征数, H_out, W_out]
- 功能:
- 提取区域特征
|
|
|
输入输出及功能
"""
二维卷积
- 输入:
- 类--对象:
- in_channels:代表输入的图像是几个通道的
- out_channels:代表输出的特征图是几个通道的
- kernel_size:代表卷积核的大小
- stride:代表卷积移动时的步长
- padding:代表补零的个数(上下对称,左右对称)
- 对象 -- 函数:
- [N, C_in, H_in, W_in]
- [N, C_out, H_out, W_out]
- 功能:
- 提取区域特征
"""
import torch from torch import nn from torch.nn import functional as F
X=torch.linspace(start=1,end=20,steps=20).reshape(-1,5).unsqueeze(0).unsqueeze(0)
X=X.reshape(2,1,2,5)
X
tensor([[[[ 1., 2., 3., 4., 5.],
[ 6., 7., 8., 9., 10.]]],
[[[11., 12., 13., 14., 15.],
[16., 17., 18., 19., 20.]]]])
X.shape
torch.Size([2, 1, 2, 5])
[2, 5]就代表一张图片,重在观察各API的参数,输入,输出
两个批次,一个批次就是一张图片,一个样本
imgs=X conv2d = nn.Conv2d(in_channels=1, out_channels=2, kernel_size=3, stride=1, padding=1) y = conv2d(imgs) y |
|
输入输出及功能
"""
一维卷积
- 输入和输出:
- 类 -- 对象:
- 跟二维一样
- 对象 -- 函数:
- 输入:[N, C_in, L_in]
- 输出:[N, C_out, L_out]
- 功能:
- 提取序列特征
"""
import torch from torch import nn from torch.nn import functional as F X=torch.linspace(start=1,end=20,steps=20).reshape(-1,5).unsqueeze(0).unsqueeze(0) X 1维卷积的数据格式为[B,C,L] imgs=X.reshape(2,1,2*5) conv1d = nn.Conv1d(in_channels=1, out_channels=2, kernel_size=3, stride=1, padding=1) y = conv1d(imgs) |
"""
Batch Normalization
- 目的:
- 对卷积层的输出,进行标准化:
- 将分布中心拉到0,让分布以0为中心,
- 将数据元素之间平均距离变换到1
- 分布中元素尽量保持相对位置收缩/扩大,
- 使得元素之间的平均距离接近1
- 加快模型的收敛速度
- 输入:
- num_features:特征个数
- 针对图像来说,指的是通道数(特征图的个数,也就是把一个特征图看做是一个特征)
- 输出:
- 输入和输出维度都不变
- 特点:
- 训练时:从本批次的数据中提取参数,提取参数来进行标准化操作
- 推断时:使用训练时各批次的参数来评估了一个整体的参数来标准化操作
"""
import torch from torch import nn from torch.nn import functional as F
X=torch.linspace(start=1,end=20,steps=20).reshape(-1,5).unsqueeze(0).unsqueeze(0)
X=X.reshape(2,1,2,5)
X
tensor([[[[ 1., 2., 3., 4., 5.],
[ 6., 7., 8., 9., 10.]]],
[[[11., 12., 13., 14., 15.],
[16., 17., 18., 19., 20.]]]])
X.shape
torch.Size([2, 1, 2, 5])
[2, 5]就代表一张图片,重在观察各API的参数,输入,输出
两个批次,一个批次就是一张图片,一个样本
|
bn = nn.BatchNorm2d(num_features=1) y = bn(imgs) y
tensor([[[[-1.6475, -1.4741, -1.3007, -1.1272, -0.9538],
[-0.7804, -0.6070, -0.4336, -0.2601, -0.0867]]],
[[[ 0.0867, 0.2601, 0.4336, 0.6070, 0.7804],
[ 0.9538, 1.1272, 1.3007, 1.4741, 1.6475]]]],
grad_fn=NativeBatchNormBackward0)
|
定义一个模板类,参数是特征数,即同一特征才一起做归一化,不同特征之间无交叉 nn.BatchNorm2d(num_features=1) 调用对象,传入数据即可 y = bn(imgs) 归一化,就是(x-mean)/std 批归一化中的“批”,指的是同一特征,所有批次为一个整体进行归一化 没有跨特征,但跨了样本,将批次中所有样本的相同特征看作一个整体 观察数据输入输出
tensor([[[[ 1., 2., 3., 4., 5.],
[ 6., 7., 8., 9., 10.]]],
[[[11., 12., 13., 14., 15.],
[16., 17., 18., 19., 20.]]]])
从整个批次看,原数据的中心在10附近,
批归一化后,数据的中心在[-0.0867,0.0867],即0附近
tensor([[[[-1.6475, -1.4741, -1.3007, -1.1272, -0.9538],
[-0.7804, -0.6070, -0.4336, -0.2601, -0.0867]]],
[[[ 0.0867, 0.2601, 0.4336, 0.6070, 0.7804],
[ 0.9538, 1.1272, 1.3007, 1.4741, 1.6475]]]],
grad_fn=NativeBatchNormBackward0)
|
|
|
|
|
|
|
import torch from torch import nn from torch.nn import functional as F X=torch.linspace(start=1,end=20,steps=20).reshape(-1,5).unsqueeze(0).unsqueeze(0) X
tensor([[[[ 1., 2., 3., 4., 5.],
[ 6., 7., 8., 9., 10.],
[11., 12., 13., 14., 15.],
[16., 17., 18., 19., 20.]]]])
imgs=X.reshape(2,1,2,5) 2*2选1,padding=0直接舍弃
pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
y = pool(imgs)
y
tensor([[[[ 7., 9.]]],
[[[17., 19.]]]])
的确没有取中最后一个核的最大值,但池化的作用就是舍弃,在边上的数据,丢掉还可以, 当然,补一下也不会有什么问题,应该说会更好一些 |
|
|
"""
激活层
- ReLU
- 引入非线性因素
- 负的舍弃,正的原样输出
"""
舍弃一部分值,留下的,是符合某个维度的数据, 这来自于对错,是非,开关的二选一, 是某个维度的数据留下,不是的,过滤/丢弃 直接看的话,是比较难理解的,但网络参数是动态的 随着训练,参数改变自己,以达到可以二选一的位置, 数据分布也在改变,改变到从某个维度看,符合二选一的标准 也就是说,数据本身是错综复杂的,但流过参数网络后, 变得有条理,有纹理,经纬分明, 变得可以二选一之后,rule这个激活函数的作用就出来了 是rule这个激活函数加入到 具有自适应能力的参数网络中后, 参数网络经过适应,慢慢地让relu可以起到作用, 从这点来讲,relu应该放到maxpool的后面 - 因为maxpool分块选择出了特征图的主要结构/节点脉络 - 从稀疏但仍有原特征的结构中进行操作更高效一些 - 但个人感觉,实际上可能效果不明显 |
import torch
from torch import nn
from torch.nn import functional as F
X=torch.linspace(start=1,end=20,steps=20).reshape(-1,5).unsqueeze(0).unsqueeze(0)
X
tensor([[[[ 1., 2., 3., 4., 5.],
[ 6., 7., 8., 9., 10.],
[11., 12., 13., 14., 15.],
[16., 17., 18., 19., 20.]]]])
imgs=X.reshape(2,1,2,5) bn=nn.BatchNorm2d(num_features=1) imgs = bn(imgs) imgs
tensor([[[[-1.6475, -1.4741, -1.3007, -1.1272, -0.9538],
[-0.7804, -0.6070, -0.4336, -0.2601, -0.0867]]],
[[[ 0.0867, 0.2601, 0.4336, 0.6070, 0.7804],
[ 0.9538, 1.1272, 1.3007, 1.4741, 1.6475]]]],
grad_fn=NativeBatchNormBackward0)
ReLU在BN之后,真的就直接抹掉了一半数据
relu = nn.ReLU()
relu(imgs)
tensor([[[[0.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[0.0000, 0.0000, 0.0000, 0.0000, 0.0000]]],
[[[0.0867, 0.2601, 0.4336, 0.6070, 0.7804],
[0.9538, 1.1272, 1.3007, 1.4741, 1.6475]]]], grad_fn=ReluBackward0)
之前在上课的时候,向老师提过个人的理解: BN将数据拉到标准正态分布,relu放在BN之后,直接抹掉了一半数据 剩下的一半,仍然具有数据的结构,有数据的规律/性质, 并且不是那种随机去减,可能会让整体规律集中彻底丢失的减, 而是完整保留对称结构中一半的减,这样即保证了数据的规律,而降低了数据量 老师说不是这样的,但没说原因,我理解他的不是,是从各个组件本身的作用去说的, - BN就是为了加速收敛 - relu就是增加了非线性能力 而没有,或者说老师从未从联系的角度思考过他们,一时听到这样的说法大脑一时有些思考不过来... 好像有道理,但又与原来已有的理解有些不符... 如果这个人理解有道理,那么应该将以下顺序放更合理一些: maxpool从原数据中取主脉络 relu抹去0以下的数据 BN再将之拉回正态分布 |
|
|
|
|
|
|
一叶知秋,蛛丝马迹, 从少量的数据中判断出某些规律,这样的能力是强大的 全力出手解决一件事,当然没有只出七分力来得轻松,前提是出七分力也把这事解决了 从事物的一部分推断出整体,这就是dropout的能力 - 建立在提取的这部分,足以分类/达到预期效果 的前提上
过拟合
- 如果训练数据的信息量足够大,那么噪声也随之会足够大
- 这时的模型,它不会主动丢弃噪声,都是有什么学什么
- 在模型看来,所有的数据都是可学习的,且是要学习的,
- 这里就容易出现过拟合
- 而dropout一定程度上,可以解决/缓解了 过拟合的问题
|
import torch
from torch import nn
from torch.nn import functional as F
X=torch.linspace(start=1,end=20,steps=20).reshape(-1,5).unsqueeze(0).unsqueeze(0)
X
tensor([[[[ 1., 2., 3., 4., 5.],
[ 6., 7., 8., 9., 10.],
[11., 12., 13., 14., 15.],
[16., 17., 18., 19., 20.]]]])
imgs=X.reshape(2,1,2,5) dropout = nn.Dropout(p=0.2) dropout(imgs)
tensor([[[[ 1.2500, 2.5000, 3.7500, 5.0000, 0.0000],
[ 7.5000, 8.7500, 10.0000, 0.0000, 0.0000]]],
[[[13.7500, 15.0000, 16.2500, 17.5000, 18.7500],
[ 0.0000, 21.2500, 22.5000, 23.7500, 25.0000]]]])
0.2*20=4 有4个数变成了0,同时非0元素都膨胀了一点点 舍弃哪些数据是概率随机的 dropout = nn.Dropout(p=0.2) dropout(imgs)
tensor([[[[ 1.2500, 0.0000, 3.7500, 0.0000, 0.0000],
[ 0.0000, 8.7500, 0.0000, 11.2500, 12.5000]]],
[[[ 0.0000, 15.0000, 16.2500, 17.5000, 18.7500],
[ 0.0000, 21.2500, 22.5000, 23.7500, 25.0000]]]])
|
将一个向量变换成另外一个向量 全连接每次计算的是1维数据,其数据的输入格式最多为2维, 其中dim=0是批次的维度 2维矩阵进行全连接,本质还是遍历dim=0的维度,每次处理的还是1维数据 1维示例 import torch from torch import nn x=torch.tensor([1.,2.,3.]) line = nn.Linear(in_features=1*3,out_features=2) line(x) tensor([-0.9335, -1.3012], grad_fn=ViewBackward0) |
|
2维示例 import torch from torch import nn X=torch.linspace(start=1,end=20,steps=20).reshape(-1,5).unsqueeze(0).unsqueeze(0) imgs=X.reshape(2,1,2,5) 使用全连接之前,要先将一个样本转化为1维矩阵,即向量 flat=nn.Flatten() imgs = flat(imgs) line = nn.Linear(in_features=1*2*5,out_features=2) line(imgs)
tensor([[ 6.9716, 0.8715],
[22.2193, -0.9051]], grad_fn=AddmmBackward0)
|
|
|