paint-brush
Büyük Dil Modelleriyle dbt Projenizi Nasıl Geliştirebilirsiniz?ile@klimmy
465 okumalar
465 okumalar

Büyük Dil Modelleriyle dbt Projenizi Nasıl Geliştirebilirsiniz?

ile Kliment Merzlyakov15m2024/06/02
Read on Terminal Reader

Çok uzun; Okumak

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), dbt ortamınızda kalarak otomatik olarak çözebilirsiniz. Talimatlar, ayrıntılar ve kod aşağıdadır
featured image - Büyük Dil Modelleriyle dbt Projenizi Nasıl Geliştirebilirsiniz?
Kliment Merzlyakov HackerNoon profile picture
0-item
1-item



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:

  • Makine öğrenimi modellerini dbt akışının dışına uygulayın (veya bir LLM'yi arayın)
  • CASE WHEN ifadelerini kullanarak dbt modelleri içindeki basit kategorizasyonları tanımlayın
  • Kategorileri önceden tanımlayın ve bunları ham veritabanı katmanınıza yükleyin veya dbt çekirdek işlevinden yararlanın


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).

Ortamı Ayarlayı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:


  1. Dbt projesini ayarlayın . Resmi belgeler

    1. Bu kılavuz için hazırladığımı GitHub'dan kolayca kopyalayabilirsiniz.

    2. Profiles.yml dosyanızı oluşturmayı/güncellemeyi unutmayın.


  2. 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.

    1. Ş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.


  3. Kaynak verilerini hazırlayın

    1. Veri kümesi olarak TidyTuesday deposunda yayınlanan bir R paketi meta verilerini kullandım.

      1. Buradan indirebilirsiniz . Veri kümesiyle ilgili ayrıntılarburada
      2. Alternatif olarak, buradaki depomdaki hafif bir sürümü kullanabilirsiniz.
    2. Veritabanınıza yükleyin.

    3. Veritabanınız ve şema adlarınızla eşleşecek şekilde dbt projesindeki source.yml dosyasını güncelleyin.


  4. OpenAI API anahtarını edinin

    1. Resmi belgelerdeki hızlı başlangıç talimatlarını izleyin.

    2. 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.

    3. Daha dikkatli olmak için bir harcama limiti belirleyin.


  5. Snowflake'te Harici Erişim Entegrasyonunu Ayarlama

    1. Bu yalnızca Snowflake kullanıyorsanız geçerlidir.
    2. Bu yapılmazsa dbt Python modelleri internetteki hiçbir API'ye (OpenAI API dahil) erişemez.
    3. Resmi talimatları izleyin.
    4. OpenAI API anahtarını bu entegrasyonda saklayın.

Bir Kategori Listesi Oluşturun

İ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:

  1. Önceden tanımlanmış kategorilerin bir listesini manuel olarak oluşturun

    1. Sabit ve öngörülebilir kategorilere ihtiyacınız varsa uygundur.

    2. Buraya "Diğerleri" eklemeyi unutmayın, böylece Yüksek Lisans belirsiz olduğunda bu seçeneklere sahip olacaktır.

    3. İsteminizde LLM'den "Diğerleri" kategorisini kullandığında bir kategori adı önermesini isteyin.

    4. Önceden tanımlanmış bir listeyi veritabanının ham katmanına veya dbt projenize CSV olarak yükleyin ( dbt seed kullanarak).


  2. Verilerinizin bir örneğini LLM'ye gönderin ve ondan N kategori bulmasını isteyin.

    1. Önceki yaklaşımla aynı, ancak liste konusunda yardım alıyoruz.

    2. GPT kullanıyorsanız, tekrarlanabilirlik açısından burada tohum kullanmak daha iyidir.


  3. Önceden tanımlanmış kategoriler olmadan gidin ve LLM'nin işi hareket halindeyken yapmasına izin verin.

    1. Bu daha az öngörülebilir sonuçlara yol açabilir.

    2. Aynı zamanda, eğer bir rastlantısallık payına sahipseniz bu da yeterince iyidir.

    3. 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.

OpenAI API'sini Çağırmak için bir dbt Python Modeli oluşturun

Ş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.


  1. 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
  2. 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'), )
  3. Dbt modelini artımlı yapın ve tam yenilemeleri kapatın.

    • Bu bölüm OpenAI API maliyetlerini düşük tutmak için gereklidir.
    • Aynı metni birden çok kez kategorize etmesini önleyecektir.
    • Aksi takdirde, günde birkaç kez olabilen dbt run her çalıştırdığınızda OpenAI'ye tüm verileri gönderirsiniz.
    • Dbt.config dosyasına materialized='incremental' , incremental_strategy='append' , full_refresh = False ekliyoruz.
    • Artık tam tarama yalnızca ilk dbt çalıştırması için olacak ve daha sonraki çalıştırmalar için (artımlı veya tam yenileme fark etmez) yalnızca deltayı kategorilere ayıracaktır.
    • Daha dikkatli olmak istiyorsanız, benzersiz girişlerin sayısını azaltmak için verilerinizi biraz ön işleme tabi tutabilirsiniz, ancak LLM'ler doğal dille daha iyi çalıştığı için çok fazla ön işleme yapmaktan kaçının.
     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


  4. Artımlılık mantığı ekleyin

    • Artımlı çalıştırmada (kurulumumuz nedeniyle, ilki dışındaki tüm çalıştırmalarda anlamına gelir), zaten kategorize edilmiş tüm başlıkları kaldırmamız gerekir.
    • Bunu sadece 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), :]
  5. Toplu olarak OpenAI API'yi çağırın

    • Maliyetleri azaltmak için verileri OpenAI API'ye toplu olarak göndermek daha iyidir.
    • Sistem istemi, sınıflandırmamız gereken metinden 5 kat daha büyük olabilir. Her oyun için ayrı ayrı sistem istemi gönderirsek, tekrarlanan şeyler için çok daha yüksek token kullanımına yol açacaktır.
    • Ancak partinin büyük olmaması gerekiyor. Büyük partilerde GPT daha az istikrarlı sonuçlar üretmeye başlar. Deneylerime göre parti büyüklüğü = 5 yeterince iyi çalışıyor.
    • Ayrıca yanıtın ilgili boyutu aşmamasını sağlamak için 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)


  6. 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.


  • Talimatı doğrudan noktaya tutun.
  • SQL enjeksiyonlarından kaçınmak için ``` tekniğini kullanın.
  • Sonuç formatı konusunda net olun. Benim durumumda "|" istedim hem giriş hem de çıkışlar için ayırıcı olarak


  1. 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

Maliyet Tahminleri

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:


  1. GPT-4 Turbo : 4,7 dolar . Fiyatlandırma: girdi: 10$ / 1 milyon token; çıktı: 30 $ / 1 milyon jeton.
  2. GPT-4 : 12,6 dolar. Fiyatlandırma: girdi: 30 ABD doları / 1 milyon token; çıktı: 60 $ / 1 milyon jeton.
  3. 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.

Sonuçlar

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:


  • İlk 1 kategori 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.


  • 2023'te en çok büyüyen iki kategori 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ı.


  • İlk 30 kategori arasında yıldan yıla en büyük büyüme 2019'da 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 :)

Diğer Fikirler

  1. 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).


  2. 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.


  3. 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.


  4. 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.


  5. 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ü.


  6. 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.

Bağlantılar

GitHub'daki kodun tamamı: bağlantı

Tableau Genel kontrol paneli: bağlantı

TidyTuesday R veri kümesi:bağlantı