Tren dividido, conjuntos de prueba y validación con conjuntos de datos de Tensorflow - tfds

En este tutorial, use la API Splits de Tensorflow Datasets (tfds) y aprenda a realizar una división de conjunto de entrenamiento, prueba y validación, así como incluso divisiones, a través de ejemplos prácticos de Python.

Introducción

Tensorflow Datasets, también conocido como tfds, es una biblioteca que sirve como contenedor para una amplia selección de conjuntos de datos, con funciones patentadas para cargar, dividir y preparar conjuntos de datos para Machine y Deep Learning, principalmente con Tensorflow.

{.icon aria-hidden=“true”}

Nota: Si bien la biblioteca Tensorflow Datasets se usa para obtener datos, no se usa para preprocesar datos. Ese trabajo se delega a la biblioteca Tensorflow Data (tf.data).

Todos los conjuntos de datos adquiridos a través de los conjuntos de datos de Tensorflow se envuelven en objetos tf.data.Dataset, por lo que puede obtener y preparar fácilmente una amplia variedad de conjuntos de datos mediante programación. Uno de los primeros pasos que tomará después de cargar y familiarizarse con un conjunto de datos es una división entrenamiento/prueba/validación.

En esta guía, veremos qué son los conjuntos de entrenamiento, prueba y validación antes de aprender cómo cargar y realizar una división de entrenamiento/prueba/validación con Tensorflow Datasets.

Conjuntos de entrenamiento y prueba {#conjuntos de entrenamiento y prueba}

Cuando trabaje en tareas de aprendizaje supervisado, querrá obtener un conjunto de funciones y un conjunto de etiquetas para esas funciones, ya sea como entidades separadas o dentro de un único “Conjunto de datos”. Solo entrenar la red en todos los datos está bien y es excelente, pero no puede probar su precisión en esos mismos datos, ya que evaluar el modelo de esa manera sería recompensar la memorización en lugar de la generalización.

En su lugar, entrenamos los modelos en una parte de los datos, reteniendo una parte para probar el modelo una vez que haya terminado el entrenamiento. La proporción entre estos dos es comúnmente 80/20, y ese es un valor predeterminado bastante sensato. Según el tamaño del conjunto de datos, puede optar por diferentes proporciones, como 60/40 o incluso 90/10. Si hay muchas muestras en el conjunto de prueba, no es necesario tener un gran porcentaje de muestras dedicadas a él. Por ejemplo, si el 1% del conjunto de datos representa 1.000.000 de muestras, ¡probablemente no necesite más que eso para la prueba!

Para algunos modelos y arquitecturas, ¡no tendrá ningún conjunto de pruebas! Por ejemplo, al entrenar Generative Adversarial Networks (GAN) que generan imágenes, ¡probar el modelo no es tan fácil como comparar las etiquetas reales y predichas! En la mayoría de los modelos generativos (música, texto, video), al menos a partir de ahora, normalmente se requiere una persona para juzgar los resultados, en cuyo caso, un conjunto de prueba es totalmente redundante.

El conjunto de prueba debe mantenerse desde el modelo hasta la etapa de prueba, y solo debe usarse para inferencia, no para entrenamiento. Es una práctica común definir un conjunto de prueba y "olvidarlo" hasta las etapas finales en las que valida la precisión del modelo.

Conjuntos de validación {#conjuntos de validación}

Un conjunto de validación es un conjunto extremadamente importante y, a veces, se pasa por alto. Los conjuntos de validación a menudo se describen como “tomados de” conjuntos de prueba, ya que es conveniente imaginarlo, pero en realidad, son conjuntos separados. No hay una regla establecida para las proporciones divididas, pero es común tener un conjunto de validación de tamaño similar al conjunto de prueba, o un poco más pequeño, algo como 75/15/10, 70/ 15/15 y 70/20/10.

Se utiliza un conjunto de validación durante el entrenamiento, para aproximadamente validar el modelo en cada época. Esto ayuda a actualizar el modelo dando "sugerencias" sobre si está funcionando bien o no. Además, no tiene que esperar a que termine un conjunto completo de épocas para obtener una visión más precisa del rendimiento real del modelo.

{.icon aria-hidden=“true”}

Nota: El conjunto de validación no se usa para el entrenamiento, y el modelo no entrena en el conjunto de validación en ningún punto dado. Se utiliza para validar el rendimiento en una época determinada. Dado que afecta el proceso de entrenamiento, el modelo indirectamente entrena en el conjunto de validación y, por lo tanto, no se puede totalmente confiar en él para las pruebas, pero es una buena aproximación/proxy para actualizar las creencias durante el entrenamiento.

Esto es análogo a saber cuándo estás equivocado, pero no saber cuál es la respuesta correcta. Eventualmente, al actualizar sus creencias después de darse cuenta de que no tiene razón, se acercará más a la verdad sin que se le diga explícitamente cuál es. Un conjunto de validación indirectamente entrena tu conocimiento.

Usando un conjunto de validación: puede interpretar fácilmente cuándo un modelo ha comenzado a sobreajustarse significativamente en tiempo real y, en función de la disparidad entre las precisiones de validación y entrenamiento, puede optar por desencadenar respuestas, como detener automáticamente el entrenamiento, actualizar el aprendizaje tarifa, etc

Dividir conjuntos de entrenamiento, prueba y validación usando conjuntos de datos de Tensorflow

La función load() del módulo tfds se carga en un conjunto de datos, dado su nombre. Si aún no se ha descargado en la máquina local, descargará automáticamente el conjunto de datos con una barra de progreso:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import tensorflow_datasets as tfds

# Load dataset
dataset, info = tfds.load("cifar10", as_supervised=True, with_info=True)

# Extract informative features
class_names = info.features["label"].names
n_classes = info.features["label"].num_classes

print(class_names) # ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
print(n_classes) # 10

Uno de los argumentos opcionales que puedes pasar a la función load() es el argumento split.

La nueva API de división le permite definir qué divisiones del conjunto de datos desea dividir. De forma predeterminada, para este conjunto de datos, solo admite una división de 'entrenamiento' y 'prueba': estas son las divisiones \"oficiales\" para *este conjunto de datos*. No hay división válida`.

{.icon aria-hidden=“true”}

Nota: Cada conjunto de datos tiene una división "oficial". Algunos solo tienen la división 'entrenamiento', algunos tienen una división 'entrenamiento' y 'prueba' y algunos incluso incluyen una división 'validación'. Esta es la división prevista y solo si un conjunto de datos admite una división, puede usar el alias de cadena de esa división. Si un conjunto de datos contiene solo una división de 'entrenamiento', puede dividir esos datos de entrenamiento en un conjunto de entrenamiento/prueba/válido sin problemas.

Estos corresponden a las enumeraciones tfds.Split.TRAIN y tfds.Split.TEST y tfds.Split.VALIDATION, que solían estar expuestas a través de la API en una versión anterior.

Realmente puede dividir un ‘Conjunto de datos’ en cualquier número arbitrario de conjuntos, sin embargo, normalmente hacemos tres: ’tren_conjunto’, ‘prueba_conjunto’, ‘válido_conjunto’:

1
2
3
4
5
6
7
test_set, valid_set, train_set = tfds.load("cifar10", 
                                           split=["test", "train[0%:20%]", "train[20%:]"],
                                           as_supervised=True, with_info=True)

print("Train set size: ", len(train_set)) # Train set size:  40000
print("Test set size: ", len(test_set))   # Test set size:  10000
print("Valid set size: ", len(valid_set)) # Valid set size:  10000

Hemos tomado la división 'test' y la hemos extraído en test_set. La porción entre el 0% y el 20% de la división 'tren' se asigna al conjunto_válido y todo lo que esté más allá del 25% es el conjunto_tren. Esto también se valida a través de los tamaños de los conjuntos.

En lugar de porcentajes, puede usar valores absolutos o una combinación de porcentaje y valores absolutos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Absolute value split
test_set, valid_set, train_set = tfds.load("cifar10", 
                                           split=["test", "train[0:10000]", "train[10000:]"],
                                           as_supervised=True)

print("Train set size: ", len(train_set)) # Train set size:  40000
print("Test set size: ", len(test_set))   # Test set size:  10000
print("Valid set size: ", len(valid_set)) # Valid set size:  10000


# Mixed notation split
# 5000 - 50% (25000) left unassigned
test_set, valid_set, train_set = tfds.load("cifar10", 
                                           split=["train[:2500]", # First 2500 are assigned to `test_set`
                                           "train[2500:5000]",    # 2500-5000 are assigned to `valid_set`
                                           "train[50%:]"],        # 50% - 100% (25000) assigned to `train_set`
                                           as_supervised=True)

Además, puede hacer una * unión * de conjuntos, que se usa con menos frecuencia, ya que los conjuntos se intercalan entonces:

1
2
3
4
5
6
train_and_test, half_of_train_and_test = tfds.load("cifar10", 
                                split=['train+test', 'train[:50%]+test'],
                                as_supervised=True)
                                
print("Train+test: ", len(train_and_test))               # Train+test:  60000
print("Train[:50%]+test: ", len(half_of_train_and_test)) # Train[:50%]+test:  35000

Estos dos conjuntos ahora están fuertemente intercalados.

Divisiones pares para N conjuntos

Nuevamente, puede crear cualquier número arbitrario de divisiones, simplemente agregando más divisiones a la lista de divisiones:

1
split=["train[:10%]", "train[10%:20%]", "train[20%:30%]", "train[30%:40%]", ...]

Sin embargo, si está creando muchas divisiones, especialmente si son pares, las cadenas que pasará son muy predecibles. Esto se puede automatizar creando una lista de cadenas, con un intervalo igual dado (como 10 %) en su lugar. Exactamente para este propósito, la función tfds.even_splits() genera una lista de cadenas, dada una cadena de prefijo y el número deseado de divisiones:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import tensorflow_datasets as tfds

s1, s2, s3, s4, s5 = tfds.even_splits('train', n=5)
# Each of these elements is just a string
split_list = [s1, s2, s3, s4, s5]
print(f"Type: {type(s1)}, contents: '{s1}'")
# Type: <class 'str'>, contents: 'train[0%:20%]'

for split in split_list:
    test_set = tfds.load("cifar10", 
                                split=split,
                                as_supervised=True)
    print(f"Test set length for Split {split}: ", len(test_set))

Esto resulta en:

1
2
3
4
5
Test set length for Split train[0%:20%]:  10000
Test set length for Split train[20%:40%]:  10000
Test set length for Split train[40%:60%]:  10000
Test set length for Split train[60%:80%]:  10000
Test set length for Split train[80%:100%]:  10000

Alternativamente, puede pasar toda la split_list como el propio argumento split, para construir varios conjuntos de datos divididos fuera de un bucle:

1
2
3
ts1, ts2, ts3, ts4, ts5 = tfds.load("cifar10", 
                                split=split_list,
                                as_supervised=True)

Conclusión

En esta guía, hemos analizado qué son los conjuntos de entrenamiento y prueba, así como la importancia de los conjuntos de validación. Finalmente, exploramos la nueva API de divisiones de la biblioteca de conjuntos de datos de Tensorflow y realizamos una división de entrenamiento/prueba/validación. ba/validación.