目录
前言
李沐老师的《动手学深度学习》 原书中MXNet代码已被改为TensorFlow2实现。
在此向为那些为改编作出贡献的人表示感谢。
Github项目地址:https://github.com/trickygo/dive-into-dl-tensorflow2.0
网页版:https://trickygo.github.io/Dive-into-DL-TensorFlow2.0/#/
本书结构:
1.深度学习简介
假设我们要将一张图片分为两类:有猫/无猫:
该图像:400*400像素
每个像素有RGB红绿蓝三个数值
因此共有:400*400*3≈50万个数值
我们的目标是从整个图像中寻找那些能表示猫的特征。
解决方式:“用数据编程”——利用人类肉眼在图像中识别猫的能力,用真实图像数据拟合一个函数,函数的参数由数据确定。
深度学习是指这样一类函数,它们的形式通常为多层神经网络。
绝大多数神经网络都包含以下的核心原则:
- 交替使用线性处理单元与非线性处理单元,它们经常被称为“层”。
- 使用链式法则(即反向传播)来更新网络的参数。
深度学习长足发展的部分原因:
发展 | 作用 |
---|---|
优秀的容量控制方法 | 如丢弃法,通过在神经网络训练时注入噪声解决过拟合问题 |
注意力机制 | 重点关注部分信息而非整体,忽略低价值信息 |
记忆网络、神经编码器—解释器 | 使得针对推理过程的迭代建模方法变得可能 |
对抗网络 | 生成假样本,使得辨别器不能再分辨真实的和生成的样本 |
分布式并行训练算法 | 使得快速训练复杂神经网络成为可能 |
深度学习框架 | 第二代:TensorFlow、CNTK、 Caffe 2 、Apache MXNet; 第三代(命令式深度学习框架):PyTorch、MXNet的Gluon API |
1.1 深度学习的特点
- 深度学习是具有多级表示的表征学习方法。在每一级(从原始数据开始),深度学习通过简单的函数将该级的表示变换为更高级的表示。深度学习是多种简单函数的复合。
- 深度学习将自动找出每一级表示数据的合适方式。
- 深度学习是端到端的训练,机器学习通常将特征提取与机器学习模型构建分开处理。
- 深度学习正在经历从含参数统计模型转向完全无参数的模型。
机器学习、深度学习、表征学习关系如下:
2.预备知识
2.1 数据操作
在TensorFlow中,tensor是一个类,也是存储和变换数据的主要工具。
2.1.1 创建tensor
x = tf.constant(range(12))
x.shape # tensor形状
len(x) # tensor中元素个数
x
<tf.Tensor: shape=(12,), dtype=int32, numpy=array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])>
reshape()改变tensor形状
X = tf.reshape(x,(3,4)) # 利用reshape()函数把向量x的形状改为3行4列矩阵
x.reshape((-1,4)) # 亦可写为这种形式,-1表示自动推断,只指定列
生成特定元素的矩阵
tf.zeros((2,3)) # 生成全0阵
tf.ones((2,3)) # 生成全1阵
可以通过列表list指定需要创建的tensor中每个元素的值:
Y = tf.constant([[2,1,4,3],[1,2,3,4],[4,3,2,1]])
Y
随机生成tensor中每个元素的值,符合均值为0,标准差为1的比标准正态分布:
tf.random.normal(shape=[3,4], mean=0, stddev=1)
2.1.2 运算
X + Y # 按元素加法
X * Y # 按元素乘法
X / Y # 按元素除法
指数运算:
Y = tf.cast(Y, tf.float32) # 将Y元素转换为float32类型
tf.exp(Y)
使用matmul作矩阵乘法:
X(3 * 4),Y(4 * 3) 相乘得到3*3的矩阵
Y = tf.cast(Y,tf.int32)
tf.matmul(X, tf.transpose(Y)) # transpose()函数求转置
连接两个矩阵:
tf.concat([X,Y], axis=0) # axis=0按行连接,axis=1为按列连接
使用条件判断式得到元素为F或T的新的tensor:
tf.equal(X,Y) # 判断X,Y对应位置是否相等
对tensor中的所有元素求和得到只有一个元素的tensor:
tf.reduce_sum(X)
norm()函数计算范数
X = tf.cast(X, tf.float32)
tf.norm(X) # 计算范数
2.1.3 广播机制
当两个形状不同的tensor按元素运算时,可能会处罚广播(broadcasting)机制:先适当复制元素使这两个tensor形状相同后再按元素运算。
A = tf.reshape(tf.constant(range(3)), (3,1))
B = tf.reshape(tf.constant(range(2)), (1,2))
A,B
(<tf.Tensor: shape=(3, 1), dtype=int32, numpy=
array([[0],
[1],
[2]])>,
<tf.Tensor: shape=(1, 2), dtype=int32, numpy=array([[0, 1]])>)
A + B
<tf.Tensor: shape=(3, 2), dtype=int32, numpy=
array([[0, 1],
[1, 2],
[2, 3]])>
2.1.4 索引
tensor的索引从0开始
X[1:3]
在tensorflow的世界里,变量的定义和初始化是分开的。一开始,tf.Variable 得到的是张量,而张量并不是具体的值,而是计算过程。对张量取name并初始化之后,才变成变量。
X = tf.Variable(X)
X[1,2].assign(9) # assign()赋值函数
为行索引为1的元素重新赋值
X[1:2,:].assign(tf.ones(X[1:2,:].shape,dtype = tf.float32)*12)
2.1.5 运算的内存开销
即使对变量X和Y执行 Y=X+Y 操作,也会新开内存,再将Y指向新内存。
为了节省内存,我们可以利用前面的索引来进行替换操作。
Z = tf.Variable(tf.zeros_like(Y)) # 创建与Y形状相同的全0变量Z
before = id(Z)
Z[:].assign(X+Y) #利用索引替换Z中的值
id(Z) == before
True
before = id(X)
X.assign_add(Y)
id(X) == before
True
2.1.6 tensor和numpy相互变换
import numpy as np
P = np.ones((2,3))
# numpy变换tensor
D = tf.constant(P)
# tensor变为numpy
np.array(D)
2.2 自动求梯度
利用tensorflow提供的 GradientTape 自动求梯度。
GradientTape:“梯度带”
分为两个阶段:
记录阶段:记录运算过程中被监视变量的关系图;
求导阶段:通过搜索路径,从而计算出偏微分。
GradientTape 默认(watch_accessed_variables=True)将所有可训练变量(created by tf.Variable, where trainable=True)视为需要“监控”的 source node 。
对于不可训练的变量(比如tf.constant)可以使用tape.watch()对其进行“监控”。
此外,还可以设定watch_accessed_variables=False,然后使用tf.watch()精确控制需要“监控”哪些变量。
简单示例:
求
y
=
2
x
T
x
y = 2{x^T}x
y=2xTx 中y对x的导数
x = tf.reshape(tf.Variable(range(4), dtype=tf.float32),(4,1))
with tf.GradientTape() as t:
t.watch(x)
y = 2*tf.matmul(tf.transpose(x),x)
dy_dx = t.gradient(y,x)
dy_dx
<tf.Tensor: shape=(4, 1), dtype=float32, numpy=
array([[ 0.],
[ 4.],
[ 8.],
[12.]], dtype=float32)>
2.3 查阅文档
查询模块中可调用的函数与类:dir()函数
dir(tf.random)
[‘Algorithm’,
‘Generator’,
‘__builtins__’,
‘__cached__’,
‘__doc__’,
‘__file__’,
‘__loader__’,
‘__name__’,
‘__package__’,
‘__path__’,
‘__spec__’,
‘_sys’,
‘all_candidate_sampler’,
‘categorical’,
‘create_rng_state’,
‘experimental’,
‘fixed_unigram_candidate_sampler’,
‘gamma’,
‘get_global_generator’,
‘learned_unigram_candidate_sampler’,
‘log_uniform_candidate_sampler’,
‘normal’,
‘poisson’,
‘set_global_generator’,
‘set_seed’,
‘shuffle’,
‘stateless_binomial’,
‘stateless_categorical’,
‘stateless_gamma’,
‘stateless_normal’,
‘stateless_parameterized_truncated_normal’,
‘stateless_poisson’,
‘stateless_truncated_normal’,
‘stateless_uniform’,
‘truncated_normal’,
‘uniform’,
‘uniform_candidate_sampler’]
通常可以忽略:
以__开头和结尾的函数:Python的特别对象,
以_开头的函数:Python内部函数
根据其他的成员名字我们可以大致猜测出这个模块提供了各种随机数的生成方法,包括从均匀分布采样(uniform)、从正态分布采样(normal)、从泊松分布采样(poisson)等。
了解某个函数/类具体用法时,可以使用help函数。
help(tf.ones)
Help on function ones in module tensorflow.python.ops.array_ops:
ones(shape, dtype=tf.float32, name=None)
Creates a tensor with all elements set to one (1).
See also `tf.ones_like`, `tf.zeros`, `tf.fill`, `tf.eye`.
This operation returns a tensor of type `dtype` with shape `shape` and
all elements set to one.
>>> tf.ones([3, 4], tf.int32)
<tf.Tensor: shape=(3, 4), dtype=int32, numpy=
array([[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]], dtype=int32)>
Args:
shape: A `list` of integers, a `tuple` of integers, or
a 1-D `Tensor` of type `int32`.
dtype: Optional DType of an element in the resulting `Tensor`. Default is
`tf.float32`.
name: Optional string. A name for the operation.
Returns:
A `Tensor` with all elements set to one (1).