Tutorial: Análisis de la opinión de reseñas de películas con un modelo de TensorFlow entrenado previamente en ML.NET
En este tutorial se muestra cómo usar un modelo de TensorFlow previamente entrenado para clasificar la opinión en comentarios de sitios Web. El clasificador binario de opiniones es una aplicación de consola de C# desarrollada con Visual Studio.
El modelo de TensorFlow que se usa en este tutorial se entrenó con reseñas de películas procedentes de la base de datos de IMDB. Cuando haya terminado de desarrollar la aplicación, podrá proporcionar el texto de la reseña de la película y la aplicación le indicará si la reseña tiene una opinión positiva o negativa.
En este tutorial aprenderá a:
- Carga de un modelo de TensorFlow entrenado previamente
- Transformación del texto de comentario del sitio web en características adecuadas para el modelo
- Uso del modelo para realizar una predicción
Puede encontrar el código fuente para este tutorial en el repositorio dotnet/samples.
Requisitos previos
- Visual Studio 2022 con la carga de trabajo "Desarrollo de escritorio de .NET" instalada.
Programa de instalación
Crear la aplicación
Cree una aplicación de consola en C# llamada "TextClassificationTF". Haga clic en el botón Next (Siguiente).
Seleccione .NET 6 como marco de trabajo que va a usarse. Haga clic en el botón Crear.
Cree un directorio denominado Datos en el proyecto para guardar los archivos del conjunto de datos.
Instale el paquete NuGet Microsoft.ML:
Nota
En este ejemplo se usa la versión estable más reciente de los paquetes NuGet mencionados, a menos que se indique lo contrario.
En el Explorador de soluciones, haga clic con el botón derecho en Administrar paquetes NuGet. Elija "nuget.org" como origen del paquete y luego seleccione la pestaña Examinar. Busque Microsoft.ML, seleccione el paquete que desee y luego, el botón Instalar. Acepte los términos de licencia del paquete que elija para continuar con la instalación. Repita estos pasos para Microsoft.ML.TensorFlow, Microsoft.ML.SampleUtils y SciSharp.TensorFlow.Redist.
Adición del modelo TensorFlow al proyecto
Nota:
El modelo de este tutorial procede del repositorio de GitHub, dotnet/machinelearning-testdata. El modelo tiene el formato TensorFlow SavedModel.
Descargue el archivo zip sentiment_model y descomprímalo.
El archivo zip contiene:
saved_model.pb
: el propio modelo de TensorFlow. El modelo toma una matriz de enteros de longitud fija (tamaño 600) de características que representan el texto de una cadena de reseña de IMDB y genera dos probabilidades que suman 1: la probabilidad de que la reseña de entrada tenga una opinión positiva y la probabilidad de que la reseña de entrada tenga una opinión negativa.imdb_word_index.csv
: una asignación de palabras individuales a un valor entero. La asignación se usa para generar las características de entrada para el modelo de TensorFlow.
Copie el contenido del directorio
sentiment_model
más interno en el directoriosentiment_model
del proyecto TextClassificationTF. En este directorio está el modelo y los archivos auxiliares adicionales que se necesitan en este tutorial, tal como se muestra en la imagen siguiente:En el Explorador de soluciones, haga clic con el botón derecho en cada uno de los archivos del directorio
sentiment_model
y los subdirectorios y seleccione Propiedades. En Avanzadas, cambie el valor de Copiar en el directorio de salida por Copiar si es posterior.
Adición de instrucciones Using y variables globales
Agregue las siguientes instrucciones
using
adicionales a la parte superior del archivo Program.cs:using Microsoft.ML; using Microsoft.ML.Data; using Microsoft.ML.Transforms;
Cree una variable global justo después de las instrucciones using que contenga la ruta de acceso del archivo de modelo guardado.
string _modelPath = Path.Combine(Environment.CurrentDirectory, "sentiment_model");
_modelPath
es la ruta de acceso del archivo del modelo entrenado.
Modelado de los datos
Las reseñas de películas son texto de forma libre. La aplicación convierte el texto en el formato de entrada que el modelo espera en varias fases discretas.
La primera consiste en dividir el texto en palabras independientes y usar el archivo de asignación proporcionado para asignar cada palabra a una codificación de enteros. El resultado de esta transformación es una matriz de enteros de longitud variable cuya longitud corresponde al número de palabras de la oración.
Propiedad. | Value | Tipo |
---|---|---|
ReviewText | Esta película es realmente buena | cadena |
VariableLengthFeatures | 14,22,9,66,78,... | int[] |
El tamaño de la matriz de características de longitud variable se cambia a una longitud fija de 600. Esta es la longitud que espera el modelo de TensorFlow.
Propiedad. | Value | Tipo |
---|---|---|
ReviewText | Esta película es realmente buena | cadena |
VariableLengthFeatures | 14,22,9,66,78,... | int[] |
Características | 14,22,9,66,78,... | int[600] |
Cree una clase para los datos de entrada en la parte inferior del archivo Program.cs:
/// <summary> /// Class to hold original sentiment data. /// </summary> public class MovieReview { public string? ReviewText { get; set; } }
La clase de datos de entrada,
MovieReview
, tiene un objetostring
para comentarios de usuario (ReviewText
).Cree una clase para las características de longitud variable, después de la clase
MovieReview
:/// <summary> /// Class to hold the variable length feature vector. Used to define the /// column names used as input to the custom mapping action. /// </summary> public class VariableLength { /// <summary> /// This is a variable length vector designated by VectorType attribute. /// Variable length vectors are produced by applying operations such as 'TokenizeWords' on strings /// resulting in vectors of tokens of variable lengths. /// </summary> [VectorType] public int[]? VariableLengthFeatures { get; set; } }
La propiedad
VariableLengthFeatures
tiene un atributo VectorType para designarla como vector. Todos los elementos de vector deben ser del mismo tipo. En conjuntos de datos con un gran número de columnas, la carga de varias columnas como un único vector reduce el número de pasadas de datos cuando se aplican transformaciones de datos.Esta clase se usa en la acción
ResizeFeatures
. Los nombres de sus propiedades (en este caso, solo una) se usan para indicar las columnas de DataView que se pueden usar como entrada de la acción de asignación personalizada.Cree una clase para las características de longitud fija, después de la clase
VariableLength
:/// <summary> /// Class to hold the fixed length feature vector. Used to define the /// column names used as output from the custom mapping action, /// </summary> public class FixedLength { /// <summary> /// This is a fixed length vector designated by VectorType attribute. /// </summary> [VectorType(Config.FeatureLength)] public int[]? Features { get; set; } }
Esta clase se usa en la acción
ResizeFeatures
. Los nombres de sus propiedades (en este caso, solo una) se usan para indicar las columnas de DataView que se pueden usar como salida de la acción de asignación personalizada.Tenga en cuenta que el nombre de la propiedad
Features
viene determinado por el modelo de TensorFlow. Este nombre de propiedad no se puede cambiar.Cree una clase para la predicción después de la clase
FixedLength
:/// <summary> /// Class to contain the output values from the transformation. /// </summary> public class MovieReviewSentimentPrediction { [VectorType(2)] public float[]? Prediction { get; set; } }
MovieReviewSentimentPrediction
es la clase de predicción que se utiliza tras el entrenamiento del modelo.MovieReviewSentimentPrediction
tiene una sola matrizfloat
(Prediction
) y un atributoVectorType
.Cree otra clase que contenga valores de configuración, como la longitud del vector de características:
static class Config { public const int FeatureLength = 600; }
Creación de la clase MLContext, el diccionario de búsqueda y la acción para cambiar el tamaño de las características
La clase MLContext es un punto de partida para todas las operaciones de ML.NET. La inicialización de mlContext
crea un entorno de ML.NET que se puede compartir entre los objetos del flujo de trabajo de creación de modelos. Como concepto, se parece a DBContext
en Entity Framework.
Reemplace la línea
Console.WriteLine("Hello World!")
por el siguiente código para declarar e inicializar la variable mlContext:MLContext mlContext = new MLContext();
Cree un diccionario para codificar palabras como enteros mediante el método
LoadFromTextFile
para cargar los datos de asignación de un archivo, como se aprecia en la tabla siguiente:Palabra Índice niños 362 quiero 181 incorrecto 355 efectos 302 sentimiento 547 Agregue el código siguiente para crear la asignación de búsqueda:
var lookupMap = mlContext.Data.LoadFromTextFile(Path.Combine(_modelPath, "imdb_word_index.csv"), columns: new[] { new TextLoader.Column("Words", DataKind.String, 0), new TextLoader.Column("Ids", DataKind.Int32, 1), }, separatorChar: ',' );
Agregue un objeto
Action
para cambiar el tamaño de la matriz de enteros de palabras de longitud variable a una matriz de enteros de tamaño fijo, con las siguientes líneas de código:Action<VariableLength, FixedLength> ResizeFeaturesAction = (s, f) => { var features = s.VariableLengthFeatures; Array.Resize(ref features, Config.FeatureLength); f.Features = features; };
Carga del modelo de TensorFlow entrenado previamente
Agregue código para cargar el modelo de TensorFlow:
TensorFlowModel tensorFlowModel = mlContext.Model.LoadTensorFlowModel(_modelPath);
Una vez cargado el modelo, puede extraer su esquema de entrada y de salida. Los esquemas se muestran solo a efectos de interés y aprendizaje. No necesita este código para que la aplicación final funcione:
DataViewSchema schema = tensorFlowModel.GetModelSchema(); Console.WriteLine(" =============== TensorFlow Model Schema =============== "); var featuresType = (VectorDataViewType)schema["Features"].Type; Console.WriteLine($"Name: Features, Type: {featuresType.ItemType.RawType}, Size: ({featuresType.Dimensions[0]})"); var predictionType = (VectorDataViewType)schema["Prediction/Softmax"].Type; Console.WriteLine($"Name: Prediction/Softmax, Type: {predictionType.ItemType.RawType}, Size: ({predictionType.Dimensions[0]})");
El esquema de entrada es la matriz de longitud fija de palabras codificadas en enteros. El esquema de salida es una matriz float de probabilidades que indica si la opinión de una reseña es negativa o positiva. Estos valores suman 1, ya que la probabilidad de que sea positiva es el complemento de la probabilidad de que la opinión sea negativa.
Creación de la canalización de ML.NET
Cree la canalización y divida el texto de entrada en palabras con la transformación TokenizeIntoWords para dividir el texto en palabras como la siguiente línea de código:
IEstimator<ITransformer> pipeline = // Split the text into individual words mlContext.Transforms.Text.TokenizeIntoWords("TokenizedWords", "ReviewText")
La transformación TokenizeIntoWords usa espacios para analizar el texto o la cadena por palabras. Crea otra columna y divide cada cadena de entrada en un vector de subcadenas según el separador definido por el usuario.
Asigne las palabras a su codificación de enteros con la tabla de búsqueda que declaró anteriormente:
// Map each word to an integer value. The array of integer makes up the input features. .Append(mlContext.Transforms.Conversion.MapValue("VariableLengthFeatures", lookupMap, lookupMap.Schema["Words"], lookupMap.Schema["Ids"], "TokenizedWords"))
Cambie el tamaño de las codificaciones de enteros de longitud variable al de longitud fija que requiere el modelo:
// Resize variable length vector to fixed length vector. .Append(mlContext.Transforms.CustomMapping(ResizeFeaturesAction, "Resize"))
Clasifique la entrada con el modelo de TensorFlow cargado:
// Passes the data to TensorFlow for scoring .Append(tensorFlowModel.ScoreTensorFlowModel("Prediction/Softmax", "Features"))
La salida del modelo de TensorFlow se denomina
Prediction/Softmax
. Tenga en cuenta que el nombrePrediction/Softmax
viene determinado por el modelo de TensorFlow. Este nombre no se puede cambiar.Cree otra columna para la predicción de salida:
// Retrieves the 'Prediction' from TensorFlow and copies to a column .Append(mlContext.Transforms.CopyColumns("Prediction", "Prediction/Softmax"));
Tiene que copiar la columna
Prediction/Softmax
en otra cuyo nombre pueda usarse como propiedad en una clase de C#:Prediction
. El carácter/
no está permitido en un nombre de propiedad de C#.
Creación del modelo de ML.NET a partir de la canalización
Agregue el código para crear el modelo a partir de la canalización:
// Create an executable model from the estimator pipeline IDataView dataView = mlContext.Data.LoadFromEnumerable(new List<MovieReview>()); ITransformer model = pipeline.Fit(dataView);
Un modelo de ML.NET se crea a partir de la cadena de estimadores de la canalización llamando al método
Fit
. En este caso, no se adaptan los datos para crear el modelo, puesto que el modelo de TensorFlow ya se ha entrenado previamente. Proporcionamos un objeto de vista de datos vacío para satisfacer los requisitos del métodoFit
.
Uso del modelo para realizar una predicción
Agregue el método
PredictSentiment
encima de la claseMovieReview
:void PredictSentiment(MLContext mlContext, ITransformer model) { }
Agregue el código siguiente para crear
PredictionEngine
como la primera línea en el métodoPredictSentiment()
:var engine = mlContext.Model.CreatePredictionEngine<MovieReview, MovieReviewSentimentPrediction>(model);
PredictionEngine es una API de conveniencia, que le permite realizar una predicción en una única instancia de datos.
PredictionEngine
no es seguro para subprocesos. Es aceptable usarlo en entornos de un solo subproceso o prototipo. Para mejorar el rendimiento y la seguridad para subprocesos en entornos de producción, use el servicioPredictionEnginePool
, que crea unObjectPool
de objetos dePredictionEngine
para su uso en toda la aplicación. Consulte esta guía sobre cómo usarPredictionEnginePool
en una API web de ASP.NET Core.Nota
La extensión del servicio
PredictionEnginePool
está actualmente en versión preliminar.Agregue un comentario para probar la predicción del modelo entrenado en el método
Predict()
mediante la creación de una instancia deMovieReview
:var review = new MovieReview() { ReviewText = "this film is really good" };
Pase los datos del comentario de prueba a
Prediction Engine
agregando las líneas de código siguientes al métodoPredictSentiment()
:var sentimentPrediction = engine.Predict(review);
La función Predict() realiza una predicción sobre una sola fila de datos:
Propiedad. Value Tipo Predicción [0.5459937, 0.454006255] float[] Muestre la predicción de opiniones con el código siguiente:
Console.WriteLine($"Number of classes: {sentimentPrediction.Prediction?.Length}"); Console.WriteLine($"Is sentiment/review positive? {(sentimentPrediction.Prediction?[1] > 0.5 ? "Yes." : "No.")}");
Agregue una llamada a
PredictSentiment
después de la llamada al métodoFit()
:PredictSentiment(mlContext, model);
Resultados
Compile y ejecute su aplicación.
Los resultados deberían ser similares a los indicados a continuación. Durante el procesamiento, se muestran mensajes. Puede ver las advertencias o mensajes de procesamiento. Estos mensajes se han quitado de los resultados siguientes para mayor claridad.
Number of classes: 2
Is sentiment/review positive ? Yes
¡Enhorabuena! Ha creado correctamente un modelo de Machine Learning para clasificar y predecir la opinión de los mensajes reutilizando un modelo de TensorFlow
entrenado previamente en ML.NET.
Puede encontrar el código fuente para este tutorial en el repositorio dotnet/samples.
En este tutorial ha aprendido a:
- Carga de un modelo de TensorFlow entrenado previamente
- Transformación del texto de comentario del sitio web en características adecuadas para el modelo
- Uso del modelo para realizar una predicción