TL;DR
Metin verileriniz için tipik Doğal Dil İşleme görevlerini (sınıflandırma, duyarlılık analizi vb.) LLM kullanarak 1 milyon satır başına 10 ABD doları kadar ucuza (göreve ve modele bağlıdır) otomatik olarak çözebilir ve dbt ortamınızda kalabilirsiniz. Talimatlar, ayrıntılar ve kod aşağıdadır
Dönüştürme katmanınız olarak dbt kullanıyorsanız, yapılandırılmamış metin verilerinden anlamlı bilgiler çıkarmak istediğiniz bir durumla karşılaşabilirsiniz. Bu tür veriler müşteri incelemelerini, başlıkları, açıklamaları, Google Analytics kaynaklarını/araçlarını vb. içerebilir. Bunları gruplar halinde kategorilere ayırmak veya duyguları ve tonları almak isteyebilirsiniz.
Potansiyel çözümler şunlar olabilir:
Python dbt modelleri geliştikçe bir çözüm daha var: Bu Doğal Dil İşleme görevlerini dbt modellerinden biri olarak dbt ortamınızda tutabilirsiniz.
Bu sizin için yararlı olabilirse dbt projenizde OpenAI API'yi nasıl kullanacağınıza ilişkin adım adım kılavuza bakın. GitHub deposundaki kod ve veri örneğini alarak bu kılavuzdaki her şeyi ortamınızda çoğaltabilirsiniz (sondaki bağlantılara bakın).
Zaten bir dbt projeniz ve verileriniz varsa veya sonuçları yeniden oluşturmak istemiyorsanız (4)'e geçin veya bu bölümü tamamen atlayın. Aksi takdirde aşağıdakilere ihtiyacınız olacaktır:
Dbt projesini ayarlayın . Resmi belgeler
Bu kılavuz için hazırladığımı GitHub'dan kolayca kopyalayabilirsiniz.
Profiles.yml dosyanızı oluşturmayı/güncellemeyi unutmayın.
Veritabanını ayarlayın . Snowflake'i kullandım. Ne yazık ki ücretsiz bir sürümü yok ancak 30 günlük ücretsiz deneme süresi sunuyorlar.
Şu anda dbt Python modelleri yalnızca Snowflake, Databricks ve BigQuery (PostgreSQL yok) ile çalışmaktadır. Bu nedenle, bazı ayrıntılar farklılık gösterse de, bu eğitim bunlardan herhangi biri için işe yarayacaktır.
Kaynak verilerini hazırlayın
Veri kümesi olarak TidyTuesday deposunda yayınlanan bir R paketi meta verilerini kullandım.
Veritabanınıza yükleyin.
Veritabanınız ve şema adlarınızla eşleşecek şekilde dbt projesindeki source.yml
dosyasını güncelleyin.
OpenAI API anahtarını edinin
Resmi belgelerdeki hızlı başlangıç talimatlarını izleyin.
Not: Ücretsiz değildir ancak kullandıkça öde yöntemidir. Dolayısıyla, 10 satırlık test veri kümesiyle, denemeleriniz sırasında sizden 1 ABD dolarından fazla ücret alınmaz.
Daha dikkatli olmak için bir harcama limiti belirleyin.
Snowflake'te Harici Erişim Entegrasyonunu Ayarlama
İlk olarak, eğer bir sınıflandırma görevini çözüyorsanız, LLM isteminizde kullanmak için kategorilere (diğer adıyla sınıflara) ihtiyacınız vardır. Temel olarak şöyle diyeceksiniz: "Bu kategorilerin bir listesi var, bu metnin hangisine ait olduğunu tanımlayabilir misiniz?"
Buradaki bazı seçenekler:
Önceden tanımlanmış kategorilerin bir listesini manuel olarak oluşturun
Sabit ve öngörülebilir kategorilere ihtiyacınız varsa uygundur.
Buraya "Diğerleri" eklemeyi unutmayın, böylece Yüksek Lisans belirsiz olduğunda bu seçeneklere sahip olacaktır.
İsteminizde LLM'den "Diğerleri" kategorisini kullandığında bir kategori adı önermesini isteyin.
Önceden tanımlanmış bir listeyi veritabanının ham katmanına veya dbt projenize CSV olarak yükleyin ( dbt seed
kullanarak).
Verilerinizin bir örneğini LLM'ye gönderin ve ondan N kategori bulmasını isteyin.
Önceki yaklaşımla aynı, ancak liste konusunda yardım alıyoruz.
GPT kullanıyorsanız, tekrarlanabilirlik açısından burada tohum kullanmak daha iyidir.
Önceden tanımlanmış kategoriler olmadan gidin ve LLM'nin işi hareket halindeyken yapmasına izin verin.
Bu daha az öngörülebilir sonuçlara yol açabilir.
Aynı zamanda, eğer bir rastlantısallık payına sahipseniz bu da yeterince iyidir.
GPT kullanım durumunda, yeniden çalıştırmanız gerekmesi durumunda farklı sonuçlardan kaçınmak için sıcaklık = 0 değerini ayarlamak daha iyidir.
Bu blog yazısında 3. seçeneği kullanacağım.
Şimdi bu yazının ana kısmına geçelim ve yukarı akış tablosundan yeni metin verilerini alacak, bunu OpenAI API'sine besleyecek ve kategoriyi tabloya kaydedecek bir dbt modeli oluşturalım.
Yukarıda bahsettiğim gibi R paketleri veri kümesini kullanacağım. R, veri analizinde oldukça popüler bir programlama dilidir. Bu veri kümesi, CRAN projesindeki R paketleri hakkında sürüm, lisans, yazar, başlık, açıklama vb. bilgileri içerir. Her paket için başlığına göre bir kategori oluşturacağımız için title
alanıyla ilgileniyoruz.
Modelin tabanını hazırlayın
dbt config, dbt.config(...)
yöntemi aracılığıyla aktarılabilir.
dbt.config dosyasında ek argümanlar vardır; örneğin, packages
bir paket gereksinimidir.
dbt Python modeli, yukarı akış modellerine referans verebilir dbt.ref('...')
veya dbt.source('...')
Bir DataFrame döndürmesi gerekir. Veritabanınız onu tablo olarak kaydedecektir.
import os import openai import pandas as pd COL_TO_CATEGORIZE = 'title' def model(dbt, session): import _snowflake dbt.config( packages=['pandas', 'openai'], ) df = dbt.ref('package').to_pandas() df.drop_duplicates(subset=[COL_TO_CATEGORIZE], inplace=True) return df
OpenAI API'sine bağlanın
secrets
ve external_access_integrations
dbt.config'e aktarmamız gerekiyor. Snowflake Harici Erişim Entegrasyonunuzda saklanan gizli referansı içerecektir.
Not: Bu özellik yalnızca birkaç gün önce yayımlandı ve yalnızca beta dbt sürüm 1.8.0-b3'te mevcut.
dbt.config( packages=['pandas', 'openai'], secrets={'openai_key': 'openai_key', 'openai_org': 'openai_org'}, external_access_integrations=['openai_external_access_integration'], ) client = openai.OpenAI( api_key=_snowflake.get_generic_secret_string('openai_key'), organization=_snowflake.get_generic_secret_string('openai_org'), )
Dbt modelini artımlı yapın ve tam yenilemeleri kapatın.
dbt run
her çalıştırdığınızda OpenAI'ye tüm verileri gönderirsiniz.materialized='incremental'
, incremental_strategy='append'
, full_refresh = False
ekliyoruz. dbt.config( materialized='incremental', incremental_strategy='append', full_refresh = False, packages=['pandas', 'openai'], secrets={'openai_key': 'openai_key', 'openai_org': 'openai_org'}, external_access_integrations=['openai_external_access_integration'], ) if dbt.is_incremental: pass
Artımlılık mantığı ekleyin
dbt.this
kullanarak yapabiliriz. Normal artımlı modellere benzer. if dbt.is_incremental: categorized_query = f''' SELECT DISTINCT "{ COL_TO_CATEGORIZE }" AS primary_key FROM { dbt.this } WHERE "category" IS NOT NULL ''' categorized = [row.PRIMARY_KEY for row in session.sql(categorized_query).collect()] df = df.loc[~df[COL_TO_CATEGORIZE].isin(categorized), :]
Toplu olarak OpenAI API'yi çağırın
max_tokens
kısıtlamasını ekledim. BATCH_SIZE = 5 n_rows = df.shape[0] categories = [None for idx in range(n_rows)] for idx in range(0, n_rows, BATCH_SIZE): df_sliced = df.iloc[idx:idx+BATCH_SIZE, :] user_prompt = f'```{ "|".join(df_sliced[COL_TO_CATEGORIZE].to_list()) }```' chat_completion = client.chat.completions.create( messages=[ {'role': 'system', 'content': SYSTEM_PROMPT}, {'role': 'user', 'content': user_prompt} ], model='gpt-3.5-turbo', temperature=0, max_tokens=10*BATCH_SIZE + 2*BATCH_SIZE, ) gpt_response = chat_completion.choices[0].message.content gpt_response = [category.strip() for category in gpt_response.split('|')] categories[idx:idx + len(gpt_response)] = gpt_response df['category'] = categories df.dropna(subset=['category'], inplace=True)
LLM için bir istem hakkında konuşmanın zamanı geldi. Elimde şu var:
Size ``` parantez içinde CRAN R paket başlıklarının bir listesi verilecektir. Başlıklar "|" ile ayrılacaktır imza. Her başlık için bir kategori bulun. Yalnızca "|" ile ayrılmış kategori adlarını döndür imza.
Son dbt model kodu
import os import openai import pandas as pd SYSTEM_PROMPT = '''You will be provided a list of CRAN R package titles in ``` brackets. Titles will be separated by "|" sign. Come up with a category for each title. Return only category names separated by "|" sign. ''' COL_TO_CATEGORIZE = 'title' BATCH_SIZE = 5 def model(dbt, session): import _snowflake dbt.config( materialized='incremental', incremental_strategy='append', full_refresh = False, packages=['pandas', 'openai'], secrets={'openai_key': 'openai_key', 'openai_org': 'openai_org'}, external_access_integrations=['openai_external_access_integration'], ) client = openai.OpenAI( api_key=_snowflake.get_generic_secret_string('openai_key'), organization=_snowflake.get_generic_secret_string('openai_org'), ) df = dbt.ref('package').to_pandas() df.drop_duplicates(subset=[COL_TO_CATEGORIZE], inplace=True) if dbt.is_incremental: categorized_query = f''' SELECT DISTINCT "{ COL_TO_CATEGORIZE }" AS primary_key FROM { dbt.this } WHERE "category" IS NOT NULL ''' categorized = [row.PRIMARY_KEY for row in session.sql(categorized_query).collect()] df = df.loc[~df[COL_TO_CATEGORIZE].isin(categorized), :] n_rows = df.shape[0] categories = [None for idx in range(n_rows)] for idx in range(0, n_rows, BATCH_SIZE): df_sliced = df.iloc[idx:idx+BATCH_SIZE, :] user_prompt = f'```{ "|".join(df_sliced[COL_TO_CATEGORIZE].to_list()) }```' chat_completion = client.chat.completions.create( messages=[ {'role': 'system', 'content': SYSTEM_PROMPT}, {'role': 'user', 'content': user_prompt} ], model='gpt-3.5-turbo', temperature=0, max_tokens=10*BATCH_SIZE + 2*BATCH_SIZE, ) gpt_response = chat_completion.choices[0].message.content gpt_response = [category.strip() for category in gpt_response.split('|')] categories[idx:idx + len(gpt_response)] = gpt_response df['category'] = categories df.dropna(subset=['category'], inplace=True) return df
OpenAI API Fiyatlandırması burada listelenmiştir. Talep edilen ve iade edilen jeton sayısına göre ücret alırlar. Belirteç, isteğinizdeki bir dizi karakterle ilişkilendirilen bir örnektir. Belirli bir metin için bir dizi belirteci değerlendirmek için açık kaynak paketleri vardır. Örneğin Tiktoken . Manuel olarak değerlendirmek isterseniz gidilecek yer burada resmi bir OpenAI tokenizerdır.
Veri setimizde ~18K başlık bulunmaktadır. Kabaca, 320.000 giriş tokenına (parti boyutu = 5 kullanırsak 180.000 başlık ve 140.000 sistem istemi) ve 50.000 çıkış tokenına eşittir. Modele bağlı olarak tam taramanın maliyeti şu şekilde olacaktır:
GPT-4 Turbo
: 4,7 dolar . Fiyatlandırma: girdi: 10$ / 1 milyon token; çıktı: 30 $ / 1 milyon jeton.GPT-4
: 12,6 dolar. Fiyatlandırma: girdi: 30 ABD doları / 1 milyon token; çıktı: 60 $ / 1 milyon jeton.GPT-3.5 Turbo
: 0,2 ABD doları. Fiyatlandırma: girdi: 0,5 ABD Doları / 1 milyon token; çıktı: 1,5 ABD doları / 1 milyon jeton.Dbt modeli bir cazibe gibi çalıştı. 18K paketlerin tamamını boşluk bırakmadan başarıyla kategorize ettim. Modelin uygun maliyetli olduğu ve birden fazla dbt çalıştırılmasına karşı korunduğu kanıtlandı.
Sonuç kontrol panelini burada Tableau Public'te yayınladım. Onunla oynamaktan, verileri indirmekten ve bunun üzerinde dilediğinizi oluşturmaktan çekinmeyin.
Bulduğum bazı ilginç ayrıntılar:
Data Visualization
(1.190 paket veya %6). Sanırım bu, özellikle Shiny, Plotly ve diğerleri gibi paketlerde R'nin bir görselleştirme aracı olarak popülerliğini kanıtlıyor.
Data Import
ve Data Processing
oldu. Görünüşe göre R daha çok bir veri işleme aracı olarak kullanılmaya başlandı.
Natural Language Processing
gerçekleşti. Ünlü "Attention Is All You Need" makalesinden iki yıl sonra ve GPT-1'in yayınlanmasından altı ay sonra :)Alternatif bir yaklaşım kullanabiliriz: GPT yerleştirmeleri .
Çok daha ucuz.
Ancak daha çok mühendislik ağırlıklı çünkü sınıflandırma kısmını kendi başınıza yapmalısınız (bu seçeneği sonraki yazılardan birinde inceleyeceğim için bizi takip etmeye devam edin).
Elbette bu kısmı dbt'den çıkarıp bulut işlevlerine veya kullandığınız altyapıya aktarmak mantıklı olacaktır. Aynı zamanda, eğer onu dbt altında tutmak istiyorsanız - bu yazı tam size göre.
Modele herhangi bir mantık eklemekten kaçının. Tek bir iş yapmalı: LLM'yi arayın ve sonucu kaydedin. Bu, tekrar çalıştırmaktan uzak durmanıza yardımcı olacaktır.
Dbt projenizde birçok ortamı kullanma olasılığınız yüksektir. Dikkatli olmanız ve bu modeli her geliştirici ortamında her Çekme İsteğinde tekrar tekrar çalıştırmaktan kaçınmanız gerekir.
Bunu yapmak için, mantığı if dbt.config.get("target_name") == 'dev'
ile birleştirebilirsiniz.
Sınırlayıcıyla verilen yanıt kararsız olabilir.
Örneğin, GPT beklediğinizden daha az öğe döndürebilir ve ilk başlıkları kategori listesiyle eşleştirmek zor olacaktır.
Bunun üstesinden gelmek için JSON çıktısını gerektirecek şekilde isteğinize response_format={ "type": "json_object" }
ekleyin. Resmi belgelere bakın.
JSON çıktısıyla, {"title": "category"} biçiminde bir yanıt sağlamanızı isteyebilir ve ardından bunu başlangıç değerlerinizle eşleştirebilirsiniz.
Yanıt boyutunu artıracağından daha pahalı olacağını unutmayın.
Garip bir şekilde, GPT 3.5 Turbo için JSON'a geçtiğimde sınıflandırma kalitesi önemli ölçüde düştü.
Snowflake'te cortex.complete() işlevini kullanan bir alternatif var. Dbt blogunda Joel Labes'in harika gönderisine göz atın.
Bu kadar! Ne düşündüğü söyle.
GitHub'daki kodun tamamı: bağlantı
Tableau Genel kontrol paneli: bağlantı
TidyTuesday R veri kümesi:bağlantı