Obtención de datos en los modelos de TensorFlow Estimator

Foto de Mathew Schwartz en Unsplash

El aprendizaje automático se trata de la cantidad y calidad de sus datos. Dichos datos suelen estar disponibles en una variedad de fuentes:

  • Archivos de texto (CSV, TSV, Excel)
  • Bases de datos
  • Fuentes de transmisión

Las personas o personas que extraen los archivos de texto ponen a disposición datos de otra fuente, pero desean ahorrarle el estrés de extraer los datos usted mismo. Los datos pueden estar en uno o más archivos, con o sin encabezados.

Los estimadores TensorFlow funcionan con funciones de entrada. La firma de una función de entrada devuelve una tupla de características y etiquetas. Las características son un diccionario de nombres de funciones y matrices de valores numéricos. Las etiquetas son una matriz de valores. Es necesario que ocurra algo de administración, como mezclar los datos y devolverlos en lotes. El enfoque que tome determina cuánto esfuerzo debe realizar.

Comencemos con la opción simple. Si tiene sus datos en un archivo, que puede leer completamente en la memoria (los denominados ejemplos de juguetes), y el archivo está en formato delimitado por texto (CSV, TSV, etc.), la cantidad de esfuerzo requerido es mínima. . Puede leer sus archivos con numpy o pandas, como suele ser el caso.

Como recordatorio, cuando trabaje con la API de tf.estimator, debe pasar una función de entrada durante el entrenamiento. Esta es la firma de función para el entrenamiento:

tren (
 input_fn, 
 hooks = None, 
 pasos = None, 
 max_steps = None, 
 saving_listeners = None 
) [19659011] ¡Nuestro foco está en input_fn! Trabajaremos con los datos populares de Boston Housing que están alojados  aquí .

Si tiene sus datos en formato numpy, puede usar tf.estimator.inputs.numpy_input_function para obtener sus datos. Primero usted necesita definir un diccionario para sus características:

 # extraer datos numpy de un DataFrame 
 crim = train_df ['crim'] .values ​​
 zn = train_df ['zn'] .values ​​
 indus = train_df ['indus'] .values ​​
 chas = train_df ['chas'] .values ​​
 nox = train_df ['nox'] .values ​​
 rm = train_df ['rm'] .values ​​
 age = train_df ['age'] .values ​​
 dis = train_df ['dis'] .values ​​
 rad = train_df ['rad'] .values ​​
 tax = train_df ['tax'] .values ​​
 ptratio = train_df ['ptratio'] .values ​​
 black = train_df ['black']. values ​​
 lstat = train_df ['lstat'] .values ​​
 medv = train_df ['medv'] .values ​​
 # crear un diccionario 
 x_dict = {
 & # 039; crim & # 039 ;: crim, 
 & # 039; zn & # 039 ;: zn, 
 & # 039; indus & # 039 ;:indus, 
 & # 039; chas & # 039 ;: chas, 
 & # 039; nox & # 039 ;: nox, 
 & # 039; rm & # 039 ;: rm, 
 & # 039; edad & # 039 ;: edad, 
 & # 039; dis & # 039 ;: dis, 
 & # 039; rad & # 039 ;: rad, 
 & # 039; tax & # 039 ;: tax, 
 & # 039; ptratio & # 039 ;: ptratio, 
 & # 039; black & # 039 ;: negro, 
 & # 039; lstat & # 039 ;: lstat 
}

Con nuestro diccionario en su lugar, podemos proceder a definir nuestra función de entrada.

 def np_training_input_fn (x, y): 
 return tf.estimator.inputs.numpy_input_fn (
 x = x, 
 y = y, 
 batch_size = 32, 
 num_epochs = 5, # de esta manera puede omitir los pasos del entrenamiento 
 ] shuffle = True, 
 queue_capacity = 5000 
)

En nuestra función, pasamos x, que es nuestro diccionario, y y, que es nuestra etiqueta. También podemos pasar nuestro tamaño de lote, número de épocas y si se mezclan o no los datos. Tenga en cuenta que siempre desea mezclar sus datos. El tamaño del lote es un hiper parámetro que debe archivar empíricamente. La cantidad de épocas es la cantidad de veces que desea revisar sus datos. Para el entrenamiento, establece cualquier número. Para la prueba, configure esto en 1.

Antes de crear su estimador, necesitará columnas de características.

 feature_cols = [tf.feature_column.numeric_column(k) for k in x_dict.keys()]
 lin_model = tf.estimator.LinearRegressor (feature_columns = feature_cols)
 lin_model. train (np_training_input_fn (x_dict, medv), steps = 10)

Puede omitir los pasos, por lo que la capacitación utiliza las épocas especificadas en la función de entrada de entrenamiento o especifica la cantidad de pasos a seguir para el entrenamiento. Eso es todo por la entrada numpy.

Para un DataFrame, procedería a definir la función de entrada de la siguiente manera:

 def pd_input_fn (df, y_label): 
 return tf.estimator.inputs.pandas_input_fn (
 x = df, 
 y = df [y_label]
 batch_size = 32, 
 num_epochs = 5, 
 shuffle = True, 
 queue_capacity = 1000, 
 num_threads = 1 
)

Tenga en cuenta que en el método anterior, procedemos a pasar en nuestro DataFrame, con la etiqueta en él. Si la etiqueta no está en lo que pasa a x, obtendrá un error. Pasas una serie a y. Los otros parámetros son los mismos que cuando se trata de numpy.

El modelo se trata de la misma manera en adelante. Usted crea el modelo y especifica las columnas de características. Luego procedes a entrenar el modo.

 lin_model = tf.estimator.LinearRegressor (feature_columns = feature_cols)
lin_model.train (pd_input_fn (train_df, & # 039; medv & # 039;), pasos = 10) [19659011] Todo está bien cuando puedes leer tus datos en la memoria. Pero, ¿qué pasa cuando no puedes? ¿Qué sucede cuando el conjunto de datos de capacitación es de 100 GB?

La ​​buena noticia es que un conjunto de datos normalmente será producido por un sistema distribuido, por lo que sus archivos se fragmentarán. Eso significa que los datos se almacenarán en diferentes archivos con nombres como data-0001-of-1000.

Si nunca ha tratado con Big Data, su primer pensamiento podría ser usar glob. No hagas eso a menos que sepas que estás tratando con un ejemplo de juguete. Va a agotar su memoria y el entrenamiento se detendrá.

Este tipo de archivos normalmente no tienen encabezados, y eso es algo bueno. Comenzará por definir una lista de nombres de columnas que debe estar en el orden en que existen sus columnas en los archivos. En segundo lugar, defina una columna de etiqueta. Finalmente, defina una lista de valores predeterminados para que pueda manejar valores perdidos cuando los encuentre durante la lectura.

CSV_COLUMNS = ['medv', 'crim', 'zn', 'lstat', 'tax', 'rad', 'chas', 'nox', 'indus', 'ptratio', 'age', 'black', 'rm', 'dis']
 LABEL_COLUMN = & # 039; medv & # 039; 
 DEFAULTS = [[0.0][0.0] [0.0] [0.0][0.0][0.0][0.0][0.0][0.0][0.0][0.0][0.0]] [19659011] A continuación, definimos una función para leer datos de texto y devolvemos nuestro formato de la misma manera que las funciones anteriores los manejaban. Una ventaja de la forma en que se crea la función es que puede manejar comodines, como data- *.
  def  read_dataset (filename, mode, batch_size = 512): 
   def  _input_fn (): 
     def  decode_csv (value_column): 
 columns = tf.decode_csv (value_column, record_defaults = DEFAULTS) 
 features = dict (zip (CSV_COLUMNS, columns)) 
 label = features.pop (LABEL_COLUMN) 
       return  características, etiqueta 

     # Crear lista de archivos que coinciden con el patrón 
     file_list = tf.gfile.Glob (filename) 

     # Crear conjunto de datos de la lista de archivos [19659041] dataset = tf.data.TextLineDataset (file_list) .map (decode_csv) 
     if  mode == tf.estimator.ModeKeys.TRAIN: 
 num_epochs = None  # indefinidamente 
     conjunto de datos = dataset.shuffle (buffer_size = 10 * batch_size) 
     else : 
 num_epochs = 1  # final-de-entrada después de este 

     datas et = dataset.repeat (num_epochs) .batch (batch_size) 
     return  dataset.make_one_shot_iterator (). get_next () 
   return  _input_fn 

La función tiene tres parámetros: un patrón tan podemos unir múltiples archivos, un modo (entrenamiento o evaluación) y un tamaño de lote. Tenga en cuenta que read_dataset devuelve una función. Hemos llamado a esa función _input_fn. Dentro de esta función, tenemos una función llamada decode_csv que creará un diccionario, extraerá una serie y devolverá ambas en el formato de tupla que mencionamos al principio de este artículo.

En segundo lugar, nuestra función crea una lista de nombres de archivo usando glob. Sí, glob todavía se usa, pero no pasamos el resultado a pandas.read_csv (). En cambio, cumple con tf.data.TextLineDataset (). Toma tres parámetros: una lista de nombres de archivos, el formato de compresión (ninguno, ZLIB o GZIP) y un tamaño de búfer. La principal diferencia entre read_csv y TextLineDataset es que el primero lee el contenido en la memoria (podemos leer en lotes), mientras que el último devuelve un iterador.

Por lo tanto, nuestra función crea un conjunto de datos utilizando TextLineDataset llamando a la función del mapa, pasando en decode_csv. Lo siguiente que hace es verificar si estamos o no en el modo de entrenamiento. Si no lo somos, nuestro número de épocas se establece en 1. Si lo somos, se establece en cuantas épocas nos gustaría. Nuestro conjunto de datos de entrenamiento también se mezcla. Nuestro conjunto de datos luego se configura para repetir el número de épocas que nos gustaría y se configura para nuestro tamaño de lote.

Finalmente, devolvemos un iterador de un solo uso y llamamos a get_next (). Todo este trabajo se maneja detrás de escena por las funciones que vimos anteriormente. Podemos crear nuestras funciones de entrenamiento, evaluación y entrada de prueba utilizando el siguiente enfoque:

  def  get_train (): 
   return  read_dataset (& # 039; ./ train -. * & # 039 ;, mode = tf.estimator.ModeKeys.TRAIN) 

 def  get_valid (): 
   return  read_dataset (& # 039; ./ valid.csv & # 039 ;, mode = tf.estimator.ModeKeys.EVAL) 

 def  get_test (): 
   return  read_dataset (& # 039; ./test.csv & # 039 ;, mode = tf.estimator.ModeKeys.EVAL )

El resto del proceso es exactamente el mismo que hemos visto. Podemos crear nuestro estimador y entrenarlo como de costumbre.

Para proyectos reales, comenzará leyendo en uno de sus archivos de entrenamiento usando pandas y tf.estimator.inputs. Sin embargo, para utilizar todos sus archivos en formación, querrá utilizar tf.data.TextLineDataset.

Happy coding.


Obtener datos en TensorFlow Estimator Models se publicó originalmente en Towards Data Science en Medium, donde las personas continúan la conversación resaltando y respondiendo a esta historia.

Dejá un comentario