tensorflow2 自定义损失函数使用的隐藏坑
Keras的核心原则是逐步揭示复杂性,可以在保持相应的高级便利性的同时,对操作细节进行更多控制。当我们要自定义fit中的训练算法时,可以重写模型中的train_step方法,然后调用fit来训练模型。
这里以tensorflow2官网中的例子来说明:
import numpy as np
import tensorflow as tf
from tensorflow import keras
x = np.random.random((1000, 32))
y = np.random.random((1000, 1))
class CustomModel(keras.Model):
tf.random.set_seed(100)
def train_step(self, data):
# Unpack the data. Its structure depends on your model and
# on what you pass to `fit()`.
x, y = data
with tf.GradientTape() as tape:
y_pred = self(x, training=True) # Forward pass
# Compute the loss value
# (the loss function is configured in `compile()`)
loss = self.compiled_loss(y, y_pred, regularization_losses=self.losses)
# Compute gradients
trainable_vars = self.trainable_variables
gradients = tape.gradient(loss, trainable_vars)
# Update weights
self.optimizer.apply_gradients(zip(gradients, trainable_vars))
# Update metrics (includes the metric that tracks the loss)
self.compiled_metrics.update_state(y, y_pred)
# Return a dict mapping metric names to current value
return {m.name: m.result() for m in self.metrics}
# Construct and compile an instance of CustomModel
inputs = keras.Input(shape=(32,))
outputs = keras.layers.Dense(1)(inputs)
model = CustomModel(inputs, outputs)
model.compile(optimizer="adam", loss=tf.losses.MSE, metrics=["mae"])
# Just use `fit` as usual
model.fit(x, y, epochs=1, shuffle=False)
32/32 [==============================] - 0s 1ms/step - loss: 0.2783 - mae: 0.4257
<tensorflow.python.keras.callbacks.History at 0x7ff7edf6dfd0>
这里的loss是tensorflow库中实现了的损失函数,如果想自定义损失函数,然后将损失函数传入model.compile中,能正常按我们预想的work吗?
答案竟然是否定的,而且没有错误提示,只是loss计算不会符合我们的预期。
def custom_mse(y_true, y_pred):
return tf.reduce_mean((y_true - y_pred)**2, axis=-1)
a_true = tf.constant([1., 1.5, 1.2])
a_pred = tf.constant([1., 2, 1.5])
custom_mse(a_true, a_pred)
<tf.Tensor: shape=(), dtype=float32, numpy=0.11333332>
tf.losses.MSE(a_true, a_pred)
<tf.Tensor: shape=(), dtype=float32, numpy=0.11333332>
以上结果证实了我们自定义loss的正确性,下面我们直接将自定义的loss置入compile中的loss参数中,看看会发生什么。
my_model = CustomModel(inputs, outputs)
my_model.compile(optimizer="adam", loss=custom_mse, metrics=["mae"])
my_model.fit(x, y, epochs=1, shuffle=False)
32/32 [==============================] - 0s 820us/step - loss: 0.1628 - mae: 0.3257
<tensorflow.python.keras.callbacks.History at 0x7ff7edeb7810>
我们看到,这里的loss与我们与标准的tf.losses.MSE明显不同。这说明我们自定义的loss以这种方式直接传递进model.compile中,是完全错误的操作。
正确运用自定义loss的姿势是什么呢?下面揭晓。
loss_tracker = keras.metrics.Mean(name="loss")
mae_metric = keras.metrics.MeanAbsoluteError(name="mae")
class MyCustomModel(keras.Model):
tf.random.set_seed(100)
def train_step(self, data):
# Unpack the data. Its structure depends on your model and
# on what you pass to `fit()`.
x, y = data
with tf.GradientTape() as tape:
y_pred = self(x, training=True) # Forward pass
# Compute the loss value
# (the loss function is configured in `compile()`)
loss = custom_mse(y, y_pred)
# loss += self.losses
# Compute gradients
trainable_vars = self.trainable_variables
gradients = tape.gradient(loss, trainable_vars)
# Update weights
self.optimizer.apply_gradients(zip(gradients, trainable_vars))
# Compute our own metrics
loss_tracker.update_state(loss)
mae_metric.update_state(y, y_pred)
return {"loss": loss_tracker.result(), "mae": mae_metric.result()}
@property
def metrics(self):
# We list our `Metric` objects here so that `reset_states()` can be
# called automatically at the start of each epoch
# or at the start of `evaluate()`.
# If you don't implement this property, you have to call
# `reset_states()` yourself at the time of your choosing.
return [loss_tracker, mae_metric]
# Construct and compile an instance of CustomModel
inputs = keras.Input(shape=(32,))
outputs = keras.layers.Dense(1)(inputs)
my_model_beta = MyCustomModel(inputs, outputs)
my_model_beta.compile(optimizer="adam")
# Just use `fit` as usual
my_model_beta.fit(x, y, epochs=1, shuffle=False)
32/32 [==============================] - 0s 960us/step - loss: 0.2783 - mae: 0.4257
<tensorflow.python.keras.callbacks.History at 0x7ff7eda3d810>
终于,通过跳过在 compile() 中传递损失函数,而在 train_step 中手动完成所有计算内容,我们获得了与之前默认tf.losses.MSE完全一致的输出,这才是我们想要的结果。
总结一下,当我们在模型中想用自定义的损失函数,不能直接传入fit函数,而是需要在train_step中手动传入,完成计算过程。
tensorflow2 自定义损失函数使用的隐藏坑的更多相关文章
- TensorFlow笔记-06-神经网络优化-损失函数,自定义损失函数,交叉熵
TensorFlow笔记-06-神经网络优化-损失函数,自定义损失函数,交叉熵 神经元模型:用数学公式比表示为:f(Σi xi*wi + b), f为激活函数 神经网络 是以神经元为基本单位构成的 激 ...
- tensorflow 自定义损失函数示例
这个自定义损失函数的背景:(一般回归用的损失函数是MSE, 但要看实际遇到的情况而有所改变) 我们现在想要做一个回归,来预估某个商品的销量,现在我们知道,一件商品的成本是1元,售价是10元. 如果我们 ...
- tensflow自定义损失函数
tensflow 不仅支持经典的损失函数,还可以优化任意的自定义损失函数. 预测商品销量时,如果预测值比真实销量大,商家损失的是生产商品的成本:如果预测值比真实值小,损失的则是商品的利润. 比如如果一 ...
- 机器学习之路: tensorflow 自定义 损失函数
git: https://github.com/linyi0604/MachineLearning/tree/master/07_tensorflow/ import tensorflow as tf ...
- Tensorflow 损失函数(loss function)及自定义损失函数(三)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/limiyudianzi/article ...
- SpringMVC自定义配置消息转换器踩坑总结
问题描述 最近在开发时候碰到一个问题,springmvc页面向后台传数据的时候,通常我是这样处理的,在前台把数据打成一个json,在后台接口中使用@requestbody定义一个对象来接收,但是这次数 ...
- Fidder详解-工具简介(保存会话、decode解码、Repaly、自定义会话框、隐藏会话、会话排序)
前言 本文会对Fidder这款工具的一些重要功能,进行详细讲解,带大家进入Fidder的世界,本文会让你明白,Fidder不仅是一个抓包分析工具,也是一个请求发送工具,更加可以当作为Mock Serv ...
- 隐藏软键盘(解决自定义Dialog中无法隐藏的问题)
/** * Dialog中隐藏软键盘不管用 * @param activity */ public static void HideSoftKeyBoard(Activity activity){ t ...
- IOS 极光推送自定义通知遇到的一些坑
主要方法: //自定义推送 - (void)networkDidReceiveMessage:(NSNotification *)notification { NSDictionary * userI ...
随机推荐
- 电阻存储器为edge-AI提供了仿生架构
电阻存储器为edge-AI提供了仿生架构 Resistive memories enable bio-inspired architectures for edge AI 近年来,脑启发计算领域的研究 ...
- .NET平台系列21:云原生时代 .NET5 雄霸天下
系列目录 [已更新最新开发文章,点击查看详细] 随着互联网持续高歌猛进,相关技术名词也是层出不穷.微服务.容器化.DevOps.ServerLess.FaaS,这两年最火的当属云原生Cloud ...
- MySQL8性能优化
MySQL8.0 引擎: 来看看MySQL8提供的引擎: 常用引擎: InnoDB:支持事务,行级锁,外键,崩溃修复,多版本并发控制:读写效率相对较差,内存使用相对较高,占用数据空间相对较大. MyI ...
- Java基准性能测试--JMH使用介绍
JMH是什么 JMH是Java Microbenchmark Harness的简称,一个针对Java做基准测试的工具,是由开发JVM的那群人开发的.想准确的对一段代码做基准性能测试并不容易,因为JVM ...
- 乘风破浪,下载安装体验Adobe XD流程,全新的引导和安装体验设计
简介 Adobe XD是一款适用于网站和应用程序等的快速且功能强大的UI/UX设计解决方案.可实现设计.线框.动画制作.原型创建.协作和共享等,功能一应俱全. https://www.adobe.co ...
- lms框架服务注册中心
服务注册中心原理 在分布式系统里的注册中心.原理是将部署服务的机器地址记录到注册中心,服务消费者在有需求的时候,只需要查询注册中心,输入提供的服务名,就可以得到地址,从而发起调用. 在微服务架构下,主 ...
- To_Heart—题解——AT2165
这是一篇解题报告 首先,看到标签,考虑二分答案. 我们二分答案(即塔顶的值),把大于或等于这个值的变为1,否则变为0. 很容易发现,如果塔顶的答案是1,那么就说明值可以更大,否则相反. 复制一波样例 ...
- 使用Oracle SQL Developer报错:Unable to find a Java Virtual Machine
1.环境 win7 x64,oracle 11g r2,jdk6 x64 2.问题 第一次启动Oracle SQL Developer的时候会让我们填写java.exe的路径,我在jdk安装目录下的b ...
- 使用 python 把一个文件生成 C 语言中的数组并保存到头文件中
(一)要做什么 之前有这么一个需求,是要把一个二进制文件里面的数据,转换成 C 代码里面的数组,可以看之前的一篇文章: NUC980 运行 RT-Thread 驱动 SPI 接口 OLED 播放 ba ...
- BGV方案
BGV方案 SIMD技术 中国剩余定理 在<孙子算经>中有这样一个问题:"今有物不知其数,三三数之剩二(除以3余2),五五数之剩三(除以5余3),七七数之剩二(除以7余2),问物 ...