Path: blob/master/site/es-419/guide/ragged_tensor.ipynb
25115 views
Copyright 2018 The TensorFlow Authors.
Documentación de la API: tf.RaggedTensor
tf.ragged
Preparación
Descripción general
Sus datos vienen en muchas formas; sus tensores también deberían venir en muchas formas. Los tensores irregulares son el equivalente de TensorFlow a las listas anidadas de longitud variable. Facilitan el almacenamiento y procesamiento de datos con formas no uniformes, que incluyen:
Funciones de longitudes variables, como el conjunto de actores de una película.
Lotes de entradas secuenciales de longitud variable, como oraciones o videoclips.
Entradas jerárquicas, como documentos de texto que se subdividen en secciones, párrafos, oraciones y palabras.
Campos individuales en entradas estructuradas, como búferes de protocolo.
Qué se puede hacer con un tensor irregular
Los tensores irregulares son compatibles con más de cien operaciones de TensorFlow, incluidas las operaciones matemáticas (como tf.add
y tf.reduce_mean
), operaciones de arreglos (como tf.concat
y tf.tile
), operaciones de manipulación de cadenas de texto (como tf.strings.substr
), operaciones de flujo de control (como tf.while_loop
y tf.map_fn
) y muchas otras:
También hay una serie de métodos y operaciones que son específicos de los tensores irregulares, incluidos los métodos de fábrica, métodos de conversión y operaciones de mapeo de valores. Para ver una lista de operaciones compatibles, consulte la documentación del paquete de tf.ragged
.
Los tensores irregulares son compatibles con muchas API de TensorFlow, incluidas Keras, Datasets, tf.function, SavedModels y tf.Example. Para obtener más información, consulte la sección sobre las API de TensorFlow abajo.
Al igual que con los tensores normales, se puede utilizar la indexación estilo Python para acceder a segmentos específicos de un tensor irregular. Para obtener más información, consulte la sección sobre Indexación abajo.
Y al igual que los tensores normales, se pueden utilizar operadores aritméticos y de comparación de Python para realizar operaciones por elementos. Para obtener más información, consulte la sección sobre Operadores sobrecargados abajo.
Si necesita realizar una transformación por elementos de los valores de un RaggedTensor
, puede usar tf.ragged.map_flat_values
, que toma una función y uno o más argumentos y aplica la función para transformar los valores de RaggedTensor
.
Los tensores irregulares se pueden convertir en list
de Python anidada y en array
NumPy:
Construir un tensor irregular
La forma más sencilla de construir un tensor irregular es usar tf.ragged.constant
, que construye el RaggedTensor
correspondiente a una list
de Python anidada o array
NumPy ingresado:
Los tensores irregulares también se pueden construir al emparejar tensores de valores planos con tensores de partición de filas que indican cómo se deben dividir esos valores en filas, utilizando métodos de clase de fábrica como tf.RaggedTensor.from_value_rowids
, tf.RaggedTensor.from_row_lengths
y tf.RaggedTensor.from_row_splits
.
tf.RaggedTensor.from_value_rowids
If you know which row each value belongs to, then you can build a RaggedTensor
using a value_rowids
row-partitioning tensor:
tf.RaggedTensor.from_row_lengths
Si sabe cuánto mide cada fila, entonces puede usar un tensor de partición de filas row_lengths
:
tf.RaggedTensor.from_row_splits
Si conoce el índice donde comienza y termina cada fila, entonces puede usar un tensor de partición de filas row_splits
:
Consulte la documentación de la clase tf.RaggedTensor
para obtener una lista completa de los métodos de fábrica.
Nota: De forma predeterminada, estos métodos de fábrica agregan afirmaciones de que el tensor de partición de filas está bien formado y es consistente con la cantidad de valores. El parámetro validate=False
se puede utilizar para omitir estas comprobaciones si se puede garantizar que las entradas estén bien formadas y sean consistentes.
Qué se puede almacenar en un tensor irregular
Al igual que con los Tensor
normales, todos los valores en un RaggedTensor
deben tener el mismo tipo; y todos los valores deben estar a la misma profundidad de anidamiento (el rango del tensor):
Caso de uso de ejemplo
El siguiente ejemplo demuestra cómo se pueden usar los RaggedTensor
para construir y combinar incrustaciones de unigramas y bigramas para un lote de consultas de longitud variable. Se usan marcadores especiales para el principio y el final de cada oración. Para obtener más detalles sobre las operaciones usadas en este ejemplo, consulte la documentación del paquete tf.ragged
.
Dimensiones irregulares y uniformes
Una dimensión irregular es una dimensión cuyos segmentos pueden tener diferentes longitudes. Por ejemplo, la dimensión (de la columna) interna de rt=[[3, 1, 4, 1], [], [5, 9, 2], [6], []]
es irregular ya que los segmentos de la columna (rt[0, :]
, ..., rt[4, :]
) tienen longitudes diferentes. Las dimensiones cuyos segmentos tienen la misma longitud se denominan dimensiones uniformes.
La dimensión más externa de un tensor irregular es siempre uniforme, ya que consta de un solo segmento (y, por lo tanto, no hay posibilidad de diferentes longitudes de segmento). Las dimensiones restantes pueden ser irregulares o uniformes. Por ejemplo, puede almacenar las incrustaciones de palabras para cada palabra en un lote de oraciones usando un tensor irregular con forma [num_sentences, (num_words), embedding_size]
, donde los paréntesis alrededor de (num_words)
indican que la dimensión es irregular.
Los tensores irregulares pueden tener varias dimensiones irregulares. Por ejemplo, podría almacenar un lote de documentos de texto estructurados con un tensor con forma [num_documents, (num_paragraphs), (num_sentences), (num_words)]
(donde nuevamente se usan paréntesis para indicar las dimensiones irregulares).
Al igual que con tf.Tensor
, el rango de un tensor irregular es su número total de dimensiones (incluidas las dimensiones irregulares y uniformes). Un tensor potencialmente irregular es un valor que puede ser tf.Tensor
o tf.RaggedTensor
.
Al describir la forma de un RaggedTensor, las dimensiones irregulares se indican entre paréntesis. Por ejemplo, como vimos anteriormente, la forma de un RaggedTensor 3D que almacena incrustaciones de palabras para cada palabra en un lote de oraciones se puede escribir como [num_sentences, (num_words), embedding_size]
.
El atributo RaggedTensor.shape
devuelve un tf.TensorShape
para un tensor irregular donde las dimensiones irregulares tienen un tamaño None
:
Se puede usar el método tf.RaggedTensor.bounding_shape
para encontrar una forma delimitadora ajustada para un RaggedTensor
determinado:
Irregular versus disperso
No se puede considerar un tensor irregular como un tipo de tensor disperso. En particular, los tensores dispersos son codificaciones eficientes para tf.Tensor
que modelan los mismos datos en un formato compacto; pero el tensor irregular es una extensión de tf.Tensor
que modela una clase ampliada de datos. Esta diferencia es crucial a la hora de definir operaciones:
Aplicar una operación a un tensor disperso o denso siempre debería dar el mismo resultado.
Aplicar una operación a un tensor irregular o disperso puede dar resultados diferentes.
Como ejemplo ilustrativo, considere cómo se definen operaciones de arreglo como concat
, stack
y tile
para tensores irregulares frente a tensores dispersos. La concatenación de tensores irregulares une cada fila para formar una sola fila con la longitud combinada:
Sin embargo, concatenar tensores dispersos equivale a concatenar los tensores densos correspondientes, como se ilustra en el siguiente ejemplo (donde Ø indica los valores faltantes):
Para ver otro ejemplo de por qué esta distinción es importante, considere la definición de "el valor medio de cada fila" para una operación como tf.reduce_mean
. Para un tensor irregular, el valor medio de una fila es la suma de los valores de la fila dividida por el ancho de la fila. Pero para un tensor disperso, el valor medio de una fila es la suma de los valores de la fila dividida por el ancho total del tensor disperso (que es mayor o igual que el ancho de la fila más larga).
Las API de TensorFlow
Keras
tf.keras es la API de alto nivel de TensorFlow para crear y entrenar modelos de aprendizaje profundo. Los tensores irregulares se pueden pasar como entradas a un modelo de Keras al establecer ragged=True
en tf.keras.Input
o tf.keras.layers.InputLayer
. También se pueden pasar tensores irregulares entre las capas de Keras y devolverlos mediante los modelos de Keras. El siguiente ejemplo muestra un modelo LSTM de juguete que se entrena con tensores irregulares.
tf.Example
tf.Example es una codificación protobuf estándar para datos de TensorFlow. Los datos codificados con las tf.Example
suelen incluir funciones de longitud variable. Por ejemplo, el siguiente código define un lote de cuatro mensajes tf.Example
con diferentes longitudes de función:
Puede analizar estos datos codificados con tf.io.parse_example
, que toma un tensor de cadenas serializadas y un diccionario de especificación de funciones, y devuelve un diccionario que asigna nombres de funciones a tensores. Para leer las funciones de longitudes variables en tensores irregulares, simplemente use tf.io.RaggedFeature
en el diccionario de especificación de funciones:
tf.io.RaggedFeature
también se puede utilizar para leer funciones con vafrias dimensiones irregulares. Para obtener más información, consulte la documentación de la API.
Conjuntos de datos
tf.data
es una API que le permite desarrollar canalizaciones de entradas complejas a partir de piezas reutilizables simples. Su estructura de datos principal es tf.data.Dataset
, que representa una secuencia de elementos, en la que cada elemento se compone de uno o más componentes.
Construir conjuntos de datos con tensores irregulares
Los conjuntos de datos se pueden construir a partir de tensores irregulares con los mismos métodos que se usan para construir los tensores desde los tf.Tensor
o array
NumPy, como Dataset.from_tensor_slices
:
Nota: Dataset.from_generator
aún no admite tensores irregulares, pero pronto se podrá.
Cómo agrupar o desagrupar conjuntos de datos con tensores dispersos
Los conjuntos de datos con tensores irregulares se pueden agrupar (lo que combina n elementos consecutivos en un solo elemento) con el método Dataset.batch
.
Por el contrario, un conjunto de datos agrupado se puede transformar en un conjunto de datos plano con Dataset.unbatch
.
Agrupar conjuntos de datos con tensores no irregulares de longitud variable
Si tiene un conjunto de datos que contiene tensores no irregulares y las longitudes de los tensores varían según los elementos, puede agrupar esos tensores no irregulares en tensores irregulares aplicando la transformación dense_to_ragged_batch
:
Transformar conjuntos de datos con tensores irregulares
También se pueden crear o transformar tensores irregulares en los conjuntos de datos con Dataset.map
:
tf.function
tf.function es un decorador que precalcula gráficos de TensorFlow para funciones de Python, lo que puede mejorar sustancialmente el rendimiento de su código de TensorFlow. Los tensores irregulares se pueden usar de forma clara con funciones decoradas @tf.function
. Por ejemplo, la siguiente función funciona con tensores irregulares y no irregulares:
Si quiere specificar explícitamente input_signature
para tf.function
, puede hacerlo con tf.RaggedTensorSpec
.
Funciones concretas
Las funciones concretas encapsulan gráficos trazados individuales creados por tf.function
. Los tensores irregulares se pueden usar de forma clara con funciones concretas.
SavedModels
Un SavedModel es un programa serializado de TensorFlow, que incluye pesos y cálculos. Se puede construir a partir de un modelo de Keras o de un modelo personalizado. En cualquier caso, los tensores irregulares se pueden usar de forma clara con las funciones y métodos definidos por un SavedModel.
Ejemplo: guardar un modelo de Keras
Ejemplo: guardar un modelo personalizado
Nota: Las signaturas de SavedModel son funciones concretas. Como explicamos en la sección anterior sobre funciones concretas, los tensores irregulares solo se manipulan correctamente mediante funciones concretas que comienzan con TensorFlow 2.3. Si necesita usar signaturas de SavedModel en una versión anterior de TensorFlow, se recomienda descomponer el tensor irregular en los tensores que lo componen.
Operadores sobrecargados
La clase RaggedTensor
sobrecarga los operadores aritméticos y de comparación estándar de Python, lo que facilita que se realicen operaciones matemáticas básicas por elementos:
Dado que los operadores sobrecargados realizan cálculos por elementos, las entradas a todas las operaciones binarias deben tener la misma forma o deben poder transmitirse a la misma forma. En el caso de transmisión más simple, un único escalar se combina elemento a elemento con cada valor en un tensor irregular:
Para ver una explicación de casos más avanzados, consulte la sección sobre Transmición.
Los tensores irregulares sobrecargan el mismo conjunto de operadores que los Tensor
normales: los operadores unarios -
, ~
y abs()
; y los operadores binarios +
, -
, *
, /
, //
, %
, **
, &
, |
, ^
, ==
, <
, <=
, >
y >=
.
Indexación
Los tensores irregulares admiten la indexación al estilo Python, incluida la indexación y la segmentación multidimensional. Los siguientes ejemplos demuestran la indexación de tensores irregulares con un tensor irregular 2D y 3D.
Ejemplos de indexación: tensor irregular 2D
Ejemplos de indexación: tensor irregular 3D
RaggedTensor
admite la indexación y la segmentación multidimensional con una restricción: no se permite la indexación en una dimensión irregular. Este caso es problemático porque el valor indicado puede existir en algunas filas pero no en otras. En tales casos, no queda claro si se debería (1) generar un IndexError
; (2) utilizar un valor predeterminado; o (3) omitir ese valor y devolver un tensor con menos filas que las que tenía al principio. Según las directrices de Python ("Ante la ambigüedad, rechaze la tentación de adivinar"), actualmente, es una operación no permitida.
Conversión de tipo tensor
La clase RaggedTensor
define métodos que se pueden usar para convertir entre los RaggedTensor
y los tf.Tensor
o tf.SparseTensors
:
Evaluar tensores irregulares
Para acceder a los valores en un tensor irregular, se puede:
Usar
tf.RaggedTensor.to_list
para convertir el tensor irregular en una lista de Python anidada.Usar
tf.RaggedTensor.numpy
para convertir el tensor irregular en un arreglo NumPy cuyos valores son arreglos NumPy anidados.Descomponer el tensor irregular en sus componentes, con las propiedades
tf.RaggedTensor.values
ytf.RaggedTensor.row_splits
, o métodos de partición de filas comotf.RaggedTensor.row_lengths
ytf.RaggedTensor.value_rowids
.Usar la indexación de Python para seleccionar los valores del tensor irregular.
Formas irregulares
La forma de un tensor especifica el tamaño de cada eje. Por ejemplo, la forma de [[1, 2], [3, 4], [5, 6]]
es [3, 2]
, ya que hay 3 filas y 2 columnas. TensorFlow tiene dos formas distintas pero que están relacionadas para describir formas:
forma estática: información sobre los tamaños de los ejes que se conocen estáticamente (por ejemplo, al trazar una
tf.function
). Puede especificarse parcialmente.forma dinámica: información del tiempo de ejecución sobre los tamaños de los ejes.
Forma estática
La forma estática de un tensor contiene información sobre los tamaños de sus ejes que se conoce en el momento de la construcción del gráfico. Tanto para tf.Tensor
como para tf.RaggedTensor
, está disponible mediante la propiedad .shape
y está codificado mediante tf.TensorShape
:
La forma estática de una dimensión irregular es siempre None
(es decir, sin especificar). Sin embargo, lo contrario no es cierto: si una dimensión TensorShape
es None
, podría indicar que la dimensión es irregular o podría indicar que la dimensión es uniforme pero que su tamaño no se conoce estáticamente.
Forma dinámica
La forma dinámica de un tensor contiene información sobre los tamaños de sus ejes que se conocen cuando se ejecuta el gráfico. Se construye con la operación tf.shape
. Para tf.Tensor
, tf.shape
devuelve la forma como un Tensor
entero de una dimensión, donde tf.shape(x)[i]
es el tamaño del eje i
.
Sin embargo, un Tensor
una dimensión no es lo suficientemente expresivo para describir la forma de un tf.RaggedTensor
. En cambio, la forma dinámica de los tensores irregulares se codifica mediante un tipo dedicado, tf.experimental.DynamicRaggedShape
. En el siguiente ejemplo, DynamicRaggedShape
que devuelve tf.shape(rt)
indica que el tensor irregular tiene 4 filas, con longitudes de 1, 3, 0 y 2:
Forma dinámica: operaciones
DynamicRaggedShape
se puede usar con la mayoría de las operaciones de TensorFlow que necesitan formas, incluidas tf.reshape
, tf.zeros
, tf.ones
. tf.fill
, tf.broadcast_dynamic_shape
y tf.broadcast_to
.
Forma dinámica: indexación y segmentación
DynamicRaggedShape
también se puede indexar para obtener los tamaños de las dimensiones uniformes. Por ejemplo, podemos encontrar el número de filas en un tensor irregular con tf.shape(rt)[0]
(tal como lo haríamos para un tensor no irregular):
Sin embargo, es un error utilizar la indexación para intentar recuperar el tamaño de una dimensión irregular, ya que no tiene un tamaño único. (Dado que RaggedTensor
realiza un seguimiento de qué ejes son irregulares, este error solo se genera durante la ejecución eager o cuando se traza una tf.function
.; jamás ocurrirá al ejecutar una función concreta).
Los DynamicRaggedShape
también se pueden segmentar, siempre que el segmento comience con el eje 0
o contenga solo dimensiones densas.
Forma dinámica: codificación
DynamicRaggedShape
se codifica con dos campos:
inner_shape
: Un vector entero que da la forma de untf.Tensor
denso.row_partitions
: una lista de objetostf.experimental.RowPartition
, que describe cómo se debe segmentar la dimensión más externa de esa forma interna para agregar ejes irregulares.
Para obtener más información sobre las particiones de filas, consulte la sección "Codificación de RaggedTensor" a continuación y la documentación de la API para tf.experimental.RowPartition
.
Forma dinámica: construcción
DynamicRaggedShape
se construye con mayor frecuencia al aplicar tf.shape
a un RaggedTensor
, pero también se puede construir directamente:
Si las longitudes de todas las filas se conocen estáticamente, también se puede usar DynamicRaggedShape.from_lengths
para construir una forma irregular dinámica. (Esto es especialmente útil para probar y demostrar código, ya que es raro que las longitudes de las dimensiones irregulares se conozcan estáticamente).
Transmisión
La transmisión es el proceso de hacer que tensores con diferentes formas tengan formas compatibles para las operaciones por elementos. Para obtener más información sobre la transmisión, consulte:
tf.broadcast_dynamic_shape
tf.broadcast_to
Estos son los pasos básicos para transmitir dos entradas x
e y
para tener formas compatibles:
Si
x
ey
no tienen el mismo número de dimensiones, agregue las dimensiones exteriores (con tamaño 1) hasta que sean iguales.Para cada dimensión donde
x
y
tengan tamaños diferentes:
Si
x
oy
tienen el tamaño1
en la dimensiónd
, repita sus valores en la dimensiónd
para que coincida con el otro tamaño de la entrada.De lo contrario, genere una excepción (
x
ey
no son compatibles con la transmisión).
Si el tamaño de un tensor en una dimensión uniforme es un solo número (el tamaño de los segmentos en esa dimensión); y el tamaño de un tensor en una dimensión irregular es una lista de longitudes de segmentos (para todos los segmentos en esa dimensión).
Ejemplos de transmisión
A continuación se muestran algunos ejemplos de formas que no se transmiten:
Codificar RaggedTensor
Los tensores irregulares se codifican mediante la clase RaggedTensor
. Internamente, cada RaggedTensor
se compone de:
Un tensor
values
, que concatena las filas de longitud variable en una lista aplanada.Una
row_partition
, que indica cómo se dividen los valores aplanados en filas.
La row_partition
se puede almacenar con cuatro codificaciones diferentes:
row_splits
es un vector entero que especifica los puntos de división entre filas.value_rowids
es un vector entero que especifica el índice de fila para cada valor.row_lengths
es un vector entero que especifica la longitud de cada fila.uniform_row_length
es un escalar entero que especifica una única longitud para todas las filas.
También se puede incluir un número entero escalar nrows
en la codificación row_partition
para tener en cuenta las filas finales vacías con value_rowids
o las filas vacías con uniform_row_length
.
La elección de qué codificación usar para las particiones de las filas se gestiona internamente mediante tensores irregulares para mejorar la eficiencia en algunos contextos. En particular, algunas de las ventajas y desventajas de los diferentes esquemas de partición de filas son:
Indexación eficiente: la codificación
row_splits
permite la indexación en tiempo constante y la división en tensores irregulares.Concatenación eficiente: la codificación
row_lengths
es más eficiente al concatenar tensores irregulares, ya que las longitudes de las filas no cambian cuando dos tensores se concatenan juntos.Tamaño de codificación pequeño: la codificación
value_rowids
es más eficiente cuando se almacenan tensores irregulares que tienen una gran cantidad de filas vacías, ya que el tamaño del tensor depende solo del número total de valores. Por otro lado, las codificacionesrow_splits
yrow_lengths
son más eficientes cuando se almacenan tensores irregulares con filas más largas, ya que solo requieren un valor escalar para cada fila.Compatibilidad: el esquema
value_rowids
coincide con el formato de segmentación que utilizan las operaciones, comotf.segment_sum
. El esquemarow_limits
coincide con el formato que utilizan las operaciones comotf.sequence_mask
.Dimensiones uniformes: como se analiza a continuación, la codificación
uniform_row_length
se utiliza para codificar tensores irregulares con dimensiones uniformes.
Varias dimensiones irregulares
Un tensor irregular con varias dimensiones irregulares se codifica con un RaggedTensor
anidado para el tensor values
. Cada RaggedTensor
anidado agrega una única dimensión irregular.
La función de fábrica tf.RaggedTensor.from_nested_row_splits
se puede usar para construir un RaggedTensor con varias dimensiones irregulares directamente al proporcionar una lista de tensores row_splits
:
Rango irregular y valores planos
El rango irregular de un tensor irregular es la cantidad de veces que se divide el tensor values
subyacente (es decir, la profundidad de anidamiento de los objetos RaggedTensor
). El tensor values
más interno se conoce como flat_values. En el siguiente ejemplo, conversations
tienen ragged_rank=3 y sus flat_values
son un Tensor
de una dimension con 24 cadenas de texto:
Dimensiones internas uniformes
Los tensores irregulares con dimensiones internas uniformes se codifican con un tf.Tensor
multidimensional para los flat_values (es decir, los values
más internos).
Dimensiones no internas uniformes
Los tensores irregulares con dimensiones uniformes no internas se codifican al particionar las filas con uniform_row_length
.