文章目录
前言
keras学习
keras 建模介绍
目标:使用tf.keras建立深度学习的模型,对keras.layer有系统的理解。
要求:
keras的三个层级
建议不要用sequential,直接用functional。序列属于傻瓜开发,会让你越来越不会用keras。
sequential model 的要点
整个模型的参数数量是根据第一个layer的给定大小来计算的
keras layer的理解
查阅keras的layer需要从keras官网手册里面查,tf里面没有。此外我们要从面相对象的角度上理解每个layer。
在理解面向对象之前需要理解每个layer是一个类,传入的中间参数是构造函数,下图是自定义简单的类。当我们能把一个layer的输入加上layer本身的参数结合起来能和他的输出对应才算真正理解这个layer,尤其是lstm这种集成度非常高的layer.
sequential 简单演示
要明白怎么计算的,25120 = 32*(784+1),这里1是每个wx对应的偏值b。relu没有改变输入输出数量,只改了内部的数值。
Function API
使用背景如下,建议会用function 不要再用sequential
function的特点:理解fit数据的时候是通过各个layer的操作把整个tensor链接起来,构成一个计算图。
使用方法:始于input,结束于model
input不用放批量大小,只定义一个数据的输入大小。返回的是一个tensor,然后使用定义好的dense作用这个tensor,生成一个新的tensor。model是整体构造这个图,将一些加入数据和显示结果等工程集成到一个类中。
总结
实战:使用tf.keras复现2015年cvpr论文
使用function API复现2015年cvpr论文框架
目标:
任务概述
阅读reID领域的cvpr论文An Improved Deep Learning Architecture for Person Re-Identification内容,提炼一些关键信息,尤其是对于模型的关键量化信息,尤其是学习参数和网络架构。在本小节根据论文信息一步步地复现出这篇论文模型,后面我们会围绕这篇论文的完整复现来进一步学习数据fit,custm自定义层。(2015年那会的论文一般都是没有的,有的经典工作有人会复现出来)通过这篇论文学习还可以让我们知道如何去读深度学习的论文
论文阅读
当我们看一篇论文需要这样做: 首先查看这个领域是干嘛的,了解这个领域的工作。 其次知道文章的结构:摘要,背景介绍,相关工作,实验模型,数据特征分析,实验细节和结果分析,总结。当不是自己领域的时候通常这里我们只关注网络架构还有实验细节和参数比对,保证我们能够完整地复现作者的工作。需要注意这篇论文的难度是不低的,作者花了半个月才完全复现。
这里我们只看论文的第三章结构部分,阅读之后我理解了作者的网络参数设置。
1.Input layer 和 tired Conv 和Maxpooling
batch16060*3大小的输入层
两个conv+maxpooling 层,20个卷积核553(对应rgb通道数量,卷积是三个层各个点相加)。
shared wight: 上层的卷积核下层的卷积核共享同一个权重,这是多输入模型常用的结构。
了解了结构之后我们去keras官方网址的core layer中查阅我们想用layer怎么用。
搭建代码:(注意共享层的实现方法是一个类调用两次,而不是创建两个类)
import tensorflow as tf
from tensorflow.keras.layers import Input,Conv2D,MaxPooling2D
# input data
inputOne = Input(shape=(160,60,3))
inputTwo = Input(shape=(160,60,3))
# conv + maxpool
shareConvOne = Conv2D(20,5,name="shareConvOne")# share wight 1
x1 = shareConvOne(inputOne)
x2 = shareConvOne(inputTwo)
x1 = MaxPooling2D(pool_size=(2,2))(x1)
x2 = MaxPooling2D(pool_size=(2,2))(x2)
shareConvTwo = Conv2D(25,5,name="shareConvTwo")# share wight 1
x1 = shareConvTwo(x1)
x2 = shareConvTwo(x2)
x1 = MaxPooling2D(pool_size=(2,2))(x1)
x2 = MaxPooling2D(pool_size=(2,2))(x2)
cross-Input
因为完全实现论文的底层是需要自定义层的,原文的意思是把上面特征图一个像素点直接扩大复制25份,下面取像素点临近的25个像素。然后把这两个像素相减差值绝对值作为像素值。这里我们简化一下,用两个上采样层加上lambda层取两个图片直接扩大25倍的差,不影响总体的参数数量情况下保证效果不太差。
ps:在keras中搭建模型常用的方法有两种:
(1)一种是较为简单的序列模型Sequential(该方法适用于搭建简单的模型)
(2)一种是使用Keras函数式的API(该方法最为常用)
无论使用哪种方法在搭建model时都要求使用keras中继承自Layer的层(例如keras.layers.Conv1D等等),但有时候又需要使用一些keras.layers中没有的层(例如expand_dim, squeeze或者自己定义的层等)。这时候必须想办法将其转换成keras中的Layer,一般有两种方法,一种是直接定义类class然后继承Layer,一种是直接使用Lambda函数。这里使用Lambda函数的方法,该方法比较简单。
代码:
from tensorflow.keras.layers import UpSampling2D,Lambda,Add
x1_up = UpSampling2D(size=(5, 5))(x1)
x2_up = UpSampling2D(size=(5, 5))(x2)
x1_nn = Lambda(lambda x : -x)(x1_up)
x2_nn = Lambda(lambda x : -x)(x2_up)
x1 = Add()([x1_up, x2_nn])
x2 = Add()([x2_up, x1_nn])
论文其他层
其它层根据论文介绍和上文的经验搭建,注意这里conv不是共享层结构,图中concatenate没有给出图。具体细节看论文中的图。
conv3_1 = Conv2D(25, 5, strides=(5, 5),name="conv_3_1")
conv3_2 = Conv2D(25, 5, strides=(5, 5), name="conv_3_2")
x1 = conv3_1(x1)
x2 = conv3_2(x2)
conv4_1 = Conv2D(25,3, name="conv4_1")
conv4_2 = Conv2D(25,3, name="conv4_2")
x1 = conv4_1(x1)
1
x2 = conv4_2(x2)
x1 = MaxPooling2D(pool_size=(2, 2),padding= 'same')(x1)
x2 = MaxPooling2D(pool_size=(2, 2),padding= 'same')(x2)
from tensorflow.keras.layers import Concatenate, Flatten, Dense
y = Concatenate()([x1, x2] )
y = Flatten()(y)
y = Dense(500)(y)
y_output = Dense(2)(y)
model = tf.keras.Model(inputs= [inputOne,inputTwo], outputs= [y_output])
model.summary()
模型结果summary
打印显示的参数和论文总参数一样,都是2,308,147。模型完成之后我们还没有考虑激活层和正则化,需要自己从论文中再找相关的介绍,进行补充。
简单复现论文的train部分
要求能配置如下内容:
阅读论文训练部分
阅读论文时候针对复现代码的五个点进行笔记:优化方法采用sgd;一对图片输入,0和1输出;正则化参数;动量随机梯度下降;采用relu激活。但是下图五个点有如下的内容没说到:
(ps:文中虽然没有说用什么loss,但是softmax激活函数天生和交叉熵loss搭配,其实也算暗示了。)
回顾之前的模型
回顾之前的模型,将论文中的非modle框架信息也加入进去。
那些layer带学习参数:参数不为0的层。
对conv和dense添加正则化:
添加激活层
从论文收获关键词模型部分只有cross input层、第三个卷积、dense总共三个层用到relu激活,其他地方没有提到激活函数,这里如果不自定义激活函数,默认就是原来的数据只做权重处理,不进行数据整体激活调整。
添加loss和optimizers
论文中lr其实是动态变化的,但是要实现动态变化需要借助keras的callback机制去自定义,这里先默认0.01。
loss函数选择下图这个是有理论依据的,其实也可以魔改一下,自己定义一个loss函数去让优化器走到你定义的loss最优解,但是不一定acc就会高。
阶段总结
目前已经完成了以下工作:
- 模型和训练之间的搭建
- 认识到数据到模型到loss到使用优化器更新wight过程
目前没完成的工作:
keras的callback复现论文的动态学习率
callback 重要性不亚于layer,学会它可以灵活按照自己的想法去调整train 部分。
什么是keras callback?
- callback是一组函数list,自己按照callback规定增加函数之后会放入list中,modle.fit会调用整个函数list,执行满足条件的函数。
- callback 修改训练过程的逻辑。
为什么需要callback?
callback为了让训练过程按照自己的思路去控制。
有时候我们希望训练到一定程度,加载另外一个权重去看看效果 和之前的结果接近么?这样可以分析精度是否是可信的。还有一个应用是晚上睡觉前可以设置这样的一个callback去让训练多执行几次。充分利用晚上时间。
如何使用官方已经定义好的callback?
reduceLR是基于callback虚基类实现的新类,它可以实现学习率的更改,reduce_lr是这个高级类的实例化,通过callbacks=([])来实例化传入多个高级类的实例,用逗号隔开。
keras内置的callback
动态模型保存:根据效果只保存最优的模型
动态训练终止:如果验证loss基本不再变化的话就停止,一般和动态训练保存结合。
远程事件监控:监控数据,一般发送报警提示邮件
自定义动态学习率:按照计划进行的更新学习率
数据可视化tensorboard:实际是基于远程事件监控callback,但是它在此后端基础上还增加了web前端,效果更明显。
Pateau策略学习率:按照当前的效果去更新学习率
csv格式训练日志持久化:
简单自定义callback: 感觉没啥用,直接用虚基类去调整。
自定义callback:后面专门开一小节去介绍custm。
论文中动态学习率的更新实现
论文中是这样说的:
可以看出下一个lr 等于上一个lr (1+0.001batch数)的负0.75次方,动量参数为0.9,步长0.005。下面我们根据他的要求实现代码:
# 实现论文的动态更新策略函数
def _learning_rate_schedule(epoch):
step = epoch * 100
learning_rate = 0.01 * (1 + 0.0001 * step) ** (-0.75)# 这个0.01是初始的sgd,如果动量也要更改的话需要自定义callback了
return learning_rate
# 生成一个带动量的sgd
sgd = tf.keras.optimizers.SGD(lr = 0.01,momentum = 0.9)
model.compile(optimizer=sgd,loss= 'categorical_crossentropy',metrics= ['accuracy'])
# 生成一个动态更新的callback对象
callback_lrs = tf.keras.callbacks.LearningRateScheduler(schedule=_learning_rate_schedule,verbose=1)
总结
其中希望按照一定的条件自动重新加载特定权重需要开发人员自定义。
callback本质是试图观察训练信息和控制训练过程。
Tensorboard
tensorboard 为你提供有效的反馈,便于你优化原本的假设。
什么是Tensorboard
怎么用tensorboard
总的使用步骤
例如将动态学习率显示到tensorboard。
具体操作细节
- 安装jupyter tensorboard
!pip install jupyter-tensorboard
- 加载jupyter插件
%load_ext tensorboard
- 添加数据和模型
- 添加tensorboard
5.jupyter启动tensorboard
tensorboard --logdir logs
custom tensorboard
没理解太深,略。
阶段总结
tf.data 使用
为什么要用tf.data
tf目的通过开发tf.data统一数据处理过程。重点是如何将清洗好的数据处理成模型需要的输入数据集。它为了解决以下的问题:
怎么使用tf.data
将硬盘的数据,pandas数据,dataset数据,需要迭代器实现的数据转换成tf模型中dataset格式
dataset是什么?
怎么使用dataset?
元素和元素结合:
查看dataset单个元素的大小:
dataset. e Lement_ spec
dataset 拼接数据集
map去操作每一个元素
dataset常见的处理函数
batch:将数据按照batch划分开
cache:
prefetch:提前去硬盘那数据
range : 切片
concatenate :数据集链接
filter : 筛选数据,重要
from_ generator : 从generator获取数据,一般不要用。
from_ tensor_ slices::从numpy或者tensor转换成切片
interleave :
map : 对整体数据进行操作,例如对图片变色。重要
repeat :重复多倍数据
shard:
shuffle:随机打乱
window :
zip :
将原始数据转换成dataset一些经验:
大数据集是指远远大于内存大小的数据集,这种背景下需要从硬盘建立dataset管道,读取一次训练的数据之后删除再从硬盘中读取下一部分。
如果数据还需要进行挑选,修改等复杂工作,用generator
将Dataset喂给modle
配置好dataset后在fit函数喂。
阶段总结
总结就是dataset可以对数据灵活操作,按照自己想法将数据喂到模型中。
custom in keras
自定义分为layer层和modle层。layer一般用于end to art 论文复现,而modle自定义用于和数据、外部参数交互。
custom layer
layer基类的执行流程:
init中放入卷积核参数等除了shape参数, 计算流程在call()中根据input来写。build函数在最开始调用call中会调用。
代码案例
自定义layer类:
上图定义了N批次的32维度的,能够trainable的w和32维度的b。(这部分介绍不详细,需要自己查看手册再学)
modle: 和layer基本相似,可以在该class增加一些其他的参数,打印想要的参数,判断停止点。
阶段总结
keras适合感知类数据,也就是图像语音的dl。而estimator适合大型数据库内结构化数据(如表格),适合机器学习。
estimator
estimator适合大型数据库内结构化数据(如表格),适合机器学习。暂时略过,因为我目前不涉及机器学习。