本文记录了在TensorFlow框架中自定义训练函数的模板并简述了使用自定义训练函数的优势与劣势。

首先需要说明的是,本文中所记录的训练函数模板参考自https://stackoverflow.com/questions/59438904/applying-callbacks-in-a-custom-training-loop-in-tensorflow-2-0中的回答以及Hands-On Machine Learning with Scikit-Learn, Keras, and Tensorflow一书中第12.3.9节的内容,如有错漏,欢迎指正。

为什么和什么时候需要自定义训练函数

除非你真的需要额外的灵活性,否则应该更倾向使用fit()方法,为不是实现你自己的循环,尤其是在团队合作中。

如果你还在困惑为什么需要自定义训练函数的时候,那说明你还不需要自定义训练函数。通常只有在搭建一些结构奇特的模型时,我们才会发现model.fit()无法完全满足需求,接下来首先该尝试的方法是去看TensorFlow相关部分的源码,看看有没有认识之外的参数或方法,其次才是考虑使用自定义训练函数。毫无疑问,自定义训练函数会让代码更长、更难维护、更难懂。

但是,自定义训练函数的灵活性是fit()方法无法比拟的。比如,在自定义函数中你可以实现使用多个不同优化器的训练循环或是在多个数据集上计算验证循环。

自定义训练函数模板

模板设计的目的在于让我们通过对代码块的复用以及对关键部位的填空快速完成自定义训练函数,以使我们更专注于训练函数结构本身而非一些细枝末节的部分(如未知长度训练集的处理)并实现一些fit()方法支持的功能(如Callback类的使用)。

 def train(model:keras.Model,train_batchs,epochs=1,initial_epoch=0,callbacks=None,steps_per_epoch=None,val_batchs=None):
callbacks = tf.keras.callbacks.CallbackList(
callbacks, add_history=True, model=model) logs_dict = {} # init optimizer, loss function and metrics
optimizer = keras.optimizers.Nadam(learning_rate=0.0005)
loss_fn = keras.losses.MeanSquaredError train_loss_tracker = keras.metrics.Mean(name="train_loss")
val_loss_tracker = keras.metrics.Mean(name="val_loss")
# train_acc_metric = tf.keras.metrics.BinaryAccuracy(name="train_acc")
# val_acc_metric = tf.keras.metrics.BinaryAccuracy(name="val_acc") def count(): # infinite iter
x = 0
while True:yield x;x+=1 def print_status_bar(iteration, total, metrics=None):
metrics = " - ".join(["{}:{:.4f}".format(m.name,m.result()) for m in (metrics or [])])
end = "" if iteration < total or float('inf') else "\n"
print("\r{}/{} - ".format(iteration,total) + metrics, end=end) def train_step(x,y,loss_tracker:keras.metrics.Metric):
with tf.GradientTape() as tape:
outputs = model(x)
main_loss = tf.reduce_mean(loss_fn(y,outputs)) loss = tf.add_n([main_loss] + model.losses)
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients,model.trainable_variables))
loss_tracker.update_state(loss)
return {loss_tracker.name:loss_tracker.result()} def val_step(x,y,loss_tracker:keras.metrics.Metric):
outputs = model.predict(x,verbose=0)
main_loss = tf.reduce_mean(loss_fn(y,outputs)) loss = tf.add_n([main_loss] + model.losses)
loss_tracker.update_state(loss)
return {loss_tracker.name:loss_tracker.result()} # init train_batchs
train_iter = iter(train_batchs) callbacks.on_train_begin(logs=logs_dict)
for i_epoch in range(initial_epoch, epochs): # init steps
infinite_flag = False
if steps_per_epoch is None:
infinite_flag = True
step_iter = count()
else:
step_iter = range(steps_per_epoch) # train_loop
for i_step in step_iter:
callbacks.on_batch_begin(i_step, logs=logs_dict)
callbacks.on_train_batch_begin(i_step, logs=logs_dict) try:
X_batch, y_batch = train_iter.next()
except StopIteration:
train_iter = iter(train_batchs)
if infinite_flag is True:
break
else:
X_batch, y_batch = train_iter.next() train_logs_dict = train_step(x=X_batch,y=y_batch,loss_tracker=train_loss_tracker)
logs_dict.update(train_logs_dict) print_status_bar(i_step, steps_per_epoch or i_step, [train_loss_tracker]) callbacks.on_train_batch_end(i_step, logs=logs_dict)
callbacks.on_batch_end(i_step, logs=logs_dict) if steps_per_epoch is None:
print()
steps_per_epoch = i_step if val_batchs is not None:
# val_loop
for i_step,(X_batch,y_batch) in enumerate(iter(val_batchs)):
callbacks.on_batch_begin(i_step, logs=logs_dict)
callbacks.on_test_batch_begin(i_step, logs=logs_dict) val_logs_dict = val_step(x=X_batch,y=y_batch,loss_tracker=val_loss_tracker)
logs_dict.update(val_logs_dict) callbacks.on_test_batch_end(i_step, logs=logs_dict)
callbacks.on_batch_end(i_step, logs=logs_dict) logs_dict.update(val_logs_dict) print_status_bar(steps_per_epoch, steps_per_epoch, [train_loss_tracker, val_loss_tracker])
callbacks.on_epoch_end(i_epoch, logs=logs_dict) for metric in [train_loss_tracker, val_loss_tracker]:
metric.reset_states() callbacks.on_train_end(logs=logs_dict) # Fetch the history object we normally get from keras.fit
history_object = None
for cb in callbacks:
if isinstance(cb, tf.keras.callbacks.History):
history_object = cb
return history_object

TensorFlow自定义训练函数的更多相关文章

  1. 深度学习笔记 (二) 在TensorFlow上训练一个多层卷积神经网络

    上一篇笔记主要介绍了卷积神经网络相关的基础知识.在本篇笔记中,将参考TensorFlow官方文档使用mnist数据集,在TensorFlow上训练一个多层卷积神经网络. 下载并导入mnist数据集 首 ...

  2. 在 C/C++ 中使用 TensorFlow 预训练好的模型—— 直接调用 C++ 接口实现

    现在的深度学习框架一般都是基于 Python 来实现,构建.训练.保存和调用模型都可以很容易地在 Python 下完成.但有时候,我们在实际应用这些模型的时候可能需要在其他编程语言下进行,本文将通过直 ...

  3. 在 C/C++ 中使用 TensorFlow 预训练好的模型—— 间接调用 Python 实现

    现在的深度学习框架一般都是基于 Python 来实现,构建.训练.保存和调用模型都可以很容易地在 Python 下完成.但有时候,我们在实际应用这些模型的时候可能需要在其他编程语言下进行,本文将通过 ...

  4. 在C#下使用TensorFlow.NET训练自己的数据集

    在C#下使用TensorFlow.NET训练自己的数据集 今天,我结合代码来详细介绍如何使用 SciSharp STACK 的 TensorFlow.NET 来训练CNN模型,该模型主要实现 图像的分 ...

  5. 关于jqGrig如何写自定义格式化函数将JSON数据的字符串转换为表格各个列的值

    首先介绍一下jqGrid是一个jQuery的一个表格框架,现在有一个需求就是将数据库表的数据拿出来显示出来,分别有id,name,details三个字段,其中难点就是details字段,它的数据是这样 ...

  6. 自定义el函数

    1.1.1 自定义EL函数(EL调用Java的函数) 第一步:创建一个Java类.方法必须是静态方法. public static String sayHello(String name){ retu ...

  7. ORACLE 自定义聚合函数

    用户可以自定义聚合函数  ODCIAggregate,定义了四个聚集函数:初始化.迭代.合并和终止. Initialization is accomplished by the ODCIAggrega ...

  8. SQL Server 自定义聚合函数

    说明:本文依据网络转载整理而成,因为时间关系,其中原理暂时并未深入研究,只是整理备份留个记录而已. 目标:在SQL Server中自定义聚合函数,在Group BY语句中 ,不是单纯的SUM和MAX等 ...

  9. Matlab中如何将(自定义)函数作为参数传递给另一个函数

    假如我们编写了一个积分通用程序,想使它更具有通用性,那么可以把被积函数也作为一个参数.在c/c++中,可以使用函数指针来实现上边的功能,在matlab中如何实现呢?使用函数句柄--这时类似于函数指针的 ...

随机推荐

  1. Vue3 与依赖注入

    Vue3 与依赖注入 本文写于 2021 年 2 月 19 日 在 React 中,我们可以通过 context 与 useContext 实现单例.注入--等诸多特性. 详细请看上一篇文章:如何利用 ...

  2. EF Core 的关联查询

    0 前言 本文会列举出 EF Core 关联查询的方法: 在第一.二.三节中,介绍的是 EF Core 的基本能力,在实体中配置好关系,即可使用,且其使用方式,与编程思维吻合,是本文推荐的方式. 第四 ...

  3. JavaScript中if语句优化和部分语法糖小技巧推荐

    前言 在前端日常开发过程中,if else判断语句使用的次数应该是比较频繁的了,一些较为复杂的场景,可能会用到很多判断,在某个代码块使用很多if else时,代码会显得较为冗余,阅读起来不够清晰. 除 ...

  4. 解决windows server 2008r2服务器自动关机

    问题 具体表现就是系统自动关机,网上说是开机后2小时就会自动关机 系统版本: 解决 PsTools下载 解压:PSTools.zipg,如解压到C:\PSTools目录下 执行如下命令,打开注册表 W ...

  5. Java高并发-Java内存模型和线程安全

    一.原子性 原子性是指一个操作是不可中断的.即使在多个线程一起执行的时候,一个操作一旦开始,就不会被其它线程干扰. i++是原子操作吗? 不是,包含3个操作:读i,i=i+1,写i 32位的机子上读取 ...

  6. k8s docker 中部署think php 并搭建php websocket

    不得不说php 对云原生有点不够友好,之前用java .net打包docker镜像 一下就ok了,php倒腾了好久才算部署成功. 场景:使用阿里云ack(k8s) 部署采用thinkPHP框架的php ...

  7. 好客租房27-state的基本使用

    5.1state的基本使用 状态:数据 是组件内部的私有数据 只能再组件内部使用 state的值是对象 表示一个组件中可以有多个数据 获取数据 this.state //导入react     imp ...

  8. Egg上层框架CabloyJS是如何输出SQL语句日志的?

    背景 在Egg开发实践中,经常会遇到一个问题:如何查看刚刚执行过的Egg组装的原生SQL语句呢? 1. 现有方案 可以直接在项目的config配置文件中添加MySQL配置debug: true.这会启 ...

  9. AtCoder ABC 242 题解

    AtCoder ABC 242 题解 A T-shirt 排名前 \(A\) 可得 T-shirt 排名 \([A+1,B]\) 中随机选 \(C\) 个得 T-shirt 给出排名 \(X\) ,求 ...

  10. 2 万字 + 20张图| 细说 Redis 九种数据类型和应用场景

    作者:小林coding 计算机八股文网(操作系统.计算机网络.计算机组成.MySQL.Redis):https://xiaolincoding.com 大家好,我是小林. 我们都知道 Redis 提供 ...