1. 深度学习框架
① 主流框架:封装了优化器和反向传播算法等
Google的Tensorflow、Facebook的Pytorch、华为的MindSpore、Caffe、theano、MXNet、CNTK
② Pytorch的特点:Python优先:保证代码基本跟原生的python实现一致
动态神经网络:Pytorch的程序可以在执行时动态构建/调整计算图
易于Debug:运行时可以生成动态图,开发者可以在调试器中停掉解释器并查看某个节点的输出
Pytorch提供了支持 CPU和 GPU的Tensor,加速计算
Tensorflow1.x的弊端:静态计算图(调试困难,API混乱)
TensorFlow1.0里在创建了Tensor之后,不能直接返回结果。而是需要创建session会话机制
,包含graph的概念在里面,而且需要session.run才能运行。
Tensorflow2.x的优点:Keras高级接口、去掉了graph和session机制、标准化了API、动态图机制:Eager execution
多语言、多平台:Python、C++、go、java; 从手机到计算机集群都能生成你的训练模型
分布式、运算性能强:多进程,不同服务器并行运算;在谷歌的AI芯片TPU上运行性能是最好的
2. TensorFlow2基础理论
① 张量(tensor):一个多维的数组;常量:储存超参数;变量:存储权重和矩阵
② 常量创建方式:
const_a = tf.constant([[1,2,3,4]],shape=[2,2],dtype=tf.float32) # 创建常量tensor浮点型2x2矩阵
a.numpy() --> [[1. 2.] [3. 4.]] # 常量数值读取
zeros_b = tf.zeros(shape=[2, 3], dtype-tf.int32) # 创建2x3矩阵,元素值均为0
zeros_like_c = tf.zeros_like(const_a) # 全零矩阵和张量const_a的形状是一样的
fill_d = tf.fil1([3,3],8) # 用一个具体值充满张量
random_e = tf.random.normal([5,5],mean=0,stddev=1.0) # 创建正态分布的张量,均值为0,标准差为1
list_f =[1,2,3,4,5,6]
tensor_f = tf.convert_to_tensor(list_f,dtype=tf.float32) # 转化为张量类型,变成6维向量
③ 变量的创建方式:
var_1 = tf.Variable(tf.ones([2,3])) # 创建变量,只需提供初始值
var_1.read_value()
tf.Tensor([[1. 1. 1.][1. 1. 1.]],shape=(2,3),dtype=float32) # 变量数值读取
var_1.assign_add(tf.ones([2,3])) # 变量加法,每个数字加1
④ 张量的切片与索引:
索引:
tensor_h= tf.random.normal([4,100,100,3]) # 包含4张图片,每张图片大小100*100*3
tensor_h[0][20][40][1] # 取出第一张图片第二个通道中在[20,40]位置的像素点
tf.Tensor: shape=o, dtype=float32,numpy=-1.8221084> # CPU:MHWC 样本数量 高 宽 维度; GPU(CUDA):NCHW
indices = [0,1,3] tf.gather(tensor_h,axis=O,indices=indices) # 取出tensor_h([4,100,100,3])中的第1,2,4张图像。
indices =[[0,1,1,0],[1,2,2,0]] # 取出tensot_h([4,100,100,3])中,
tf.gather_nd(tensor_h,indices=indices) # 第一张图像第一个维度[1,1]的像素点;第二张图片第一像素点[2,2]的像素点
切片:
tensor_h[0, :, :, :] # 取出第一张图片
tensor_hl[: : 2, ...] # 每两张图片取出一张的切片
tensor_hl[: : -1] # 倒序切片
[start: end] # 从tensor的开始位置到结束位置的数据切片;
[start :end :step]或者[::step] # 从tensor的开始位置到结束位置每隔step的数据切片
[::-1] # 负数表示倒序切片
‘...’ # 任意长
⑤ 张量的维度变化
# 查看维度常用的三种方式
const_d_1.shape (2,2)
const_d_1.get_shape() (2,2)
tf.shape(const_d_1) tf.Tensor([2 2],shape=(2,),dtype=int32) # 输出为张量类型对象
# 维度重组
reshape_l = tf.constant([[1,2,3],[4,5,6]])
tf.reshape(reshape_1,(3,2)) # 将2*3重组为3*2
# 维度增加(在cpu中的NHWC数据格式)
expand_sample_1.shape # 原始数据尺寸:(100,100,3)
tf.expand_dims(expand_sample_1,axis=0).shape) # 在第一个维度前增加:(1,100,100,3)
tf.expand_dims(expand_sample_l,axis=1).shape) # 在第二个维度前增加:(100,1,100,3)
,tf.expand_dims(expand_sample_l, axis=-1).shape) # 在最后一个维度后增加:(100,100,3,1)
# 维度减少(数据可视化用matplotlib、opencv)
squeeze_sample_1.shape # 原始数据尺寸:(1,100,100,3)
tf.squeeze(squeeze_sample_l,axis=0) # 维度压缩后的数据尺寸:(100,100,3)
# 转置
tf.transpose(trans_sample_1) # 从2*3变成3*2
tf.transpose(trans_sample_2,[0,2,1,3]) # 从[0,1,2,3]变成[0,2,1,3],图片旋转90度
# 广播
broadcast_sample_l.numpy() # 原始数据:[1 2]
tf.broadcast_to(broadcast_sample_1,shape=[4,6]) # 广播后数据:[[12][12][12][12]]
⑥ 张量的算术运算
# 矩阵加法
a = tf.constant([[3,5],[4,8]])
b = tf.constant([[1,6],[2,9]])
tf.add (a,b)) --> tf.Tensor([[4 11] [6 17]],shape=(2,2),dtype=int32)
# 矩阵乘法
tf.matmul(a,b) --> tf.reduce_sum(reduce_sample_l, axis=None/0/1).numpy())
tireduce_prod(乘法) t.reduce_min(最小) tfreduce_max(最大) tf reduce_mean(均值)
tfreduce_all (逻辑和) tf.reduce_any(逻辑或)tf.reduce_logsumexp (log(sum(exp)))操作)
⑦ 张量的拼接与分割
# 张量的拼接
tf.contact() # 将向量按指定维连起来,其余维度不变
tf.stack() # 将一组R维张量变为R+1维张量,拼接前后维度变化
eg:
concat_sample_l = tf.random.normal([4,100,100,3]) # 4张图片
concat_sample_2 = tf.random. normal([40,100,100,3]) # 40张图片
tf.concat([concat_sample_1,concat_sample_2],axis=0) # 44张图片 (44,100,100,3)
stack_sample_l = tf.random.normal([100,100,3]) # 1张图片
stack_sample_2 = tf.random. normal([100,100,3]) # 1张图片
stack_1=tf.stack([concat_sample_1,concat_sample_2],axis=0) # 2张图片 (2,100,100,3)
# 张量的分割
tf.unstack() # 将张量按照特定维度分解
tf.split() # 将张量按照特定维度划分为指定的分数
tf.unstack(stack_1,axis=0) # 分割成2张照片100*100*3
split_sample_l = tf.random. norma1([10,100,100,3])
tf.split(split_sample_l,num_or_size_splits=[3,5,2],axis=0) # 将张量分为3份
⑧ 张量排序
# 张量排序
tf.sort() # 按照升序或者降序对张量进行排序,返回排序后的张量
tf.argsort() # 按照升序或者降序对张量进行排序,但返回的是索引
sort_1 =tf.random.shuffle(tf.range(4)) # 原数据:[2 1 3 0]
tf.sort(sort_1 , direction="ASCENDING") # 升序:[0 1 2 3]
tf.argsort(sort_1 ,direction="DECENDING") # 降序并返回的索引:[2 0 1 3]
tf.nn.top_k() # 返回前k个最大值
values,index = tf.nn.top_k(sort_1, 3) # 返回前三个最大值
values.numpy() # [3 2 1]
index.numpy() # 降序并返回的索引:[2 0 1]
⑨ Eager Execution与AutoGraph(RELU激活函数,卷积层)
# Eager Execution可以使用原生控制流(if while)并立即执行得到返回值
import tensorflow.compat.vl as tf # tensorflow 1.x引用
# AutoGraph
eg1:
@tf.function
def simple_nn_layer(w,x,b):
print(b) # 此处为静态图print不会输出值
return tf.nn.relu(tf.matmu1(w,x)+b)
w = tf.random.uniform(3,3))
x = tf.random.uniform((3,3))
b = tf.constant(0.5,dtype='float32')
simple_nn_layer(w,x,b) -->
[1.413028,0.8224975,1.7023976],[1.9083244,1.2047547,1.2964082],[1.9147431,1.1107702,1.7441201]],
eg2:
import timeit # timeit测量小段代码的裁行时间
CNN_cell=tf.keras.layers.Conv2D(filters=100,kernel_size=2,strides=(1,1))
# 创建一个卷积层,keras接口,Conv2D二维的卷积,100个卷积核 卷积核大小2*2,步长1*1
image = tf.zeros([100,200,200,3]) # 初始化一个张量
@tf.function # 利用@tf.function,将操作转化为graph
def CNv_fn(image):
return CNN_ce11(image)
timeit.timeit(1ambda:CN_ce1l(image),number=10)) # 执行10次卷积层时间为13秒
timeit.timeit(1ambda: CNN_fn(image),number10)) # 执行10次卷积层时间为7秒
结论:在静态图graph的模式下,如果神经网络有很多重复的模块,可以定义函数用tf.function将模块封装起来,提高代码执行效率
3. TensorFlow2常用模块
① 网络拓扑架构构建
tf.data: # 实现对数据集的操作;包括读取从内存中直接读取数据集、读取CSV文件、读取tfrecord文件和数据增强等。
tf.image # 实现对图像处理的操作﹔包括图像亮度变换、饱和度变换、图像尺寸变换、图像旋转和边缪检测等操作。
tf.gfile # 实现对文件的操作﹔包括对文件的读写操作、文件重命名和文件夹操作等。
tf.keras # 用于构建和训练深度学习模型的高阶API﹔
1.1 模型堆叠
import tensorflow.keras.layers as layers
model = tf.keras.Sequential()
# 层的堆叠,一层一层的添加网络层
mode1.add(layers.Dense(32,activation='relu'))
# 做分类的全连接网络,有32个神经元,激活函数为relu,网络层为Dense,也可以用Conv2D,LSTM
mode1.add(layers.Dense(32,activation='relu'))
mode1.add(1ayers.Dense(10,activation='softmax'))
1.2 函数式模型(可以构建残差网络,生成对抗网络或图像分割的网络拓扑结构)
tf.keras.Input(shape=(32,))
# 网络输入层,神经元个数是32,以上一层的输出作为下一层的输入
hl = layers.Dense(32,activation='relu')(x)
# 全连接层,输入为x
h2 = layers.Dense(32,activation='relu')(hl)
y = layers.Dense(10,activation='softmax')(h2)
model_sample_2 = tf.keras.models.Mode1(x,y)
model_sample_2.summary()
# 打印模型拓扑结构、每一层输出尺、及参数量
② 网络层的构建()
tf.keras.layers 模块的主要作用为配置神经网络层。其中常用的类包括:
tf.keras.layers.Dense # 构建全连接层
tf.keras.layers.Conv2D # 构建2维卷积层;
tf.keras.layers.MaxPooling2D/AveragePooling2D # 构建最大/平均池化层
tf.keras.layers.RNN # 构建循环神经网络层
tf.keras.layers.LSTM/tf.keras.layers.LSTMCell # 构建LSTM网络层/LSTM unit
tf.keras.layers.GRU/tf.keras.layers.GRUCell # 构建CRU unit/CRU网络层
tf.keras.layers.Embedding # 嵌入层将正整数(下标)转换为具有囤定大小的向量:[[4],[20]]->[[0.25,0.1],[10.6,-1.2]]
# Etbeding层只能作为模型的第一层;
tf.keras.layers.Dropout # 构建dropout层
2.1 构建全连接层
units: # 神经元个数
activation # 激活函数
use_bias # 是否使用偏置项。默认为使用
kernel_initializer # 创建层权重核的初始化方案
bias_initializer # 创建层权重偏置的初始化方案
kernel_regularizer # 应用层权重核的正则化方案
bias_regularizer # 应用层权重偏置的正则化方案
activity_regularizer # 施加在输出上的正则项,为Regularizer对象
kernel_constraint # 施加在权重上的约束项
bias_constraint # 施加在权重上的约束项
eg:
tf.keras.layers.Dense(32,activation='sigmoid') # 创建包含32个神经元的全连接层,其中的激活函数设置为sigmoid.
tf.keras.layers.Dense(32,kernel_initializer=tf.keras.initializers.he_normal)
# 设置kerneL initializer参数
tf.keras.layers.Dense(32,kernel_regularizer=tf.keras.regularizers.12(0.01))
# 设置kernel regularizer为L2正则
2.2 构建二维卷积神经网络
filters # 卷积核的数目(即输出的维度)
kernel _size # 卷积核的宽度和长度
strides # 卷积的步长
padding # 补0策略
# padding="valid"代表只进行有效的卷积,即对边界数据不处理,
# padding="same"代表保留边界处的卷积结果,通常会导致输出shape与输入shape相同;
activation # 激活函数:
data_ format # 数据格式,为"channels_first" 或“channels_last"之一
# 以128x128的RGB图像为例,"channels_ first"应将数据组织为(3,128,128)
# 而"channels_last"应将数据组织为(128,128,3)。
# 该参数的默认值是~/.keras/keras.json中设置的值,若从未设置过,则为“channels_last"
eg:
layers.Conv2D(64, [1, 1], 2, padding- same',activation- relu")
# 64个卷积核,卷积核大小1*1,步长为2,补0操作,激活函数relu
2.3 构建最大/平均池化层
pool _size # 池化kerne1的大小。如取矩阵(2, 2)将使图片在两个维度上均变为原长的一半。为整数意为各个维度值都为该数字
strides # 步长值
eg:
layers.MaxPooling2D(pool. size=(2, 2), strides=(2, 1))
# 卷积核2*2,步长为2
2.4 构建LSTM网络层/LSTM unit;
units # 单元数
input_shape # (timestep, input. dim), timestep可以设置为None, input _dim为输入数据维度
return_sequences # =True时,返回全部序列,=False时,返回输出序列中的最后一个cell的输出
③ 网络的训练、评估与测试
3.1 模型编译
optimizer # 优化器
loss # 损失函数,对于二分类任务就是交叉熵,回归任务就是mse之类的
metrics # 在训练和测试期间的模型评估标准。
# 比如metrics=['accuracy'],指定不同的评估标准,需要传递-一个字典,如metrics={'output_a':'accuracy'}
loss_weights # 如果模型有多个任务输出,在优化全局loss的时候,需要给每个输出指定相应的权重。
eg:
model = tf.keras.Sequential()
model.add(layers.Dense(10,activation='softmax'))
model.compile(optimizer=tf.keras.optimizers.Adam(0.001),
loss=tf.keras.losses.categorical_crossentropy,
metrics=[tf.keras.metrics.categorical_accuracy])
# 确定优化器(optimizer),损失函数(loss),模型评估方法(metrics)
3.2 模型训练
x # 输入训练数据;
y # 目标(标签)数据:
batch_size # 每次梯度更新的样本数。如果未指定,默认为32; .
epochs # 训练模型迭代轮次;
verbose=0,1或2 # 日志显示模式。0=不显示,1=进度条, 2=每轮显示一行:
callbacks # 在训练时使用的回调函数:
validation_split # 验证集与训练数据的比例:
validation_data # 验证集;这个参数会覆盖validation_ split:
shuffle # 是否在每轮迭代之前混洗数据。 当steps_per_epoch非None时,这个参数无效;
initial_epoch # 开始训练的轮次,常用于恢复之前的训练权重
steps_per_epoch: # 数据集大小/batch_size.
eg:
train_x = np.random.random(10000,36)) # 1000个训练集36维的数据标签样本
train_y = np.random.randlm(1000,10)) # 1000个训练集10维的数据标签样本
val _x = np.random.random(200,36)) # 200个验证集36维的数据标签样本
val y = np.random.random(200,10)) # 200个验证集10维的数据标签样本
model. fit(train_x,train_y,epochs=10,batch_size=100,validation_data=(val_x,val_y))
# 训练10次,每次训练更新样本数100个
3.3 回调函数
# 模型训练方法
Epochs = 10 # 超参数设置
def lr_Scheduler(epoch): # 定义一个学习率动态设置函数,轮数增加,学习率降低
if epoch > 0.9 * Epochs: # 第10轮
lr=0.0001
elif epoch > 0.5 * Epochs: # 第5~9轮
lr = 0.001
elif epoch > 0.25 * Epochs: # 第2.5~5轮
lr = 0.01
else:
lr = 0.1
print(1r)
return lr
callbacks = [
tf.keras. callbacks. BarlyStopping( # 早停函数
monitor='val _loss', # 不再提升的关注指标
min_ delta=1e-2, # 不再提升的阚值
patience=2),
# 不再提升的轮次
tf.keras.callbacks.ModelCheckpoint( # 定期保存模型:
filepath='testmodel_{epoch).h5', # 模型路径
save_best_only=True, # 是否保存最佳模型
monitor='val_loss'), # 监控指标
tf.keras.callbacks.LearningRateScheduler(lr_Scheduler) # 动态更改学习率
tf.keras.callbacks.TensorBoard(log_dir='./logs') # 使用TensorBoard
]
model.fit(train_x, train_y, batch_size=16, epochs=Epochs,
callbacks=callbacks, validation_data=(val_x, val_y))
# 输入训练集,一批的大小16个,训练的轮次10,早停程序,输入验证集,
3.4 模型评估与预测
# 模型评估
test_x = np.random.random(1000,36))
test_y = np.random.randm((1000,10))
mode1.evaluate(test_x,test_y, batch_size=32)
#模型预测
pre_x = np.random.random((10,36))
result = model.predict(tes _x,)
4. TensorFlow2开发(MNIST手写体识别)
import os
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers,optimizers,datasets
from matplotlib import pyplot as plt
import numpy as np
一、数据集处理
# 构建模型
(x_train_raw, y_train_raw),(x_test_raw,y_test_raw) = datasets.mnist.load_data()
print(y_train_raw[0]) # 5
print(x_train_raw.shape, y_train_raw.shape) # (60000,28,28)6万张训练集
print(x_test_raw.shape, y_test_raw.shape) # (10000,28,28)1万张测试集
num_classes = 10
y_train= keras.utils.to_categorical(y_train_raw,num_classes) # 将分类标签变为独热码(onehot)
y_test = keras.utils.to_categorical(y_test_raw,num_classes)
print(y_train[O]) # [0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
# 数据可视化
plt.figure()
for i in range(9):
plt.subplot(3,3,i+1)
plt.imshow(x_train_raw[i])
plt.axis('off')
plt.show()
二、构建并编译全连接和卷积神经网络
# 编译全连接层
x_train = x_train_raw.reshape(60000,784) # 将28*28的图像展开成784*1的向量
x_test = x_test_raw.reshape(10000,784) # 将图像像素值归一化0~1
x_train= x_train.astype('float32')/255
x_test = x_test.astype('float32')/255
model = keras.Sequential([ # 创建模型。模型包括3个全连接层和两个RELU激活函数
layers.Dense(512,activation='relu', input_dim = 784), # 降维处理
layers.Dense(256,activation='relu'),
layers.Dense(124,activation='relu'),
layers.Dense(num_classes,activation='softmax')
])
# 编译卷积神经网络层
model=keras.Sequential() # 创建网络序列
mode1.add(keras.layers.Conv2D(filters=32,kernel_size = 5,strides = (1,1),
padding ='same',activation = tf.nn.relu,input_shape = (28,28,1)))
# 添加第一层卷积层和池化层
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides = (2,2),padding = 'valid'))
# 添加第二层卷积层和泄化层
model.add(keras.layers.Conv2D(filters=64, kernel_size = 3, strides=(1, 1),padding='same', activation = tf.nn.relu))
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides = (2,2),padding = 'valid'))
# 添加dropout层 以减少过拟合
model.add (keras.layers.Dropout(0.25)) # 随机丢弃神经元的比例
mode1.add (keras.layers.Flatten())
# 添加两层全连接层
model.add (keras.layers.Dense(units=128,activation = tf.nn.relu))
model.add (keras.layers.Dropout(0.5))
model.add(keras.layers.Dense(units=10,activation = tf.nn.softmax))
三、训练网络
Optimizer = optimizers.Adam(0.001)
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=Optimizer, # Adam优化器
metrics=['accuracy']
)
model.fit(x_train,y_train, # 训练集数据标签
batch_size=128, # 批大小
epochs=10, # 训练的轮次
verbose=1) # 输出日志
# 将数据扩充维度,以适应CNN模型
X_train=x_train.reshape(60000,28,28,1)
X_test=x_test.reshape(10000,28,28,1)
model.compile(optimizer-tf.train.AdamOptimizer(),loss="categorical_crossentropy",metrics=['accuracy'])
model.fit(x=X_train,y=y_train,epochs=5,batch_size=128) # 轮次为5
四、测试模型
score = model.evaluate(x_test,y_test,verbose=O)
print('Test loss:', score[0]) # 损失函数: 0.0853068439
print('Test accuracy:', score[1]) # 精确度: 0.9767
test_loss,test_acc = model.evaluate(x=X_test,y=y_test)
print("Test Accuracy %.2f"%test_acc) # 精确度: 0.9
五、保存模型
model.save('./mnist_mode1/final_DNN_mode1.h5') # 保存DNN模型
model.save('./mnist_model/final_CNN_model.h5') # 保存CNN模型
六、加载保存的模型
from tensorflow.keras.models import load_model
new_model = load_model('./mnist_model/final_CNN_model.h5')
new_model = keras.Sequential([
layers.Dense(512,activation='relu',input_dim = 784),
layers.Dense(256,activation='relu'),
layers.Dense(124,activation='relu'),
layers.Dense(num_classes,activation='softmax')
])
new_model.compile(loss='binary_crossentropy',optimizer='rmsprop',metrics=['accuracy'])
new_model = new_mode1.load_weights('./mnist_mode1/model_weights.h5')
new_model.summary()
七、测试数据进行可视化测试
import matplotlib.pyplot as plt
@matplotlib.inline
def res_Visual(n):
final_opt_a=new_model.predict_classes(X_test[0:n]) # 通过模型预测测试集
fig, ax = plt.subplots(nrows=int(n/5), ncols=5)
ax = ax.flatten()
print('前{}张图片预测结果为:'.format(n))
for i in range(n):
print(final_opt_a[i],end='.')
if int((i+1)%5)=0:
print('\t')
# 图片可视化展示
img = X_test[i].reshape((28,28)) # 读取每行数据,格式为Ndarry
plt.axis("off")
ax[i].imshow(img,cmap='Greys',interpolation='nearest') # 可视化
ax[i].axis("off")
print('测试集前(张图片为:'.format(n))
res_Visual(20) 前20张图片