1.根据导数定义
使用tensorflow近似求导:
# 求导数
def approximate_derivative(func, x, eps=1e-3):
return (func(x + eps) - func(x)) / eps
# 求偏导数
def approximate_gradient(g, x1, x2, eps=1e-3):
dg_x1 = approximate_derivative(lambda x: g(x, x2), x1, eps)
dg_x2 = approximate_derivative(lambda x: g(x1, x), x2, eps)
return dg_x1, dg_x2
2.使用tensorflow的自动求导功能官方API链接www.tensorflow.org
x1 = tf.Variable(2.) # 网络里会发生变化的变量,一般是权重,需要定义在求导记录外
x2 = tf.Variable(3.)
with tf.GradientTape() as tape: # 使用with打开一个记录
z = g(x1, x2) # 具体操作
dz_x1 = tape.gradient(z, x1) # 求得z对x1的偏导
---------------------------------------------------------------
dz_x1
tape使用过一次后便会释放,若想多次使用,需要加入参数persistent=True(这样的话后面也需要手动释放tape,以免造成内存泄漏):
x1 = tf.Variable(2.) # 网络里会发生变化的变量,一般是权重,需要定义在求导记录外
x2 = tf.Variable(3.)
with tf.GradientTape(persistent=True) as tape:
z = g(x1, x2)
dz_x1 = tape.gradient(z, x1)
dz_x2 = tape.gradient(z, x2)
# 也可使用list包裹要求偏导的变量
dz_x1x2 = tape.gradient(z, [x1, x2])
del tape # 记住释放tape
对于tf.constant类型的变量,也可以使用tape.watch加入自动求导记录里。API参考链接
x1 = tf.constant(2.)
x2 = tf.constant(3.)
with tf.GradientTape(persistent=True) as tape:
tape.watch(x1)
tape.watch(x2)
z = g(x1, x2)
dz_x1x2 = tape.gradient(z, [x1, x2])
---------------------------------------------------
[tf.Tensor(9.0, shape=(), dtype=float32),
tf.Tensor(42.0, shape=(), dtype=float32)]
也可以同时对多个函数求导,输出的是对各个函数的倒数之和:
x = tf.Variable(5.)
with tf.GradientTape() as tape:
z1 = 3 * x
z2 = x ** 3
print(tape.gradient([z1, z2], x))
----------------------------------------------------
tf.Tensor(78.0, shape=(), dtype=float32)
最后,是求二阶倒数,嵌套两次tf.GradientTape。先求出inner_grads,即列表[
,
] 。再对列表中每个元素求偏倒,形成二维列表[[
,
],[
,
]]:
x1 = tf.Variable(2.)
x2 = tf.Variable(3.)
with tf.GradientTape(persistent=True) as outer_tape:
with tf.GradientTape(persistent=True) as inner_tape:
z = g(x1, x2)
inner_grads = inner_tape.gradient(z, [x1, x2]) # list
outer_grads = [outer_tape.gradient(inner_grad, [x1, x2]) for inner_grad in inner_grads] # list 列表生成
del outer_tape
del inner_tape
接下来,就可以通过tf.GranientTape自定义训练了,也就是自己实现model.compile 和model.fit()的功能。
首先,如之前的教程一样,自定义一个模型:
class MyModel(keras.models.Model):
def __init__(self):
super(MyModel, self).__init__()
self.d_1 = tf.keras.layers.Dense(30, activation='relu')
self.d_2 = tf.keras.layers.Dense(1)
def call(self, x, training=True, mask=None):
return self.d_2(self.d_1(x))
model = MyModel()
接着,定义一下总共的循环次数epochs,每一批的大小batch_size,以及一次循环多少批steps_per_epoch。
epochs = 100
batch_size = 32
steps_per_epoch = len(x_train_scaled) // batch_size
然后,是优化器与度量方式。优化器,也就是搜索策略,tf集成了很多常用的优化器,一般不需要自定义,不过在这还是自己实现了基本的数学运算,以便启发读者自定义未被集成的方法:
def train(model, input, true_output, learning_rate=0.01):
with tf.GradientTape() as tape:
pred_output = model(input)
current_loss = tf.reduce_mean(
keras.losses.mean_squared_error(true_output, pred_output))
grads = tape.gradient(current_loss, model.variables)
# 对模型中的每个变量进行计算
for idx in range(len(model.variables)):
model.variables[idx].assign_sub(learning_rate * grads[idx])
# 进行训练
for epoch in range(epochs):
for step in range(steps_per_epoch):
# random_batch起到随机遍历的作用,在此没有实现
x_batch, y_batch = random_batch(x_train_scaled, y_train, batch_size)
train(MyModel, x_batch, y_batch)
官方还是更推荐使用已有的优化器:
optimizer = keras.optimizers.SGD()
def train(model, input, true_output, learning_rate=0.01):
with tf.GradientTape() as tape:
pred_output = model(input)
current_loss = tf.reduce_mean(
keras.losses.mean_squared_error(true_output, pred_output))
grads = tape.gradient(current_loss, model.variables)
grads_and_variables = zip(grads, model.variables)
optimizer.apply_gradients(grads_and_variables)
# 进行训练
for epoch in range(epochs):
for step in range(steps_per_epoch):
# random_batch起到随机遍历的作用,在此没有实现
x_batch, y_batch = random_batch(x_train_scaled, y_train, batch_size)
train(MyModel, x_batch, y_batch)
附一个官网的自定义训练教程。