Tensorflow自定义模型与训练超详细讲解
作者:沐兮Krystal 发布时间:2023-09-19 10:18:00
前言
Tensorflow的核心与NumPy非常相似,但具有GPU支持;
Tensorflow支持分布式计算(跨多个设备和服务器)。
像NumPy一样使用TensorFlow
@运算符是在Python 3.5 中添加的,用于矩阵乘法,等效于 tf.matmul() 函数。
Keras的底层API
Keras API在keras.backend中有自己的底层API,如果要编写可移植到其他Keras实现中的代码,则应使用这些Keras函数。
from tensorflow import keras
K = keras.backend
K.square(K.transpose(t)) + 10
当从NumPy数组创建张量时,需设置 dtype=tf.float32;
定制模型和训练算法
自定义损失函数
实现Huber损失:
def huber_fn(y_true, y_pred):
error = y_true - y_pred
is_small_error = tf.abs(error) < 1
squared_loss = tf.square(error) / 2
linear_loss = tf.abs(error) - 0.5
return tf.where(is_small_error, squared_loss, linear_loss)
编译Keras模型,训练模型:
model.compile(loss=huber_fn, optimizer="nadam")
model.fit(X_train, y_train, [...])
保存和加载包含自定义组件的模型
当加载包含自定义对象的模型时,需要将名称映射到对象。
model = keras.models.load_model("my_model_with_a_custom_loss.h5",custom_objects={<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->"huber_fn": huber_fn})
创建一个函数,该函数创建已配置的损失函数:
def create_huber(threshold=1.0):
def huber_fn(y_true, y_pred):
error = y_true - y_pred
is_small_error = tf.abs(error) < threshold
squared_loss = tf.square(error) / 2
linear_loss = threshold * tf.abs(error) - threshold**2 / 2
return tf.where(is_small_error, squared_loss, linear_loss)
return huber_fn
model.compile(loss=create_huber(2.0), optimizer="nadam")
在加载模型的时候必须指定阈值:
model = keras.models.load_model("my_model_with_a_custom_loss.h5",custom_objects={"huber_fn": create_huber(2.0)})
通过创建 keras.losses.Loss 类的子类,然后实现其 get_config() 方法来解决此问题:
class HuberLoss(keras.losses.Loss):
def __init__(self, threshold=1.0, **kwargs):
self.threshold = threshold
super().__init__(**kwargs)
def call(self, y_true, y_pred):
error = y_true - y_pred
is_small_error = tf.abs(error) < self.threshold
squared_loss = tf.square(error) / 2
linear_loss = self.threshold * tf.abs(error) - self.threshold**2 / 2
return tf.where(is_small_error, squared_loss, linear_loss)
def get_config(self):
base_config = super().get_config()
return {**base_config, "threshold": self.threshold}
以上父类构造函数处理标准超参数:损失的name和用于聚合单个实例损失的reduction算法。
get_config() 方法返回一个字典,将每个超参数映射到其值。首先调用父类的get_config() 方法,然后将新的超参数添加到此字典中。
可在编译模型时使用此类的任何实例:
model.compile(loss=HuberLoss(2.),optimizer="nadam")
当保存模型的时候,阈值会同时一起保存。在加载模型时,只需要将类名映射到类本身:
model = keras.models.load_model("my_model_with_a_custom_loss.h5",custom_objects={<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->"HuberLoss": HuberLoss})
保存模型时,Keras会调用损失实例的 get_config() 方法,并将配置以 JSON 格式保存到 HDF5 文件中。
自定义激活函数与初始化与正则化和约束
编写简单的函数进行自定义
def my_softplus(z):
return tf.math.log(tf.exp(z)+1.0)
def my_glorot_initializer(shape, dtype=tf.float32):
stddev = tf.sqrt(2. / (shape[0] + shape[1]))
return tf.random.normal(shape, stddev=stddev, dtype=dtype)
def my_l1_regularizer(weights):
return tf.reduce_sum(tf.abs(0.01 * weights))
def my_positive_weights(weights): # return value is just tf.nn.relu(weights)
return tf.where(weights < 0., tf.zeros_like(weights), weights)
使用这些自定义函数
layer = keras.layers.Dense(30, activation=my_softplus,
kernel_initializer=my_glorot_initializer,
kenel_regularizer=my_l1_regularizer,
kenel_constraint=my_positive_weights)
在每个训练步骤中,权重将传递给正则化函数,以计算正则化损失,并将其添加到主要损失中得到用于训练的最终损失。
必须为损失、层(包括激活函数)和模型实现 call() 方法,或者为正则化、初始化和约束实现 __call__()方法。
自定义指标
可以将创建的损失函数作为指标。
model.compile(loss="mse", optimizer="nadam", metrics=[create_huber(2.0)])
流式指标(状态指标)是逐批次更新的。
自定义层
创建不带任何权重的自定义层:
exponential_layer = keras.layers.Lambda(lambda x: tf.exp(x))
当要预测的值具有非常不同的标度(例如0.001、10、1000)时,有时会在回归模型的输出层中使用指数层。
构建自定义的有状态层(即具有权重的层):
class MyDense(keras.layers.Layer):
# 将所有超参数用作参数
def __init__(self, units, activation=None, **kwargs):
super().__init__(**kwargs)
self.units = units
self.activation = keras.activations.get(activation)
# 创建层的变量
def build(self, batch_input_shape):
self.kernel = self.add_weight(
name="kernel", shape=[batch_input_shape[-1], self.units],
initializer="glorot_normal")
self.bias = self.add_weight(
name="bias", shape=[self.units], initializer="zeros")
super().build(batch_input_shape) # must be at the end
# 调用父类方法,告诉keras这一层被构建了,设置 self.built=true
def call(self, X):
return self.activation(X @ self.kernel + self.bias)
def compute_output_shape(self, batch_input_shape):
return tf.TensorShape(batch_input_shape.as_list()[:-1] + [self.units])
def get_config(self):
base_config = super().get_config()
return {**base_config, "units": self.units,
"activation": keras.activation.serialize(self.activation) }
创建多输入,多输出的层:
class MyMultiLayer(keras.layers.Layer):
def call(self, X):
X1, X2 = X
return [X1 + X2, X1 * X2, X1 / X2]
def compute_output_shape(self, batch_input_shape):
b1, b2 = batch_input_shape
return [b1, b1, b1]
如果层在训练期间和测试期间需要具有不同的行为,比如,创建一个在训练期间(用于正则化)添加高斯噪声,但在测试期间不执行任何操作:
class MyGaussianNoise(keras.layers.Layer):
def __init__(self, stddev, **kwargs):
super().__init__(**kwargs)
self.stddev = stddev
def call(self, X, training=None):
if training:
noise = tf.random.normal(tf.shape(X), stddev=self.stddev)
return X + noise
else:
return X
def compute_output_shape(self, batch_input_shape):
return batch_input_shape
自定义模型
首先创建一个 ResidualBlock 层:
class ResidualBlock(keras.layers.Layer):
def __init__(self, n_layers, n_nerons, **kwargs):
super().__init__(**kwargs)
self.hidden = [keras.layers.Dense(n_nerons, activation="elu",
kenel_initializer="he_normal")
for _ in range(n_layers)]
def call(self, inputs):
Z = inputs
for layer in self.hidden:
Z = layer(Z)
return inputs + Z
使用子类API定义模型:
class ResidualRegressor(keras.Model):
def __init__(self, output_dim, **kwargs):
super().__init__(**kwargs)
self.hidden1 = keras.layers.Dense(30, activation="elu",
kernel_initializer="he_normal")
self.block1 = ResidualBlock(2, 30)
self.block2 = ResidualBlock(2, 30)
self.out = keras.layers.Dense(output_dim)
def call(self, inputs):
Z = self.hidden1(inputs)
for _ in range(1 + 3):
Z = self.block1(Z)
Z = self.block2(Z)
return self.out(Z)
在构造函数中创建层,在call()方法中使用它们。
带有自定义重建损失的自定义模型,此自定义模型在上部隐藏层的顶部有辅助输出,与该辅助输出相关的损失称为重建损失。
class ReconstructingRegressor(keras.Model):
def __init__(self, output_dim, **kwargs):
super().__init__(**kwargs)
self.hidden = [keras.layers.Dense(30, activation="selu",
kernel_initializer = "lecun_normal")
for _ in range(5)]
self.out = keras.layers.Dense(output_dim)
def build(self, batch_input_shape):
n_inputs = batch_input_shape[-1]
self.reconstruct = keras.layers.Dense(n_inputs) # 该层用于重建模型的输入
super().build(batch_input_shape)
def call(self, inputs):
Z = inputs
for layer in self.hidden:
Z = layer(Z)
reconstruction = self.reconstruct(Z)
recon_loss = tf.reduce_mean(tf.square(reconstruction - inputs))
self.add_loss(0.05 * recon_loss)
return self.out(Z)
正则化,在输入变化不大时惩罚那些变化很大的激活。
来源:https://blog.csdn.net/GW_Krystal/article/details/127788879
猜你喜欢
- 本文实例为大家分享了pytorch实现线性回归以及多元回归的具体代码,供大家参考,具体内容如下最近在学习pytorch,现在把学习的代码放在
- 正常时间显示<SCRIPT language=javascript><!--function Ye
- Python 3.7中一个令人兴奋的新特性是 data classes 。 数据类通常是一个主要包含数据的类,尽管实际上没有任何限制。 它是
- 我们熟悉了对象和类的基本概念。我们将进一步拓展,以便能实际运用对象和类。调用类的其它信息上一讲中提到,在定义方法时,必须有self这一参数。
- 关于 *args与**args的用法*args 和 **kwargs主要用于函数定义,你可以将不定数量的参数传递给某个函数。*args*ar
- 让我们描绘一下本文的情节:假设您要在本地机器上运行一个进程,而部分程序逻辑却在另一处。让我们特别假设这个程序逻辑会不时更新, 而您运行进程时
- 完成这个小球的完全弹性碰撞游戏灵感来自于:下面是我花了一周下班时间所编写的一个小球完全弹性碰撞游戏:游戏初始化状态:最下面的游标和修改小球的
- 此文仅当学习笔记用.这个实例是在Python环境下如何爬取弹出窗口的内容,有些时候我们要在页面中通过点击,然后在弹出窗口中才有我们要的信息,
- 使用input和raw_input都可以读取控制台的输入,但是input和raw_input在处理数字时是有区别的纯数字输入当输入为纯数字时
- 很多小伙伴在学习Django的时候,总是搞不定版本的问题,下面来一起看一张表,轻松解决Python版本和Django版本的兼容问题。Djan
- 前言最近学习了 django 的一个 restframework 框架,对于里面的执行流程产生了兴趣,经过昨天一晚上初步搞清楚了执行流程(部
- 做教育业的网站,会将此遇到这个问题:如何在网页上显示音标?音标为什么显示为乱字符?等等类似的问题。前两天做沪江网某英语页面的时候也碰到了这个
- 官方文档:https://elasticsearch-py.readthedocs.io/en/master/1、介绍python提供了操作
- 插值主要用于物理学数学中,逼近某一确定值的方法(1)插值是通过已知的离散数据求未知数据的方法。(2)与拟合不同,插值要求曲线通过所有的已知数
- 这个问题的解决方案网上挺多的。其中我推荐的就是:with open(r"F:\Desktop\Book3.csv",
- 1.什么是labelpandas处理数据时,我们会经常看到dataframe结构使用loc, iloc, ix等方法。那么这些方法到底有啥区
- 先看看 allure 命令的帮助文档cmd 敲allure -hallure 命令的语法格式allure [options] [comman
- 本文实例讲述了Python中文分词实现方法。分享给大家供大家参考,具体如下:在Python这pymmseg-cpp 还是十分方便的!环境 u
- 【摘 要】 我只是提供我几个我认为有助于提高写高性能的asp.net应用程序的技巧,本文提到的提高asp.net性能的技巧只是一个起步,更多
- 1. axis的基本使用axis常常用在numpy和tensorflow中用到,作为对矩阵(张量)进行操作时需要指定的重要参数之一。设定ax