Recomendaciones para TensorFlow: crea el modelo

Este artículo es la primera parte de una serie de instructivos donde se detalla cómo implementar un sistema de recomendaciones de aprendizaje automático (AA) con TensorFlow 1.x y AI Platform en Google Cloud Platform (GCP). En esta parte, se muestra cómo instalar el código del modelo de TensorFlow en un sistema de desarrollo y ejecutarlo en el conjunto de datos MovieLens.

El sistema de recomendación en el instructivo usa el algoritmo de mínimos cuadrados alternos ponderados (WALS). WALS está incluido en el paquete contrib.factorization de la base de código de TensorFlow 1.x y se usa para factorizar una gran matriz de calificaciones de usuarios y elementos. Para obtener más información sobre WALS, consulta la descripción general.

Este artículo describe el código del modelo en detalle, incluido el procesamiento previo de datos y la ejecución del algoritmo WALS en TensorFlow.

La serie consta de estas partes:

Objetivos

  • Comprender la estructura del código de TensorFlow que se usa para aplicar WALS a la factorización de matrices
  • Ejecutar el código de muestra de TensorFlow de manera local para realizar recomendaciones en el conjunto de datos MovieLens

Costos

En este instructivo, se usa Cloud Storage y AI Platform; ambos son servicios facturables. Puedes usar la calculadora de precios para calcular los costos según el uso previsto. El costo previsto para este instructivo es de $0.15. Si eres un usuario nuevo de GCP, puedes optar por una prueba gratuita.

Antes de comenzar

  1. En la página de selección de proyectos de Cloud Console, selecciona o crea un proyecto de Cloud.

    Ir a la página Selector de proyectos

  2. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud. Obtén información sobre cómo confirmar que tienes habilitada la facturación para tu proyecto.

  3. Habilita las API de Compute Engine and AI Platform.

    Habilita las API

Ejecuta el modelo de TensorFlow

Puedes ejecutar los pasos en esta sección en una instancia de Compute Engine con al menos 7G de memoria, como se muestra en el procedimiento siguiente. Como alternativa, puedes ejecutar los pasos en esta sección en un sistema macOS o Linux local; en ese caso, no es necesario crear una instancia de Compute Engine.

Crea la instancia de Compute Engine

  1. En Google Cloud Console, ve a la página Instancias de VM.

    IR A LA PÁGINA INSTANCIAS DE VM

  2. Haz clic en Crear instancia.

  3. Nombra tu instancia como quieras y elige una zona. Si aún no tienes una zona de preferencia, elige una que esté geográficamente cerca.

  4. En la lista desplegable del tipo de máquina, selecciona 2 CPU virtuales con n1-standard-2.

  5. En la sección Alcances del acceso, selecciona Permitir el acceso total a todas las API.

  6. Haz clic en Crear.

Instala el código

  1. Ve a la página Instancias de VM.

    Ir a la página Instancias de VM

  2. En la fila de tu instancia, haz clic en SSH para abrir una terminal basada en el navegador que esté conectada de forma segura a la instancia.

  3. En la ventana de la terminal nueva, actualiza los repositorios de software de tu instancia.

    sudo apt-get update
    
  4. Instala git, bzip2 y unzip.

    sudo apt-get install -y git bzip2 unzip
    
  5. Clona el repositorio de código de muestra:

    git clone https://github.com/GoogleCloudPlatform/tensorflow-recommendation-wals
  6. Instala Miniconda. El código de muestra requiere Python 2.7.

    wget https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh
    bash Miniconda2-latest-Linux-x86_64.sh
    export PATH="/home/$USER/miniconda2/bin:$PATH"
  7. Instala los paquetes de Python y TensorFlow. Este instructivo se ejecutará en cualquier versión 1.x de TensorFlow.

    cd tensorflow-recommendation-wals
    conda create -y -n tfrec
    conda install -y -n tfrec --file conda.txt
    source activate tfrec
    pip install -r requirements.txt
    pip install tensorflow==1.15
  8. Descarga el conjunto de datos de MovieLens. Hay varias versiones del conjunto de datos.

    • Para fines de desarrollo, recomendamos usar la versión 100k, que contiene 100,000 calificaciones de 943 usuarios en 1,682 elementos. Descárgala con los comandos siguientes:

      curl -O 'http://files.grouplens.org/datasets/movielens/ml-100k.zip'
      unzip ml-100k.zip
      mkdir -p data
      cp ml-100k/u.data data/
    • Para fines de entrenamiento, recomendamos el conjunto de datos de 1m, que contiene un millón de calificaciones. El formato del conjunto de 1m es un poco diferente al conjunto de 100k. Por ejemplo, el archivo de calificaciones está delimitado por caracteres ::. El código de muestra te permite usar el argumento --delimiter para especificar que el conjunto de datos use este delimitador.

      curl -O 'http://files.grouplens.org/datasets/movielens/ml-1m.zip'
      unzip ml-1m.zip
      mkdir -p data
      cp ml-1m/ratings.dat data/
    • También puedes usar el conjunto de datos de 20m con este proyecto. El conjunto de datos se proporciona en un archivo CSV. Si usas este conjunto de datos, debes pasar la marca --headers, porque el archivo contiene una línea de encabezado.

      curl -O 'http://files.grouplens.org/datasets/movielens/ml-20m.zip'
      unzip ml-20m.zip
      mkdir -p data
      cp ml-20m/ratings.csv data/

Comprende el código del modelo

El código del modelo se incluye en el directorio wals_ml_engine. La funcionalidad de alto nivel del código se implementa con los siguientes archivos:

mltrain.sh
+ Inicia varios tipos de trabajos de AI Platform. Esta secuencia de comandos de shell acepta argumentos para la ubicación del archivo de conjunto de datos, el delimitador utilizado con el propósito de separar los valores en el archivo y si el archivo de datos tiene una línea de encabezado. Se recomienda crear una secuencia de comandos que configure y ejecute los trabajos de AI Platform de forma automática.
task.py
+ Analiza los argumentos para el trabajo de AI Platform y ejecuta el entrenamiento.
model.py
+ Carga el conjunto de datos.
  • Crea dos matrices dispersas a partir de los datos, una dirigida a entrenamiento y otra a pruebas. Ejecuta WALS en la matriz de entrenamiento disperso de calificaciones.
wals.py
+ Crea el modelo de WALS.
  • Ejecuta el algoritmo de WALS.
  • Calcula la raíz cuadrada del error cuadrático medio (RMSE) para un conjunto de factores de fila/columna y una matriz de calificaciones.

Cómo el modelo procesa los datos

El código del modelo realiza el procesamiento previo de los datos con el propósito de crear una matriz de calificaciones dispersas y prepararla para la factorización de la matriz. Esto implica los siguientes pasos:

  1. El código del modelo carga los datos de un archivo de texto delimitado. Cada fila contiene una sola calificación.

    ratings_df = pd.read_csv(input_file,
                             sep=args['delimiter'],
                             names=headers,
                             header=header_row,
                             dtype={
                               'user_id': np.int32,
                               'item_id': np.int32,
                               'rating': np.float32,
                               'timestamp': np.int32,
                             })
  2. El código establece un conjunto 0-indexado de ID únicos para usuarios y artículos. Esto garantiza que un ID único corresponda a índices de fila y columna específicos de la matriz de calificaciones dispersas.

    • Los datos de MovieLens 100k usan ID basados en 1 en los que el índice más bajo del conjunto único es 1. Para normalizar, el código resta uno de cada índice. De model.py:

      ratings = ratings_df.as_matrix(['user_id', 'item_id', 'rating'])
      # deal with 1-based user indices
      ratings[:,0] -= 1
      ratings[:,1] -= 1
    • Los conjuntos de datos de 1m y 20m MovieLens omiten algunos ID de usuarios y elementos. Esto genera un problema: tienes que asignar el conjunto de ID de usuarios únicos a un conjunto de índices igual a [0 ... num_users-1]] y hacer lo mismo para los ID de elementos. La asignación de elementos se realiza mediante el código siguiente [numpy](http://www.numpy.org/). El código crea un arreglo de tamaño [0..max_item_id]] para realizar la asignación, por lo que si el ID máximo del elemento es muy grande, este método puede usar demasiada memoria.

      np_items = ratings_df.item_id.as_matrix()
      unique_items = np.unique(np_items)
      n_items = unique_items.shape[0]
      max_item = unique_items[-1]
      
      # map unique items down to an array 0..n_items-1
      z = np.zeros(max_item+1, dtype=int)
      z[unique_items] = np.arange(n_items)
      i_r = z[np_items]
    • El código para asignar usuarios es, básicamente, el mismo que el de los elementos.

  3. El código del modelo selecciona aleatoriamente un conjunto de pruebas de calificaciones. De forma predeterminada, el 10% de las calificaciones se eligen para el conjunto de pruebas. Estas calificaciones se quitan del conjunto de entrenamiento y se usarán para evaluar la precisión predictiva del usuario y los factores del elemento.

    test_set_size = len(ratings) / TEST_SET_RATIO
    test_set_idx = np.random.choice(xrange(len(ratings)),
                                    size=test_set_size, replace=False)
    test_set_idx = sorted(test_set_idx)
    
    ts_ratings = ratings[test_set_idx]
    tr_ratings = np.delete(ratings, test_set_idx, axis=0)
  4. Por último, el código crea una matriz dispersa scipy de manera conjunta (coo_matrix) que incluye índices y calificaciones de usuarios y elementos. El objeto coo_matrix actúa como un wrapper para una matriz dispersa. También realiza la validación de los índices de usuarios y calificaciones, y verifica errores en el procesamiento previo.

    u_tr, i_tr, r_tr = zip(*tr_ratings)
    tr_sparse = coo_matrix((r_tr, (u_tr, i_tr)), shape=(n_users, n_items))

Cómo se implementa el algoritmo de WALS en TensorFlow

Una vez que los datos se procesan con anterioridad, el código pasa la matriz de entrenamiento dispersa al modelo de WALS de TensorFlow para que se factorice en el factor de fila X y el factor de columna Y.

El código de TensorFlow que ejecuta el modelo es muy simple, ya que se basa en la clase WALSModel incluida en el módulo contrib.factorization_ops de TensorFlow.

  1. Un objeto SparseTensor se inicializa con los ID de usuarios y de elementos como índices y con las calificaciones como valores. De wals.py:

    input_tensor = tf.SparseTensor(indices=zip(data.row, data.col),
                                    values=(data.data).astype(np.float32),
                                    dense_shape=data.shape)

    La variable de datos es el objeto coo_matrix de las clasificaciones de entrenamiento creadas en el paso de procesamiento previo.

  2. En el modelo se crea una instancia:

    model = factorization_ops.WALSModel(num_rows, num_cols, dim,
                                        unobserved_weight=unobs,
                                        regularization=reg,
                                        row_weights=row_wts,
                                        col_weights=col_wts)
  3. Los factores de fila y los tensores de factores de columna los crea de forma automática la clase WALSModel y se recuperan a fin de que puedan evaluarse después de factorizar la matriz:

    # retrieve the row and column factors
    row_factor = model.row_factors[0]
    col_factor = model.col_factors[0]
  4. El proceso de entrenamiento ejecuta el bucle siguiente dentro de una sesión de TensorFlow con el método simple_train en wals.py:

    row_update_op = model.update_row_factors(sp_input=input_tensor)[1]
    col_update_op = model.update_col_factors(sp_input=input_tensor)[1]
    
    sess.run(model.initialize_op)
    sess.run(model.worker_init)
    for _ in xrange(num_iterations):
        sess.run(model.row_update_prep_gramian_op)
        sess.run(model.initialize_row_update_op)
        sess.run(row_update_op)
        sess.run(model.col_update_prep_gramian_op)
        sess.run(model.initialize_col_update_op)
        sess.run(col_update_op)
  5. Después de que se hayan ejecutado las iteraciones num_iterations, los tensores de factor de fila y columna se evalúan en la sesión con el fin de producir arreglos numpy para cada factor:

    # evaluate output factor matrices
    output_row = row_factor.eval(session=session)
    output_col = col_factor.eval(session=session)

Estos arreglos de factores se usan para calcular el RMSE en el conjunto de calificaciones de prueba. Los dos arreglos también se guardan en el directorio de salida en formato numpy.

Entrena el modelo

En este contexto, el entrenamiento del modelo implica factorizar una matriz dispersa de calificaciones en una matriz de factores de usuario X y una matriz de factores de elementos Y. Los factores de elementos y usuarios guardados se pueden usar como modelos base para un sistema de recomendación.

Este sistema toma a un usuario como entrada, recupera el vector de factores de usuario para ese usuario de X, multiplica ese vector por todos los factores del elemento Y y muestra los principales elementos N de acuerdo con la calificación predicha.

En la Parte 4 de este instructivo, se proporcionan más detalles sobre un sistema que usa el modelo entrenado para realizar predicciones y se muestra cómo implementar este sistema en GCP.

Entrena el modelo de manera local

Entrenar el modelo de manera local es útil para propósitos de desarrollo. Te permite probar con rapidez los cambios de código, incluidos los puntos de interrupción para una depuración fácil. Para ejecutar el modelo en Cloud Shell o desde tu sistema local, ejecuta la secuencia de comandos mltrain.sh desde el directorio wals_ml_engine con la opción local.

cd wals_ml_engine
  • Para el conjunto de datos MovieLens 100k, especifica la ruta al archivo de datos 100k:

    ./mltrain.sh local ../data u.data
  • Para el conjunto de datos MovieLens 1m, incluye la opción --delimiter y especifica la ruta al archivo de datos 1m:

    ./mltrain.sh local ../data ratings.dat --delimiter ::
  • Para el conjunto de datos MovieLens 20m, usa las opciones --delimiter y --headers:

    ./mltrain.sh local ../data ratings.csv --headers --delimiter ,

El resultado del trabajo de entrenamiento muestra el RMSE calculado en el conjunto de prueba. Para el conjunto de datos 1m, y con los hiperparámetros predeterminados especificados en el código fuente, el resultado debe verse de la siguiente manera:

INFO:tensorflow:Train Start: <timestamp>
...
INFO:tensorflow:Train Finish: <timestamp>
INFO:tensorflow:train RMSE = 1.29
INFO:tensorflow:test RMSE = 1.34

Para obtener más detalles, consulta la Parte 2.

El RMSE corresponde al error promedio en las calificaciones predichas en comparación con el conjunto de prueba. En promedio, cada calificación que realiza el algoritmo está dentro de ± 1,29 de la calificación real del usuario en el conjunto de pruebas en el conjunto de datos 1m. El algoritmo de WALS tiene un rendimiento mucho mejor cuando se ajustan los hiperparámetros, como se muestra en la Parte 2 de esta serie.

Limpieza

Si creaste una instancia de Compute Engine para ejecutar TensorFlow, debes detenerla a fin de evitar incurrir en cargos en tu cuenta de GCP. Esta instancia no se usa en la Parte 2 de esta serie. Sin embargo, la instancia de Compute Engine es necesaria para la Parte 3 y la Parte 4.

Detén la instancia de Compute Engine

  1. En Cloud Console, abre la página de lista de instancias de VM de Compute Engine.
  2. Selecciona el nombre de la instancia.
  3. Haz clic en Detener y confirma la operación.

Borra el proyecto

La manera más fácil de eliminar la facturación es borrar el proyecto que creaste para el instructivo.

Para borrar el proyecto, sigue estos pasos:

  1. En Cloud Console, ve a la página Administrar recursos.

    Ir a la página Administrar recursos

  2. En la lista de proyectos, selecciona el proyecto que deseas borrar y haz clic en Borrar .
  3. En el cuadro de diálogo, escribe el ID del proyecto y haz clic en Cerrar para borrar el proyecto.

Próximos pasos