本文内容来自该网址https://github.com/zht007/tensorflow-practice,非常感谢作者为学者提供简洁又精髓的学习资料。
谷歌免费使用GPU与CPU
万事开头难,对于机器学习初学者来说,最困难的可能是如何在计算机中搭建机器学习所需要的环境,特别是如何配置GPU问题,让很多老鸟都颇为头疼。
好消息是Google爸爸已经替大家把这些问题都解决了,现在只需要有一台能(科学)上网电脑,一个浏览器就能可以开启机器学习之路了,Google甚至把昂贵的GPU和TPU都开放出来了,还等什么,赶紧上车吧。
1.Colab简介
Colab是Google开发的一个完全基于云端的Jupyter Notebook开发环境,使用者不需要做任何设置就可以在上面运行代码。当然也支持从本地和Github导入数据和文件。
2. Colab保存文件
在Colab中,可以完全像在本地使用Jupyter Notebook,新建,导入,运行Jupyter Notebook.
但是要注意的是如果你想保存文件最好"Save a copy to Google Drive",否则关掉浏览器数所有数据都会丢失掉的。当然你也可以下载".py"或者".ipnb"文件。
这些选项都在“File”中可以找到。
3. Colab实践
我们试一下从Gitbut中导入之前文章中用到的Jupyter Notebook 文件吧。
点击"File ——> Upload Notebook" 选择Github选项并输入Github地址就能找到我们之前的Jupyter Notbook文件啦。
导入之后,你就可以向在本地运行Jupyter Notebook一样在云端训练你的模型啦。由于训练是在云端进行,本地电脑该干嘛还可以继续干嘛,不用担心功CPU、内存、GPU占用率过高的问题啦。
4. 使用GPU和TPU
如果模型太复杂或者数据量太大,GPU和TPU(Tensor processing unit )可以大大地提高运算和训练速度。
选择GPU和TPU对训练进行加速也非常简单,只需要点击"Runtime —> Change Runtime Type"就可以啦。
Eager模式像原生Python一样简洁优雅
众所周知,Tensorflow入门之所以困难,与其采用的Graph 和 Session 模式有关,这与原生的 Python 代码简单、直观的印象格格不入。同时,由于计算仅仅发生在Session里面,所以初始化参数和变量的时候没办法将结果打印出来,以至于调试起来也十分困难。
当然Google官方也意识到了这点,于是引入了Eager模式,在这个模式下tensorflow的常量和变量可以直接计算并打印出来,甚至还可以和numpy数组混合计算。本文代码参考官方教程(from github with Apache License 2.0)

import tensorflow as tf import tensorflow.contrib.eager as tfe #tfe在后面优化器(Optimizer)的时候需要用到,故先在这里定义了。 import numpy as np import os import matplotlib.pyplot as plt os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' #设置打印日志的等级 ''' 1.激活Eager模式,激活Eager模式也非常简单,仅几行代码。 注意,eager模式在程序开始就要激活,且不能与普通模式混用。 ''' tf.compat.v1.enable_eager_execution() a = tf.constant([[1, 2], [3, 4]]) b = tf.Variable(np.zeros((2, 2))) print('Eger模式下,定义的变量或者常量可以直接打印出来') print('a=', a) print('\n b=', b) print('张量可以直接转为numpy数组,甚至可以与numpy混合计算。') print(a.numpy()) print() print(b.numpy()) print() x = tf.Variable([[6, 7], [8.0, 9.0]], dtype="float32") y = np.array([[1, 2], [3, 4]], dtype="float32") mtl = tf.matmul(x, y) print(mtl) print() print(mtl.numpy()) '''eager模式下训练线性回归模型''' # 3.1 # 创建模拟数据 # 与之前的数据一样,此处数据是100万个带噪音的线性数据,100 # 万个点用plt是画不出来的,图中随机采样了250个点 # 我们定义一个帮助函数方便以batch的形式这100万个数据点中随机抽取batch # size大小的数据进行训练 def next_batch(x_data,y_true, batch_size): batch_index = np.random.randint(len(x_data), size=(batch_size)) x_train = x_data[batch_index] y_train = y_true[batch_index] return x_train, y_train # 定义变量 # 此处与普通模式下的tensorflow变量没有任何区别 w_tfe = tf.Variable(np.random.uniform()) b_tfe = tf.Variable(np.random.uniform(1, 10)) # 线性函数 # 在普通模式下的tensorflow中我们需要定义计算图谱,这里我们直接以python函数的形式, # 定义要训练的线性回归函数。 def linear_regression(inputs): return inputs * w_tfe + b_tfe # 损失函数 # 同样的,MS(Mean Square)损失函数也要以python函数的形式定义,而不是计算图谱。 def mean_square_fn(model_fn, inputs, labels,batch_size): return tf.reduce_sum(tf.pow(model_fn(inputs) - labels, 2)) / (2 * batch_size) # 优化器 # 同样使用Gradient Descent的优化器,不同在于,普通模式下我们创建一个计算图谱train = optimizer.minimize(error), # 在Eager模式下,要用tfe.implicit_gradients()来返回一个函数。 optimizer = tf.compat.v1.train.GradientDescentOptimizer(learning_rate=0.001) grad = tfe.implicit_gradients(mean_square_fn) # 模型训练 # 由于没有计算图谱,所以也不需要初始化变量,也不需在Session下运行,而是类似于原生Python # 函数的形式将数据传入"Optimizer模型"函数。训练完成之后,w和b的参数也自动保存下来,不必在Session中提取。 #创建数据 np.random.seed(28) x_data = np.random.normal(5,3,size=(100,2)) for i in range(10,30,5): x_data = np.vstack((x_data,np.random.normal(i,3,size=(100,2)))) BATCH_SIZE = 10 BATCHS = len(x_data) // BATCH_SIZE for step in range(BATCHS): x_train, y_train = next_batch(x_data[:,0],x_data[:,1],BATCH_SIZE) optimizer.apply_gradients(grad(linear_regression, x_train, y_train,BATCH_SIZE)) print(w_tfe.numpy()) print(b_tfe.numpy()) # 验证训练结果,直接将最终的 w和b test_data = np.arange(-5,35) predict_y = w_tfe*test_data + b_tfe plt.scatter(x_data[:,0],x_data[:,1]) plt.plot(test_data,predict_y,'r-') plt.show()
自动求导与线性回归
1.Tensorflow 2.0 初始化
写作本文的时候 Tensorflow 2.0 已经出到 RC 版本了,与正式版应该相差不大了。如何安装该版本请参考官方说明。
# upgrade pip pip install --upgrade pip # Current stable release for CPU-only pip install tensorflow # Preview nightly build for CPU-only (unstable) pip install tf-nightly # Install TensorFlow 2.0 RC pip install tensorflow==2.0.0-rc1
如果使用 Colab 只需要在初始的代码框运行这几行代码即可
try: # %tensorflow_version only exists in Colab. %tensorflow_version 2.x except Exception: pass
2. 自动求导
微分求导是机器学习的基础,Tensorflow 提供了强大的自动求导工具,下面我们就用 Tensorflow 2.0 计算函数 y(x)=x^2 在 x=3 时的导数
import tensorflow as tf x = tf.Variable(initial_value=3.) with tf.GradientTape() as tape: # 在 tf.GradientTape() 的上下文内,所有计算步骤都会被记录以用于求导 y = tf.square(x) y_grad = tape.gradient(y, x) # 计算y关于x的导数 print([y.numpy(), y_grad.numpy()])
该部分代码参考 github repo with MIT License
我们可以得到 y = 3*3 = 9, y_grad = 2 * 3 =6 的结果。
tf.GradientTape()
是一个自动求导的记录器,在其中的变量和计算步骤都会被自动记录。在上面的示例中,变量 x
和计算步骤 y = tf.square(x)
被自动记录,因此可以通过 y_grad = tape.gradient(y, x)
求张量 y
对变量 x
的导数。
3. 线性回归
该部分模拟生成的数据,我们之前用 Keras, Tensorflow 1.0 以及 Tensorflow Eager 模式都训练过了,感兴趣的读者可以找来对比一下。
3.1 创建模拟数据
与之前的数据一样,此处数据是100万个带噪音的线性数据,100万个点用plt是画不出来的,图中随机采样了250个点
我们定义一个帮助函数方便以batch的形式这100万个数据点中随机抽取batch size大小的数据进行训练
def next_batch(x_data, batch_size): batch_index = np.random.randint(len(x_data),size=(BATCH_SIZE)) x_train = x_data[batch_index] y_train = y_true[batch_index] return x_train, y_train
3.2 定义变量
此处与 Tensorflow 1.0 变量没有任何区别
w = tf.Variable(initial_value=0.)
b = tf.Variable(initial_value=0.)
3.3 定义优化器
为了让 Tensorflow 自动更新参数,我们需要用到优化器,这里我用 SGD 来更新参数。
optimizer = tf.keras.optimizers.SGD(learning_rate= 1e-3)
3.4 线性回归模型训练
在这里我们需要理解一下几点
- 要更新参数就需要对参数求导,这里需要更新的参数(变量)为 w 和 b。
- 要让模型最优,及需要求变量(w, b)对损失函数求导(偏微分)
- 与前面一样,使用
tape.gradient(ys, xs)
自动计算梯度 - 使用
optimizer.apply_gradients(grads_and_vars)
自动更新模型参数。
for step in range(BATCHS): x_train, y_train = next_batch(x_data, BATCH_SIZE) with tf.GradientTape() as tape: y_pred = w * x_train + b loss = tf.reduce_sum(tf.square(y_pred - y_train))/(BATCH_SIZE) grads = tape.gradient(loss, [w, b]) optimizer.apply_gradients(grads_and_vars=zip(grads,[w,b]))
3.5 训练结果
此处结果也相当符合预期
4. 总结
Tensorflow 2.0 提供了一个非常优雅和简洁的方式对参数进行自动求导和自动更新。 tf.GradientTape()
记录计算步骤用于自动求导和自动更新参数的方式请务必牢记,在更复杂的模型下也将会被用到。
tf.GradientTape().gradient()只能被调用一次,如果需要多次调用就需要多次定义tf.GradientTape()或把求导封装成一个函数。

import tensorflow as tf import os import numpy as np import tensorflow.contrib.eager as tfe tf.compat.v1.enable_eager_execution() os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' x = tf.Variable(-0.5) y = tf.Variable(0.05) iters = 10 for i in range(iters): with tf.GradientTape() as tape: #表达式需要写在上下文内 z = tf.subtract(tf.square(x), tf.square(y)) x_grad, y_grad = tape.gradient(z, [x, y]) x.assign(tf.subtract(x, 0.25 * x_grad)) y.assign(tf.subtract(y, 0.25 * y_grad)) print(x_grad.numpy()) print(y_grad.numpy())

import tensorflow as tf import os import numpy as np import tensorflow.contrib.eager as tfe tf.compat.v1.enable_eager_execution() os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' x = tf.Variable(-0.5) y = tf.Variable(0.05) iters = 10 def gradient_func(): with tf.GradientTape() as tape: #表达式需要写在上下文内 z = tf.subtract(tf.square(x), tf.square(y)) grad_result_list = tape.gradient(z, [x, y]) x.assign(tf.subtract(x, 0.25 * grad_result_list[0])) y.assign(tf.subtract(y, 0.25 * grad_result_list[1])) return grad_result_list for i in range(iters): x_grad,y_grad = gradient_func() print(x_grad.numpy()) print(y_grad.numpy())
快速建立模型
Keras 是一个用于构建和训练深度学习模型的高阶 API。它可用于快速设计原型、高级研究和生产。
keras的3个优点: 方便用户使用、模块化和可组合、易于扩展
tensorflow2推荐使用keras构建网络,常见的神经网络都包含在keras.layer中(最新的tf.keras的版本可能和keras不同)

import tensorflow as tf import os import tensorflow_datasets as tfds import matplotlib.pyplot as plt import numpy as np import glob os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' from PIL import Image cat_img = glob.glob('./test_data/cat/*.*.jpg') def _parse_function(filename): # print(filename) image_string = tf.io.read_file(filename) image_decoded = tf.image.decode_jpeg(image_string,channels=3) print(type(image_decoded)) image_resized = tf.cast(tf.image.resize(image_decoded,[200,200]),tf.uint8) # image_resized = tf.image.resize_with_crop_or_pad(image_decoded, 200, 200) # image_decoded = tf.image.decode_image(image_string) # (375, 500, 3) # image_resized = tf.image.resize_with_crop_or_pad(image_decoded, 200, 200) # return tf.squeeze(mage_resized,axis=0) print(type(image_decoded)) return image_resized # dataset = tf.data.Dataset.from_tensor_slices(cat_img) # # dataset = dataset.map(_parse_function) # dataset = dataset.shuffle(10).repeat(10).batch(2) # iterator = tf.compat.v1.data.make_one_shot_iterator(dataset) # img = iterator.get_next() # # with tf.compat.v1.Session() as sess: # for i in sess.run(img): # plt.imshow(i) # plt.show() # import numpy as np # p = 0.5 #dropout的概率,也就是保留一个神经元的存活率 # def train_step(X,W1,W2,W3,B1,B2,B3): # #FP阶段:对于3层NN # H1 = np.maximum(0, np.dot(W1,X) + B1) #maximum相当于做了relu # U1 = np.random.rand(*H1.shape) < p # H1 *= U1 #drop要不转换为0,要不直接原始值 # # H2 = np.maximum(0, np.dot(W2, H1) + B2) # U2 = (np.random.rand(*H2.shape) < p) / p #这里做了一次除以p的操作。可以不做。 # H2 *= U2 # out = np.dot(W3, H2) + B3 # # #BP操作:计算梯度...(省略) # #更新参数...(省略) # # #预测 # def predict(X,W1,W2,W3,B1,B2,B3): # #直接向前计算,不需要乘以p的值 # H1 = np.maximum(0, np.dot(W1,X) + B1) # H2 = np.maximum(0, np.dot(W2, H1) + B2 ) # out = np.dot(W3, H2) + B3 tf.compat.v1.enable_eager_execution() '''构建模型的网络流程''' # model = tf.keras.Sequential() # model.add(tf.keras.layers.Dense(32, activation='relu')) # model.add(tf.keras.layers.Dense(32, activation='relu')) # model.add(tf.keras.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]) #构建好模型后,通过调用 compile 方法配置该模型的学习流程 # '''产生数据''' train_x = np.random.random((1000, 72)) train_y = np.random.random((1000, 10)) val_x = np.random.random((200, 72)) val_y = np.random.random((200, 10)) # # '''模型训练''' # model.fit(train_x, train_y, epochs=10, batch_size=100, # validation_data=(val_x, val_y)) # dataset = tf.data.Dataset.from_tensor_slices((train_x, train_y)) # dataset = dataset.batch(32) # dataset = dataset.repeat() # val_dataset = tf.data.Dataset.from_tensor_slices((val_x, val_y)) # val_dataset = val_dataset.batch(32) # val_dataset = val_dataset.repeat() # # model.fit(dataset, epochs=10, steps_per_epoch=30, # validation_data=val_dataset, validation_steps=3) # '''模型评估''' # test_x = np.random.random((1000, 72)) # test_y = np.random.random((1000, 10)) # model.evaluate(test_x, test_y, batch_size=32) #评估 # test_data = tf.data.Dataset.from_tensor_slices((test_x, test_y)) # test_data = test_data.batch(32).repeat() # model.evaluate(test_data, steps=30) # # '''模型预测''' # result = model.predict(test_x, batch_size=32) # print(result.shape) '''构建高级模型''' ''' tf.keras.Sequential 模型是层的简单堆叠,无法表示任意模型。使用 Keras 函数式 API 可以构建复杂的模型拓扑,例如: 多输入模型, 多输出模型, 具有共享层的模型(同一层被调用多次), 具有非序列数据流的模型(例如,残差连接)。 使用函数式 API 构建的模型具有以下特征: 层实例可调用并返回张量。 输入张量和输出张量用于定义 tf.keras.Model 实例。 此模型的训练方式和 Sequential 模型一样。 ''' # input_x = tf.keras.Input(shape=(72,)) # hidden1 = tf.keras.layers.Dense(32, activation='relu')(input_x) # hidden2 = tf.keras.layers.Dense(16, activation='relu')(hidden1) # pred = tf.keras.layers.Dense(10, activation='softmax')(hidden2) # # model = tf.keras.Model(inputs=input_x, outputs=pred) # model.compile(optimizer=tf.keras.optimizers.Adam(0.001), # loss=tf.keras.losses.categorical_crossentropy, # metrics=['accuracy']) # model.fit(train_x, train_y, batch_size=32, epochs=5) '''模型子类化''' ''' 通过对 tf.keras.Model 进行子类化并定义您自己的前向传播来构建完全可自定义的模型。 在 init 方法中创建层并将它们设置为类实例的属性。在 call 方法中定义前向传播 ''' class MyModel(tf.keras.Model): def __init__(self, num_classes=10): super(MyModel, self).__init__(name='my_model') self.num_classes = num_classes self.layer1 = tf.keras.layers.Dense(32, activation='relu') self.layer2 = tf.keras.layers.Dense(num_classes, activation='softmax') def call(self,inputs,training=None,mask=None): h1 = self.layer1(inputs) out = self.layer2(h1) return out def compute_output_shape(self, input_shape): print(type(tf.TensorShape(input_shape))) shape = tf.TensorShape(input_shape).as_list() shape[-1] = self.num_classes return tf.TensorShape(shape) # model = MyModel(num_classes=10) # model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001), # loss=tf.keras.losses.categorical_crossentropy, # metrics=['accuracy']) # # model.fit(train_x, train_y, batch_size=16, epochs=5) '''自定义层''' ''' 通过对 tf.keras.layers.Layer 进行子类化并实现以下方法来创建自定义层: build:创建层的权重。使用 add_weight 方法添加权重。 call:定义前向传播。 compute_output_shape:指定在给定输入形状的情况下如何计算层的输出形状。 或者,可以通过实现 get_config 方法和 from_config 类方法序列化层。 ''' class MyLayer(tf.keras.layers.Layer): def __init__(self, output_dim, **kwargs): self.output_dim = output_dim super(MyLayer, self).__init__(**kwargs) def build(self, input_shape): shape = tf.TensorShape((input_shape[1], self.output_dim)) self.kernel = self.add_weight(name='kernel1', shape=shape, initializer='uniform', trainable=True) super(MyLayer, self).build(input_shape) def call(self, inputs, **kwargs): return tf.matmul(inputs, self.kernel) def compute_output_shape(self, input_shape): shape = tf.TensorShape(input_shape).as_list() shape[-1] = self.output_dim return tf.TensorShape(shape) def get_config(self): base_config = super(MyLayer, self).get_config() base_config['output_dim'] = self.output_dim return base_config @classmethod def from_config(cls, config): return cls(**config) # model = tf.keras.Sequential([MyLayer(10), tf.keras.layers.Activation('softmax')]) # model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001), # loss=tf.keras.losses.categorical_crossentropy, # metrics=['accuracy']) # # model.fit(train_x, train_y, batch_size=16, epochs=5) '''回调''' # callbacks = [ # tf.keras.callbacks.EarlyStopping(patience=2, monitor='val_loss'), # tf.keras.callbacks.TensorBoard(log_dir='./logs') # ] # model.fit(train_x, train_y, batch_size=16, epochs=5, # callbacks=callbacks, validation_data=(val_x, val_y)) '''权重保存''' # model = tf.keras.Sequential([ # tf.keras.layers.Dense(64, activation='relu'), # tf.keras.layers.Dense(10, activation='softmax')]) # # model.compile(optimizer=tf.keras.optimizers.Adam(0.001), # loss='categorical_crossentropy', # metrics=['accuracy']) # # #加载参数 # model.load_weights('./weights/model.ckpt') #载入最新版模型 # latest = tf.train.latest_checkpoint('./weights/') # model.load_weights(latest) # model.fit(train_x,train_y,batch_size=32,epochs=10) # model.load_weights('./weights/model.h5') # model.summary() #查看模型信息 #保存模型参数 # model.save_weights('./weights/model.ckpt') # model.save_weights('./weights/model.h5') '''保存整个模型''' # model = tf.keras.Sequential([ # tf.keras.layers.Dense(10, activation='softmax', input_shape=(72,)), # tf.keras.layers.Dense(10, activation='softmax') # ]) # model.compile(optimizer='rmsprop', # loss='categorical_crossentropy', # metrics=['accuracy']) # model.fit(train_x, train_y, batch_size=32, epochs=5) # model.save('all_model.h5') # # model = tf.keras.models.load_model('all_model.h5') ''' 将keras用于Estimator Estimator API 用于针对分布式环境训练模型。它适用于一些行业使用场景,例如用大型数据集进行分布式训练并导出模型以用于生产 ''' # model = tf.keras.Sequential([tf.keras.layers.Dense(10,activation='softmax'), # tf.keras.layers.Dense(10,activation='softmax')]) # # model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001), # loss='categorical_crossentropy', # metrics=['accuracy']) # # estimator = tf.keras.estimator.model_to_estimator(model)
tensorflow回调函数
回调函数Callbacks
回调函数是一组在训练的特定阶段被调用的函数集,你可以使用回调函数来观察训练过程中网络内部的状态和统计信息。通过传递回调函数列表到模型的.fit()
中,即可在给定的训练阶段调用该函数集中的函数。
【Tips】虽然我们称之为回调“函数”,但事实上Keras的回调函数是一个类,回调函数只是习惯性称呼
keras.callbacks.Callback()
这是回调函数的抽象类,定义新的回调函数必须继承自该类。
类属性
-
params:字典,训练参数集(如信息显示方法verbosity,batch大小,epoch数)
-
model:
keras.models.Model
对象,为正在训练的模型的引用回调函数以字典logs
为参数,该字典包含了一系列与当前batch或epoch相关的信息。目前,模型的.fit()
中有下列参数会被记录到logs
中:
-
在每个epoch的结尾处(on_epoch_end),
logs
将包含训练的正确率和误差,acc
和loss
,如果指定了验证集,还会包含验证集正确率和误差val_acc)
和val_loss
,val_acc
还额外需要在.compile
中启用metrics=['accuracy']
。 -
在每个batch的开始处(on_batch_begin):
logs
包含size
,即当前batch的样本数 -
在每个batch的结尾处(on_batch_end):
logs
包含loss
,若启用accuracy
则还包含acc
BaseLogger
keras.callbacks.BaseLogger()
该回调函数用来对每个epoch累加metrics
指定的监视指标的epoch平均值
该回调函数在每个Keras模型中都会被自动调用
ProgbarLogger
keras.callbacks.ProgbarLogger()
该回调函数用来将metrics
指定的监视指标输出到标准输出上
History
keras.callbacks.History()
该回调函数在Keras模型上会被自动调用,History
对象即为fit
方法的返回值
ModelCheckpoint
keras.callbacks.ModelCheckpoint(filepath, monitor='val_loss', verbose=0, save_best_only=False, save_weights_only=False, mode='auto', period=1)
该回调函数将在每个epoch后保存模型到filepath
filepath
可以是格式化的字符串,里面的占位符将会被epoch
值和传入on_epoch_end
的logs
关键字所填入
例如,filepath
若为weights.{epoch:02d-{val_loss:.2f}}.hdf5
,则会生成对应epoch和验证集loss的多个文件。
参数
-
filename:字符串,保存模型的路径
-
monitor:需要监视的值
-
verbose:信息展示模式,0或1
-
save_best_only:当设置为
True
时,将只保存在验证集上性能最好的模型 -
mode:‘auto’,‘min’,‘max’之一,在
save_best_only=True
时决定性能最佳模型的评判准则,例如,当监测值为val_acc
时,模式应为max
,当检测值为val_loss
时,模式应为min
。在auto
模式下,评价准则由被监测值的名字自动推断。 -
save_weights_only:若设置为True,则只保存模型权重,否则将保存整个模型(包括模型结构,配置信息等)
-
period:CheckPoint之间的间隔的epoch数
EarlyStopping
keras.callbacks.EarlyStopping(monitor='val_loss', patience=0, verbose=0, mode='auto')
当监测值不再改善时,该回调函数将中止训练
参数
-
monitor:需要监视的量
-
patience:当early stop被激活(如发现loss相比上一个epoch训练没有下降),则经过
patience
个epoch后停止训练。 -
verbose:信息展示模式
-
mode:‘auto’,‘min’,‘max’之一,在
min
模式下,如果检测值停止下降则中止训练。在max
模式下,当检测值不再上升则停止训练。
RemoteMonitor
keras.callbacks.RemoteMonitor(root='http://localhost:9000')
该回调函数用于向服务器发送事件流,该回调函数需要requests
库
参数
- root:该参数为根url,回调函数将在每个epoch后把产生的事件流发送到该地址,事件将被发往
root + '/publish/epoch/end/'
。发送方法为HTTP POST,其data
字段的数据是按JSON格式编码的事件字典。
LearningRateScheduler
keras.callbacks.LearningRateScheduler(schedule)
该回调函数是学习率调度器
参数
- schedule:函数,该函数以epoch号为参数(从0算起的整数),返回一个新学习率(浮点数)
TensorBoard
keras.callbacks.TensorBoard(log_dir='./logs', histogram_freq=0, write_graph=True, write_images=False, embeddings_freq=0, embeddings_layer_names=None, embeddings_metadata=None)
该回调函数是一个可视化的展示器
TensorBoard是TensorFlow提供的可视化工具,该回调函数将日志信息写入TensorBorad,使得你可以动态的观察训练和测试指标的图像以及不同层的激活值直方图。
如果已经通过pip安装了TensorFlow,我们可通过下面的命令启动TensorBoard:
tensorboard --logdir=/full_path_to_your_logs
更多的参考信息,请点击这里
参数
-
log_dir:保存日志文件的地址,该文件将被TensorBoard解析以用于可视化
-
histogram_freq:计算各个层激活值直方图的频率(每多少个epoch计算一次),如果设置为0则不计算。
-
write_graph: 是否在Tensorboard上可视化图,当设为True时,log文件可能会很大
- write_images: 是否将模型权重以图片的形式可视化
- embeddings_freq: 依据该频率(以epoch为单位)筛选保存的embedding层
- embeddings_layer_names:要观察的层名称的列表,若设置为None或空列表,则所有embedding层都将被观察。
- embeddings_metadata: 字典,将层名称映射为包含该embedding层元数据的文件名,参考这里获得元数据文件格式的细节。如果所有的embedding层都使用相同的元数据文件,则可传递字符串。
ReduceLROnPlateau
keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=10, verbose=0, mode='auto', epsilon=0.0001, cooldown=0, min_lr=0)
patience
个epoch中看不到模型性能提升,则减少学习率
参数
- monitor:被监测的量
- factor:每次减少学习率的因子,学习率将以
lr = lr*factor
的形式被减少 - patience:当patience个epoch过去而模型性能不提升时,学习率减少的动作会被触发
- mode:‘auto’,‘min’,‘max’之一,在
min
模式下,如果检测值触发学习率减少。在max
模式下,当检测值不再上升则触发学习率减少。 - epsilon:阈值,用来确定是否进入检测值的“平原区”
- cooldown:学习率减少后,会经过cooldown个epoch才重新进行正常操作
- min_lr:学习率的下限
CSVLogger
keras.callbacks.CSVLogger(filename, separator=',', append=False)
将epoch的训练结果保存在csv文件中,支持所有可被转换为string的值,包括1D的可迭代数值如np.ndarray.
参数
- fiename:保存的csv文件名,如
run/log.csv
- separator:字符串,csv分隔符
- append:默认为False,为True时csv文件如果存在则继续写入,为False时总是覆盖csv文件
LambdaCallback
keras.callbacks.LambdaCallback(on_epoch_begin=None, on_epoch_end=None, on_batch_begin=None, on_batch_end=None, on_train_begin=None, on_train_end=None)
用于创建简单的callback的callback类
该callback的匿名函数将会在适当的时候调用,注意,该回调函数假定了一些位置参数on_eopoch_begin
和on_epoch_end
假定输入的参数是epoch, logs
. on_batch_begin
和on_batch_end
假定输入的参数是batch, logs
,on_train_begin
和on_train_end
假定输入的参数是logs
参数
- on_epoch_begin: 在每个epoch开始时调用
- on_epoch_end: 在每个epoch结束时调用
- on_batch_begin: 在每个batch开始时调用
- on_batch_end: 在每个batch结束时调用
- on_train_begin: 在训练开始时调用
- on_train_end: 在训练结束时调用
示例

# Print the batch number at the beginning of every batch. batch_print_callback = LambdaCallback( on_batch_begin=lambda batch,logs: print(batch)) # Plot the loss after every epoch. import numpy as np import matplotlib.pyplot as plt plot_loss_callback = LambdaCallback( on_epoch_end=lambda epoch, logs: plt.plot(np.arange(epoch), logs['loss'])) # Terminate some processes after having finished model training. processes = ... cleanup_callback = LambdaCallback( on_train_end=lambda logs: [ p.terminate() for p in processes if p.is_alive()]) model.fit(..., callbacks=[batch_print_callback, plot_loss_callback, cleanup_callback])
编写自己的回调函数
我们可以通过继承keras.callbacks.Callback
编写自己的回调函数,回调函数通过类成员self.model
访问访问,该成员是模型的一个引用。
这里是一个简单的保存每个batch的loss的回调函数:

class LossHistory(keras.callbacks.Callback): def on_train_begin(self, logs={}): self.losses = [] def on_batch_end(self, batch, logs={}): self.losses.append(logs.get('loss'))

class LossHistory(keras.callbacks.Callback): def on_train_begin(self, logs={}): self.losses = [] def on_batch_end(self, batch, logs={}): self.losses.append(logs.get('loss')) model = Sequential() model.add(Dense(10, input_dim=784, kernel_initializer='uniform')) model.add(Activation('softmax')) model.compile(loss='categorical_crossentropy', optimizer='rmsprop') history = LossHistory() model.fit(X_train, Y_train, batch_size=128, epochs=20, verbose=0, callbacks=[history]) print(history.losses) # outputs ''' [0.66047596406559383, 0.3547245744908703, ..., 0.25953155204159617, 0.25901699725311789]

from keras.callbacks import ModelCheckpoint model = Sequential() model.add(Dense(10, input_dim=784, kernel_initializer='uniform')) model.add(Activation('softmax')) model.compile(loss='categorical_crossentropy', optimizer='rmsprop') ''' saves the model weights after each epoch if the validation loss decreased ''' checkpointer = ModelCheckpoint(filepath="/tmp/weights.hdf5", verbose=1, save_best_only=True) model.fit(X_train, Y_train, batch_size=128, epochs=20, verbose=0, validation_data=(X_test, Y_test), callbacks=[checkpointer])

# import tensorflow as tf # import os # import numpy as np # tf.compat.v1.enable_eager_execution() # # # #读取数据 # (train_x,train_y),(test_x,test_y) = tf.keras.datasets.mnist.load_data() # train_x = train_x.reshape(train_x.shape[0],-1).astype('float32')/255 # test_x = test_x.reshape(test_x.shape[0],-1).astype('float32')/255 # print(train_x.shape) # print(train_y.shape) # print(test_x.shape) # print(test_y.shape) # # '''构建bp网络''' # input_layer = tf.keras.Input(shape=(784,),name='input_layer') # hidden_layer = tf.keras.layers.Dense(32,activation=tf.keras.activations.sigmoid,name='hidden_layer')(input_layer) # out_layer = tf.keras.layers.Dense(10,activation="softmax",name='output_layer')(hidden_layer) # # '''创建模型并编译''' # model = tf.keras.Model(inputs=input_layer,outputs=out_layer,name='mnist_model') # model.summary() #查看模型的构建信息 # # tf.keras.utils.plot_model(model, './test_data/mnist_model.png') #画出模型的网络图 # # tf.keras.utils.plot_model(model, './test_data/model_info.png', show_shapes=True) # # #编译模型:构建模型的学习流程。 # model.compile(optimizer=tf.keras.optimizers.RMSprop(), # loss='sparse_categorical_crossentropy', # metrics=['accuracy']) # # '''模型训练及收集训练信息与评估''' # #防止写TensorBoard信息文件时报错找不到目录的方法 # # os.makedirs('./log_dir/plugins/profile') #方法1:给相当路径时需要加这行代码 # dir_log = 'D:\\AI_pycharm_Code_backups\\Deep_learning_TensorFlow\\log_dir\\mnist_log' #方法2:给定一个绝对路径。 # callbacks = [tf.keras.callbacks.TensorBoard(dir_log,histogram_freq=1,write_images=True,)] # #模型训练 # 第一次训练 # first_epoch = 3 # model.fit(train_x,train_y,batch_size=32,epochs=first_epoch,callbacks=callbacks,validation_split=0.2) # # # test_evaluate = model.evaluate(test_x,test_y,batch_size=32,verbose=0) # # print('loss:{}'.format(test_evaluate[0])) # # print('acc:{}'.format(test_evaluate[1])) # # model.save_weights('./test_model/my_model_weights.h5') #保存的模型位置 # # 重新训练 # json_string = model.to_json() # del model # model = tf.keras.models.model_from_json(json_string) # model.load_weights('./test_model/my_model_weights.h5') #载入模型 # # model.compile(optimizer=tf.keras.optimizers.RMSprop(), # # loss='sparse_categorical_crossentropy', # # metrics=['accuracy']) # # second_epoch = 3 # history = model.fit(x=train_x, y=train_y,epochs=first_epoch+second_epoch,callbacks=callbacks,validation_split=0.2,initial_epoch=first_epoch) #关键的初始化epoch数 # print(history) # # #保存整个模型 # model.save('./test_model/my_model.h5') # '''模型加载做预测''' # new_model = tf.keras.models.load_model('./test_model/my_model.h5') # true_y = test_y[:10] # predict_y = new_model.predict(test_x[:10]) # print(true_y) # print(np.argmax(predict_y,axis=1)) # test_evaluate = new_model.evaluate(test_x,test_y,batch_size=32,verbose=0) # print('loss:{}'.format(test_evaluate[0])) # print('acc:{}'.format(test_evaluate[1])) # # #还可以继续训练 # history = new_model.fit(x=train_x, y=train_y,epochs=3,validation_split=0.2) #关键的初始化epoch数 # print(history.history)
更多学习去下面的连接:
https://zhuanlan.zhihu.com/p/59507137
https://github.com/zht007/tensorflow-practice