总体:AI从历史数据中学习规律 1. 数据加载器,准备数据与标签,并进行批次处理 2. 损失函数,分析问题类型,选择或设计一个损失函数,以求模型输出与标签的偏差 3. 模型层设计,设计模型的参数网络,使得数据流过该参数网络后, 得到一个与标签shape一致的输出,以便损失函数计算 4. 优化器,使用梯度下降法修改模型参数,试图得到一组参数,使得损失函数在该数据集上,值最小 |
正向传播 求损失,求两个分布的平均损失 反向传播 求梯度,求每个参数变量的梯度 梯度下降 求极值,优化参数找一个极小值 --------------------------------------------------------- |
深度学习中所有数据皆以批次的形式,即矩阵的形式进行运算 数据,输入模型的数据,或者从模型中输出的数据,至少是2维的 第1维,即index=0的维度上,永远是批次的维度,代表样本的个数 对于数据X,第1维,机器学习与深度学习皆是一样的,代表一个样本 对于标签y, - 机器学习中是1维,即一个列表 - 深度学习中是2维,第1维代表批次,第2维代表样本对应的数值/类别 在深度学习,一个样本对应的是一个标签向量 ![]() |
标签不做标准化 标签不需要做归一化 - 深度学习中 标签通常不做标准化/归一化处理 - 标签是损失函数的参数,参与损失函数计算 标签可以做归一化,但需要反解 - 不方便,或者说多此一举 - 对于小于1的数,反解之后会与原来的数有差异 数据必须做标准化 输入模型之前的标准化 - 统一量纲 模型内每一层的标准化 - 深度学习中层较多,为了防止数据爆炸导致无法计算,每一层都会进行一次归一化处理 - 批归一化 |
|
一切数据都是tensor对象 在torch中一切数都是张量,包含单个数字的标量,多维矩阵等, 张量就是tensor 所有的数据都是一个tensor对象,它的浮点类型默认是float32, numpy的浮点类型默认是float64 float32在进行大数据量运算时,性能消耗比float64低一些 具体可以看一下pytorch部分的知识 |
如果你之前不是这行的,那么看数据没有维度的概念 但这行,看数据全看维度,即shape 通常说的矩阵是二维 tensor, import torch a=torch.tensor([[1,1,2],[1,2,3]]) a.ndim 2 a.shape torch.Size([2, 3]) 这个要反复地提醒自己,直至本能化, 看所有事物都是向量,就是看问题,想问题 要从多个角度/维度去观察思考/分析 看一类事物都是矩阵, 就是任何事物都不是单独存在的, 有很多同类的, 多看几个才更容易找出本质特征 ... 这是个艰难且缓慢的过程, 技术易学,思维方式难改, 没有几年的反反复复,改变不过来的 ... |
|
|
|
概述 数据处理 模型定义:期望有个算法能近似表示数据中的规律 学习训练:损失函数计算模型输出与目标的距离大小/差异,优化器让这个距离越来越小 预测处理 深度学习发展之初大致就这四步, 损失函数因为比较通用,就没有在此过程描述,但损失函数的作用依然是核心 数据处理 数据决定了模型的上限 数据有批次,即矩阵的形式 数据--向量--矩阵--批次化 数据集 from torch.utils.data import Dataset from torch.utils.data import DataLoader 数据通常制作成数据集,并以批次的形式加载 模型定义:输入,输出,网络结构 完成一堆参数的初始化, 主要工作是 设计参数的网络结构, 数据会 流过 这个网络结构, 调用时,主要看输入,输出的shape 模型结构 继承nn.Module类 init函数中初始化参数 forward方法中计算逻辑 损失函数:要能够衡量模型输出与标签之间的差异 差异越小,代表模型设计越接近标签中隐藏的规律 - 这里直接使用数据代表其规律 - 但要知道,数据是残缺且有噪声的 - 因此,所谓的规律只是真实规律的一个近似的片面 损失函数,常用的有五六个,它的输入参数有两个: 模型输出:可自动求导,求导工作torch后台自动完成,开发者几乎感受不到这个过程 目标数据:常量 学习训练 损失函数定义/设计 优化器:w = w - 学习率×模型输出的梯度 每调用一次优化器,就会更新一次参数, 让模型的参数网络 整体/大致 朝着损失函数更小的方向调整 学习率用于控制w的变化幅度, 比如,学习率设置为一个很小的数0.005,那么一次改变量只有梯度的千分之五 梯度 函数曲线梯度越大,越陡峭,梯度越小,越平缓 陡峭时w变化大一点,平缓时,变化小一点 最核心的还是正负 还有个附加操作,就是torch这个框架,梯度默认累加, 每次损失函数梯度下降计算后,得到的梯度是历史累加的结果, 为了防止与上次的计算结果叠加, 每次损失计算后都要手动清空一次梯度 预测处理 将数据代入模型,得到一个结果;2维的数表/矩阵 如果有需要,再对该结果进行一番业务逻辑处理,让业务人员能明白其含义 这就是预测处理 |
最简DL模型 import torch from torch import nn class DLModel(nn.Module): """模型定义 """ def __init__(self, in_features, out_features): """参数网络设计 - 总体来说,做的事件是将数据从一个维度转换到另外一个维度 """ super(DLModel, self).__init__() self.linear = nn.Linear(in_features=in_features, out_features=out_features) def forward(self, X): """正向传播 - 调用定义的参数网络 - 让数据流过参数网络,常量数据流过不过的参数产生不同的值 - 这个过程参数本身不会变 - 让参数变化的是后面的优化器 """ out = self.linear(X) return out 查看模型结构 model = DLModel(in_features=13, out_features=1) model DLModel( (linear): Linear(in_features=13, out_features=1, bias=True) ) 查看模型参数 for param in model.parameters(): print(param) Parameter containing: tensor([[ 0.0875, -0.1299, 0.1730, 0.2226, -0.1479, -0.1526, -0.0852, 0.0231, -0.2111, 0.0999, 0.2695, 0.2554, 0.0442]], requires_grad=True) Parameter containing: tensor([-0.0163], requires_grad=True) 参数分为两部分W,b xW+b W是参数,b是偏置 |
|
模型定义和网络参数分开保存 模型参数保存示例 import torch from torch import nn class Model1(nn.Module): def __init__(self,in_features,out_features): super().__init__() self.layer1 = nn.Linear(in_features=in_features,out_features=out_features) def forward(self,X): x = self.layer1(X) return x model = Model1(in_features=200,out_features=2) torch.save(model.state_dict(),"model/m1_param.pkl") model_dict_params=torch.load("model/m1_param.pkl") model.load_state_dict(model_dict_params) torch对参数的保存就是save,加载就是load,保存的是参数,加载的也是参数 模型使用指定参数时,调用model.load_state_dict方法,model中所有方法以load开头的只有load_state_dict这一个方法, 所以,只需要记住save,load这两个单词就可以了 |
|
使用神经网络建模从历史数据中学习规律
算法工程师出一个模型, 这里面有神经网络,也可能会有一些其他的处理技巧, 用于学习/模拟 现有历史数据的规律 简单说,就是以线性变换为主设计一个网络模型, 以此为核心,再不断地展开, 比如,怎么设计数据的结构使之方便设计网络 怎么设计一个损失函数, 是使用已有的还是需要自己单独设计一个, 使之能更好地衡量 模型输出与目标数据 之间的差异 怎么设计日志,以方便观察损失值的变化 怎么设计一个方法,可以更好地反映预测结果的精度 ... ... ... 参数网络结构设计 才是深度学习的根,其他都是枝 要把主要精力放在这个方向上 当然了,其他的也需要会用...
自定义模型嵌套torch模板类
class DLModel(nn.Module): """模型定义 """ def __init__(self, in_features, out_features): """参数网络设计 - 总体来说,做的事件是将数据从一个维度转换到另外一个维度 """ super(DLModel, self).__init__() self.linear = nn.Linear(in_features=in_features, out_features=out_features) nn.Linear是一个模板类,实现一个功能,可以认为它嵌套进了自定义的模型DLModel中 这个init方法中也可以嵌套自定义的模板类,
自定义模型嵌套自定义模板类
import torch from torch import nn class DLModelBase(nn.Module): """模型定义 """ def __init__(self, in_features, out_features): """参数网络设计 - 总体来说,做的事件是将数据从一个维度转换到另外一个维度 """ super().__init__() self.linear = nn.Linear(in_features=in_features, out_features=out_features) def forward(self, X): """正向传播 - 调用定义的参数网络 - 让数据流过参数网络,常量数据流过不过的参数产生不同的值 - 这个过程参数本身不会变 - 让参数变化的是后面的优化器 """ out = self.linear(X) return out class DLModel(nn.Module): """模型定义 """ def __init__(self, in_features, out_features): """参数网络设计 - 总体来说,做的事件是将数据从一个维度转换到另外一个维度 """ super().__init__() self.linear = DLModelBase(in_features=in_features, out_features=out_features) def forward(self, X): """正向传播 - 调用定义的参数网络 - 让数据流过参数网络,常量数据流过不过的参数产生不同的值 - 这个过程参数本身不会变 - 让参数变化的是后面的优化器 """ out = self.linear(X) return out X = torch.randn(3,13) model = DLModel(in_features=13,out_features=2) y_out = model(X) y_out tensor([[ 0.0909, -0.4304], [ 1.0879, 1.4130], [-0.1355, 0.1395]], grad_fn=)
forward 是实现了类似__call__方法
class Model(object): """调用对象即调用方法 """ def __init__(self): pass def __call__(self, x): return x+1 model = Model() y_out = model(x=3) y_out 4
模型类的核心功能
模型类定义了参数网络, 主要就是参数网络/结构, 目的在于让数据流过一个怎样的参数结构 甚至说,参数的初始化都不必在类中完成, 当然了,在类中完成时,写代码会方便一点
forward
model = 模板类(参数网络需要的初始化值...) y_out = model(数据X) forward就实现这么一个功能,功效就是让人写代码舒服点
model.parameters
torch中所有自带的模板类实现有parameters()方法, 继承nn.Module的类也会有个parameters()方法 pytorch 把不同模板类的参数都集中到这个方法中,后续调用模型对象的参数就方便多了
分割开的功能设计
本来,参数网络定义(模型),参数梯度求解(损失函数反向传播), 参数更新(优化器), 这三者是紧密相连的, 为了省事,很容易将它们设计成一个类的不同方法 但Pytorch没有这么设计,而是拆分开来, 拆分成一个个小的组件,让 用户/开发者 自已去组装 就像现在的电脑一样,有人做主板,有人做内存,有人做显卡,有人做磁盘 还有一部分人,做电脑组装... 给打游戏的装,给办公的人装,给做深度学习的人装... 不同群体的需求不一样,就给它装不同的配置