[Не удалось] Исследование методов машинного обучения для улучшения тестов – V


Введение

Это часть серии постов блога, связанных с внедрением искусственного интеллекта. Если вам интересна предыстория этой истории или то, как она происходит:

Ссылки на предыдущие записи блога
Как соскрести результаты Google Local Results с помощью искусственного интеллекта
Реальный пример машинного обучения на Rails
Советы и сравнения по обучению искусственному интеллекту
Машинное обучение в скраппинге с помощью Rails
Реализация моделей ONNX в Rails
Как гибридный парсер ML побеждает традиционный парсер
Как провести бенчмаркинг реализаций ML на Rails
Исследование методов машинного обучения для улучшения спецификационных тестов
Исследование методов машинного обучения для улучшения спецификационных тестов – II
Исследование методов машинного обучения для улучшения тестов спецификаций – III
Исследование методов машинного обучения для улучшения спецификационных тестов – IV
Как обучить масштабируемый классификатор с помощью FastAPI и SerpApi?

На этой неделе мы продемонстрируем хранение и повторное использование обученных весов, а также расскажем о решающей ошибке, которую я допустил при расчете ранних результатов модели. Для сбора данных мы будем использовать SerpApi’s Google Organic Results Scraper API. Также вы можете ознакомиться с более подробным представлением данных, которые мы будем использовать, на игровой площадке.

Решающая ошибка, которую я допустил при расчете точности модели

Позвольте мне сначала рассказать о том, как я проводил расчеты на учебных примерах:

    true_examples = key_array.map {|el| el = el.first == "1" ? el.second : nil}.compact
    false_examples = key_array.map {|el| el = el.first == "0" ? el.second : nil}.compact

    predictions = []

    false_examples.each do |example|
      prediction = test example, 2, vector_array, key_array
      predictions << prediction
    end

    predictions.map! {|el| el = el == 1 ? 0 : 1}

    true_examples.each_with_index do |example, index|
      puts "--------------"
      prediction = test example, 2, vector_array, key_array
      predictions << prediction
      puts "Progress #{(index.to_f/true_examples.size.to_f).to_f}"
      puts "--------------"
    end

    prediction_train_accuracy = predictions.sum.to_f / predictions.size.to_f

    puts "Prediction Accuracy for Training Set is: #{prediction_train_accuracy}"
Войти в полноэкранный режим Выход из полноэкранного режима

Мы берем примеры, которые являются сниппетами, и примеры, которые не являются сниппетами, и запускаем их в обученной модели. Если предсказание примеров без сниппета окажется равным 0, то они будут засчитаны как правильные предсказания, а если результаты со сниппетом будут засчитаны как 1, то они также будут засчитаны как правильные результаты. В итоге результат скорости правильного предсказания составил 0,8187793427230047. Позже я использовал более крупный набор данных, и результат составил около 89%.

Вот логическое заблуждение, на которое я попался; Было исчерпывающе больше результатов без сниппетов по сравнению с результатами со сниппетами. Предположим, что это соотношение составляет 1:9 в наборе примеров из 10 единиц. Если модель склонна называть вещи non-snippet чаще, чем snippet в случайном порядке, как это было в данном случае, то результаты non-snippet будут предсказаны правильно, что создаст смещение в результатах.

Причина, по которой этот показатель увеличился до 89 процентов в более крупном наборе данных, заключается в том, что в нем было больше типов ключей. Это привело к тому, что соотношение размера сниппета и размера не сниппета еще больше уменьшилось, что вызвало перекос в ложноположительных предсказаниях результатов, не относящихся к сниппетам.

В действительности мне следовало протестировать модель, используя только примеры сниппетов. Я так и сделал и обнаружил, что модель бесполезна. Я постараюсь подправить модель и найти способ сделать ее полезной. Но я думаю, что лучше показать, почему я сделал неудачный расчет до этого, чтобы проинформировать всех и не дать другим людям совершить ту же ошибку.

Хранение обученных весов пользовательским способом

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

Вот полный код для этого:

    class Predict 
      def initialize csv_path, trained_weights_path, vocab_path, object = "Snippet", k = 2
        @@csv_path = csv_path
        @@trained_weights_path = trained_weights_path
        @@vocab_path = vocab_path
        @@object = object
        @@k = k
        @@key_arr = []
        @@vector_arr = []
        @@weights = []
        @@maximum_word_size = 0
        @@vocab = {}
      end

      def self.construct
        @@weights = initialize_trained_weights @@trained_weights_path
        @@vocab = read_vocab @@vocab_path
        @@key_arr = read_csv @@csv_path
        @@vector_arr = define_training_set @@key_arr
        @@maximum_word_size = @@weights.size
        extend_vectors
      end

      def self.read_csv csv_path
        CSV.read(csv_path)
      end

      def self.read_vocab vocab_path
        vocab = File.read vocab_path
        JSON.parse(vocab)
      end

      def self.initialize_trained_weights trained_weights_path
        weights = File.read trained_weights_path
        weights = JSON.parse(weights)
        Vector.[](*weights)
      end

      def self.define_training_set vectors
        @@key_arr.map { |word| word_to_tensor word[1] }
      end

      def self.default_dictionary_hash
        {
          /"/ => "",
          /'/ => " '  ",
          /./ => " . ",
          /,/ => ", ",
          /!/ => " ! ",
          /?/ => " ? ",
          /;/ => " ",
          /:/ => " ",
          /(/ => " ( ",
          /)/ => " ) ",
          /// => " / ",
          /s+/ => " ",
          /<br />/ => " , ",
          /http/ => "http",
          /https/ => " https ",
        }
      end

      def self.tokenizer word, dictionary_hash = default_dictionary_hash
        word = word.downcase
        dictionary_hash.keys.each do |key|
          word.sub!(key, dictionary_hash[key])
        end
        word.split
      end

      def self.word_to_tensor word
        token_list = tokenizer word
        token_list.map {|token| @@vocab[token]}
      end

      def self.extend_vector vector
        vector_arr = vector.to_a
        (@@maximum_word_size - vector.size).times { vector_arr << 1 }
        Vector.[](*vector_arr)
      end

      def self.extend_vectors
        @@vector_arr.each_with_index do |vector, index|
          @@vector_arr[index] = extend_vector vector
        end
      end

      def self.product vector
        @@weights.each_with_index do |weight, index|
          vector[index] = weight * vector[index]
        end

        vector
      end

      def self.euclidean_distance vector_1, vector_2
        subtractions = (vector_1 - vector_2).to_a
        subtractions.map! {|sub| sub = sub*sub }
        Math.sqrt(subtractions.sum)
      end

      def self.execute example
        example_vector = word_to_tensor example
        example_vector.map! {|el| el = el.nil? ? 0: el}
        example_vector = extend_vector example_vector
        weighted_example = product example_vector

        distances = []
        @@vector_arr.each_with_index do |comparison_vector, vector_index|
          distances << euclidean_distance(comparison_vector, weighted_example)
        end

        indexes = []
        @@k.times do 
          index = distances.index(distances.min)
          indexes << index
          distances[index] = 1000000000
        end

        predictions = []
        indexes.each do |index|
          predictions << @@key_arr[index].first.to_i
        end

        puts "Predictions: #{predictions}"

        prediction = (predictions.sum/predictions.size).to_f
        if prediction < 0.5
          puts "False - Item is not #{@@object}"
          return 0
        else
          puts "True - Item is #{@@object}"
          return 1
        end
      end
    end

    csv_path = "organic_results/organic_results__snippet.csv"
    trained_weights_path = "organic_results/snippet_weights.json"
    vocab_path = "organic_results/vocab.json"

    Predict.new csv_path, trained_weights_path, vocab_path, object = "Snippet", k = 5
    Predict.construct

    true_examples = CSV.read(csv_path)
    true_examples = true_examples.map {|el| el = el.first == "1" ? el.second : nil}.compact

    true_examples.each_with_index do |example, index|
      puts "--------"
      puts "#{index}"
      Predict.execute example
      puts "--------"
    end
Войти в полноэкранный режим Выйти из полноэкранного режима

Заключение

Я сделал честную попытку в области, которая могла бы облегчить написание тестов, и потерпел неудачу. Тонкие ошибки в пользовательских кодах могут привести к общей неудаче. Я благодарен за то, что попробовал и увидел, что этот подход не так эффективен, как я думал. Я буду продолжать работать над этим в будущем. Однако для следующей записи в блоге тема, скорее всего, будет другой. Я хотел бы извиниться перед читателями за предоставление недостоверных результатов в предыдущей записи блога и поблагодарить их за внимание.

Первоначально опубликовано на сайте https://serpapi.com 4 мая 2022 года.

Оцените статью
Procodings.ru
Добавить комментарий