01.TensorFlow简介
1.1 TensorFlow和Keras简介
1.使用tf.data加载数据。
使用tf.data实例化读取训练数据和测试数据
2.模型的建立与调试
使用动态图模式Eager Execution 和著名的神经网络高级API框架Keras。结合可视化工具TensorBoard,简易、快速地建立和调试模型
3.模型的训练:
支持CPU、单GPU、单机多卡GPU、多机集群、TPU训练模型
4.预训练模型部署
通过Tensorflow Hub,可以方便的调用预训练完毕的医用成熟模型
5.模型的部署
通过TensorFlow Serving /TensorFlow Lite /TensorFlow.js等组件,可以将TensorFlow模型部署
1.2 TensorFlow安装
GPU版本的安装
pip install tensoeflow-gpu==2.2.0 -i http://pypi.douban.com/simple
1.3 张量及其操作
1.3.1 张量Tensor
print('hello world')
import tensorflow as tf
import numpy as np
首先创建基础的张量:
# 创建int32类型的0维张量
rank_0_tensor = tf.constant(4)
print(rank_0_tensor)
# 创建flout32类型的1维张量
rank_1_tensor = tf.constant([2.0, 3.0 4.0])
print(rank_1_tensor)
# 创建flout16类型的2维张量
rank_2_tensor = tf.constant([[1,2],
[3,4],
[5,6]], dtype=tf.flout16)
print(rank_2_tensor)
输出结果为:
tf.Tensor(4, shape=(), dtype=flout32) # 标量scalar
tf.Tensor([2. 3. 4.],shape=(3,), dtype=flout32) # 向量 vector
tf.Tensor([[1. 2.]
[3. 4.]
[5. 6.]], shape=(3,2), dtype=flout16) # 矩阵 metrix
2.转换成numpy
-
np.array
# 将张量转换成array形式 tensor1 =tf.constant([1,2,3,4,5]) np.array(tensor1)
3.常用函数
# 定义张量a和b
a = tf.constant([[1,2],[3,4]])
b = tf.conatant([[1,1],[1,1]])
# 加法
tf.add(a,b)
# 元素相乘
tf.multiply(a,b)
# 矩阵乘法
tf.matmul(a,b)
# 最大值
tf.reduce_max(a)
# 最大值索引
tf.argmax(a)
4.变量
特殊张量,形状不可变,但可以更改其中的参数
my_variable = tf.Variable([[1,2],[3,4]])
my_variable.shape
my_variable.dtype
1.4 tf.Keras介绍
tensor2.0的高阶API接口
1.4.1 常用模块
activations 激活函数
applications 预训练网络模块
datasets
layers
losses
metrics
models
optimizers
1.4.2 常用方法
- 数据获取
- 数据处理
- 模型创建于训练
- 模型测试与评估
- 模型预测
1.导入tf.keras
import tensorflow
from tensorflow import keras
2.数据输入
3. 模型构建
4.训练与评估
model.compile()
model.fit()
5.回调函数(callbacks)
6.模型的保存和恢复
- 只保存参数(save weights)
- 保存整个模型(save model.h5)
1.4.3 快速入门模型
# 导入相关的库
# 绘图
import tensorflow
import seaborn as sns
# 机器学习
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegressionCV
# 深度学习:tf.keras
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras import utils
'数据处理’
# 读取数据
iris = sns.load_dataset('iris')
# 将数据之间的关系可视化
sns.pairplot(iris, hue='species')
# 花瓣和花萼的数据(获取数据集的特征值和目标值)
X = iris.values[:,:4]
Y = iris.values[:,4]
# 数据集划分
train_x,test_x,train_y,test_y = train_teat_split(X,Y, test_size=0.5,random_states=0)
# tf.keras 实现
# 数据处理:目标值的进行热编码
def one_hot_encode(arr):
# 获取目标值中的所有类别,并进行热编码
uniques,ids = np.unique(arr,return_inverse=True)
return utils.to_categorical(ids,len(uniques))
# 对目标值进行编码
train_y_ohe = one_hot_encode(train_y)
test_y_ohe = one_hot_encode(test_y)
# 模型搭建
# 利用Sequential方式构建模型
model = Sequential([
# 隐藏层
Dense(10, activation = "relu", input_shape = (4,)),
# 隐藏层
Dense(10, activation ="relu" ),
# 输出层
Dense(3, activation = "softmax")
])
------------------------------------------------------------------
model.summary() # 查看网络结构
utils.plot_model(model, show_shapes=True) # 查看网络结构图
------------------------------------------------------------------
# 模型训练与评估
# 设置模型的相关参数:优化器、(交叉熵)损失函数和评价标准
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
# 类型转换
train_x = np.array(train_x, dtype=np.float32)
test_x = np.array(test_x, dtype=np.float32)
# 模型训练;epochs,训练样本送入网络的次数;batch_size:每次训练的送入网络中的样本个数
model.fit(train_x,train_y_ohe,epochs=10,batch_size=1,verbose=1)
# 模型评估:计算模型的损失与准确率
loss, accuracy = model.evaluate(test_x, test_y_ohe,verbose=1)
2.1 Deep_learning简介
神经网络简介
1.什么是神经网络 ANN
Input layer —>> Hidden layers —>> Output layer
f ( b + ∑ i = 1 n x i w i ) f(b+\sum_{i=1}^{n}x_iw_i) f(b+∑i=1nxiwi)
2.激活函数
-
sigmoid/logistics函数
-
import tensorflow as tf import tensorflow.keras as keras import matplotlib.pyplot as plt x=np.linspace(-10,10,1000) y=tf.nn.sigmoid(x) plt.plot(x,y) plt.grid()
-
-
tanh(双曲正切)
-
import tensorflow as tf import tensorflow.keras as keras import matplotlib.pyplot as plt x=np.linspace(-10,10,1000) y=tf.nn.tanh(x) plt.plot(x,y) plt.grid()
-
-
RELU
-
# Relu是一部分神经元输出为0,造成网络的稀疏性,减少过拟合 import tensorflow as tf import tensorflow.keras as keras import matplotlib.pyplot as plt x=np.linspace(-10,10,1000) y=tf.nn.relu(x) plt.plot(x,y) plt.grid()
-
-
LeakRelu
f ( x ) = m a x ( 0.1 x , x ) f(x) = max(0.1x,x) f(x)=max(0.1x,x)
-
import tensorflow as tf import matplotlib.pyplot as plt import tensorflow.keras as keras x = np.linspace(-10,10,1000) y=tf.nn.leak_relu(x) plt.plot(x,y) plt.grid()
-
-
Softmax
-
s o f t m a x ( z i ) = e ( z i ) ∑ j e ( z j ) softmax(z_i) = \frac{e^(z_i)}{\sum_j e^(z_j)} softmax(zi)=∑je(zj)e(zi)
-
就是将网络输出的logits通过softmax函数映射成(0,1)的值,这些值的累计和为1
-
import tensorflow as tf import matplotlib.pyplot as plt import tensorflow.keras as keras import numpy as np # 数字中的score x = tf.constant([0.2,0.02,0.15,1.3,0.5,0.06,1.1,0.05,3.75]) # 将其送入到softmax中计算分类结果 y = tf.nn.softmax(x) # 将结果进行打印 print(y)
-
-
其它激活函数
- identity function
- binary step
- Logistic
- PRelu
- RRelu
- ELU
隐藏层:优先使用RELU激活函数,效果不好时可以考虑Leaky_relu,需要注意Dead Relu问题
输出层:二分类sigmoid 多分类softmax函数 回归identity
-
参数初始化
-
随机初始化:高斯分布取样
-
标准初始化:均匀随机取值
以下两种使用最多
-
Xavier初始化
基本思想:各层的激活值和梯度的方差在传播过程中保持一致,也叫作Glorot初始化
# Xavizer初始化 iport tensorflow as tf # 1. 正态分布的 # 进行实例化 initializer = tf.keras.initializers.glorot_normal() # 采样得到权重 values = initializers((9,1)) # 2. 标准化:均匀分布的 # 进行实例化 initializer = tf.keras.initializers.glorot_uniform() # 采样得到权重 values = initializers(shape=(9,1)) print(values)
- He初始化
正向传播时,激活值的方差保持不变;反向传播时。关于状态值的梯度的方差保持不变
# He初始化 iport tensorflow as tf # 1. 正态分布 # 实例化 initializer = tf.keras.initializers.he_normal() # 采样得到权重 values = initializers(shape=(9,1)) print(values) # 2. 均匀分布 # 实例化 initializer = tf.keras.initializers.he_uniform() # 采样得到权重 values = initializers(shape=(9,1)) print(values)
-
-
神经网络的搭建
一种使用Sequential构建 一种通过model类进行构建(函数式编程或继承model类)
4.1 通过Sequential构建
'神经网络的搭建'
# 导入相关的工具包
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
# 定义model,构建模型、
model = keras.Sequential([
# 第一个隐层
layers.Dense(3,activation='relu',kernel_initializer='he_normal',name = "layer1", input_shape=(3,)),
# 第二个隐层
layers.Dense(2,activation='relu',kernel_initializer='he_normal',name = "layer2"),
# 输出层
layer.Dense(2,activation='sigmoid',kernel_initializer='he_normal',name = "layer3")]
name="sequential"
)
# model.summary()
# keras.untils.plot_model(model)
4.2 通过functional API构建
将层作为可调用的对象并返回张量,并将输入向量和输出向量提供给’tf.keras.Model’的’inputs’和’outputs’参数,实现方法如下:
# 导入工具包
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
# 定义模型的输入
inputs = keras.Input(shape=(3,), name="input")
# 第一层:激活函数为relu,其它默认
x = layers.Dense(3, activation='relu',name = 'layer1')(inputs)
# 第二层:激活函数为relu,其它默认
x = layers.Dense(2, activation='relu',name = 'layer2')(x)
# 第三层(输出层):激活函数为sigmoid
outputs = layers.Dense(2, activation='sigmoid',name = 'output')(x)
# 使用model来创建模型,指明输入和输出
model = keras.Model(inputs=inputs, outputs=outputs, name="Functional_API_model")
---------------------------------------------------
model.summary()
keras.untils.plot_model(model,show_shapes=True)
4.3 通过model的子类进行构建
通过model的子类进行构建,此时需要在—init—中定义神经网络的层,在call方法中定义网络的前向传播过程,实现方法如下:
# 导入工具包
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
# 定义一个model的子类
class MyModel(keras.Model):
# 在init方法中定义网络的层结构
def __init__(self):
super(MyModel, self).__init__()
# 第一层:激活函数为relu,权值初始化为he_normal
self.layer1 = layers.Dense(3,activation="relu", name="layer1")
# 第二个隐层
self.layer2 = layers.Dense(2,activation="relu", name="layer2")
# 输出层
self.layer3 = layers.Dense(2,activation="sigmoid", name="layer3")
# 定义网络的前向传播
def class(self,inputs):
x = self.layer1(inputs)
x = self.layer2(x)
outputs = self.layer3(x)
return outputs
# 实例化模型
model = MyModel()
# 设置输入
x = tf.ones((1,3))
y = model(x)
-
神经网络的优缺点
-
优点:可以接近任意非线性函数了,大量框架和库可使用;
-
缺点:黑箱,没办法了解怎么工作的,训练时间长,需要大量计算力,网络结构复杂,需要调整超参数,小数据集容易过拟合。
-
常见的损失函数
衡量模型参数的函数 Loss/cost/objective/error Function
分类任务
-
多分类任务
softmax损失: L = − ∑ i − 1 n y i l o g ( S ( f Θ ( X i ) ) ) L=-\sum_{i-1}^{n} y_ilog(S(f_\Theta(X_i))) L=−∑i−1nyilog(S(fΘ(Xi)))
# 交叉熵损失函数
import tensorflow as tf
import tensorflow.keras as keras
# 设置真实值和预测值
y_true = [[0,1,0],[0,0,1]]
y_pred = [[0.05,0.9,0.05],[0.3,0.2,0.5]]
# 实例化交叉熵损失
cce = keras.losses.CategoricalCrossentropy()
# 计算损失结果
cce(y_true,y_pred)
-
二分类任务
L = − y l o g y ^ − ( 1 − y ) l o g ( 1 − y ^ ) L=-ylog\hat{y} - (1-y)log(1-\hat{y}) L=−ylogy^−(1−y)log(1−y^) 使用sigmoid激活函数
# 二分类的交叉熵损失函数 import tensorflow as tf import tensorflow.keras as keras # 设置真实值和预测值 y_true = [[0],[1]] y_pred = [[0.9],[0.5]] # 实例化交叉熵损失 cce = keras.losses.BinaryCrossentropy() # 计算损失结果 cce(y_true,y_pred)
-
回归任务
-
MAE 损失
-
MSE 损失
-
smooth L1 损失 s m o o t h L 1 ( x ) = { 0.5 x 2 i f ∣ x ∣ < 1 ∣ x ∣ − 0.5 o t h e r w i s e smooth_{L_1} (x) = \begin{cases} 0.5x^2 \quad &if |x|<1 \\|x| - 0.5 \quad &otherwise \end{cases} smoothL1(x)={0.5x2∣x∣−0.5if∣x∣<1otherwise
h = tf.keras.lossses.Huber()
-
深度学习的优化方法
-
梯度下降算法
-
W i j n e w = W i j o l d − η ∂ E ∂ W i j W_{ij}^{new} = W_{ij}^{old} - \eta\frac{\partial{E}}{\partial{W_{ij}}} Wijnew=Wijold−η∂Wij∂E
-
η \eta η 为学习率
-
BGD SGD MBGD(小批量梯度下降)
# 梯度下降算法 # 导入工具包 import tensorflow as tf import tensorflow.keras as keras # 实例化 opt = tf.keras.optimizers.SGD(learning_rate=0.1) # 定义要更新的参数 var = tf.Variable(1.0) # 定义损失函数 loss = lambda:(var**2)/2.0 # 计算梯度损失,并进行参数更新 opt.minimize(loss,[var]).numpy() # 参数更新结果 var.numpy()
Epoch / Batch / Iteration
-
epoch:一代训练
-
batch:一批数据
-
iteration:一个batch一次参数更新,一次训练
梯度下降方式 Training Set Size Batch Size Number of Batches BGD N N 1 SGD N 1 N Mini-Batch N B N/B +1(针对未整除的情况)
-
-
反向传播算法(BP算法)
该方法与梯度下降算法相结合
在网络训练过程中,前向传播中的最终结果跟真实值之间存在一定误差,要减小误差,从后往前,依次求各个参数的偏导,就是反向传播。( 复合函数求偏导 )
σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{1+e^{-z}} σ(z)=1+e−z1 求导为: σ ( z ) ( 1 − σ ( z ) ) \sigma(z)(1-\sigma(z)) σ(z)(1−σ(z))
-
计算损失函数 并进行反向传播
-
计算梯度值
-
参数更新
-
更新输出层、隐藏层权重 ;偏置更新
-
until神经网络模型在验证集上的错误率不在下降
- 梯度下降优化算法
- 动量算法(Momentum)
指数加权平均
- 动量梯度下降算法
计算梯度的指数加权平均数,并利用该值来修改权重
在kears中使用Momentum算法仍使用功能SGD方法,但要设置momentum参数,实现过程如下:
Momentum算法实现
# 导入相应的包
import tensorflow as tf
# 实例化优化方法:SGD指定参数beta=0.9
opt = tf.keras.optimizers.SGD(learning_rate=0.1, momentum=0.9)
# 定义要调整的参数,初始值
var = tf.Variable(1.0)
val0 = var.value()
# 定义损失函数(L2损失函数)
loss = lambda: (var**2)/2.0
# 第一次更新:计算梯度,并对参数进行更新,步长为'- learning_rate * grad'
opt.minimize(loss, [var]).numpy()
val1 = var.value()
# 第二次更新:计算梯度,并对参数进行更新,因为加入了momentum,步长会增加
opt.minimize(loss, [var]).numpy()
val2 = var.value()
# 打印两次更新的步长
print("第一次更新步长={}".format((val0 - val1).numpy()))
print("第二次更新步长={}".format((val1 - val2).numpy()))
-------------------------------运行结果----------------------------------
'''
使用了Momentum梯度下降算法,两次步长逐渐增加
val0-val1=0.10024
val1-val2=0.18001
'''
- AdaGrad算法
使用一个小批量随机梯度g_t按元素平方的累加变量St.
s t ← s t − 1 + g t ⨀ g t s_t \leftarrow s_{t-1} + g_t\bigodot g_t st←st−1+gt⨀gt
w t ← w t − 1 − η s t + ϵ ⨀ g t w_t \leftarrow w_{t-1} - \frac{\eta}{\sqrt{s_t+\epsilon}}\bigodot g_t wt←wt−1−st+ϵη⨀gt ,其中 η \eta η 是学习率, ϵ \epsilon ϵ 是为了维持稳定性而添加的常数,如 1 0 − 6 10^{-6} 10−6 。
# 导入相应的包
import tensorflow as tf
# 实例化优化方法:SGD
opt = tf.keras.optimizers.Adagrad(learning_rate=0.1, initial_accumulator_value=0.1, epsilon=1e-06)
# 定义要调整的参数,初始值
var = tf.Variable(1.0)
# 定义损失函数(L2损失函数)
def loss():
return(var**2)/2.0
# 计算梯度,并对参数进行更新
opt.minimize(loss, [var]).numpy()
--------------------------------------
print(var)
- RMSprop算法
对Adagrad算法进行了一点小小修改,将梯度按元素平方做指数加权移动平均
# 导入相应的包
import tensorflow as tf
# 实例化优化方法
opt = tf.keras.optimizers.RMSprop(learning_rate=0.1, rho=0.9)
# 定义要调整的参数,初始值
var = tf.Variable(1.0)
# 定义损失函数(L2损失函数)
def loss():
return(var**2)/2.0
# 对参数进行更新
opt.minimize(loss, [var]).numpy()
--------------------------------------
print(var.numpy())
- Adam算法(自适应矩估计) 使用较多(首选)
在RMSprop算法基础上对小批量随机梯度做了指数加权移动平均
参数更新:学习率:需要尝试
\beta1=0.9
\beta2=0.999
\epsilon默认1e-8
# 导入相应的包
import tensorflow as tf
# 实例化优化方法
opt = tf.keras.optimizers.Adam(learning_rate=0.1) # 其它参数使用默认设置
# 定义要调整的参数,初始值
var = tf.Variable(1.0)
# 定义损失函数(L2损失函数)
def loss():
return(var**2)/2.0
# 对参数进行更新
opt.minimize(loss, [var]).numpy()
-------------------------------------------------
print(var.numpy())
学习率退火
- 分段常数衰减
- 指数衰减
- 1/t 衰减
深度学习的正则化
通过对算法的修改减少泛化误差
- L1与L2正则化
L1 对压缩模型很有用,其它情况一般选用L2正则化(直接在LAYERS中指明正则化类型和超参数即可)
- Dropout正则化
可以看成机器学习中的集成学习。一般由于单一模型,可以捕获更多的随机性,dropout使得神经网络模型优于正常的模型
rate: 每一个神经元被丢弃的概率
# Dorpout
# 导入相关的包
import tensorflow as tf
import numpy as np
# 定义dropout层
layer = tf.keras.layers.Dropout(0.2, input_shape=(2,)) # dropout层失活概率为0.2
# 定义输入数据
data = np.arange(1,11).reshape(5,2).astype(np.float32)
print(data)
# 对输入数据进行随机失活
outputs = layer(data,training=True) # 如果设置为false时dropout层不起作用
print(outputs)
- 提前停止
在tf.kears中,我们使用callbacks函数实现早期停止:
monitor参数表示监测量;patience参数表示epochs数量,当在这个过程中性能无提升时会停止训练。即虚线后patience个epoch,模型将停止训练,因此没有进一步的改善。
# 提前停止
# 导入相关的包
import tensorflow as tf
import numpy as np
# 定义回调函数
callback = tf.keras.callbacks.EarlyStopping(monitor="loss",patience=3)
# 定义一层的网络
model = tf.keras.models.Sequential([tf.keras.layers.Dense(10)])
# 模型编译
model.compile(tf.keras.optimizers.SGD(),loss='mse')
# 模型训练
history = model.fit(np.arange(100).reshape(5,20),np.array([0,1,0,1,0]), epochs=10, batch_size=1, callbacks=[callback], verbose=1) # verbose=1代表选择打印日志
h=len(history['loss'])
print(h)
- 批标准化
批标准化(BN层,Batch Normalization)
对某一批次数据的神经元的输出进行标准化(均值、方差、标准化),然后再使用变换重构,引入可学习参数$ \gamma / \beta$ 对标准化的结果进行下一步处理:
z ~ ( i ) = γ z n o r m ( i ) + β \tilde{z}^{(i)} = \gamma z_{norm}^{(i)} + \beta z~(i)=γznorm(i)+β
神经网络案例(MNIST案例)
案例实现流程
- 数据加载
- 数据处理
- 模型构建
- 模型训练
- 模型测试
- 模型保存
unit8: 图像专用特殊的数据类型(8位无符号整数),以此方式存储的图像称作8位图像。
案例代码实现
# 导入所需的工具包
import numpy as np
import matplotlib.pyplot as plt
# tf中使用的工具包
import tensorflow as tf
# 构建模型
from tensorflow.kears.models import Sequentiual
# 相关的网络层
from tensorflow.keras.layers import Dense,Dropout,Activation,BatchNormalization
# 导入辅助工具包
from tensorflow.keras import utils
# 正则化
from tensorflow.keras import regularizers
1.数据加载
# 加载数据集
(x_train,y_train),(x_test,y_test) = mnist.load_data()
# 显示数据
plt.figure()
plt.imshow(x_train[1], camp='gray') #显示索引为1的图片
2.数据处理
# 调整数据维度:每一个数字转换成一个向量
x_train = x_train.reshape(60000,784)
x_test = x_test.reshape(10000,784)
#数据类型调整
x_train = x_train.astype('float32')
x_test=x_test.astype('float32')
# 归一化
x_train = x_train/255
x_test = x_test/255
# 将目标值转换成热编码的形式
y_train = utils.to_categorical(y_train,10)
y_test = utils.to_categorical(y_test,10)
3.模型构建
# 三层全连接网络构建(序列模型)
model = Sequential()
# sequential方式 定义一个空元组 进行一步步a
# 全连接层、两个隐藏层、一个输出层
# 第一个隐层:512个神经元,先激活后BN,随机失活
model.add(Dense(512,activation='relu', input_shape=(784,)))
model.add(BatchNormalization)
model.add(Dropout(0.2))
# 第二个隐层:512个神经元,先BN后激活,随机失活
model.add(Dense(512, kernel_regularizer=regularizers.l2(0.01)))
model.add(BatchNormalization)
model.add(Activation='relu')
model.add(Dropout(0.2))
# 输出层
model.add(Dense(10),activation='softmax')
# 展示模型架构
# model.summary()
# utils.plot_model(model)
4.模型编译
设置模型训练使用的损失函数(交叉熵损失)和优化方法(adam),损失函数用来衡量预测值和真实值之间的差异,优化器用来使损失函数达到最优
# 模型编译,指明:损失函数。优化器和评估指标
model.compile(loss= tf.keras.losses.categorical_crossentropy, optimizer = tf.keras.optimizers.Adam(),
metrics=tf.keras.metrics.Accuracy())
5.模型训练
# 使用fit, 指定训练集, epochs, batch_size, val, verbose
history = model.fit(x_train,y_train,epochs=4,batch_size=128,validation_data=(x_test,y_test),verbose=1)
# 绘制损失函数
plt.figure()
plt.plot(history.history['loss'],lable="train")
plt.plot(history.history['val_loss'],lable="val")
plt.legend()
plt.grid()
# 准确率
plt.figure()
plt.plot(history.history['accuracy'],lable="train")
plt.plot(history.history['val_accuracy'],lable="val")
plt.legend()
plt.grid()
通过tensorboard 监控训练过程:
# 回调函数
tensorboard = tf.keras.callbacks.TensorBoard(log_dir = "./graph")
# 训练
history = model.fit(x_train,y_train,epochs=4,validation_data=(x_test,y_test),batch_size=128,verbose=1,
callbacks=[tensorboard])
----------------------------------------------------------------
在终端中打开指定文件夹的目录,运行一下命令:
tensorboard --logdir="./"
6.模型评估与保存
# 模型评估
model.evaluate(x_test,y_test,verbose=1)
# 模型保存
model.save("model.h5")
# 加载模型
loadmodel = tf.keras.models.load_model("model.h5")
loadmodel.evaluate(x_test,y_test,verbose=1)
2.6 卷积神经网络
全连接网络的问题:
- 需要处理的数据量大,效率低下,耗资源
- 维度调整过程中,很难保留原有的特征,导致图像处理的准确率不高
CNN网络的构成
卷积层 | 池化层 | 全连接层 |
---|---|---|
提取图像特征 | 降维、防止过拟合 | 输出结果 |
卷积层
卷积层
核心模块 目的是提取图像特征
I n p u t → F i l t e r → O u t p u t ( F e a t u r e − m a p ) Input \rightarrow Filter \rightarrow Output(Feature-map) Input→Filter→Output(Feature−map)
padding
保证卷积过程中特征图大小不变,在原图像周围用0来进行padding
stride
卷积步长 自行设置 移动卷积核
多通道卷积
实际图像都是多通道组成的
input image | Filter | Feature Map |
---|---|---|
5 ∗ 5 ∗ 3 5*5*3 5∗5∗3 | 3 ∗ 3 ∗ 3 3*3*3 3∗3∗3 | 3 ∗ 3 3*3 3∗3 |
多卷积核卷积
每个卷积核学习不同的特征,对应产生多个channel的Feature Map
有多少个卷积核,就产生有多少个通道的特征图
特征图大小
输入体积大小 H 1 ∗ W 1 ∗ D 1 H_1*W_1*D_1 H1∗W1∗D1
四个超参数:卷积核数K 卷积核大小F 步长S 零填充大小P
输出体积大小 H 2 ∗ W 2 ∗ D 2 H_2*W_2*D_2 H2∗W2∗D2
- H 2 = ( H 1 − F + 2 P ) / S + 1 H_2 = (H_1-F+2P)/S+1 H2=(H1−F+2P)/S+1
- W 2 = ( W 1 − F + 2 P ) / S + 1 W_2 = (W_1-F+2P)/S+1 W2=(W1−F+2P)/S+1
- D 2 = K D_2=K D2=K
在tf.keras中卷积核的实现:
tf.keras.layers.Conv2D(
filters, kernel_size, strides=(1, 1), padding='valid',activation=None)
主要参数说明如下:
参数 | 描述 |
---|---|
filters | 卷积过滤器的数量,对应输出特征图的通道数 |
kernel_size | 过滤器filter的大小 |
strides | 步长 |
padding | valid:在输入周围不进行padding; same: padding后使输出特征图和输入特征图形状相同 |
activation | 激活函数 |
池化层(Pooling)
降低后续输入维度,缩减模型大小,提高计算速度,防止过拟合主要对特征图进行下采样(subsampling)操作
-
最大池化 (取窗口中的最大值作为输出)
tf.keras.layers.MaxPool2D()
-
平均池化 (取窗口中的均值作为输出)
tf.keras.layers.AveragePooling2D()
全连接层
位于CNN网络的末端,进行分类或回归的操作。
在tf.keras中使用 tf.keras.dense实现。
卷积神经网络的构建
LeNet-5处理mnist数据集
输入二维图像,经过两次卷积池化,经过全连接,最后softmax分类
# 导入相关包
import tensorflow as tf
import tensorflow.keras as keras
from tensorflow.keras.datasets import mnist
# 数据集加载
(train_images,train_lables),(test_images,test_lables) = mnist.load_data()
# 数据处理(图像个数、高、宽、通道数)
# 维度调整
train_images = tf.reshape(train_images, (train_images.shape[0],train_images.shape[1],
train_images.shape[2],1)) # Tensorshape ([60000,28,28,1])
-----------------------------------------------------------------------------------------
# 模型构建
net = keras.models.Sequential([
# 卷积层:6个5*5的卷积 sigmoid
keras.layers.Conv2D(filters=6, kernel_size=5, activation='sigmoid',input_shape=(28,28,1)),
# maxpooling
keras.layers.MaxPool2D(pool_size=2, strides=2),
# 卷积层:16个5*5的卷积核 sigmoid
keras.layers.Conv2D(filters=16, kernel_size=5, activation='sigmoid'),
# maxpooling
keras.layers.MaxPool2D(pool_size=2,strides=2),
# 维度调整
keras.layers.Flatten()
# 全连接层, sigmoid
keras.layers.Dense(120,activation='sigmoid')
# 全连接层, sigmoid
keras.layers.Dense(84,activation='sigmoid')
# 输出层 softmax
keras.layers.Dense(10,activation='softmax')
])
-------------------------------------
net.summary() # 查看网络结构
keras.utils.plot_model(net)
-------------------------------------
# 模型编译
# 设置优化器、损失函数、评价指标
net.compile(optimizer=keras.optimizers.SGD(learning_rate = 0.9),
loss=keras.losses.sparse_categorical_crossentropy,metrics=['accuracy'])
# 未进行热编码的时候,就选用sparse交叉熵损失函数
# 模型训练
net.fit(train_images,train_lables, epochs=5, batch_size=128, verbose=1)
#模型评估
net.evaluate(test_images,test_lables, verbose=1)
残差网络ResNet
随着网络层数的增加,优化效果反而越差,测试数据和训练数据的准确率反而降低了,针对这一问题,何恺明提出残差网络
构建残差块
# 导入工具包
import tensorflow as tf
from tensorflow.keras import layers,activations
# 残差块
class Residual(keras.Model):
# 定义网络结构
def __init__(self,num_channels,use_1x1conv=False,strides=1):
super(Residual,self).__init__()
# 卷积层
self.conv1 = layers.Conv2D(num_channels, padding='same', kernel_size=3, strides=strides)
# 卷积层
self.conv2 = layers.Conv2D(num_channels, kernel_size=3, strides=strides)
# 是否使用1x1卷积
if use_1x1conv:
self.conv3 = layers.Conv2D(num_channels, kernel_size=1, strides=strides)
else:
self.conv3 = None
#BN层
self.bn1 = layers.BatchNoramlization()
self.bn2 = layers.BatchNoramlization()
# 定义前向传播过程
def call(self,x):
Y = activations.relu(self.bn1(self.conv1(x)))
Y = self.bn2(self.conv2(Y))
if self.conv3:
x = self.conv3(x)
output = activations.relu(Y+x)
return outputs
Resnet-18实现
# 残差模块
class ResnetBlock(tf.keras.layers.Layer):
# 定义所需的网络结构
def __init__(self,num_channels, num_res, first_block=Flase):
super(ResnetBlock,self).__init__()
# 存储残差块
self.listLayers=[]
# 遍历所有的残差数目生成模块
for i in range(num_res):
# 如果是第一个残差块,而且不是第一个模块时,
if i == 0 and not first_block:
self.listLayers.append(Residual(num_cahnnels,use_1x1conv=True, strides=2))
else:
self.listLayers.append(Residual(num_cahnnels))
# 定义前向传播过程:
def call(self,X):
for layer in self.listLayers.layers:
X = layer(X)
return X