CoderCastrov logo
CoderCastrov
Искусственный интеллект

Как с помощью искусственного интеллекта собирать данные из Google Local Results?

Как с помощью искусственного интеллекта собирать данные из Google Local Results?
просмотров
9 мин чтение
#Искусственный интеллект
Table Of Content

    Действительно, слова, описывающие передовые технологии, или само слово "передовая технология", вызывают большой ажиотаж. Как и в большинстве случаев, связанных с ажиотажем, это вызвано серией непонимания между разными сторонами, связанными с темой. Люди, которые теоретизируют о технологии, часто отделены от людей, которые реализуют ее в качестве решения, так же, как отделены и от людей, которые ее используют. С течением времени, если некоторые слова более узнаваемы и передают мощь идеи, вы окружены людьми, которые говорят о теме без какой-либо конкретики, ожидая, что их поймут. SerpApi не утверждает, что она единственная компания, имеющая право говорить о искусственном интеллекте. Тем не менее, мы стремимся приложить честные усилия к этому, и я буду делиться этим путешествием, явно, каждую среду, по мере развития реализации.

    I- Начальная точка - Проблема

    "Exceptio probat regulam de rebus non exceptis."

    Поскольку многие люди не знают, с чего начать, у нас была проблема, которую можно было бы решить с помощью искусственного интеллекта, а именно, модели машинного обучения. SerpApi's Google Local Results Scraper API был одной из самых трудоемких частей нашего сервиса для разработчиков, которые разрабатывали и исправляли ошибки, специалистов по обслуживанию клиентов, которые множество раз общались между инженерами и клиентами, и самих клиентов. Постоянные изменения в структуре страницы и именах классов, а также слишком много элементов, которые могут быть неправильно обработаны парсерами, вызывали и до сих пор вызывают некоторые сбои в коде. Крайне важно развивать реализацию вокруг проблемы, когда речь идет о внедрении новой технологии для решения старых проблем. Например, в конечном итоге эта решение должно быть способно делать то, что делает традиционный парсер, и делать это более точно. Оно должно работать с разумной скоростью (предпочтительно меньше, чем у традиционного парсера). Оно должно быть в состоянии, которое легко понять другому человеку с минимальными знаниями и обновить (предпочтительно проще, чем традиционный парсер). Оно не должно стоить больше финансово, чем текущее состояние в плане оплаты. У него должен быть приличный способ его тестирования. Оно должно использоваться для решения другой проблемы с небольшой модификацией. Оно должно соответствовать моделям на остальном интернете, чтобы сравнивать и контрастировать с легкостью.

    II - Разбиение проблемы

    "Iucundum est narrare sua mala."

    Реализация должна быть разбита на самодостаточные части, которые решают разные аспекты проблемы. В нашем случае, первая проблема, которую она должна решить, - это классификация разных извлеченных значений без необходимости использования условий внутри самого парсера. Зачем ее разбивать на части? Почему бы просто не создать модель, которая принимает HTML и возвращает результирующий JSON со всеми значениями в нем? Причины этого просты, но важны. Такая модель потребует слишком много вычислительной мощности, если она не будет тщательно оптимизирована. Это означает, что для ее обучения потребуются облачные сервисы третьих сторон, такие как Azure Machine Learning, Amazon SageMaker, Google AutoML. Не поймите меня неправильно, эти сервисы, вместе с многими другими, являются отличными инструментами для создания и обучения моделей. Однако решение одной проблемы с помощью машинного обучения не должно приводить к необходимости настройки, аренды и внедрения новых серверов. Будь то много проблем, решенных с помощью машинного обучения, такие сервисы должны быть реализуемыми. Кроме того, создание модели, которая решает всю проблему сразу, нельзя ожидать от человека с минимальными знаниями. Если возникает проблема в одной функции модели, она должна быть самодостаточной.

    Я надеюсь, что я смог передать идею разбиения проблемы, которую нужно решить с помощью взаимодополняющих моделей. Теперь давайте поговорим о том, почему классификация разных извлеченных значений является начальной точкой этой работы. Одна из основных проблем, с которой мы сталкиваемся в SerpApi's Google Local Results Scraper API, - это путаница значений в правильных ключах в JSON. Извлеченный адрес может быть представлен в качестве названия места, номер телефона может быть представлен в качестве рабочих часов и т.д. Обратите внимание, что у нас уже есть традиционные решения для проверки правильности этих значений внутри парсера. Однако, поскольку Google Local Results развивается с большой скоростью, и с нашим разнообразным пулом движков, становится все сложнее решить возникающую проблему. Поэтому лучше начать с частой проблемы, которую можно решить с помощью классифицирующей модели машинного обучения.

    III- План действий для SerpApi's Google Local Results Scraper API

    "Malum consilium quod mutari non potest"

    У нас есть идеальная структура плана для этого усилия. Однако все может измениться по мере развития реализации. Это не означает, что мы начнем все с нуля для реализации всего. Позвольте мне объяснить это, объясняя полный набор моделей, которые решат проблему.

    Идеальная модель:

    • Шаг №1) Взять HTML, разбить его на разные части для заполнения разных полей. Пример: Часть, содержащая все local_results, отделяется от остального HTML, включая скрытые внутри HTML детали, которые можно извлечь.

    • Шаг №2) Взять часть, содержащую все связанные с local_results HTML, и преобразовать ее в HTML, который не содержит нерелевантные части. Пример: Если есть реклама, она не будет включена в этот новый HTML.

    • Шаг №3) Разделить разные local_results на отдельные поля для парсинга. Пример: Извлекается основной элемент, касающийся отдельного local_result, а также скрытая внутри HTML информация о нем.

    • Шаг №4) Извлечь каждое значение и создать из них массив. Пример: Создается массив, содержащий разные поля для предоставления.

    • Шаг №5) Классифицировать каждое извлеченное значение. Пример: Адреса классифицируются как адреса, номера телефонов как номера телефонов.

    • Шаг №6) Взять каждое классифицированное значение, сравнить его с моделью, чтобы решить, правильно ли оно классифицировано, или это какое-то новое значение. Пример: Если Google начнет предоставлять метавселенную эквивалент ресторана, модель в шаге №6 должна быть способна это уловить и запустить шаг №7.

    • Шаг №7) Создать новое название ключа на основе названия отдельной части или остальных ключей в SerpApi JSON. Пример: Модель должна быть ответственна за название ключа поля. В этом примере она должна взять название title_name или разные поля в SerpApi и придумать ключ metaverse.

    Как видите, Шаг №5 имеет большое значение. Шаги №6 и №7 работают только тогда, когда есть новое поле для предоставления. Поэтому их можно реализовать позже. Все до Шага №5 уже имеет решение в традиционном парсере. Вот почему важно начать реализацию с Шага №5.

    Далее в очереди любой шаг до Шага №5. Не должно быть никакого порядка, поскольку все может быть реализовано частями в традиционном парсере.

    Шаги №6 и №7 могут быть решены путем обучения с новой базой данных, включающей новое поле, и ключ поля может быть назван вручную инженером, обновляющим модель. Поэтому они должны быть решены на более позднем этапе.

    IV - Технические проблемы - Машинное обучение на Rails

    "Sunt facta verbis difficiliora"

    Все вышеперечисленные соображения не имеют смысла без работающей реализации. Реализация на Rails - это еще одна сложная проблема из-за ограниченного количества библиотек, касающихся машинного обучения.

    Но сначала давайте ясно определимся, какую модель использовать для классификации разных полей. Мы создадим модель "Character Level Recurrent Neural Network (RNN)", чтобы решить нашу проблему. RNN - это тип прямого нейронной сети. Прямые нейронные сети - это искусственные нейронные сети, в которых узлы не образуют цикл. Проще говоря, мы будем подавать значение, и модель будет передавать его в скрытый слой, а затем скрытый слой передаст его в слой softmax, а из слоя softmax - в выходной слой.

    Каков уровень ввода? Уровень ввода будет тензором, составленным из каждой буквы в виде тензора. Вот как; если у нас есть алфавит из 5 букв, одна буква будет составлять матрицу 1x5, зависящую от ее индекса в алфавите.

    Пример:

    алфавит = [a,b,c,d,e]

    a = Tensor([1,0,0,0,0]) b = Tensor([0,1,0,0,0]) c = Tensor([0,0,1,0,0])...

    Каждое слово будет составлять 10x1x5. Почему 10? Это максимальное количество букв в слове, которое мы разрешаем.

    Пример:

    dead = Tensor(

    [0,0,0,1,0], #d

    [0,0,0,0,1], #e

    [1,0,0,0,0], #a

    [0,0,0,1,0], #d

    [0,0,0,0,0], #null

    [0,0,0,0,0], #null

    [0,0,0,0,0], #null

    [0,0,0,0,0], #null

    [0,0,0,0,0], #null

    [0,0,0,0,0]) #null

    Обратите внимание, что мы используем нулевые тензоры для остального пространства, выделенного в матрице.

    Таким образом, мы можем создать математическое выражение, с которым можно играть из слова, а затем подать его на вход модели, чтобы получить выходы softmax. Каков будет выход softmax? Это будет распределение вероятностей слова (или предложения, прочитанного как одно слово). Допустим, у нас есть 3 ключа, а именно, адрес, телефон, название.

    Пример: 5540 N Lamar Blvd #12 => модель => [адрес: 0.8, телефон: 0.5, название: 0.15]

    Из распределения softmax мы возьмем максимальное значение, и ключ максимального значения будет нашим выводом.

    Таким образом, мы подадим 5540 N Lamar Blvd #12, и он даст нам адрес.

    Для создания обучающего набора данных мы создадим json-файл, заполненный классифицированными значениями, а затем будем проверять его вручную (пока что), если есть какие-либо значения, которые не должны принадлежать классу. К счастью, парсер SerpApi's Google Local Results Scraper API в настоящее время не вызывает больших проблем, и подача набора данных будет возможна с помощью простой команды Rake.

    В Ruby в целом нет обширных библиотек, которые могли бы решить нашу проблему. Поэтому мы будем создавать модели с использованием Libtorch и Ruby-гема, который был переведен из C++ в Ruby, о котором я расскажу в следующем блог-посте. Любой инженер, который будет создавать и обучать модель, создаст необходимые файлы в Rails в папке, которая не покрывает CI. Вот причина. Libtorch с включенным CUDA (позволяет пользователю использовать графические процессоры для обучения) имеет размер около 2,5 ГБ. Развертывание его на каждом сервере будет дорогостоящим. Поэтому на данный момент любой инженер, который будет обучать модель, настроит Libtorch, а затем настроит его на своей локальной системе с пошаговой инструкцией для каждой ОС. После обучения будет создан файл PTH. В этом файле будет содержаться обученная модель.

    Вот еще одна проблема для Rails. Мы не можем читать файлы pth без Libtorch, а Libtorch зависит от локальной машины инженера. Поэтому мы подумали о создании отдельного сервера для хостинга Libtorch. Но, опять же, нам не нужны дополнительные расходы на проблему, которая на данный момент слишком узкая. Поэтому, вместо этого, мы будем преобразовывать этот файл PTH в файл ONNX, который является общепринятым форматом файла. В конце концов, гемы, отвечающие за Libtorch, так как они от него зависят, должны быть закомментированы, чтобы избежать сбоев CI. Папка, в которой находятся файлы, работающие с Libtorch, также должна быть вне области видимости CI.

    Обучение модели и преобразование ее в формат ONNX также будет возможно с помощью простой команды Rake.

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

    Итак, чтобы дать пошаговую инструкцию по общему рабочему стандарту:

    • Шаг №0) Настройте Libtorch и соответствующие библиотеки* Шаг №1) Создайте модель* Шаг №2) Создайте набор данных* Шаг №3) Вручную проверьте набор данных на наличие ошибок* Шаг №4) Обучите модель и преобразуйте ее в ONNX с помощью простой команды Rake* Шаг №5) Протестируйте модель с помощью Rspec* Шаг №6) Реализуйте модель в традиционном парсере (подавая файл ONNX)* Шаг №7) Закомментируйте Ruby-гемы, связанные с LibTorch (за исключением того, который отвечает за чтение файлов ONNX)* Шаг №8) Отправьте PR* Шаг №9) Кратко объясните, как это более эффективно, чем традиционный парсер в описании PR* Шаг №10) Объедините его и сообщите клиентам с помощью блог-поста.

    V- Заключение

    "Vi veri universum vivus vici"

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