API:API,全称Application Programming Interface,即应用程序编程接口。API是一些预定义函数,目的是用来提供应用程序与开发人员基于某软件或者硬件得以访问一组例程的能力,并且无需访问源码或无需理解内部工作机制细节。
tensorflow是Google开源的基于数据流图的机器学习框架;Keras是基于TensorFlow和Theano(由加拿大蒙特利尔大学开发的机器学习框架)的深度学习库,是由纯python编写而成的高层神经网络API,是为了支持快速实践而对tensorflow或者Theano的再次封装。
区别:keras本身并不具备底层运算的能力,所以它需要和一个具备这种底层运算能力的backend(后端)协同工作。即keras为前端,tensorflow为keras常用的后端。
tf.keras是一个不强调后端可互换性、和tensorflow更紧密整合、得到tensorflow其他组建更好支持、且符合keras标准的高层次API。如今tf.keras版本和keras进行了同步,tf.keras作为官方的tensorflow的高级API。
更加详细的区别见:
https://blog.csdn.net/u011119817/article/details/102793949
https://blog.csdn.net/u011119817/article/details/102793949
推荐查看官方文档来进行学习
官方文档:
https://tensorflow.google.cn/guide/keras/overview
https://tensorflow.google.cn/versions
tf.keras中模型定义由简到繁:
Sequential -> Functional API -> Functional API + Custom_define -> Subclassing API
模型训练由简到繁:
model.fit -> model.fit + callbacks -> call train_on_batch with GradientTape -> GradientTape with all new algorithm
tf.keras.Sequential 模型是层的简单堆叠,且输入输出都只能有一个,无法表示任意模型。
查看tensorflow版本
import tensorflow as tf
print(tf.__version__)
from tensorflow import keras
#1.构造网络模型
model = keras.models.Sequential([
keras.layers.Flatten(input_shape=(28, 28)),
#全连接层Dense输入需展平
#此部分采用的特征数据shape为(5000, 28, 28)所以在Dense之前添加一个Flatten展平
keras.layers.Dense(128, activation='relu'),
keras.layers.Dropout(0.2), #为前一层添加dropout
keras.layers.Dense(10, activation='softmax')])
#2.选择优化方式和损失函数
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
#3.训练并验证模型
model.fit(x_train, y_train, epochs=5,batch_size=32,validation_data=(x_valid, y_valid))
model.evaluate(x_test, y_test,batch_size=32)
注:
model = keras.models.Sequential([
keras.layers.Dense(30, activation='relu',
input_shape=x_train.shape[1:]),
keras.layers.Dense(1),
])
categorical_crossentropy多分类对数损失 #多分类常用
binary_crossentropy对数损失#二分类
mean_squared_error平均方差损失
mean_absolute_error平均绝对值损失
categorical_crossentropy要求target为one-hot编码,sparse_categorical_crossentropy要求target为非one-hot编码,函数内部进行one-hot编码实现。如果你的 targets 是one-hot 编码,categorical_crossentropy,如果你的 tagets是数字编码 ,用 sparse_categorical_crossentropy。
构建卷积神经网络
from tensorflow import keras
model=keras.models.Sequential([
keras.layers.Conv2D(filters=32,kernel_size=3,padding='same',
activation='relu',input_shape=[width,height,channel]),
keras.layers.Conv2D(filters=32,kernel_size=3,padding='same',
activation='relu'),
keras.layers.MaxPool2D(pool_size=2),
keras.layers.Flatten(),
keras.layers.Dense(128,activation='relu'),
keras.layers.Dense(num_classes,activaton='softmax')
])
model. compile(loss='categorical_crossentropy',
optimizer='adam',metrics=['accuracy'])
model.summary()
Conv2D层的参数
filters
:卷积核个数kernel_size
:卷积核大小,可以为一个单个的整数,表示长宽相同;也可以表示为(height,weight)。strides
:步长,可以用一个单数,也可以用元组表示沿高度和宽度方向的步长;默认为(1,1)。padding
:有“same”和“valid”两种填充方式,padding=‘valid’表示不进行填充,默认为‘valid’。data_format
:有“channels_first”和“channels_last”分别表示输入(batch, channels, height, width)和(batch, height, width, channels),默认的data_format=‘None’,一般无需指定。activation
kernel_initialize
r:卷积核中权重矩阵的初始化方式。默认kernel_initializer=‘glorot_uniform’,即Xavier初始化方式。更多初始化方式见tf.keras.initializers。bias_initializer
:卷积核偏差初始化方式。默认bias_initializer=‘zeros’。kernel_regularizer
:卷积核权重矩阵的正则化方式。默认为kernel_regularizer=None,可设定列如:kernel_regularizer=tf.keras.regularizers.l2(l=0.01),其中l即为L2正则项系数,详见keras.regularizers。bias_regularizer
activity_regularizer
:对于该层输出进行正则化的方式。batch norm(批归一化)
model = keras.models.Sequential()
model.add(keras.layers.Flatten(input_shape=[28, 28]))
#对激活函数后的a进行批归一化
for _ in range(20):
model.add(keras.layers.Dense(100, activation="relu"))
model.add(keras.layers.BatchNormalization())
#对Z进行归一化后再激活
for _ in range(20):
model.add(keras.layers.Dense(100,))
model.add(keras.layers.BatchNormalization())
model.add(keras.layers.Activation('relu'))
BatchNormalization层的参数:
axis
:要进行归一化的轴,如Conv2D中的data_format="channels_first"时,数据为(batch, channels, height, width),此时用axis=1表示在通道方向;当data_format="channels_last"时,设置axis=3或者axis=-1;axis默认为-1。trainable
:trainable是layers的层属性,在tensorflow2.0中BN的trainable和其他层的trainable有所不同:对于layers,trainable属性为可变动的bool值,决定layer是否可以训练,设置layer.trainable=False的意思是冻结该层(Frozen state),即其内部状态在训练期间不会改变:其可训练权重在fit()或train_on_batch()期间不会更新,其状态更新也不会运行。但是,在BatchNormalization层的情况下,在该层上设置trainable=False意味着该层随后将以测试模式(inference mode)运行(意味着它将使用移动平均值和移动方差来规范当前批,而不是使用当前批的平均值和方差)。此行为仅在TensorFlow 2.0之后发生。在1.*中,设置layer.trainable=False将冻结层,但不会将其切换到inference mode。BatchNormalization层的调用参数(call arguments):
training
:BN在training和inference时使用的方法是不一样的
当training =True时,表示此时归一化用于训练,此时均值和方差就是计算出当前minibatch的均值方差;
当training=False时,表示用于测试、预测(inference mode),此时再逐个计算当前的均值和方差是非常耗时的,此时会调用训练结束时保存的running_mean、running_var,在test时直接使用训练得到的running mean/var标准化数据。
训练时保存的running_mean、running_var(称为moving average)方式如下:
running_mean = momentum * running_mean + (1 - momentum) * sample_mean
running_var = momentum * running_var + (1 - momentum) * sample_var
#可以理解为每次更新running mean相当于把之前的值衰减一些(* momentum),然后把当前的minibatch sample mean加进去一部分(* (1-momentum))。其实也就是一阶指数平滑平均。
注:其中momentum为设定值,和优化方法中的momentum没什么关系。
momentum
:tensorflow中默认设定为0.99
Droupout
model = keras.models.Sequential()
model.add(keras.layers.Flatten(input_shape=[28, 28]))
model.add(keras.layers.Dense(100, activation="relu"))
model.add(keras.layers.AlphaDropout(rate=0.5))
#为上一层添加
# model.add(keras.layers.Dropout(rate=0.5))此为一般的dropout方法
# AlphaDropout相比一般方法的好处: 1. 均值和方差不变 2. 归一化性质也不变(进行归一化时其均值方差不变)
model.summary() #查看模型结构
tf.keras.Squential只能搭建简单的单输入单输出堆叠模型,无法满足以下较为复杂的情况:
模型的compile和训练fit与Squential模型方式相同,不同之处在于网络模型的构建,函数API来构建网络结构可以通过直接应用keras中已经建立好的层结构和模型,也可以自己编写自定义层和模型。tf.keras中现有的层结构有:
更详细的layer见https://tensorflow.google.cn/versions/r2.0/api_docs/python/tf/keras/layers
以下使用keras已有的基本层结构进行构建网络结构。
function API构建简单序列模型
inputs=keras.Input(shape=(340,340,3),name='easy')
x=keras.layers.Conv2D(32,3,activation='relu')(inputs)
x=keras.layers.Conv2D(64,3,activation='relu')(x)
x=keras.layers.AveragePooling2D()(x)
outputs=keras.layers.Dense(10)(x)
model=keras.Model(inputs,outputs,name='easy') #注意此行
model.summary()
Model: "easy"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
easy (InputLayer) [(None, 340, 340, 3)] 0
_________________________________________________________________
conv2d (Conv2D) (None, 338, 338, 32) 896
_________________________________________________________________
conv2d_1 (Conv2D) (None, 336, 336, 64) 18496
_________________________________________________________________
average_pooling2d (AveragePo (None, 168, 168, 64) 0
_________________________________________________________________
dense (Dense) (None, 168, 168, 10) 650
=================================================================
Total params: 20,042
Trainable params: 20,042
Non-trainable params: 0
_________________________________________________________________
编译模型、训练模型及评估模型的操作与Squential模型相同。
model.compile(loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
optimizer=keras.optimizers.RMSprop(),
metrics=['accuracy'])
history = model.fit(x_train, y_train,
batch_size=64,
epochs=5,
validation_split=0.2)
test_scores = model.evaluate(x_test, y_test, verbose=2)
function API构建的多个层可以用于多个不同模型
encoder_input = keras.Input(shape=(28, 28, 1), name='img')
x = keras.layers.Conv2D(16, 3, activation='relu')(encoder_input)
x = keras.layers.Conv2D(32, 3, activation='relu')(x)
x = keras.layers.MaxPooling2D(3)(x)
x = keras.layers.Conv2D(32, 3, activation='relu')(x)
x = keras.layers.Conv2D(16, 3, activation='relu')(x)
encoder_output = layers.GlobalMaxPooling2D()(x)
encoder = keras.Model(encoder_input, encoder_output, name='encoder')
encoder.summary()
#第二个模型直接用第一个模型构建的层结构,在此基础上再进行构建
x = keras.layers.Reshape((4, 4, 1))(encoder_output)
x = keras.layers.Conv2DTranspose(16, 3, activation='relu')(x)
x = keras.layers.Conv2DTranspose(32, 3, activation='relu')(x)
x = keras.layers.UpSampling2D(3)(x)
x = keras.layers.Conv2DTranspose(16, 3, activation='relu')(x)
decoder_output = keras.layers.Conv2DTranspose(1, 3, activation='relu')(x)
autoencoder = keras.Model(encoder_input, decoder_output, name='autoencoder')
autoencoder.summary()
function API构建的模型可看作层结构直接进行调用,来构建或合并为更为复杂的模型
encoder_input = keras.Input(shape=(28, 28, 1), name='original_img')
x = keras.layers.Conv2D(16, 3, activation='relu')(encoder_input)
x = keras.layers.Conv2D(32, 3, activation='relu')(x)
x = keras.layers.MaxPooling2D(3)(x)
x = keras.layers.Conv2D(32, 3, activation='relu')(x)
x = keras.layers.Conv2D(16, 3, activation='relu')(x)
encoder_output = keras.layers.GlobalMaxPooling2D()(x)
encoder = keras.Model(encoder_input, encoder_output, name='encoder')
encoder.summary()
decoder_input = keras.Input(shape=(16,), name='encoded_img')
x = keras.layers.Reshape((4, 4, 1))(decoder_input)
x = keras.layers.Conv2DTranspose(16, 3, activation='relu')(x)
x = keras.layers.Conv2DTranspose(32, 3, activation='relu')(x)
x = keras.layers.UpSampling2D(3)(x)
x = keras.layers.Conv2DTranspose(16, 3, activation='relu')(x)
decoder_output = keras.layers.Conv2DTranspose(1, 3, activation='relu')(x)
decoder = keras.Model(decoder_input, decoder_output, name='decoder')
decoder.summary()
#将以上两个模型调用并连接在一起构建出了新的模型
autoencoder_input = keras.Input(shape=(28, 28, 1), name='img')
encoded_img = encoder(autoencoder_input)
decoded_img = decoder(encoded_img)
autoencoder = keras.Model(autoencoder_input, decoded_img, name='autoencoder')
autoencoder.summary()
注意,通过调用一个模型,您不仅重用了模型结构,还重用了模型的权重。
function API构建分支结构
inputs = keras.Input(shape=(32, 32, 3), name='img')
x = keras.layers.Conv2D(32, 3, activation='relu')(inputs)
x = keras.layers.Conv2D(64, 3, activation='relu')(x)
block_1_output = keras.layers.MaxPooling2D(3)(x) #关键操作,残差神经网络常用
x = keras.layers.Conv2D(64, 3, activation='relu', padding='same')(block_1_output)
x = keras.layers.Conv2D(64, 3, activation='relu', padding='same')(x)
block_2_output = keras.layers.add([x, block_1_output])
x = keras.layers.Conv2D(64, 3, activation='relu', padding='same')(block_2_output)
x = keras.layers.Conv2D(64, 3, activation='relu', padding='same')(x)
block_3_output = keras.layers.add([x, block_2_output])
x = keras.layers.Conv2D(64, 3, activation='relu')(block_3_output)
x = keras.layers.GlobalAveragePooling2D()(x)
x = keras.layers.Dense(256, activation='relu')(x)
x = keras.layers.Dropout(0.5)(x)
outputs = keras.layers.Dense(10)(x)
model = keras.Model(inputs, outputs, name='toy_resnet')
model.summary()
#显示结构图
keras.utils.plot_model(model, 'mini_resnet.png', show_shapes=True)
function API多输入多输出
多输入合并
# 多输出
input_wide = keras.layers.Input(shape=[5])
input_deep = keras.layers.Input(shape=[6])
hidden1 = keras.layers.Dense(30, activation='relu')(input_deep)
hidden2 = keras.layers.Dense(30, activation='relu')(hidden1)
#将两个输入合并
concat = keras.layers.concatenate([input_wide, hidden2])
output = keras.layers.Dense(1)(concat)
output2 = keras.layers.Dense(1)(hidden2)
model = keras.Model(inputs = [input_wide, input_deep],
outputs = [output, output2])
model.compile(loss="mean_squared_error", optimizer="sgd")
callbacks = [keras.callbacks.EarlyStopping(
patience=5, min_delta=1e-2)]
model.summary()
keras.utils.plot_model(model, 'mini_resnet.png', show_shapes=True)
注:
add和concatenate的不同见https://blog.csdn.net/m0_37870649/article/details/100153897
tf.keras.layers.concatenate的用法和功能同tf.concat
tf.concat中的轴用法
t1 = [[[1, 2], [2, 3]], [[4, 4], [5, 3]]]
t2 = [[[7, 4], [8, 4]], [[2, 10], [15, 11]]]
#axis=0 可理解为在第一个[]进行拼接 两个拼接到第一个大[]内
tf.concat([t1,t2],axis=0) # 或者写为tf.concat([t1,t2],0) >>
<tf.Tensor: id=19, shape=(4, 2, 2), dtype=int32, numpy=
array([[[ 1, 2],
[ 2, 3]],
[[ 4, 4],
[ 5, 3]],
[[ 7, 4],
[ 8, 4]],
[[ 2, 10],
[15, 11]]])>
#axis=1 可理解为在第二个[]拼接
tf.concat([t1,t2],1) >>
<tf.Tensor: id=23, shape=(2, 4, 2), dtype=int32, numpy=
array([[[ 1, 2],
[ 2, 3],
[ 7, 4],
[ 8, 4]],
[[ 4, 4],
[ 5, 3],
[ 2, 10],
[15, 11]]])>
#axis=2 or axis=-1 可理解为在第三个[]拼接
tf.concat([t1,t2],-1) >>
<tf.Tensor: id=7, shape=(2, 2, 4), dtype=int32, numpy=
array([[[ 1, 2, 7, 4],
[ 2, 3, 8, 4]],
[[ 4, 4, 2, 10],
[ 5, 3, 15, 11]]])>