自定义求导
def f(x):
return 3. * x ** 2 + 2. * x - 1
def approximate_derivative(f, x, eps=1e-3):
#向左移动eps的值 向右移动eps的值 得到两个点 这两个点的斜率就是在x点的导数近似
#eps 越小 越逼近导数 纵坐标差值 / 横坐标差值
return (f(x + eps) - f(x - eps)) / (2. * eps)
print(approximate_derivative(f, 1.))
两个变量求导数
def g(x1, x2):
return (x1 + 5) * (x2 ** 2)
def approximate_gradient(g, x1, x2, eps=1e-3):
# 固定x2 函数 对x1求导
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
print(approximate_gradient(g, 2., 3.))
TensorFlow自动求导
x1 = tf.Variable(2.0)
x2 = tf.Variable(3.0)
# 导数求解
with tf.GradientTape() as tape:
z = g(x1, x2)
# 函数输出和变量
dz_x1 = tape.gradient(z, x1)
print(dz_x1)
# tape 只能调用一次 调用完会被消解释放
try:
dz_x2 = tape.gradient(z, x2)
except RuntimeError as ex:
print(ex)
x1 = tf.Variable(2.0)
x2 = tf.Variable(3.0)
# 声明可以保存
with tf.GradientTape(persistent = True) as tape:
z = g(x1, x2)
dz_x1 = tape.gradient(z, x1)
dz_x2 = tape.gradient(z, x2)
print(dz_x1, dz_x2)
# 使用完删掉
del tape
同时求x1,x2偏导
可以通过一些变量来观测constant的导数
两个函数对同一个变量求导
计算出的是 两个函数在x点的导数和
求二阶导数
x1 = tf.Variable(2.0)
x2 = tf.Variable(3.0)
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])
outer_grads = [outer_tape.gradient(inner_grad, [x1, x2])
for inner_grad in inner_grads]
print(outer_grads)
del inner_tape
del outer_tape
得出的是一个2*2 的矩阵 左上角 是z对x1的二阶导,右上角是z先对x2求导在对x1求导,左下角是z先对x1求导再对x2求导,右下角是z对x2的二阶导。
learning_rate = 0.1
x = tf.Variable(0.0)
# 循环100步
for _ in range(100):
with tf.GradientTape() as tape:
z = f(x)
# 进行求导
dz_dx = tape.gradient(z, x)
# 更新 x - lr * dz_dx
x.assign_sub(learning_rate * dz_dx)
print(x)
结合optimizer 求导
使用自定义梯度求解问题
需要修改model.fit部分的代码
# metric使用
# 均方差
metric = keras.metrics.MeanSquaredError()
# 输入是两个列表
print(metric([5.], [2.]))
#metric 有累加功能 第一个9 第二个1 平均之后是5
print(metric([0.], [1.]))
print(metric.result())
# metric不累加数据
metric.reset_states()
metric([1.], [3.])
print(metric.result())
# fit函数做的事
# 1. batch 遍历训练集 metric
# 1.1 自动求导
# 2. epoch结束 验证集 metric
#定义变量 遍历多少次
epochs = 100
batch_size = 32
#每个epoch 需要训练多少次
steps_per_epoch = len(x_train_scaled) // batch_size
optimizer = keras.optimizers.SGD()
# 度量 评估方式
metric = keras.metrics.MeanSquaredError()
# 随机取32个样本
def random_batch(x, y, batch_size=32):
idx = np.random.randint(0, len(x), size=batch_size)
return x[idx], y[idx]
model = keras.models.Sequential([
keras.layers.Dense(30, activation='relu',
input_shape=x_train.shape[1:]),
keras.layers.Dense(1),
])
for epoch in range(epochs):
# metric不累加数据
metric.reset_states()
# 循环遍历数据
for step in range(steps_per_epoch):
# 取出数据
x_batch, y_batch = random_batch(x_train_scaled, y_train,
batch_size)
# 手动计算求梯度
with tf.GradientTape() as tape:
y_pred = model(x_batch)
y_pred = tf.squeeze(y_pred, 1)
loss = keras.losses.mean_squared_error(y_batch, y_pred)
metric(y_batch, y_pred)
# 更新梯度
grads = tape.gradient(loss, model.variables)
grads_and_vars = zip(grads, model.variables)
optimizer.apply_gradients(grads_and_vars)
#打印运行结果
print("\rEpoch", epoch, " train mse:",
metric.result().numpy(), end="")
# 验证
y_valid_pred = model(x_valid_scaled)
y_valid_pred = tf.squeeze(y_valid_pred, 1)
valid_loss = keras.losses.mean_squared_error(y_valid_pred, y_valid)
print("\t", "valid mse: ", valid_loss.numpy())
训练