İnce Ayar LLM Modelleri İçin Veri Seti Oluşturma
Başlıkta belirttiğim gibi, kendi araştırmalarıma göre şu ana kadar LLM modellerini ince ayar yapmak için paylaşılmış bu büyüklükte türkçe bir veri seti bulunmuyor. Bu veri seti açığını kapatmak amacıyla technopat.net forumundan web scraping araçlarıyla veri kazındı. Veri seti toplam 2.5 milyon konudan ve ortalama 18 milyon cevaptan oluşuyor. Kazınma aşamalarına geçersek:
Veri Seti: Huggingface Bağlantısı
1. Adım: Link Toplama
Forumun sitemap’ından tüm konu linkleri çekilip toplandı. Tüm konu linkleri elimizdeydi ancak çoğu konu birden fazla sayfadan oluşuyordu. Bu yüzden, konuların ana sayfa dışındaki sayfalarına da ihtiyacımız vardı.
2. Adım: URL Oluşturma
Konuların ana sayfalarından mesaj sayısını çekip, ona göre konunun kaç sayfa olduğunu hesaplayan ve ardından URL’leri oluşturup bir txt dosyasına kaydeden bir script yazıldı. Bu işlemin bitmesi yaklaşık bir hafta sürdü. Şimdi bu oluşturulan URL’lerden konu isimlerini ve mesajları çekecek bir script yazmamız gerekiyordu.
3. Adım: Veri Çekme
Konu isimlerini ve mesajları çekecek script yazıldı ve kendi halinde çalışmaya bırakıldı. Bu aşamada en büyük düşmanım Cloudflare oldu. Cloudflare ve “mükemmel çalışan insan olduğunuzu doğrulayın” kutucukları işimi çok zorlaştırdı. Ara sıra forumun serverı kaldırmadı ve birkaç saat boyunca 501 hatası aldık. Neyse ki, 2 hafta sonunda parça parça da olsa tüm forum konuları JSON formatında elimizdeydi. Bu aşamada daha rahat çalışabilmek için Google Colab Enterprise kullandım, bu da işimi oldukça kolaylaştırdı.
Kullanılan Scriptler
Mesaj Sayısını Çekip Yeni URL’leri Oluşturan Script
!pip install python-telegram-bot
import requests
from bs4 import BeautifulSoup
from tqdm import tqdm
import concurrent.futures
import multiprocessing
import time
import telegram
import asyncio
import nest_asyncio
# Jupyter Notebook'un event loop'unu iç içe yerleştirme
nest_asyncio.apply()
# Telegram bot tokenınızı ve chat ID'nizi ekleyin
bot_token = "YOUR_BOT_TOKEN"
chat_id = "YOUR_CHAT_ID"
async def send_telegram_message(message):
"""Telegram API ile mesaj gönderir."""
try:
bot = telegram.Bot(token=bot_token)
await bot.sendMessage(chat_id=chat_id, text=message)
except Exception as e:
print(f"Telegram mesajı gönderilirken hata oluştu: {e}")
def fetch_url(url):
try:
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')
return soup
except Exception as e:
print(f"Hata: {e}")
return None
def process_url(url):
try:
soup = fetch_url(url)
if soup:
mesaj_sayisi_elementi = soup.find('li', {'title': 'Mesaj'})
if mesaj_sayisi_elementi:
mesaj_sayisi_raw = mesaj_sayisi_elementi.get_text(strip=True)
mesaj_sayisi = ''.join(filter(str.isdigit, mesaj_sayisi_raw))
mesaj_sayisi = int(mesaj_sayisi)
if mesaj_sayisi > 10:
sayfa_sayisi = mesaj_sayisi // 10 + 1
with open('/content/yeniurl.txt', 'a') as yeni_url_file:
yeni_url_file.write(f"{url}\n")
for sayfa in range(2, sayfa_sayisi + 1):
yeni_url = f"{url}page-{sayfa}"
with open('/content/yeniurl.txt', 'a') as yeni_url_file:
yeni_url_file.write(f"{yeni_url}\n")
else:
with open('/content/yeniurl.txt', 'a') as yeni_url_file:
yeni_url_file.write(f"{url}\n")
with open('/content/logyeni.txt', 'a') as output_file:
output_file.write(f"{url}: {mesaj_sayisi}\n")
else:
with open('/content/logyeni.txt', 'a') as output_file:
output_file.write(f"{url}: Mesaj sayısı bulunamadı\n")
except Exception as e:
with open('/content/logyeni.txt', 'a') as output_file:
output_file.write(f"{url}: Hata - {str(e)}\n")
async def main():
urls = []
with open('/content/urlss.txt', 'r') as file:
urls = file.readlines()
urls = [url.strip() for url in urls]
start_time = time.time()
processed_urls = 0
total_urls = len(urls)
with concurrent.futures.ProcessPoolExecutor(max_workers=5 * multiprocessing.cpu_count()) as executor:
for _ in tqdm(executor.map(process_url, urls), total=total_urls):
processed_urls += 1
elapsed_time = time.time() - start_time
if elapsed_time >= 600: # 10 dakika (600 saniye)
message = f"İlerleme: {processed_urls}/{total_urls}"
await send_telegram_message(message)
start_time = time.time() # Zamanlayıcıyı sıfırla
if __name__ == "__main__":
asyncio.run(main())
Mesajları Ve Konuları Çeken Script
import httpx
from bs4 import BeautifulSoup
import json
from concurrent.futures import ThreadPoolExecutor, as_completed
from tqdm import tqdm
import multiprocessing
import time
# URL'leri içeren txt dosyasının yolunu belirtin
file_path = '/content/url.txt'
# URL'leri txt dosyasından okuyun
with open(file_path, 'r') as file:
url_list = [line.strip() for line in file if line.strip()]
disclaimer = "'zynp_msgdata' veri seti 'sekerlipencere' tarafından hazırlanmıştır."
cpu_count = multiprocessing.cpu_count()
max_workers = cpu_count * 300 # İşlemci çekirdek sayısının 20 katı kadar iş parçacığı oluştur
def fetch_content(url):
try:
with httpx.Client(timeout=5) as client:
response = client.get(url)
response.raise_for_status()
return url, response.text
except Exception as e:
print(f"URL alınamadı: {url} - Hata: {e}")
return url, None
def process_content(url_content):
url, webpage = url_content
if webpage is None:
return None
try:
soup = BeautifulSoup(webpage, 'html.parser')
soru_div = soup.find('div', class_='p-title')
if soru_div:
soru = soru_div.get_text(strip=True)
ayrintili_soru_div = soup.find('div', class_='bbWrapper')
ayrintili_soru = ayrintili_soru_div.get_text(strip=True) if ayrintili_soru_div else ''
cevap_divs = soup.find_all('div', class_='bbWrapper')[1:]
cevaplar = [cevap.get_text(strip=True) for cevap in cevap_divs]
return {
'soru': soru,
'url': url,
'ayrintili_soru': ayrintili_soru,
'cevaplar': cevaplar,
'atıf': disclaimer
}
except Exception as e:
print(f"İçerik işlenirken hata oluştu: {url} - Hata: {e}")
return None
def write_to_json(result):
if result:
with open('sonuc.json', 'a', encoding='utf-8') as f:
json.dump(result, f, ensure_ascii=False, indent=4)
f.write('\n')
def main():
batch_size = 500 # Toplu işleme için isteklerin gruplanacağı boyut
with ThreadPoolExecutor(max_workers=max_workers) as executor:
for i in range(0, len(url_list), batch_size):
batch_urls = url_list[i:i+batch_size]
futures = [executor.submit(fetch_content, url) for url in batch_urls]
with tqdm(total=len(futures), desc="Toplam İşleniyor", unit="URL") as pbar:
for future in as_completed(futures):
url_content = future.result()
result = process_content(url_content)
write_to_json(result)
pbar.update(1)
if __name__ == "__main__":
start_time = time.time()
main()
end_time = time.time()
print(f"Toplam süre: {end_time - start_time:.2f} saniye")