主体:卷积+池化 数据集[批次,特征数,特征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) |
|