Поделиться через


Учебник. Анализ тональности отзывов о фильмах с помощью предварительно обученной модели TensorFlow в ML.NET

В этом руководстве показано, как классифицировать тональность комментариев на веб-сайте с помощью предварительно обученной модели TensorFlow. Двоичный классификатор тональности — это консольное приложение на C#, разработанное с помощью Visual Studio.

Модель TensorFlow, используемая в этом руководстве, была обучена на отзывах о фильмах из базы данных IMDB. Завершив разработку приложения, вы сможете добавить текст отзыва о фильме, и приложение сообщит вам, положительный это отзыв или отрицательный.

В этом руководстве вы узнаете, как:

  • Загрузить предварительно обученную модель TensorFlow.
  • Преобразовать текст комментария на веб-сайте в признаки, пригодные для модели.
  • Использование модели для прогноза

Исходный код для этого руководства можно найти в репозитории dotnet/samples.

Предварительные требования

  • Visual Studio 2022 с установленной рабочей нагрузкой "Разработка классических приложений .NET".

Установка

Создание приложения

  1. Создайте консольное приложение C# с именем TextClassificationTF. Нажмите кнопку Далее.

  2. Выберите .NET 6 в качестве используемой платформы. Нажмите кнопку Создать .

  3. Создайте каталог с именем Data в проекте, чтобы сохранять файлы набора данных.

  4. Установите пакет NuGet для Microsoft.ML:

    Примечание

    В этом примере используется последняя стабильная версия пакетов NuGet, упомянутых выше, если не указано иное.

    В обозревателе решений щелкните проект правой кнопкой мыши и выберите Управление пакетами NuGet. Выберите nuget.org в качестве источника пакета, а затем выберите вкладку Обзор. Найдите Microsoft.ML, выберите пакет и нажмите кнопку Установить. Продолжите установку, соглашаясь с условиями лицензии для выбранного пакета. Повторите эти действия для пакетов Microsoft.ML.TensorFlow, Microsoft.ML.SampleUtils и SciSharp.TensorFlow.Redist.

Добавление модели TensorFlow в проект

Примечание

Модель для этого руководства взята из репозитория GitHub dotnet/machinelearning-testdata и сохранена в формате TensorFlow SavedModel.

  1. Скачайте файл sentiment_model zip и распакуйте его.

    ZIP-файл содержит:

    • saved_model.pb: собственно модель TensorFlow. Модель принимает целочисленный массив признаков фиксированной длины (600 символов), представляющий текст в строке отзыва IMDB, и выводит две вероятности, сумма которых равна 1: вероятность того, что указанный отзыв имеет положительную тональность, и вероятность того, что отзыв имеет отрицательную тональность.
    • imdb_word_index.csv: сопоставление отдельных слов с целочисленным значением. Сопоставление используется для создания входных признаков для модели TensorFlow.
  2. Скопируйте содержимое самого внутреннего каталога sentiment_model в каталог sentiment_model проекта TextClassificationTF. Этот каталог содержит модель и дополнительные файлы поддержки, необходимые для работы с этим руководством, как показано на следующем рисунке:

    Содержимое каталога sentiment_model

  3. В обозревателе решений щелкните правой кнопкой мыши каждый файл в каталоге sentiment_model и подкаталоге и выберите Свойства. В разделе Дополнительно для параметра Копировать в выходной каталог установите значение Копировать более позднюю версию.

Добавление операторов using и глобальных переменных

  1. Добавьте следующие новые операторы using в начало файла Program.cs:

    using Microsoft.ML;
    using Microsoft.ML.Data;
    using Microsoft.ML.Transforms;
    
  2. Создайте глобальную переменную сразу после операторов using, чтобы сохранить путь к файлу модели.

    string _modelPath = Path.Combine(Environment.CurrentDirectory, "sentiment_model");
    
    • _modelPath — путь к файлу обученной модели.

Моделирование данных

Отзывы на фильмы — это текст произвольной формы. Приложение преобразует текст в формат входных данных, ожидаемый в модели, за несколько отдельных этапов.

Первый этап — разделение текста на отдельные слова и сопоставление каждого слова с кодировкой целого числа при помощи предоставленного файла сопоставления. Результатом этого преобразования является массив целых чисел переменной длины, которая соответствует числу слов в предложении.

Свойство. Значение Type
ReviewText this film is really good (это очень хороший фильм) string
VariableLengthFeatures 14,22,9,66,78,... int[]

Затем размер массива признаков переменной длины изменяется на фиксированную длину 600. Это ожидаемая длина для модели TensorFlow.

Свойство. Значение Type
ReviewText this film is really good (это очень хороший фильм) string
VariableLengthFeatures 14,22,9,66,78,... int[]
Функции 14,22,9,66,78,... int[600]
  1. Создайте класс для входных данных в конце файла Program.cs:

    /// <summary>
    /// Class to hold original sentiment data.
    /// </summary>
    public class MovieReview
    {
        public string? ReviewText { get; set; }
    }
    

    У класса входных данных MovieReview есть string (строка) для комментариев пользователей (ReviewText).

  2. Создайте класс для признаков переменной длины после класса 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; }
    }
    

    Свойство VariableLengthFeatures имеет атрибут VectorType, который указывает вектор. Все элементы вектора должны относиться к одному типу. В наборах данных с большим количеством столбцов загрузка нескольких столбцов в виде одного вектора сокращает количество передаваемых данных при преобразовании данных.

    Этот класс используется в действии ResizeFeatures. Имена его свойств (в этом случае — только одного свойства) используются для указания того, какие столбцы в DataView могут использоваться в качестве входных данных для пользовательского действия сопоставления.

  3. Создайте класс для признаков фиксированной длины после класса 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; }
    }
    

    Этот класс используется в действии ResizeFeatures. Имена его свойств (в этом случае — только одного свойства) используются для указания того, какие столбцы в DataView могут использоваться в качестве выходных данных для пользовательского действия сопоставления.

    Обратите внимание, что имя свойства Features определяется моделью TensorFlow. Это имя свойства нельзя изменить.

  4. Создайте класс для прогнозирования после класса FixedLength:

    /// <summary>
    /// Class to contain the output values from the transformation.
    /// </summary>
    public class MovieReviewSentimentPrediction
    {
        [VectorType(2)]
        public float[]? Prediction { get; set; }
    }
    

    MovieReviewSentimentPrediction — этот класс прогноза используется после обучения модели. MovieReviewSentimentPrediction имеет один массив float (Prediction) и атрибут VectorType.

  5. Создайте другой класс для хранения значений конфигурации, например длины вектора признаков:

    static class Config
    {
        public const int FeatureLength = 600;
    }
    

Создание MLContext, словаря подстановки и действия для изменения размера признаков

Класс MLContext является отправной точкой для всех операций ML.NET. Инициализация mlContext создает новую среду ML.NET, которую могут совместно использовать объекты рабочего процесса создания модели. По существу он аналогичен классу DBContext в Entity Framework.

  1. Замените строку Console.WriteLine("Hello World!") следующим кодом, чтобы объявить и инициализировать переменную mlContext:

    MLContext mlContext = new MLContext();
    
  2. Создайте словарь для кодирования слов в виде целых чисел с помощью метода LoadFromTextFile, чтобы загрузить данные сопоставления из файла, как показано в следующей таблице.

    Слово Индекс
    kids (дети) 362
    want (хотеть) 181
    wrong (неправильно) 355
    effects (эффекты) 302
    feeling (чувство) 547

    Добавьте приведенный ниже код для создания карты подстановки.

    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: ','
        );
    
  3. Добавьте Action, чтобы преобразовать массив целых чисел переменной длины в массив целых чисел фиксированного размера с помощью следующих строк кода:

    Action<VariableLength, FixedLength> ResizeFeaturesAction = (s, f) =>
    {
        var features = s.VariableLengthFeatures;
        Array.Resize(ref features, Config.FeatureLength);
        f.Features = features;
    };
    

Загрузка предварительно обученной модели TensorFlow

  1. Добавьте код для загрузки модели TensorFlow:

    TensorFlowModel tensorFlowModel = mlContext.Model.LoadTensorFlowModel(_modelPath);
    

    После загрузки модели можно извлечь схему ее входных и выходных данных. Схемы отображаются только для интереса и изучения. Для работы окончательного варианта приложения этот код не требуется.

    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]})");
    
    

    Схема входных данных — это массив фиксированной длины из слов, закодированных в виде целых чисел. Схема выходных данных — это массив вероятностей с плавающей запятой, указывающий, является ли тональности обзора отрицательной или положительной. Сумма этих значений равна 1, так как вероятность положительной тональности является дополнением вероятности отрицательной тональности.

Создание конвейера ML.NET

  1. Создайте конвейер и разделите входной текст на слова с помощью преобразования TokenizeIntoWords, чтобы разбить текст на слова в виде следующей строки кода:

    IEstimator<ITransformer> pipeline =
        // Split the text into individual words
        mlContext.Transforms.Text.TokenizeIntoWords("TokenizedWords", "ReviewText")
    

    В преобразовании TokenizeIntoWords используются пробелы для разбиения текста или строки на слова. Оно создает новый столбец и разделяет каждую входную строку на вектор подстрок на основе определяемого пользователем разделителя.

  2. Сопоставьте слова с кодировкой целых чисел, используя таблицу подстановки, приведенную выше:

    // 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"))
    
  3. Измените размер кодировок целых чисел переменной длины на фиксированную длину, необходимую для модели:

    // Resize variable length vector to fixed length vector.
    .Append(mlContext.Transforms.CustomMapping(ResizeFeaturesAction, "Resize"))
    
  4. Классифицируйте входные данные с помощью загруженной модели TensorFlow:

    // Passes the data to TensorFlow for scoring
    .Append(tensorFlowModel.ScoreTensorFlowModel("Prediction/Softmax", "Features"))
    

    Имя выходных данных модели TensorFlow — Prediction/Softmax. Обратите внимание, что имя Prediction/Softmax определяется моделью TensorFlow. Это имя нельзя изменить.

  5. Создайте новый столбец для прогнозирования выходных данных:

    // Retrieves the 'Prediction' from TensorFlow and copies to a column
    .Append(mlContext.Transforms.CopyColumns("Prediction", "Prediction/Softmax"));
    

    Необходимо скопировать столбец Prediction/Softmax в столбец с именем, которое можно использовать как свойство в классе C# Prediction. В имени свойства C# нельзя использовать символ /.

Создание модели ML.NET из конвейера

  1. Добавьте код для создания модели из конвейера:

    // Create an executable model from the estimator pipeline
    IDataView dataView = mlContext.Data.LoadFromEnumerable(new List<MovieReview>());
    ITransformer model = pipeline.Fit(dataView);
    

    Модель ML.NET создается из цепочки средств оценки в конвейере с помощью вызова метода Fit. В этом случае мы не будем подбирать данные для создания модели, так как модель TensorFlow уже обучена. Мы предоставим пустой объект представления данных в соответствии с требованиями метода Fit.

Использование модели для прогноза

  1. Добавьте метод PredictSentiment над классом MovieReview:

    void PredictSentiment(MLContext mlContext, ITransformer model)
    {
    
    }
    
  2. Добавьте следующий код в качестве первой строки в методе PredictSentiment() для создания PredictionEngine:

    var engine = mlContext.Model.CreatePredictionEngine<MovieReview, MovieReviewSentimentPrediction>(model);
    

    Класс PredictionEngine представляет собой удобный API, позволяющий осуществить прогнозирование на основе единственного экземпляра данных. PredictionEngine не является потокобезопасным. Допустимо использовать в средах прототипов или средах с одним потоком. Для улучшенной производительности и потокобезопасности в рабочей среде используйте службу PredictionEnginePool, которая создает ObjectPool объектов PredictionEngine для использования во всем приложении. См. руководство по использованию PredictionEnginePool в веб-API ASP.NET Core.

    Примечание

    Расширение службы PredictionEnginePool сейчас доступно в предварительной версии.

  3. Добавьте комментарий для проверки прогнозирования обученной модели в методе Predict(), создав экземпляр MovieReview:

    var review = new MovieReview()
    {
        ReviewText = "this film is really good"
    };
    
  4. Передайте тестовые данные комментариев в Prediction Engine, добавив следующие строки кода в метод PredictSentiment():

    var sentimentPrediction = engine.Predict(review);
    
  5. Функция Predict() создает прогноз по одной строке данных.

    Свойство. Значение Type
    Прогноз [0.5459937, 0.454006255] float[]
  6. Выведите прогноз тональности, используя следующий код:

    Console.WriteLine($"Number of classes: {sentimentPrediction.Prediction?.Length}");
    Console.WriteLine($"Is sentiment/review positive? {(sentimentPrediction.Prediction?[1] > 0.5 ? "Yes." : "No.")}");
    
  7. Добавьте вызов метода PredictSentiment после вызова метода Fit():

    PredictSentiment(mlContext, model);
    

Результаты

Скомпонуйте и запустите приложение.

Результаты выполнения должны выглядеть примерно так, как показано ниже. Во время обработки отображаются сообщения. Вы можете видеть предупреждения или обработанные сообщения. Для удобства эти сообщения удалены из следующих результатов.

Number of classes: 2
Is sentiment/review positive ? Yes

Поздравляем! Вы успешно создали модель машинного обучения для классификации и прогнозирования тональности сообщений с помощью предварительно обученной модели TensorFlow в ML.NET.

Исходный код для этого руководства можно найти в репозитории dotnet/samples.

В этом руководстве вы узнали, как:

  • Загрузить предварительно обученную модель TensorFlow.
  • Преобразовать текст комментария на веб-сайте в признаки, пригодные для модели.
  • Использование модели для прогноза