Ler em inglês

Compartilhar via


OpenAI do Azure para big data

O serviço Azure OpenAI pode ser usado para resolver um grande número de tarefas de linguagem natural por meio da solicitação da API de conclusão. Para facilitar a escala dos fluxos de trabalho de solicitação de alguns exemplos para grandes conjuntos de dados de exemplos, integramos o serviço OpenAI do Azure com a biblioteca de aprendizado de máquina distribuída SynapseML. Essa integração facilita o uso da estrutura de computação distribuída do Apache Spark para processar milhões de prompts com o serviço OpenAI. Este tutorial mostra como aplicar modelos de linguagem grandes em uma escala distribuída usando o Azure OpenAI e o Azure Synapse Analytics.

Pré-requisitos

Os principais pré-requisitos para este início rápido incluem um recurso do OpenAI do Azure em funcionamento e um cluster do Apache Spark com o SynapseML instalado.

Importar este guia como um notebook

A próxima etapa é adicionar esse código ao cluster do Spark. Você pode criar um notebook em sua plataforma Spark e copiar o código nesse notebook para executar a demonstração. Ou baixe o notebook e importe-o para o Synapse Analytics

  1. Baixar essa demonstração como um bloco de anotações (selecione Bruto e salve o arquivo)
  2. Importe o notebook para o workspace do Synapse ou, se estiver usando o Fabric, imprte para o workspace do Fabric
  3. Instale o SynapseML no cluster. Consulte as instruções de instalação do Synapse na parte inferior do site do SynapseML. Se estiver usando o Fabric, consulte o Guia de Instalação. Isso requer colar outra célula na parte superior do notebook que você importou.
  4. Conecte seu notebook a um cluster e acompanhe, editando e executando as células abaixo.

Preencha as informações do serviço

Em seguida, edite a célula no notebook para apontar para o serviço. Em especial, defina as variáveis service_name, deployment_name, location e key para que correspondam às do seu serviço OpenAI:

import os
from pyspark.sql import SparkSession
from synapse.ml.core.platform import running_on_synapse, find_secret

# Bootstrap Spark Session
spark = SparkSession.builder.getOrCreate()

if running_on_synapse():
    from notebookutils.visualization import display

# Fill in the following lines with your service information
# Learn more about selecting which embedding model to choose: https://openai.com/blog/new-and-improved-embedding-model
service_name = "synapseml-openai"
deployment_name = "gpt-35-turbo"
deployment_name_embeddings = "text-embedding-ada-002"

key = find_secret(
    "openai-api-key"
)  # please replace this line with your key as a string

assert key is not None and service_name is not None

Criar um conjunto de dados de prompts

Em seguida, crie um dataframe que consiste em uma série de linhas, com um prompt por linha.

Você também pode carregar dados diretamente do ADLS ou de outros bancos de dados. Para obter mais informações sobre como carregar e preparar dataframes do Spark, consulte o Guia de carregamento de dados do Apache Spark.

df = spark.createDataFrame(
    [
        ("Hello my name is",),
        ("The best code is code thats",),
        ("SynapseML is ",),
    ]
).toDF("prompt")

Criar o cliente do Apache Spark OpenAICompletion

Para aplicar o serviço de Conclusão OpenAI ao dataframe que você acabou de criar, crie um objeto que sirva como um cliente distribuído. Os parâmetros do serviço podem ser definidos com um único valor ou por uma coluna do dataframe com os setters apropriados no OpenAICompletion objeto. Aqui, estamos definindo maxTokens como 200. Um token tem cerca de quatro caracteres e esse limite se aplica à soma do prompt e do resultado. Também estamos definindo o promptCol parâmetro com o nome da coluna de prompt no dataframe.

from synapse.ml.cognitive import OpenAICompletion

completion = (
    OpenAICompletion()
    .setSubscriptionKey(key)
    .setDeploymentName(deployment_name)
    .setCustomServiceName(service_name)
    .setMaxTokens(200)
    .setPromptCol("prompt")
    .setErrorCol("error")
    .setOutputCol("completions")
)

Transformar o dataframe com o cliente OpenAICompletion

Depois de concluir o dataframe e o cliente de conclusão, você pode transformar o conjunto de dados de entrada e adicionar uma coluna chamada completions com todas as informações que o serviço adiciona. Selecione apenas o texto para simplificar.

from pyspark.sql.functions import col

completed_df = completion.transform(df).cache()
display(
    completed_df.select(
        col("prompt"),
        col("error"),
        col("completions.choices.text").getItem(0).alias("text"),
    )
)

A saída deve ter uma aparência semelhante a essa. O texto da conclusão será diferente da amostra.

prompt error text
Olá, meu nome é nulo Makaveli tenho 18 anos e quero ser rapper quando crescer adoro escrever e fazer música sou de Los Angeles, CA
O melhor código é o código que é nulo compreensível Essa é uma instrução subjetiva e não há uma resposta definitiva.
SynapseML é nulo Um algoritmo de aprendizado de máquina que é capaz de aprender a prever o resultado futuro dos eventos.

Mais exemplos de uso

Gerando inserções de texto

Além de concluir o texto, também podemos inserir texto para uso em algoritmos downstream ou arquiteturas de recuperação de vetor. A criação de inserções permite pesquisar e recuperar documentos de grandes coleções e pode ser usada quando a engenharia de prompt não é suficiente para a tarefa. Para obter mais informações sobre como usar OpenAIEmbedding, consulte nosso guia de inserção.

from synapse.ml.cognitive import OpenAIEmbedding

embedding = (
    OpenAIEmbedding()
    .setSubscriptionKey(key)
    .setDeploymentName(deployment_name_embeddings)
    .setCustomServiceName(service_name)
    .setTextCol("prompt")
    .setErrorCol("error")
    .setOutputCol("embeddings")
)

display(embedding.transform(df))

Conclusão de Chat.

Modelos como ChatGPT e GPT-4 são capazes de entender chats em vez de prompts únicos. O transformador OpenAIChatCompletion expõe essa funcionalidade em escala.

from synapse.ml.cognitive import OpenAIChatCompletion
from pyspark.sql import Row
from pyspark.sql.types import *


def make_message(role, content):
    return Row(role=role, content=content, name=role)


chat_df = spark.createDataFrame(
    [
        (
            [
                make_message(
                    "system", "You are an AI chatbot with red as your favorite color"
                ),
                make_message("user", "Whats your favorite color"),
            ],
        ),
        (
            [
                make_message("system", "You are very excited"),
                make_message("user", "How are you today"),
            ],
        ),
    ]
).toDF("messages")


chat_completion = (
    OpenAIChatCompletion()
    .setSubscriptionKey(key)
    .setDeploymentName(deployment_name)
    .setCustomServiceName(service_name)
    .setMessagesCol("messages")
    .setErrorCol("error")
    .setOutputCol("chat_completions")
)

display(
    chat_completion.transform(chat_df).select(
        "messages", "chat_completions.choices.message.content"
    )
)

Melhorar a taxa de transferência com o envio em lote de solicitação

O exemplo acima faz várias solicitações para o serviço, uma para cada prompt. Para concluir vários prompts em uma única solicitação, use o modo de lote. Primeiro, no objeto OpenAI Completion, em vez de definir a coluna Prompt como "Prompt", especifique "batchPrompt" para a coluna BatchPrompt. Para fazer isso, crie um dataframe com uma lista de prompts por linha.

No momento em que texto está sendo escrito, existe um limite de 20 prompts em uma solicitação e um limite de 2048 "tokens", ou aproximadamente 1500 palavras.

batch_df = spark.createDataFrame(
    [
        (["The time has come", "Pleased to", "Today stocks", "Here's to"],),
        (["The only thing", "Ask not what", "Every litter", "I am"],),
    ]
).toDF("batchPrompt")

Em seguida, criamos o objeto OpenAICompletion. Em vez de definir a coluna de prompt, defina a coluna batchPrompt se a coluna for do tipo Array[String].

batch_completion = (
    OpenAICompletion()
    .setSubscriptionKey(key)
    .setDeploymentName(deployment_name)
    .setCustomServiceName(service_name)
    .setMaxTokens(200)
    .setBatchPromptCol("batchPrompt")
    .setErrorCol("error")
    .setOutputCol("completions")
)

Na chamada de transformação, será feita uma solicitação por linha. Como há vários prompts em uma única linha, cada solicitação é enviada com todos os prompts daquela linha. Os resultados conterão uma linha para cada linha na solicitação.

completed_batch_df = batch_completion.transform(batch_df).cache()
display(completed_batch_df)

Usando um mini-lote automático

Se os dados estiverem no formato de coluna, você poderá transpor-os para o formato de linha usando SynapseMLFixedMiniBatcherTransformer.

from pyspark.sql.types import StringType
from synapse.ml.stages import FixedMiniBatchTransformer
from synapse.ml.core.spark import FluentAPI

completed_autobatch_df = (
    df.coalesce(
        1
    )  # Force a single partition so that our little 4-row dataframe makes a batch of size 4, you can remove this step for large datasets
    .mlTransform(FixedMiniBatchTransformer(batchSize=4))
    .withColumnRenamed("prompt", "batchPrompt")
    .mlTransform(batch_completion)
)

display(completed_autobatch_df)

Engenharia de prompt para tradução

O serviço Azure OpenAI pode resolver muitas tarefas de linguagem natural diferentes por meio da engenharia de prompt. Aqui, mostramos um exemplo de solicitação de tradução de idioma:

translate_df = spark.createDataFrame(
    [
        ("Japanese: Ookina hako \nEnglish: Big box \nJapanese: Midori tako\nEnglish:",),
        (
            "French: Quel heure et il au Montreal? \nEnglish: What time is it in Montreal? \nFrench: Ou est le poulet? \nEnglish:",
        ),
    ]
).toDF("prompt")

display(completion.transform(translate_df))

Prompt para resposta de perguntas

Aqui, solicitamos gpt-3 para resposta de perguntas de conhecimento geral:

qa_df = spark.createDataFrame(
    [
        (
            "Q: Where is the Grand Canyon?\nA: The Grand Canyon is in Arizona.\n\nQ: What is the weight of the Burj Khalifa in kilograms?\nA:",
        )
    ]
).toDF("prompt")

display(completion.transform(qa_df))