Tensorflow.keras小案例Mnist数字识别

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()
               # 打印模型拓扑结构、每一层输出尺、及参数量

   Tensorflow.keras小案例Mnist数字识别_第1张图片

  ② 网络层的构建()

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张图片

 

你可能感兴趣的:(Tensorflow.keras小案例Mnist数字识别)