#tensorflow2.0
#tensorflow2.0
Вопрос:
import tensorflow as tf
import numpy as np
x = tf.Variable(2, name='x', trainable=True, dtype=tf.float32)
with tf.GradientTape() as t:
t.watch(x)
log_x = tf.math.log(x)
y = tf.math.square(log_x)
opt = tf.optimizers.Adam(0.5)
# train = opt.minimize(lambda: y, var_list=[x]) # FAILS
@tf.function
def f(x):
log_x = tf.math.log(x)
y = tf.math.square(log_x)
return y
yy = f(x)
train = opt.minimize(lambda: yy, var_list=[x]) # ALSO FAILS
Выдает ошибку значения:
No gradients provided for any variable: ['x:0'].
Это похоже на примеры, которые они частично приводят. Я не уверен, является ли это ошибкой с eager или 2.0 или что-то, что я делаю неправильно.
Обновить:
Вставил приукрашенную версию решения ниже, поскольку в ней были некоторые проблемы и интересные примечания.
import numpy as np
import tensorflow as tf
x = tf.Variable(3, name='x', trainable=True, dtype=tf.float32)
with tf.GradientTape(persistent=True) as t:
# log_x = tf.math.log(x)
# y = tf.math.square(log_x)
y = (x - 1) ** 2
opt = tf.optimizers.Adam(learning_rate=0.001)
def get_gradient_wrong(x0):
# this does not work, it does not actually update the value of x
x.assign(x0)
return t.gradient(y, [x])
def get_gradient(x0):
# this works
x.assign(x0)
with tf.GradientTape(persistent=True) as t:
y = (x - 1) ** 2
return t.gradient(y, [x])
#### Option 1
def a(x0, tol=1e-8, max_iter=10000):
# does not appear to work properly
x.assign(x0)
err = np.Inf # step error (banach), not actual erro
i = 0
while err > tol:
x0 = x.numpy()
# IMPORTANT: WITHOUT THIS INSIDE THE LOOP THE GRADIENTS DO NOT UPDATE
with tf.GradientTape(persistent=True) as t:
y = (x - 1) ** 2
gradients = t.gradient(y, [x])
l = opt.apply_gradients(zip(gradients, [x]))
err = np.abs(x.numpy() - x0)
print(err, x.numpy(), gradients[0].numpy())
i = 1
if i > max_iter:
print(f'stopping at max_iter={max_iter}')
return x.numpy()
print(f'stopping at err={err}<{tol}')
return x.numpy()
#### Option 2
def b(x0, tol=1e-8, max_iter=10000):
x.assign(x0)
# To use minimize you have to define your loss computation as a funcction
def compute_loss():
log_x = tf.math.log(x)
y = tf.math.square(log_x)
return y
err = np.Inf # step error (banach), not actual erro
i = 0
while err > tol:
x0 = x.numpy()
train = opt.minimize(compute_loss, var_list=[x])
err = np.abs(x.numpy() - x0)
print(err, x.numpy())
i = 1
if i > max_iter:
print(f'stopping at max_iter={max_iter}')
return x.numpy()
print(f'stopping at err={err}<{tol}')
return x.numpy()
Ответ №1:
Вы делаете что-то неправильно. У вас есть два варианта:
Используйте ленту для вычисления градиентов
В этом случае вам придется использовать оптимизатор только для применения правила обновления.
import tensorflow as tf
x = tf.Variable(2, name='x', trainable=True, dtype=tf.float32)
with tf.GradientTape() as t:
# no need to watch a variable:
# trainable variables are always watched
log_x = tf.math.log(x)
y = tf.math.square(log_x)
#### Option 1
# Is the tape that computes the gradients!
trainable_variables = [x]
gradients = t.gradient(y, trainable_variables)
# The optimize applies the update, using the variables
# and the optimizer update rule
opt.apply_gradients(zip(gradients, trainable_variables))
Определите потерю как функцию
В этом случае вы можете использовать метод optimizer .minimize
, который создаст ленту для вычисления градиента обновит параметры для вас
#### Option 2
# To use minimize you have to define your loss computation as a funcction
def compute_loss():
log_x = tf.math.log(x)
y = tf.math.square(log_x)
return y
train = opt.minimize(compute_loss, var_list=trainable_variables)
Комментарии:
1. И важный, тонкий момент в функции потерь, по-видимому, заключается в том, что вам нужно СКОНСТРУИРОВАТЬ потерю в функции. Например, вы не можете просто сконструировать y и передать потерю как lambda: y . Я не совсем понимаю, почему пока нет.
2. Потому что эта функция обернута в градиентную ленту, и на ленте записываются операции. Если вы пройдете
y
, лента не будет иметь представления о созданных операцияхy
и, следовательно, градиент не может быть вычислен3. И для первого примера, похоже, нужно снова и снова восстанавливать градиентную ленту внутри цикла. В принципе, та же схема, что и с функцией. Действительно ли это правильный способ сделать это? Такое ощущение, что мы все еще чего-то не хватает.
4. Вы ничего не упускаете, цикл обучения — это просто вычисление потерь внутри ленты с последующим применением правила обновления через оптимизатор. Это дает вам большую гибкость, поскольку вы можете выполнять настройки типа «при каждой нечетной итерации я обрезаю градиент» или что-либо еще по вашему желанию. Использование ленты для вычисления градиентов выполняется быстро, не беспокойтесь о производительности
5. Интересно. Таким образом, по сути, это самый общий шаблон «динамического графика» по умолчанию. Следовательно, ожидается, что график будет восстанавливаться каждый раз. Потрясающе, если это быстро даже для больших сетей.
Ответ №2:
Я также проголосовал за принятое решение выше, но мне все еще требовалось некоторое время, чтобы запустить комплексное решение, поэтому позвольте мне поделиться и этим с вами, код решает какую-то простую математическую головоломку:
f(x)=x-(6/7)*x-1/7
g (x)=f(f(f(f(x))))
Найдите x такое, чтобы g (x) == 0
!pip install setuptools --upgrade
!pip install -q tensorflow==2.0.0-beta1
import tensorflow as tf
import numpy as np
tf.__version__ #=> '2.0.0-beta1'
@tf.function
def f(x):
return x-(6/7)*x-1/7
print(tf.autograph.to_code(step.python_function))
x = tf.Variable(0, trainable=True, dtype=tf.float64)
y = tf.constant([0], dtype=tf.float64)
@tf.function
def g(x):
return f(f(f(f(x))))
print(tf.autograph.to_code(compute.python_function))
# Create a list of variables which needs to be adjusted during the training process, in this simple case it is only x
variables = [x]
# Instantiate a Gradient Decent Optimizer variant, it this case learning rate and specific type of optimizer doesn't matter too much
optimizer = tf.optimizers.Adam(0.5)
# We need to somehow specify the error between the actual value of the evaluated function in contrast to the target (which is zero)
loss_object = tf.keras.losses.MeanAbsoluteError()
# Since we are not running inside a TensorFlow execution graph anymore we need some means of keeping state of the gradient during training
# so a persistent GradientTape is your friend and the way to go in TensorFlow 2.0
with tf.GradientTape(persistent=True) as tape:
#Let's train for some iterations
for i in range(1000):
# given the actual value of X (which we now continueously adjust in order to find the root of the equation)
y_pred = g(x)
# At this point we are actually setting the whole equation to zero. Since X is variable, the goal is to find an X which satisfies the condition
# (that the whole equations becomes zero). We are doing this by defining a loss which becomes zero if y_pred approximates y. Or in other words,
# since y is zero, the loss becomes zero if y_pred approximates zero.
loss = loss_object(y,y_pred)
# Now the magic happens. Loss basically represents the error surface and is only dependent on X. So now let's compute the first derivative and
# see in which direction we need to adjust X in order to minimize the error and getting a value (output of the nested equations) closer to zero
grads = tape.gradient(loss, variables)
# Once we've found this magic number magically, let's update the value of X based on this magic number in order to perform better on the next
# iteration
optimizer.apply_gradients(zip(grads, variables))
# And now it's pretty cool, we can just print the current error (loss) and the actual value of X in each iteration. At the end of the training,
# we've found the optima wich a loss / error close to zero and a value of X close to 400 where 400 is the correct solution.
# Small deviations from the true solutions stem from numeric errors
print('Loss: {}, X: {}'.format(loss.numpy(), x.numpy()))