Cómo calcular la perplejidad de RNN en tensorflow

Estoy ejecutando la implementación de la palabra RNN del flujo tensor de la palabra RNN

Cómo calcular la perplejidad de RNN.

A continuación se muestra el código de entrenamiento que muestra la pérdida de entrenamiento y otras cosas en cada época:

for e in range(model.epoch_pointer.eval(), args.num_epochs): sess.run(tf.assign(model.lr, args.learning_rate * (args.decay_rate ** e))) data_loader.reset_batch_pointer() state = sess.run(model.initial_state) speed = 0 if args.init_from is None: assign_op = model.batch_pointer.assign(0) sess.run(assign_op) assign_op = model.epoch_pointer.assign(e) sess.run(assign_op) if args.init_from is not None: data_loader.pointer = model.batch_pointer.eval() args.init_from = None for b in range(data_loader.pointer, data_loader.num_batches): start = time.time() x, y = data_loader.next_batch() feed = {model.input_data: x, model.targets: y, model.initial_state: state, model.batch_time: speed} summary, train_loss, state, _, _ = sess.run([merged, model.cost, model.final_state, model.train_op, model.inc_batch_pointer_op], feed) train_writer.add_summary(summary, e * data_loader.num_batches + b) speed = time.time() - start if (e * data_loader.num_batches + b) % args.batch_size == 0: print("{}/{} (epoch {}), train_loss = {:.3f}, time/batch = {:.3f}" \ .format(e * data_loader.num_batches + b, args.num_epochs * data_loader.num_batches, e, train_loss, speed)) if (e * data_loader.num_batches + b) % args.save_every == 0 \ or (e==args.num_epochs-1 and b == data_loader.num_batches-1): # save for the last result checkpoint_path = os.path.join(args.save_dir, 'model.ckpt') saver.save(sess, checkpoint_path, global_step = e * data_loader.num_batches + b) print("model saved to {}".format(checkpoint_path)) train_writer.close() 

El proyecto al que hace referencia utiliza sequence_to_sequence_loss_by_example , que devuelve la pérdida de entropía cruzada. Por lo tanto, para calcular la perplejidad del entrenamiento, solo necesita exponer la pérdida como se explica aquí .

 train_perplexity = tf.exp(train_loss) 

Tenemos que usar e en lugar de 2 como base, porque TensorFlow mide la pérdida de entropía cruzada con el logaritmo natural ( Documentación TF ). Gracias, @Matthias Arro y @Colin Skow por la pista.

Explicación detallada

La entropía cruzada de dos distribuciones de probabilidad P y Q nos dice el número promedio mínimo de bits que necesitamos para codificar eventos de P, cuando desarrollamos un esquema de encoding basado en Q. Por lo tanto, P es la verdadera distribución, que generalmente no hacemos. t sabe Queremos encontrar una Q lo más cerca posible de P, para poder desarrollar un esquema de encoding agradable con la menor cantidad de bits por evento posible.

No debería decir bits, porque solo podemos usar bits como medida si usamos la base 2 en el cálculo de la entropía cruzada. Pero TensorFlow usa el logaritmo natural, así que en lugar de eso, midamos la entropía cruzada en nats .

Entonces, digamos que tenemos un modelo de lenguaje malo que dice que cada token (carácter / palabra) en el vocabulario es igualmente probable que sea el siguiente. Para un vocabulario de 1000 tokens, este modelo tendrá una entropía cruzada de log (1000) = 6.9 nats . Al predecir el siguiente token, tiene que elegir uniformemente entre 1000 tokens en cada paso.

Un mejor modelo de lenguaje determinará una distribución de probabilidad Q que esté más cerca de P. Por lo tanto, la entropía cruzada es más baja; podríamos obtener una entropía cruzada de 3.9 nats. Si ahora queremos medir la perplejidad, simplemente exponemos la entropía cruzada:

exp (3.9) = 49.4

Entonces, en las muestras, para las cuales calculamos la pérdida, el buen modelo fue tan perplejo como si tuviera que elegir de manera uniforme e independiente entre aproximadamente 50 fichas.

Depende de si su función de pérdida le da una probabilidad de registro de los datos en base 2 o base e. Este modelo usa legacy_seq2seq.sequence_loss_by_example, que usa la crossentropy binaria de TensorFlow, que parece usar registros de base e . Por lo tanto, aunque estamos tratando con una distribución de probabilidad discreta (texto), deberíamos exponernos con e, es decir, usar tf.exp (train_loss) como sugirió Colin Skow.