PoS SCAN
Experiments that include Part of Speech to SCAN dataset.
Integrante | Correo |
---|---|
Benjamin Earle | biearle@uc.cl |
Jorge Perez | jiperez11@uc.cl |
Data
En el archivo src/data/scan.py
se encuentra el código para preparar el dataset. En particular, se utilizan 2 funciones:
get_dataset(experiment: str)
:- El argumento que toma es el split a usar de scan. Se usan 3 en particular:
simple
: Es el baseline de SCAN. Tanto el entrenamiento como el test son i.i.d.addprim_jump
: Es el experimento que se agrega la traducción de composiciones de "jump" al momento de test. En entrenamiento, solo ve "jump" sin modificaciones.mcd1
: Es un split realizado por un paper posterior. Busca maximizar la necesidad de generalización para resolver la tarea.
- Esta función preprocesa el dataset para entregarlo con el siguiente formato para cada item:
(x, p, y)
.x
: El input de scan. Es una versión codificada de una frase como "jump left and run twice".- La codificación corresponde a una lista de los índices correspondiente a cada palabra en el vocabulario. Esta lista es de largo
MAX_IN_SEQUENCE_LENGTH
(12), por lo que cada frase puede tener a lo mas 12 palabras, incluyendo<sos>
y<eos>
.
- La codificación corresponde a una lista de los índices correspondiente a cada palabra en el vocabulario. Esta lista es de largo
p
: Part of Speech. Es una versión codificada de la secuencia de part of speech para una frase. Para el ejemplo dex
, sería la codificación de "VRB DIR CNJ VRB ADV".- La codificación es la misma que para
x
, pero con el vocabulario de parts of speech.
- La codificación es la misma que para
y
: Output de scan. Corresponde a una versión codificada de una secuencia de salida. Para el ejemplo dex
sería la codificación de "TURN_LEFT JUMP RUN RUN".- La codificación corresponde a la misma que en
x
, solo que con el vocabulario de salida, y con un largo máximo deMAX_OUT_SEQUENCE_LENGTH
(50).
- La codificación corresponde a la misma que en
- Retorno:
train_dataset, test_dataset, (in_vectorizer, pos_vectorizer, out_vectorizer)
train_dataset
: Dataset de entrenamiento con el formato descrito. Ya está cacheado y con prefetch.test_dataset
: Dataset de test o validación. Ya está cacheado y con prefetch.*_vectorizer
: Son losTextVectorizer
de Keras para procesar el texto.
- El argumento que toma es el split a usar de scan. Se usan 3 en particular:
get_final_map_function(include_pos_tag: bool, teacher_forcing: float)
: Funcion que toma el dataset, y lo mapea a un formato más cómodo para hacer los experimentos. Retorna 2 diccionarios, uno para input y otro para output.- Diccionario de input: Contiene las siguientes llaves y valores.
input_embedding
: Corresponde alx
deget_dataset
.pos_embedding
(Opcional): Corresponde alp
deget_dataset
. Solo se incluye siinclude_pos_tag == "input"
, es decir, si se realizará el entrenamiento con el PoS como input del modelo.action_input
(Opcional): Se incluye siteacher_forcing > 0
. Esto es para cuando se quiere entrenar con teacher forcing. Corresponde a las acciones ground truth para entrenar el seq2seq. Es decir, ely
deget_dataset
- Diccionario de output: Contiene las siguientes llaves y valores.
action_output
: Corresponde al ground truth de las acciones, para usar como supervisión. Es la conversión a onehot dely
deget_dataset
pos_output
(Opcional): Corresponde al ground truth del Part of Speech, para usar como supervision de la tarea auxiliar. Es la conversión a onehot delp
deget_dataset
.
- Diccionario de input: Contiene las siguientes llaves y valores.
Modo de uso:
train_dataset, test_dataset, _ = get_dataset("addprim_jump")
final_map_fn = get_final_map_function(True, 0.5)
train_dataset = train_dataset.map(final_map_fn)
test_dataset = test_dataset.map(final_map_fn)
model.fit(train_dataset.shuffle(1000, reshuffle_each_iteration=True).batch(512))
Para un ejemplo de como compilar y entrenar el modelo, ver src/tasks/train.py
Notar que el modelo debe recibir como primer argumento el diccionario de input, y debe retornar un diccionario con las mismas llaves que el de output, solo que con las predicciones realizadas.
Compilar loss y accuracy para el modelo multi output
Ejemplo de src/tasks/train.py
:
# Create metrics and losses according to task
# pad_idx es el pad id que creo el vectorizador de texto.
# mask_value es una mascara para que el modelo no sobreajuste a solo predecir los valores de padding.
mask_value: tf.Tensor = tf.one_hot(pad_idx, OUT_VOCAB_SIZE)
# Categorical crossentropy, pero solo se aplica para lo que no corresponde a padding. Este viene de src/utils/loss
masked_categorical_crossentropy = get_masked_categorical_crossentropy(mask_value)
# El diccionario de losses tiene que tener las mismas llaves que el diccionario de output del modelo. Asi Tensorflow sabe automaticamente como calcular las perdidas cuando hay multiples outputs
losses = {ACTION_OUTPUT_NAME: masked_categorical_crossentropy}
metrics = {
# MaskedCategoricalAccuracy es similar al crosentropy anterior.
ACTION_OUTPUT_NAME: MaskedCategoricalAccuracy(
mask_value, name="accuracy" if params["include_pos_tag"] == "aux" else f"{ACTION_OUTPUT_NAME}_accuracy"
)
}
# Si vamos a usar PoS como tarea auxiliar, hay que entregar loss y accuracy para este output extra del modelo. Es similar a lo anterior, solo que el pad_idx debe ser el correspondiente al vocabulario de PoS.
if params["include_pos_tag"] == "aux":
pos_mask_value: tf.Tensor = tf.one_hot(pad_idx, POS_VOCAB_SIZE)
losses[POS_OUTPUT_NAME] = get_masked_categorical_crossentropy(pos_mask_value)
metrics[POS_OUTPUT_NAME] = MaskedCategoricalAccuracy(pos_mask_value, name="accuracy")
# Compile model
optimizer = keras.optimizers.Adam(learning_rate=0.001, clipnorm=5.0)
model.compile(optimizer=optimizer, loss=losses, metrics=metrics, run_eagerly=True)
Transformer
En el archivo TransformerPosTag.ipynb se encuentra el código para crear un modelo transformer, obtener los datos y entrenar el modelo. Se entregan 2 loops de entrenamiento, en donde 1 es con pos tag como tarea auxiliar y el otro es sin pos tag.