文章目录
一、深度学习
1.1、深度学习介绍
1.1.1、深度学习与机器学习的区别
1.1.1.1、特征提取方面
- 机器学习的特征工程步骤是要靠手动完成的,而且需要大量领域专业知识
- 深度学习通常有多个层组成,它们通常将简单的模型组合在一起,将数据从一层传递到另一层来构建更复杂的模型。通过训练大量数据自动得出模型,不需要人工特征提取环节
1.1.1.2、数据量和计算性能要求
- 机器学习需要的执行时间远少于深度学习,深度学习参数往往很庞大,需要通过大量数据的多次优化来训练参数。
- 深度学习需要大量的训练数据集
- 训练深度神经网络需要大量的算力
- 需要强大的GPU服务器来进行计算
- 全面管理的分布式训练与预测服务----比如谷歌、TensorFlow、 云机器学习平台
1.1.1.3、算法代表
- 机器学习
- 朴素贝叶斯、决策树等
- 深度学习
- 神经网络
1.1.2、深度学习的应用场景
- 图像识别
- 物体识别
- 场景识别
- 车型识别
- 人脸检测跟踪
- 人脸关键点定位
- 人脸身份技术
- 自然语言处理技术
- 机器翻译
- 文本识别
- 聊天对话
- 语音技术
- 语音识别
1.1.3、深度学习框架
框架名 | 主语言 | 从语言 | 灵活性 | 上手难度 | 开发者 |
---|---|---|---|---|---|
Tensoflow | C++ | cuda/python | 好 | 难 | |
Caffe | C++ | cuda/python/Matlab | 一般 | 中等 | 贾杨清 |
PyTorch | python | C/C++ | 好 | 中等 | |
MXNet | C++ | cuda/R/julia | 好 | 中等 | 李沐和陈天奇等 |
Torch | lua | C/cuda | 好 | 中等 | |
Theano | python | C++/cuda | 好 | 易 | 蒙特利尔理工学院 |
二、TensorFlow框架
2.1、TensorFlow简介
2.1.1、TensorFlow的特点
- 高度灵活
- 语言多样
- 设备支持
- Tencorboard可视化
- TensorBoard是TensorFlow的一组Web应用,用来监视Tencorflow运行过程
2.2.2、TensorFlow安装
- CPU版本
pip install tensorflow -i https://mirrors.aliyun.com/pypi/simple
- GPU版本
- GPU
- 核芯数量更多,适用于并行任务
- GPU
2.2、TensorFlow的结构
2.2.1、案例:TF实现加法运算
2.2.2、TensorFlow结构分析
- TensorFlow程序通常被组织成一个构建图阶段和一个执行图阶段
- 在构建阶段,数据与操作的执行步骤被描述成一个图
- 在执行阶段,使用会话执行构建好的图中的操作
- 图和会话
- 图:这是TensorFlow将计算表示为指令之间的依赖关系的一种表示法
- 会话(2.0已经废弃):TensorFlow跨一个或多个本地或远程设备运行数据流图的机制
- 张量(Tensor)
- TensorFlow中的基本数据对象
- 节点(Op)
- 提供图当中执行的操作
- 图和会话
- 数据流图
- TensorFlow是一个采用数据流图(data flow graphs), 用于数据计算的开源框架。
- 节点(Operation)在图中表示数学操作,线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)
2.3、TensorFlow的各个组件
2.3.1、图与TensorBoard
2.3.1.1、什么是图结构
- 图包含了一组tf.Operation代表的计算单元对象和tf.Tensor代表的计算单元之间流动的数据
2.3.1.2、图相关操作
- 默认图
- 查看默认图
- 调用方法
- tf.get_deflaut_graph()
- 查看属性
- .graph()
- 调用方法
- 查看默认图
- 创建图
- new_g = tf.Graph()
2.3.1.3、TensorBoard可视化
- 数据序列化-events文件
- 启动tensorBoard
2.3.1.4、OP
- 操作函数
- tf.constant()
- tf.add()
- 操作对象
- tf.const
- 指令名称
- name=
2.3.1.5、会话(2.0以上已废弃)
- 交互式环境
- 占位符
2.3.1.6、张量
-
张量(Tensor)
- 张量就是一个n维数组,类型为tf.Tensor
- type:数据类型
- shape:形状(阶)
- 创建张量的时候,如果不指定类型默认
- 整型 tf.int32
- 浮点 tf.float32
- 张量就是一个n维数组,类型为tf.Tensor
-
创建张量的指令
-
# 固定值0张量 a = tf.zeros(shape=[3, 4]) # 固定值1张量 a = tf.ones(shape=[3, 4]) # 固定值value张量 a = tf.constant(2, shape=[3, 4]) # 随机值张量 # TODO
-
-
张量的变换
-
类型转换
tensor_new = tf.cast(tensor1, dtype=tf.int32)
-
形状改变
-
静态形状
- 初始创建张量时的形状
- 如何改变静态形状
- 只有在形状没有完全固定下来时才能改变静态形状(placeholder占位符定义的)
- tensor.set_shape()
-
动态形状
-
如何改变动态形状
- tf.reshape(tensor,shape)
- 元素数量必须匹配
tensor2 = tf.constant([1, 2, 3, 4]) a = tf.reshape(tensor2, [2, 2]) print(a)
-
-
-
-
张量的数学运算
- 算数运算
- 基本数学函数
- 矩阵运算
- reduce运算
- 序列索引操作
2.3.1.7、变量
-
变量
- 存储持久化
- 可修改值
- 可指定被训练
-
创建变量
-
tf.Variable(initial_value=None, trainable=True, constraint=None, name=None)
- initial_value 初始化的值
- trainable 是否被训练
- constraint
a = tf.Variable(initial_value=50) b = tf.Variable(initial_value=60) c = tf.add(a, b) print(a) print(b) print(c)
-
-
变量命名空间的修改
2.3.1.8、API
- 基础API
- tf.app
- main函数入口
- tf.image
- 图像处理操作
- tf.gfile
- 文件操作函数
- tf.summary
- 生成TensorBoard可用的统计日志
- tf.python_io
- 用来读写TFRecords文件
- tf.train
- 提供训练器,与tf.nn组合实现网络的优化计算
- tf.nn
- 这个模块提供了一些构建神经网络的底层函数,TensorFlow构建网络的核心模块。其中包含了添加各种层的函数,比如添加卷积层,池化层等
- tf.app
- 高级API
- tf.keras
- 快速构建模型
- tf.layers
- 以更高级的概念层来定义一个模型
- tf.contrib
- tf.contrib.layers提供将计算图中的网络层、正则化、摘要操作、是构建图的高级操作
- tf.estimator
- 相当于Model + Training + Evaluate的合体。在模块中,已经实现了几种简单的分类器和回归器
- tf.keras
2.4、简单的线性回归案例
2.4.1、线性回归案例实现
def linear_regression():
"""
自实现一个线性回归
:return:
"""
write = tf.summary.create_file_writer("./tmp/summary")
with tf.name_scope("prepare_data") as scope:
# 1.准备数据
x = tf.random.normal(shape=[100, 1])
y_true = tf.matmul(x, [[0.8]]) + 0.7
with tf.name_scope("create_model"):
# 2.构造模型
# 定义模型参数,用变量
weights = tf.Variable(initial_value=tf.random.normal(shape=[1, 1]))
bias = tf.Variable(initial_value=tf.random.normal(shape=[1, 1]))
# 4.优化损失
print("训练前模型参数:权重%f,偏置%f" % (weights, bias))
for i in range(200):
if i == 0:
tf.summary.trace_on(graph=True, profiler=True)
loss = loader_demo(bias, weights, x, y_true)
print("第%d次训练后模型参数:权重%f,偏置%f" % (i + 1, weights, bias))
with write.as_default():
tf.summary.scalar('loss', loss, step=i)
with write.as_default():
tf.summary.trace_export(
name="my_func_trace5",
step=0,
profiler_outdir="./tmp/summary")
@tf.function
def loader_demo(bias, weights, x, y_true):
with tf.GradientTape() as tape: # 追踪梯度
tape.watch([weights, bias])
# 预测值
y_predict = tf.matmul(x, weights) + bias
# 3.构造损失函数
loss = tf.reduce_mean(tf.square(y_predict - y_true))
w, b = tape.gradient(loss, [weights, bias]) # 计算梯度
# 梯度下降
weights.assign_sub(0.01 * w)
bias.assign_sub(0.01 * b)
return loss
2.4.2、增加变量显示
- 创建事件文件
- 收集变量
- 合并变量
- 每次迭代运行一次合并变量
- 每次迭代通过summary对象写入事件文件
write = tf.summary.create_file_writer("./tmp/summary")
with write.as_default():
tf.summary.scalar('loss', loss, step=i)
2.4.3、添加命名空间
2.4.4、模型保存与加载
2.4.5、命令行参数设置
tf.compat.v1.app.flags.DEFINE_integer("max_step", 100, "训练模型步数")
FLAGS = tf.compat.v1.app.flags.FLAGS
def command_demo():
"""
命令行参数演示
:return:
"""
print(FLAGS.max_step)
python .\tensorflow_test.py --max_step=200
二、数据读取和神经网络基础
2.1、数据IO操作
2.1.1、文件读取流程
-
多线程 + 队列
-
- 构造文件名队列
- 读取与解码
- 批处理
2.1.2、图片数据
2.1.2.1、图像基本知识
- 如何将图片文件转换成机器学习算法可以处理的数据
- 组成图片的最基本单位是像素
- 图片三要素
- 图片长度
- 图片宽度
- 图片通道数
- 灰度图[长, 宽,1]
- 每一个像素点[0, 255]的数
- 彩色图[长,宽,3]
- 每一个像素点3个[0, 255]的数
- 张量形状
- 一张图片shape = (height, width, channels)
- 多张图片shape = (batch, height, width,channels)
2.1.2.2、图片特征值处理
- 缩放图片到统一大小
2.1.2.3、数据格式
- 存储:uint8(节约空间)
- 矩阵计算:float32(提高精度)
2.1.2.4、案例:图片文件读取
def load_image(file_path, size=(32, 32)):
# 读取与解码
img = tf.io.read_file(file_path)
img = tf.image.decode_jpeg(img)
# 形状修改
img = tf.image.resize(img, size) / 255.0
return img
def picture_read():
"""
狗图片读取
:return:
"""
# 构造文件名队列
file_queue = tf.data.Dataset.list_files("./dog/*.jpg") \
.map(load_image) \
.batch(10)
for i in file_queue:
print(i)
2.1.2.5、案例:二进制文件读取
import tensorflow as tf
class Cifar(object):
def __init__(self):
# 初始化操作
self.height = 32
self.width = 32
self.channels = 3
# 字节数
self.image_bytes = self.height * self.width * self.channels
self.label_bytes = 1
self.all_bytes = self.image_bytes + self.label_bytes
def read_binary(self, file_path_list):
dataset = tf.data.FixedLengthRecordDataset(filenames=file_path_list, record_bytes=self.all_bytes)
return dataset
def read_and_decode(self):
# 获取二进制文件列表
file_path_list = tf.data.Dataset.list_files("./cifar-10-batches-bin/*.bin")
# 读取二进制文件 .map(self.build_image).batch(100)
dataset = self.read_binary(file_path_list)
images = []
for element in dataset.as_numpy_iterator():
images.append(self.build_image(element))
break
dataset2 = tf.data.Dataset.from_tensor_slices(images)
batch_queue = dataset2.batch(100)
print(batch_queue)
def build_image(self, element):
# 二进制解码
decoded = tf.io.decode_raw(element, tf.uint8)
# 将目标值和特征值切片
label = tf.slice(decoded, [0], [self.label_bytes])
image = tf.slice(decoded, [1], [self.image_bytes])
# 调整图片形状
image_reshaped = tf.reshape(image, shape=[self.channels, self.height, self.width])
# 矩阵转置 self.channels, self.height, self.width -> self.height, self.width,self.channels
image_trans = tf.transpose(image_reshaped, [1, 2, 0])
# print(image_trans)
# 调整图像类型
image_cast = tf.cast(image_trans, tf.float32)
print(image_cast)
return image_cast
if __name__ == '__main__':
cifar = Cifar()
cifar.read_and_decode()
2.1.2.6、TFRecords文件
-
TFRecords其实是一种二进制文件,虽然不如其他格式好理解,但是它能更好的利用内存,更方便复制和移动,并且不需要单独的标签文件
- 使用步骤
- 获取数据
- 将数据填入到Example协议内存块(protocol buffer)
- 将协议内存块序列化为字符串,并且通过tf.io.TFRecordWriter写入到TFRecords文件
- 文件格式 *.tfrecords
- 使用步骤
-
Example结构解析
-
tf.train.Example(features=None)
-
tf.train.Features(feature=None)
- feature:字典数据
-
tf.train.Feature(options)
- options
- bytes_list
- int64_list
- options
-
例如
def write_to_tf_records(self, image_s, label_s): """ 将样本的特征值与目标值 :param label_s: :param image_s: :return: """ with tf.io.TFRecordWriter("cifar-10.tfrecords") as writer: image_iter = image_s.as_numpy_iterator() label_iter = label_s.as_numpy_iterator() for i in range(100): image = image_iter.next().tostring() label = label_iter.next()[0] print(image) print(label) record_bytes = tf.train.Example(features=tf.train.Features(feature={ "image": tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])), "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label])), })).SerializeToString() writer.write(record_bytes) @staticmethod def decode_fn(record_bytes): return tf.io.parse_single_example( # Data record_bytes, # Schema {"image": tf.io.FixedLenFeature([], dtype=tf.string), "label": tf.io.FixedLenFeature([], dtype=tf.int64)} ) def read_tf_records(self): for batch in tf.data.TFRecordDataset(["cifar-10.tfrecords"]).map(self.decode_fn): image = tf.io.decode_raw(batch['image'].numpy(), tf.uint8) # image_reshaped = tf.reshape(image, shape=[self.height, self.width, self.channels]) label = batch['label'].numpy() print(image) print(label) # print("x = {image:.4f}, y = {label:.4f}".format(**batch))
-
2.2、神经网络基础
2.2.1、神经网络简介
- 人工神经网络(ANN)简称为神经网络(NN),是一种模仿生物神经网络(动物的中枢神经系统,特别是大脑)结构和功能的计算模型。经典的神经网络结构包含三个层次的神经网络。分别为输入层、输出层和隐藏层。
- 其中每层的圆圈代表一个神经元,隐藏层和输出层的神经元有输入的数据计算后输出,输入层的神经元只是输入。
- 神经网络的特点
- 每个连接都有个权值
- 同一层神经元之间没有连接
- 最后输出结果对应的层也称之为全连接层
- 感知机(PLA)
- 感知机是一种最基础的分类模型,类似于逻辑回归,不同的是,感知机的激活函数用的是sign,而逻辑回归是sigmoid。感知机也具有连接的权重和偏置
- 感知机可以解决的问题
- 或
- 与
- https://playground.tensorflow.org/
2.2.2、神经网络原理
2.2.2.1、softmax回归
s o f t m x ( y ) i = e y i ∑ j = 1 n e y i softmx(y)_i = \frac{e^{y_i}}{\sum_{j=1}^{n}e^{y_i}} softmx(y)i=∑j=1neyieyi
- 多分类问题
2.2.2.2、交叉熵损失
-
公式
H y ′ ( y ) = − ∑ i y i ′ l o g ( y i ) H_{y'}(y) = -\sum_{i}{y_i'}log(y_i) Hy′(y)=−i∑yi′log(yi) -
损失大小
- 神经网络最后的损失为平均每个样本的损失大小
- 对所有样本的损失求和取平均值
- 神经网络最后的损失为平均每个样本的损失大小
2.2.2.3、神经网络原理总结
- 训练过程中计算机会尝试一点点增大或减小每个参数,看其如何减少相比于训练数据集的误差,以望找到最优的权重、偏置参数组合
2.2.2.4、softmax、交叉熵API
- tf.nn.softmax_cross_entropy_with_logits(labels=None, logits=None,name=None)
- labels:标签值(真实值)
- logits:样本加权之后的值
- return:返回损失值列表
- tf.reduce_mean(input_tensor)
- 计算平均值
2.2.3、首页数字识别案例
2.2.3.1 、数据集介绍
- 特征值
- 28*28像素
- 目标值
- 0~9 的one-hot编码
2.2.3.2 、Mnist数据获取API
- from tensorflow.examples.tutorials.mnist import input_data
- mnist = input_data.read_data_sets(path, one_hot=True)
2.2.3.3 、实战:Mnist手写数字识别
- 网络设计
- 全连接层计算
- 流程
- 完善模型功能
- 如何计算准确率
- 增加变量tensorboard显示
- 增加模型保存加载
- 增加模型预测结果输出
- 完整代码
三、卷积神经网络
3.1、卷积神经网络介绍
3.1.1、卷积神经网络与传统多层神经网络对比
- 传统意义上的多层神经网络是只有输入层、隐藏层、输出层。其中隐藏层的层数根据需要而定,没有明确的理论推导说明到底多少层合适
- 卷积神经网络CNN,在原来的多层神经网络基础上,加入了更加有效的特征学习部分,具体操作就是在原来的全连接层前面加入了卷积层与池化层。卷积神经网络出现,使得神经网络层数得以加深,深度学习由此而来。
- 卷积神经网络结构
- 输入层
- 隐藏层
- 卷积层
- 激活层
- 池化层
- 全连接层
- 输出层
3.1.2、卷积神经网络发展
- 网络结构加深
- 加强卷积功能
- 从分类到检测
- 新增功能模块
3.1.3、卷积网络ImageNet比赛错误率
3.2、卷积神经网络原理
3.2.1、卷积神经网络结构
- 卷积层、激活层、池化层、全连接层
- 卷积神经网络层的作用
- 卷积层:通过在原始图像上平移来提取特征
- 激活层:增加非线性分割能力
- 池化层:减少学习的参数,降低网络的复杂度(最大池化和平均池化)
3.2.2、卷积层(Convolutional Layer)
- 卷积神经网络中每层卷积层由若干卷积单元(卷积核)组成,每个卷积单元的参数都是通过反向传播算法最佳化得到的。卷积运算的目的是特征提取,第一层卷积层可能只能提取一些低级的特征如边缘、线条和角等层级,更多层的网络能从低级特征中迭代提取更复杂的特征
1、卷积核(Filter)的四大要素
-
卷积核个数
- 多个卷积核一起观察,得到多个结果
- 不同卷积核带的权重和偏置都不一样,即随机初始化参数
- 多个卷积核一起观察,得到多个结果
-
卷积核大小
- 卷积如何计算
- 输入 5 * 5 *1
- filter 3 * 3 * 1 步长1
- 输出 3 * 3* 1
- 卷积如何计算
-
卷积核步长
- 输入 5 * 5 *1
- filter 3 * 3 * 1 步长2
- 输出 2 * 2 * 1
-
卷积核零填充大小
- Filter窗口大小和步长可能会导致超出图片像素宽
- 在像素外围填充一圈值为0的像素
-
输出大小计算公式
- 已知输入图片形状、卷积核数量、卷积核大小、移动步长,输出图片形状如何计算
- 输入体积大小 H1 * W1 * D1
- 四个超参数
- Fiter数量K
- Filter大小F
- 步长S
- 零填充大小P
- 输出体积大小 H2 * W2 * D2
- H2 =
- W2 = (W1 - F + 2P)/S + 1
- D2 = K
- 已知输入图片形状、卷积核数量、卷积核大小、移动步长,输出图片形状如何计算
-
多通道图片(彩色)如何观察
- 输入 7 * 7 * 3
- filter 3 * 3 * 3 + bias 步长2 ,2个Filter
- 输出 3 * 3 * 2
2、卷积网络API
- tf.nn.conv2d(input=,filters=,strides=,padding=,name=)
- input
- 输入图像
- 要求:shape=[batch, heigh,width, channel],类型为float32,64
- filters
- weight
- 变量:shape=[F, F, D1, K]
- weight
- strides
- 步长S
- [1, S, S, 1]
- padding
- “SAME”:越过边缘取样(零填充)
- “VALID”:不越过边缘取样
- input
3、小结
-
零填充 <=> 固定输出大小
-
卷积核大小一般1 * 1,3 * 3,5 * 5,步长一般为1
-
每个过滤器带有若干权重和1个偏置
3.2.3、激活函数
- 随着神经网络的发展,大家发现原有的sigmoid等激活函数并不能达到好的效果,所以采取新的激活函数
- sigmoid函数缺点
- 计算量相对大
- 梯度消失
- 输入值的范围[-6,6]
1、Relu激活函数
R e L U = m a x ( 0 , x ) ReLU = max(0,x) ReLU=max(0,x)
- Relu优点
- 有效解决梯度消失问题
- 计算速度非常快
- 图像没有负的像素值
- API
- tf.nn.relu(features, names=None)
- features:卷积后加上偏置的结果
- tf.nn.relu(features, names=None)
3.2.4、池化层
- Pooling层主要的作用是特征提取,通过去掉Feature Map中不重要的样本,进一步减少参数数量。Pooling的方法很多,通常采用最大池化
- max_polling:取池化窗口的最大值
- avg_polling:取池化窗口的平均值
- 池化层计算
- 池化层也有窗口大小以及移动步长,计算公式跟卷积公式一样
- H2 = (H1 - F + 2P)/S + 1
- W2 = (W1 - F + 2P)/S + 1
- D2 = K
- 池化层也有窗口大小以及移动步长,计算公式跟卷积公式一样
- 池化层API
- tf.nn.max_pool(“”, ksize=,strides=,padding=,name=)
- value:4-D Tensor形状[batch, height, width, channels]
- channel:filter数量
- ksize:池化窗口大小,[1, ksize, ksize, 1]
- strides:步长大小
- [1,S,S,1]
- padding:“SAME”,“VALID”
- value:4-D Tensor形状[batch, height, width, channels]
- tf.nn.max_pool(“”, ksize=,strides=,padding=,name=)
3.2.5、全连接层
- 卷积层和池化层相当于做特征工程,最后的全连接层是在整个卷积神经网络中起到“分类器”的作用
3.3、案例:手写数字识别
3.3.1、网络设计
- 第一层
- 卷积层 32filter 大小 5 * 5 步长1 padding=“SAME”
- 激活 Relu
- 池化 大小2*2 步长2
- 第二层
- 卷积层 64filter 大小 5 * 5 步长1 padding=“SAME”
- 激活 Relu
- 池化 大小2*2 步长2
3.5、网络的优化和改进
- 初始化参数大小调整
- 模型参数大小缩小
- 使用改进版的SGD算法
- 对于深度网络使用batch normalization 或者droupout层