目录
5、用for代替tf中的tf.data.Dataset.from_tensor_slices
8、tf中用tensorflow、slim(高级库)、keras写的CNN
1、模型的保存与加载(以继续训练)、日志保存与加载
# 模型保存
saver = tf.train.Saver(max_to_keep=5) # max_to_keep只保存最新的5个模型,旧的模型会被覆盖
with tf.Session() as sess:
sess.run(……)
……
saver.save(sess, 'path', global_step=10) # global_step: 在n次迭代后再保存模型
# 模型加载,以继续训练或进行测试
with tf.Session() as sess:
# 导入模型结构(具体参考:review.ipynb的模型保存与加载)
saver = tf.train.import_meta_graph('.meta')
# 导入模型参数
saver.restore(sess, tf.train.latest_checkpoint('./'))
# 再载入一些关键的tensor,就可以进行测试或者是再训练了
sess.run(...)
# 【备注:华为杯中所用的保存为pb个的方式:https://github.com/gongtian1234/CV2019/blob/master/%E7%AC%AC%E5%85%AD%E8%AF%BEtensorflow/01savedModelAndLoad/11_2_savedAndLoadModel_mydata_success.ipynb】
# 日志文件的保存与加载
# 参考链接:https://blog.youkuaiyun.com/haoshan4783/article/details/89970227
tf.summary.scalar('accuracy',acc) #生成准确率标量图
merge_summary = tf.summary.merge_all()
train_writer = tf.summary.FileWriter(dir,sess.graph)#定义一个写入summary的目标文件,dir为写入文件地址
......(交叉熵、优化器等定义)
for step in xrange(training_step): #训练循环
train_summary = sess.run(merge_summary,feed_dict = {...})#调用sess.run运行图,生成一步的训练过程数据
train_writer.add_summary(train_summary,step)#调用train_writer的add_summary方法将训练过程以及训练步数保存
# 查看命令: tensorboard --logdir=日志文件的绝对路径(只是文件所在位置,不要写上日志文件的名字)
# 【注意:路径不要加引号,不要有中文空格等特俗符号】
# 完整日志保存的的命令示例
import tensorflow as tf
def myregression():
# 自实现一个线性回归
# 指定作用域
with tf.variable_scope('data'):
# 1、准备数据,x目标值: [100,1] y特征值: [100]
x = tf.random_normal([100, 1], mean=1.75, stddev=0.5, name='x_data')
# 矩阵相乘必须是二维的
y_true = tf.matmul(x, [[0.7]]) + 0.8
# 指定模型的作用域
with tf.variable_scope('model'):
# 2、建立一个线性回归模型 1个特征: 1个权重,1个偏置 y = x * w + b
# 随机给一个权重和偏置,让它去计算损失,然后在当前状态下优化
weight = tf.Variable(tf.random_normal([1, 1], mean=0.0, stddev=1.0), name='w')
# 用变量定义权重才能优化
bias = tf.Variable(0.0, name='b')
y_predict = tf.matmul(x, weight) + bias # 1个特征值
# 指定损失的作用域
with tf.variable_scope('loss'):
# 3、建立损失函数:均方误差
loss = tf.reduce_mean(tf.square(y_true - y_predict))
# 指定优化损失的作用域
with tf.variable_scope('optimizer'):
# 4、梯度下降,优化损失 学习率learning_rate:0~1,2,3,5,7,10
train_op = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
# 搜集tensor --->合并变量写入事件文件
tf.summary.scalar('losses', loss)
tf.summary.histogram('weights', weight)
merged = tf.summary.merge_all() # 合并变量的op
# 定义一个初始化变量的op:weight,bias(不进行初始化时会报错)
init_op = tf.global_variables_initializer()
# 5、通过会话运行程序
with tf.Session() as sess:
# 初始化变量
sess.run(init_op)
# 打印随机最先初始化的权重和偏置
print('随机初始化的参数权重为:{}, 偏置为:{}'.format(weight.eval(), bias.eval()))
# 建立事件文件
filewriter = tf.summary.FileWriter('./tmp/summary/test', graph=sess.graph)
# 循环训练 运行优化
for i in range(500): # 【循环次数怎么确定:可以用损失函数的精确度去制定规则,如上一次较这一次值变化了10^-6,这说明此时精度较高,可以停止循环】
sess.run(train_op)
# 运行合并的tensor
summary = sess.run(merged)
filewriter.add_summary(summary, i)
print('第{}次优化的参数权重为:{}, 偏置为:{}'.format(i, weight.eval(), bias.eval()))
(详见代码:06tensorflow模型的加载与保存.ipynb)
2、模型训练时学习率衰减
①学习率衰减的必要性
学习率过大,在算法优化的前期会加速学习,使得模型更容易接近局部或全局最优解。但是在后期会有较大波动,甚至出现损失函数的值围绕最小值徘徊,波动很大,始终难以达到最优,如下图蓝色曲线所示。所以引入学习率衰减的概念,直白点说,就是在模型训练初期,会使用较大的学习率进行模型优化,随着迭代次数增加,学习率会逐渐进行减小,保证模型在训练后期不会有太大的波动,从而更加接近最优解,如下图中上面一条绿色曲线所示。
②学习率衰减的办法
(1) , 其中decayRate为衰减率(是一个超参数),epochNum是迭代次数,
是初始学习率;
(2) ;
(3) 或
, 其中t为mini-batch的数字
在实际操作中发现,在迭代50次以内,学习率的衰减速度非常快,且在100次左右,学习率衰减到非常小(如e-10),这对于迭代次数较多的模型训练即为不利,所以进行了如下研究(详见学习率分析),对传统的学习率做了一些修改,欢迎大家积极留言讨论。
参考文章:必备必考 | 调参技能之学习率衰减方案(一)—超多图直观对比
后来发现tensorflow有自己的衰减函数【这篇文章强烈推荐看一看】(咳咳)
# keras中学习率自动根据val_loss下降的函数
# tf.keras.callbacks.ReduceLROnPlateau
from keras.callbacks import ReduceLROnPlateau,EarlyStopping, ModelCheckpoint
train_datagen = image.ImageDataGenerator(rotation_range=40, width_shift_range=0.2, height_shift_range=0.2,
shear_range=0.2, zoom_range=0.2, horizontal_flip=True,
fill_mode='nearest') # rescale=1/255
val_datagen = image.ImageDataGenerator()
batch_size = 64
train_generator = train_datagen.flow_from_directory('image/train', target_size=(224,224),batch_size=batch_size)
val_generator = val_datagen.flow_from_directory('image/val', target_size=(224,224), batch_size=batch_size)
# print(train_generator.class_indices)
# print(val_generator.class_indices)
earlystoping = EarlyStopping(monitor='val_loss', patience=9, verbose=1)
# checkpointer = ModelCheckpoint()
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=3, verbose=1,
mode='auto', min_delta=0.0001, min_lr=1e-7,)
model.compile(optimizer=Adam(lr=0.0001), loss='categorical_crossentropy', metrics=['accuracy'])
model.fit_generator(train_generator, steps_per_epoch=len(train_generator), epochs=201,
validation_data=val_generator, validation_steps=len(val_generator),shuffle=True,
callbacks=[earlystoping, reduce_lr])
# 参考网址有:
# 1、https://www.w3cschool.cn/tensorflow_python/tf_keras_callbacks_ReduceLROnPlateau.html(函数参数解释网址)
# 2、https://stackoverflow.com/questions/51889378/how-to-use-keras-reducelronplateau(第一次看到来源网址)
## 学习率指数衰减
with tf.name_scope('optimizer'):
global_step = tf.Variable(0, trainable=False)
learning_rate = tf.train.exponential_decay(learning_rate=learning_rate,global_step=global_step,
decay_steps=2000, decay_rate=decay_rate, staircase=True)
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
train_op = optimizer.minimize(self.cost, global_step=global_step)
补充:在keras可以直接设置衰减系数,
s = Sequential()
# 初始化优化器
optimizer = Adam(lr=0.0001, decay=6e-8) # decay学习衰减率
s.compile(optimizer=optimizer, loss='binary_crossentropy', metrics=['accuracy'])
## 以上是keras搭建神经网络的基本流程,看不懂的朋友可以找一下keras的相关流程 ##
补充2:在tensorflow中学习率可以设置分段衰减,函数为:
tf.train.piecewise_constant(
x,
boundaries,
values,
name=None
)
3、tensorflow中的交叉熵的比较
(具体内容见链接处文章)
4、tensorflow中的参数初始化方法
但是没有找到吴恩达老师讲的He initialization的接口,这在使用slim中初始化参数有些不方便,He initialization的数学公式为:
针对tanh激活函数:
针对relu激活函数:
如果一层一层的初始化权重,则可以用这种方式,但是如果用slim同一初始化参数则没有这个接口。
5、用for代替tf中的tf.data.Dataset.from_tensor_slices
一开始也挺喜欢这种mini_batch方式的,但是在华为杯中因这种方式载入模型需要初始化dataset(说实话,现在也不理解是什么鬼,总之就是在华为云上部署失败),觉得还是自己写的for循环来代替进行mini_batch操作,
for i in range(epochs):
#### 对比mini_batch和batch #### 参考网址:https://www.jianshu.com/p/d1f469d65470
## mini_batch参数下降更快,更鲁棒的收敛,可以避免局部最优,总体来看,效果优于batch #
for j in range(int(x_train.shape[0]/batch_size)+1):
x_batch = x_train[j*batch_size:(j+1)*batch_size]
y_batch = y_train[j*batch_size:(j+1)*batch_size]
_,los = sess.run([train,loss], feed_dict={x: x_batch, y: y_batch})
# _,los = sess.run([train,loss], feed_dict={x: x_train, y: y_train})
if i%200==0:
print('第{}次mse为:'.format(i),los)
6、梯度消失和梯度爆炸
在训练神经网络时,非常容易遇到这种问题,这篇文章中详细的介绍了梯度爆炸1(为什么会产生~?如何判断已经~?如何改进?)、2(从激活函数图的角度解释了梯度消失、梯度爆炸;解决方案);
7、tf中一些常用的小代码
tf.identity()可以改变一个张量的类型,或者用于给其命名
8、tf中用tensorflow、slim(高级库)、keras写的CNN
# tf中一个完整的卷积层、池化层、全连接层
wConv = tf.Variable(tf.truncated_normal([5,5,1,32],stddev=0.01))
bConv = tf.Variable(tf.zeros([32])+0.1)
aConv = tf.nn.relu(tf.nn.conv2d(net, filter=wConv, strides=[1,1,1,1], padding='SAME') + bConv)
aPool = tf.nn.max_pool(aconv, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')
aPoolFalten = tf.reshape(aPool, [-1, 7*7*64])
wFc = tf.Variable(tf.truncated_normal([7*7*64, 1024], stddev=0.01))
bFc = tf.Variable(tf.zeros([1024])+0.1)
aFc = tf.nn.relu(tf.matmul(aPoolFalten, wFc)+bFc)
keepProb = tf.placeholder(tf.float32, name='keep_prob')
aFcDropout = tf.nn.dropout(aFc, keep_prob=keepProb)
### ###
### 直接使用tensorflow每一步都得初始化参数,全连接层是一步步运算得到的
# 使用slim进行一个完整的卷积、池化、全连接层
from tensorflow.contrib import slim
with slim.arg_scope(list_ops_or_operations=[slim.conv2d, slim.fully_connected],
activation_fn=tf.nn.relu,
weights_initializer=tf.truncated_normal_initializer(stddev=0.01,seed=2020),
biases_initializer=tf.constant_initializer(0.1)):
slim.conv2d(inputs=net, num_outputs=64, kernel_size=[5,5], stride=4, padding='SAME')
slim.max_pool2d(inputs=net, kernel_size=[2,2], stride=2, padding='SAME')
slim.flatten(inputs=net)
slim.fully_connected(net, num_outputs=1024)
slim.dropout(net, keep_prob=keepProb)
#使用keras进行一个完整的卷积、池化、全连接层
from keras.layers import Conv2D,MaxPool2D,Dense,Flatten
from keras.models import Sequential
model = Sequential()
model.add(Conv2D(input_shape(28,28,1),kernel_size=(5,5),filters=32,strides=1,padding='same',activation='relu',kernel_initializer='he_normal'))
model.add(MaxPool2D(pool_size=(2,2),strides=2,padding='same'))
model.add(Flatten())
mode.add(Dense(units=1024,activation='relu/softmax',kernel_initializer='he_normal'))