Этот пост является продолжением предыдущего обсуждения влияния языка на производительность ChatGPT в задачах классификации текста и призван дать практическую информацию о разработке приложений с большими языковыми моделями (LLM) для обработки больших объемов данных.

В The Hotels Network мы предлагаем платформу динамической настройки контента для более чем 19 000 отелей по всему миру, улучшая взаимодействие с пользователем и производительность веб-сайта. Понимание веб-страниц наших клиентов и поведения пользователей имеет решающее значение, а многоязычные возможности больших языковых моделей (LLM) являются ключевыми.

Управление огромными объемами веб-контента и ежедневными посещениями пользователей требует специализированных стратегий LLM. В этом посте мы постараемся углубиться в некоторые из этих стратегий, обрисовав в общих чертах ключевые аспекты разработки и развертывания приложений. Мы также обсудим три методологии обработки больших объемов данных: обучение моделей машинного обучения воспроизведению завершения ChatGPT для вложений, использование поиска информации с вложениями для формирования контекста подсказок и ответы на запросы на естественном языке в табличных данных с использованием кода, сгенерированного ChatGPT.

Функциональные соображения

В этом разделе мы углубимся в несколько аспектов, которые, по нашему мнению, важны при разработке приложения с API ChatGPT. Эти факторы, охватывающие как технические, так и нетехнические соображения, сильно влияют на осуществимость и жизнеспособность различных подходов при решении задач, требующих большого объема данных.

1.-Стоимость.Стоимость вызовов API ChatGPT определяется на основе количества токенов (слов или фрагментов слов) как во входном вопросе, так и в сгенерированном ответе. По состоянию на 16 июня 2023 г. эти затраты значительно различаются (как показано на следующей диаграмме), особенно между запросами на завершение текста и запросами на создание встраивания.

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

2.- Задержка. Время отклика API значительно влияет на работу пользователей и производительность приложений. Время ответа завершения текста API ChatGPT пропорционально количеству токенов, сгенерированных в ответе. Эта взаимосвязь показана на следующем графике, который иллюстрирует измеренную задержку для различных экспериментов по завершению текста. На графике показано время, необходимое для создания ответа на основе количества сгенерированных слов с учетом различных моделей ChatGPT.

Согласно эмпирическим результатам, представленным на следующем графике и в таблицах, GPT3.5 показывает несколько более высокую производительность по сравнению с другими рассмотренными альтернативами.

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

3.-Ограничения запросов. Еще одним важным фактором при обработке больших объемов данных является скорость, с которой мы можем отправлять запросы API, прежде чем они будут заблокированы серверами OpenAI. API OpenAI недавно ослабил ограничения на одновременные запросы, как показано в следующей таблице на основе значений, предоставленных OpenAI.

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

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

5.-Стратегия подсказки. Написание эффективной подсказки имеет решающее значение. Хорошо построенная подсказка предназначена для получения результатов, соответствующих нашим целям. В Интернете доступно огромное количество информации о стратегиях генерации подсказок. Ключевые аспекты, которые следует учитывать при создании подсказок, включают:

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

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

6. Согласованность модели. При разработке алгоритмов машинного обучения часто возникает дилемма: повысить точность алгоритма или сохранить согласованность выходных данных модели. Хотя оптимизация ответов может быть полезной, согласованность выходных данных имеет решающее значение для обеспечения доверия пользователей к выходным данным модели и предотвращения изменений в процессах на основе этих выходных данных. Эта проблема также заметна с OpenAI, поскольку «улучшения» в моделях могут изменить их реакцию, вынуждая пользователей корректировать свое взаимодействие. Опять же, обучение моделей для простых задач с использованием вложений открытых моделей в качестве входных данных и выходных данных, полученных с помощью GPT, в качестве желаемых выходных данных изолируется от корректировок модели OpenAI.

На приведенном выше графике показано влияние на производительность модели gpt3.5-Turbo в двух версиях, до и после 13 июня 2023 г. Он демонстрирует значительное снижение точности системы в экспериментах, связанных с категоризацией текстового контента, аналогично формату проведенных экспериментов. в предыдущей статье. В этой статье измеряется производительность моделей на основе классификации текста на разных языках. Хотя эксперимент был разработан не для сравнения моделей, а для сравнения влияния подсказок и языка в рамках одной и той же модели, результаты ясно указывают на ухудшение точности при использовании одной и той же подсказки и модели в двух различных периодах времени, когда текст для быть классифицированным не написано на английском языке.

Стратегии масштабируемого использования ChatGPT

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

1.-Model Training для воспроизведения завершений ChatGPT из вложений: ChatGPT можно использовать для решения сложных задач, генерирующих ответы для определенного подмножества текстовых образцов, тем самым создавая набор обучающих данных, состоящий из запросов и ответов ChatGPT. .

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

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

2.- Создание контекстной подсказки. В этой стратегии используются вложения для идентификации и индексации контента, похожего или связанного с запросом, на который необходимо ответить. Используя Langchain, векторные базы данных, такие как Pinecone и Nuclia, и встраивания моделей, он генерирует контекст из огромного количества текстовых данных. Этот контекст, состоящий из похожих или связанных текстов, затем добавляется к исходному запросу. Следовательно, расширенный запрос, теперь содержащий соответствующий контекст, перенаправляется в ChatGPT для обработки.

3.-Использование ChatGPT для генерации кода запроса данных: эта стратегия позволяет получить доступ к объемным табличным данным с помощью автоматически сгенерированных функций запроса данных в кадрах данных pandas, являясь PandasAI реализацией этой стратегии.

Мы посвятим оставшуюся часть этой статьи подробному изучению первой стратегии с намерением обсудить следующие стратегии в следующем посте.

Обучение классификаторов на встраиваниях для имитации поведения чата GPT

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

Однако из-за системной задержки и затрат этот процесс с ChatGPT невозможен. Вместо этого мы можем использовать встраивания и обучение классификаторов, чтобы воспроизвести поведение GPT. Сначала мы выберем набор рекомендаций, сформируем пары и спросим ChatGPT, какая из каждой пары имеет более позитивный оттенок. На основе этих ответов мы будем обучать классификаторы, используя вложения текстовых пар в качестве входных данных, чтобы имитировать поведение ChatGPT.

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

import os
import openai

openai.organization = "my_organization"
openai.api_key = os.getenv('OPENAI_KEY')


def compare_review_sentiments(message1: str, message2: str, model: str = "gpt-3.5-turbo") -> str:
    prompt = f'Based on the following two hotel reviews:\n\n1: "{message1}"\n2: "{message2}"' \
             '\n\nPlease determine which review portrays a more positive impression to potential customers.' \
             ' Choose between "1", "2", or "TIE" if both reviews seem equally positive or if it is '\
             'unclear which is superior. Your response should only include "1", "2", or "TIE", '\
             'without any additional comments. The most positive review is:'

    # Create a chat completion request with GPT-4
    result = openai.ChatCompletion.create(
        model=model,
        messages=[
            {"role": "system", "content": "You are an expert in marketing with specialized experience in hotels."},
            {"role": "user", "content": prompt}
        ],
        temperature=0,
        max_tokens=3000
    )

    # Extract and return the response
    return result['choices'][0]['message']['content'].strip()

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

import numpy as np

reviews = ['review 1', 'review 2'....'reciew n']
n_reviews = len(reviews)
r1 = list(range(n_reviews))
r2 = [np.random.choice([y for y in list(range(n_reviews)) if y != x]) for x in r1]

Затем мы используем ChatGPT, чтобы построить порядок внутри каждой пары, определяемый тем, какой отзыв является более положительным.

import time

n_reviews = len(reviews)

forward = []
backward = []
i = 0
while (i < n_reviews):
    try:
        # Compare sentiments from review 1 to review 2, and vice versa
        f = compare_review_sentiments(reviews[r1[i]], reviews[r2[i]])
        b = compare_review_sentiments(reviews[r2[i]], reviews[r1[i]])
        forward.append(f)
        backward.append(b)
        i += 1
    except Exception as e:
        # sleep when OpenAI API raises error due to request per minute limit
        print(f'Processing pair {i} resulted in an error: {e}. Entering sleep mode...')
        time.sleep(20)

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

Мы оценим процесс аппроксимации определения того, какой из двух обзоров является более положительным, путем расчета вложений с использованием API OpenAI с моделью text-embedding-ada-002 и сравним его с вложениями, сгенерированными all-mpnet. -base-v2», stsb-xlm-r-multilingual, all-MiniLM-L6-v2, bert-base-multilingual-uncased-sentiment, все модели apache 2 или распределенные модели с лицензией MIT, которые мы могли установить на нашу машину.

Код для создания вложений с помощью text-embedding-ada-002OpenAI будет выглядеть следующим образом:

MODEL = "text-embedding-ada-002"
def generate_embeddings(inputs):
    res = openai.Embedding.create(
        input=inputs, engine=MODEL
    )
    return [x["embedding"] for x in res['data']]


ada_embeddings_result = []

# Process reviews in chunks of 100
for i in range(0, len(reviews), 100):
    # Get next chunk of reviews
    chunk = reviews[i:i + 100]

    # Generate embeddings for chunk
    embeddings = generate_embeddings(chunk)

    # Append embeddings to result list
    embeddings_result.extend(embeddings)

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

import torch
from transformers import AutoTokenizer, AutoModel
import torch.nn.functional as F

LOCAL_MODEL_CACHE_PATH = "/my_hugin_face_local_model_cache_folder"

def _mean_pooling(model_output, attention_mask):
    token_embeddings = model_output[0]  
    input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
    return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)


class TextModel():

    def __init__(self, model_name, device='cuda:0'):
        self.model_name = model_name
        self.tokenizer = AutoTokenizer.from_pretrained(self.model_name,
                                                       cache_dir=LOCAL_MODEL_CACHE_PATH)
        self.model = AutoModel.from_pretrained(self.model_name,
                                               cache_dir=LOCAL_MODEL_CACHE_PATH).to(device)
        self.device = device

    def encode_text(self, texts):
        encoded_input = self.tokenizer(texts, padding=True, truncation=True, return_tensors='pt').to(self.device)
        with torch.no_grad():
            model_output = self.model(**encoded_input)

        sentence_embeddings = _mean_pooling(model_output, encoded_input['attention_mask'])

        sentence_embeddings = F.normalize(sentence_embeddings, p=2, dim=1)
        sentence_embeddings = sentence_embeddings.to('cpu')

        return sentence_embeddings.numpy()

embeddings_result=[]
for block in tqdm(range(1+len(dataset['reviews'])//25)):
    all_encodings.append(embeddings_model.encode_text(dataset['reviews'][block*25:(block+1)*25]))

embedding_model=TextModel(model_name)

embeddings_result = []
# Process reviews in chunks of 25
for i in range(0, len(reviews), 25):
    # Get next chunk of reviews
    chunk = reviews[i:i + 25]

    # Generate embeddings for chunk
    embeddings = embedding_model.encode_text(chunk)

    # Append embeddings to result list
    embeddings_result.extend(embeddings)

Модели загружаются при первом использовании с Huginface и сохраняются в «/my_hugin_face_local_model_cache_folder» на вашем локальном диске. Полное имя модели должно быть предоставлено конструктору TextModel, полные имена модели: -transformers/all-MiniLM-L6-v2, «nlptown/bert-base-multilingual-uncased-sentiment».

Как только мы получим вложения, мы можем приступить к обучению и оценке наших моделей. Чтобы проиллюстрировать этот процесс, мы провели эксперименты с меньшим набором данных из 1000 отзывов. Мы обучили нейронные сети различным топологиям, примененным к набору данных с уменьшенной размерностью с помощью анализа основных компонентов (PCA), используя 100 собственных векторов. Мы измерили точность всего этого процесса, используя 10-кратную проверку. Результаты для каждого набора вложений представлены на следующей диаграмме.

Результаты этого сокращенного набора данных предполагают, что мы можем близко приблизиться к результатам, достигнутым с завершением ChatGPT в этой задаче, используя вложения. Кроме того, модель «bert-base-multilingual-uncased-sentiment», точно настроенная для классификации настроений, работает сравнимо с моделью OpenAI. Ключевым преимуществом модели «bert-base-multilingual-uncased-sentiment» является то, что ее можно запускать локально, что позволяет обойти проблемы конфиденциальности данных и ограничения запросов, связанные с моделью OpenAI.

Выводы

Универсальность ChatGPT позволяет автоматизировать множество сложных задач. Однако, когда мы используем его в производственных системах с большими объемами данных, мы сталкиваемся с проблемами, связанными с задержкой, ограничениями запросов API, затратами, согласованностью посредством обновлений модели, а также с конфиденциальностью.

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