Closed AntuVenciu closed 2 years ago
Caro Antu,
se guardi la documentazione di JointDistributionSequential la documentazione di log_prob_parts()
sarà la medesima, così come nella classe da cui ereditano entrambe, JointDistribution. Putroppo ciò che è scritto lì non è la verità. Questo è ciò che succede quando si invoca quel metodo (provalo per vedere che anche a te torni uguale)
import tensorflow as tf
import tensorflow_probability as tfp
from spqr import NeuralSplineFlow as NSF
from diglm import DIGLM
d = DIGLM(NSF(splits=2), tfp.glm.Bernoulli(), 4)
lpp = d.log_prob_parts({"features": [0.,2.,3.,5.], "labels": [1]})
wlp = d.weighted_log_prob({"features": [0.,2.,3.,5.], "labels": [1]})
print(lpp)
print(wlp)
l'output è
{'features': <tf.Tensor: shape=(), dtype=float32, numpy=-22.995024>, 'labels': <tf.Tensor: shape=(), dtype=float32, numpy=-4.5551205e-05>}
tf.Tensor(-2.299548, shape=(), dtype=float32)
come puoi ben vedere nel nostro caso lpp ritorna un dizionario di tensori. La soluzione al tuo problema, credo, sta nel non usare come argomento target_sample
di train_step
una tupla di tensorflow, bensì un dizionario, quindi
loss = train_step(optimizer, {"labels": batch_label, "features": batch_feature})
prova e fammi sapere se funge.
L'uso di JointDistributionNamed
o di JointDistributionSequential
non ha nessuna differenza tecnica, è più una quesitone di sintassi. Personalmente preferisco la forma chiave: valore perché, credo, rende più chiaro cosa è chi e chi fa cosa. Fammi sapere se ti senti d'accordo, chiaramente se ne può discutere.
Chiudo la issue perché il problema era proprio questo.
Questa è la funzione di training sulla quale sto eseguendo il loop:
@tf.function def train_step(optimizer, target_sample): with tf.GradientTape() as tape: loss = -tf.reduce_mean(diglm.weighted_log_prob(target_sample)) variables = tape.watched_variables() gradients = tape.gradient(loss, variables) optimizer.apply_gradients(zip(gradients, variables)) return loss
E sto chiamando così la funzione nel loop: `LR = 1e-3 NUM_EPOCHS = 100
learning_rate = tf.Variable(LR, trainable=False) optimizer = tf.keras.optimizers.Adam(learning_rate)
loss = 0
for epoch in range(NUM_EPOCHS): if epoch % 10 == 9: print(f"Epoch n. {epoch+1}. Loss={loss}.") for i in range(int(DATASET_SIZE/BATCH_SIZE)): batch_label = y_data.sample(BATCH_SIZE, random_state=42) batch_feature = data_train.sample(BATCH_SIZE, random_state=42) loss = train_step(optimizer, tf.tuple(batch_label, batch_feature))`
Trovo il seguente errore:
`AttributeError Traceback (most recent call last)
1 frames
/usr/local/lib/python3.7/dist-packages/tensorflow/python/framework/func_graph.py in autograph_handler(*args, **kwargs) 1145 except Exception as e: # pylint:disable=broad-except 1146 if hasattr(e, "ag_error_metadata"): -> 1147 raise e.ag_error_metadata.to_exception(e) 1148 else: 1149 raise
AttributeError: in user code:
che secondo me dipende dal fatto che il seguente codice:
def weighted_log_prob(self, value, scaling_const=.1): lpp = self.log_prob_parts(value) return lpp["labels"] + scaling_const * lpp["features"]
invoca lpp come se fosse un dizionario, ma non è vero: dalla documentazione su tesnorflow_probability.distributions.JointDistributionNamedAutoBached il return value è: "a tuple of Tensors representing the log_prob for each distribution_fn evaluated at each corresponding value."