DataChain é uma moderna biblioteca de quadros de dados Pythonic projetada para inteligência artificial. Ele é feito para organizar seus dados não estruturados em conjuntos de dados e organizá-los em escala em sua máquina local. O Datachain não abstrai ou oculta os modelos de IA e as chamadas de API, mas ajuda a integrá-los à pilha de dados pós-moderna.
Armazenamento como fonte de verdade.
Processe dados não estruturados sem cópias redundantes do S3, GCP, Azure e sistemas de arquivos locais.
Suporte de dados multimodais: imagens, vídeo, texto, PDFs, JSONs, CSVs, parquet.
Reúna arquivos e metadados em conjuntos de dados colunares persistentes e com controle de versão.
Pipelines de dados compatíveis com Python.
Operar em objetos Python e campos de objetos.
Paralelização integrada e computação sem memória sem SQL ou Spark.
Enriquecimento e Processamento de Dados.
Gere metadados usando modelos locais de IA e APIs LLM.
Filtre, junte e agrupe por metadados. Pesquise por incorporações de vetores.
Passe conjuntos de dados para Pytorch e Tensorflow ou exporte-os de volta para o armazenamento.
Eficiência.
Paralelização, cargas de trabalho sem memória e cache de dados.
Operações vetorizadas em campos de objetos Python: soma, contagem, média, etc.
Pesquisa vetorial otimizada.
$ pip instalar cadeia de dados
Um armazenamento consiste em imagens de cães e gatos (dog.1048.jpg, cat.1009.jpg), anotadas com informações básicas e inferências de modelo no formato 'json-pairs', onde cada imagem possui um arquivo JSON correspondente, como cat. 1009.json:
{"class": "cat", "id": "1009", "num_annotators": 8,"inference": {"class": "dog", "confiança": 0,68} }
Exemplo de download apenas de imagens inferidas de "gato de alta confiança" usando metadados JSON:
da coluna de importação de datachain, DataChainmeta = DataChain.from_json("gs://datachain-demo/dogs-and-cats/*json", object_name="meta")images = DataChain.from_storage("gs://datachain-demo /cães-e-gatos/*jpg")images_id = images.map(id=arquivo lambda: arquivo.path.split('.')[-2])annotated = images_id.merge(meta, on="id", right_on="meta.id")likely_cats = annotated.filter((Column("meta.inference .confiança") > 0,93) & (Column("meta.inference.class_") == "cat"))provavelmente_cats.export_files("gatos de alta confiança/", sinal="arquivo")
Inferência em lote com um modelo de sentimento simples usando a biblioteca de transformadores:
pip instalar transformadores
O código abaixo baixa os arquivos da nuvem e aplica uma função definida pelo usuário a cada um deles. Todos os arquivos com sentimento positivo detectado são então copiados para o diretório local.
de transformadores importar pipelinede datachain importar DataChain, Columnclassifier = pipeline("sentiment-análise", dispositivo="cpu",model="distilbert/distilbert-base-uncased-finetuned-sst-2-english")def is_positive_dialogue_ending(file) - > bool:dialogue_ending = file.read()[-512:]return classifier(dialogue_ending)[0]["label"] == cadeia "POSITIVA" = ( DataChain.from_storage("gs://datachain-demo/chatbot-KiT/", object_name="file", type="text") .settings(paralelo=8, cache=True) .map(is_positivo=is_positivo_dialogue_ending) .save("resposta_arquivo") )positiva_chain = chain.filter(Column("is_positivo") == True)positiva_chain.export_files("./output")print(f"{positiva_chain.count()} arquivos foram exportados")
13 arquivos foram exportados
$ ls saída/datachain-demo/chatbot-KiT/ 15.txt 20.txt 24.txt 27.txt 28.txt 29.txt 33.txt 37.txt 38.txt 43.txt ... $ ls saída/datachain-demo/chatbot-KiT/ | wc-l 13
LLMs podem funcionar como classificadores universais. No exemplo abaixo, empregamos uma API gratuita da Mistral para julgar os diálogos do chatbot disponíveis publicamente. Obtenha uma chave de API Mistral gratuita em https://console.mistral.ai
$ pip install mistralai (requer versão >=1.0.0) $ exportar MISTRAL_API_KEY=_sua_chave_
DataChain pode paralelizar chamadas de API; o nível gratuito Mistral suporta até 4 solicitações ao mesmo tempo.
from mistralai import Mistralfrom datachain import File, DataChain, ColumnPROMPT = "Esta caixa de diálogo foi bem-sucedida? Responda em uma única palavra: Sucesso ou Falha."def eval_dialogue(file: File) -> bool: client = Mistral() response = client.chat .complete( model="open-mixtral-8x22b", mensagens=[{"role": "sistema", "conteúdo": PROMPT}, {"role": "usuário", "content": file.read()}]) resultado = resposta.choices[0].message.content return resultado.lower().startswith("success")chain = ( DataChain .from_storage("gs://datachain-demo/chatbot-KiT/", object_name="arquivo") .settings(paralelo=4, cache=True) .map(is_success=eval_dialogue) .save("mistral_files") )successful_chain = chain.filter(Column("is_success") == True)successful_chain.export_files("./output_mistral")print(f"{successful_chain.count()} arquivos foram exportados")
Com a instrução acima, o modelo Mistral considera arquivos 31/50 para conter os diálogos bem-sucedidos:
$ ls saída_mistral/datachain-demo/chatbot-KiT/ 1.txt 15.txt 18.txt 2.txt 22.txt 25.txt 28.txt 33.txt 37.txt 4.txt 41.txt ... $ ls saída_mistral/datachain-demo/chatbot-KiT/ | wc-l 31
As respostas LLM podem conter informações valiosas para análise – como o número de tokens usados ou os parâmetros de desempenho do modelo.
Em vez de extrair essas informações da estrutura de dados de resposta Mistral (classe ChatCompletionResponse), o DataChain pode serializar toda a resposta LLM para o banco de dados interno:
from mistralai import Mistralfrom mistralai.models import ChatCompletionResponsefrom datachain import File, DataChain, ColumnPROMPT = "Esta caixa de diálogo foi bem-sucedida? Responda em uma única palavra: Sucesso ou Falha."def eval_dialog(file: File) -> ChatCompletionResponse: client = MistralClient() return client.chat( model="open-mixtral-8x22b", mensagens=[{"role": "system", "conteúdo": PROMPT}, {"role": "usuário", "content": file.read()}])chain = ( DataChain.from_storage("gs://datachain-demo/chatbot-KiT/", object_name="file") .settings(paralelo=4, cache=Verdadeiro) .map(resposta=eval_dialog) .map(status=resposta lambda: resposta.choices[0].message.content.lower()[:7]) .save("resposta") )chain.select("file.name", "status", "response.usage").show(5)success_rate = chain.filter(Column("status") == "success").count() / chain .count()print(f"{100*success_rate:.1f}% diálogos foram bem-sucedidos")
Saída:
resposta de resposta de status de arquivo resposta uso de uso de nome uso prompt_tokens total_tokens complete_tokens 0 1.txt sucesso 547 548 1 1 falha 10.txt 3576 3578 2 2 11.txt falha 626 628 2 3 falha em 12.txt 1144 1182 38 4 13.txt sucesso 1100 1101 1 [Limitado a 5 linhas] 64,0% dos diálogos foram bem-sucedidos
Nos exemplos anteriores, os conjuntos de dados foram salvos no banco de dados incorporado (SQLite na pasta .datachain do diretório de trabalho). Esses conjuntos de dados foram versionados automaticamente e podem ser acessados usando DataChain.from_dataset("dataset_name").
Veja como recuperar um conjunto de dados salvo e iterar sobre os objetos:
chain = DataChain.from_dataset("response")# Iterando um por um: suporta fluxo de trabalho sem memória para arquivo, resposta em chain.limit(5).collect("file", "response"):# verifique o objetos Python coletadosassert isinstance(response, ChatCompletionResponse)status = response.choices[0].message.content[:7]tokens = response.usage.total_tokensprint(f"{file.get_uri()}: {status}, tamanho do arquivo: {file.size}, tokens: {tokens}")
Saída:
gs://datachain-demo/chatbot-KiT/1.txt: Sucesso, tamanho do arquivo: 1776, tokens: 548 gs://datachain-demo/chatbot-KiT/10.txt: Falha, tamanho do arquivo: 11576, tokens: 3578 gs://datachain-demo/chatbot-KiT/11.txt: Falha, tamanho do arquivo: 2045, tokens: 628 gs://datachain-demo/chatbot-KiT/12.txt: Falha, tamanho do arquivo: 3833, tokens: 1207 gs://datachain-demo/chatbot-KiT/13.txt: Sucesso, tamanho do arquivo: 3657, tokens: 1101
Algumas operações podem ser executadas dentro do banco de dados sem desserialização. Por exemplo, vamos calcular o custo total de uso das APIs LLM, assumindo que a chamada Mixtral custa US$ 2 por 1 milhão de tokens de entrada e US$ 6 por 1 milhão de tokens de saída:
cadeia = DataChain.from_dataset("mistral_dataset")custo = chain.sum("response.usage.prompt_tokens")*0,000002 + chain.sum("response.usage.completion_tokens")*0.000006print(f"Gasto ${cost:.2f} em chamadas {chain.count()}")
Saída:
Gastei $ 0,08 em 50 ligações
Os resultados da cadeia podem ser exportados ou passados diretamente para o dataloader PyTorch. Por exemplo, se estivermos interessados em passar uma imagem e um rótulo com base no sufixo do nome do arquivo, o código a seguir fará isso:
de torch.utils.data importar DataLoaderfrom transformadores importar CLIPProcessorfrom datachain importar C, DataChainprocessor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")chain = (DataChain.from_storage("gs://datachain-demo/dogs -e-gatos/", type="imagem") .map(rótulo=nome lambda: nome.split(".")[0], params=["arquivo.nome"]) .select("arquivo", "rótulo").to_pytorch(transform=processor.image_processor,tokenizer=processor.tokenizer, ) )loader = DataLoader(cadeia, batch_size=1)
Começando
Multimodal (experimente no Colab)
Avaliações LLM (experimente no Colab)
Lendo metadados JSON (tente no Colab)
Contribuições são muito bem-vindas. Para saber mais, consulte o Guia do Colaborador.
Documentos
Registre um problema se encontrar algum problema
Bate-papo de discórdia