هزار؛ بزرگ‌ترین کتابخانه متن‌باز هوش مصنوعی برای فارسی

هزار: کتابخانه جامع هوش مصنوعی برای زبان فارسی
هزار: کتابخانه جامع هوش مصنوعی برای زبان فارسی

آپدیت‌ها:

  • ۱۳ آبان ۱۴۰۲ - نسخه اول

تقریبا ۴ هفته قبل از انتشار همین نوشته، پست معرفی «هزار» رو روی لینکدین منتشر کردیم و با استقبال غافلگیرکننده کاربران مواجه شدیم. قبلش تصمیم گرفته بودیم که وقتی مخزن «هزار» روی گیت هاب به ۲۰۰ تا استار رسید یه پست معرفی درست درمون روی ویرگول منتشر کنیم و خیال می‌کردیم چند ماهی طول میکشه احتمالا؛ ولی به لطف حمایت‌های جانانه کامیونیتی متن‌باز فارسی، تو همون سه روز اول این عدد رو رد کردیم که شاید در تاریخ اوپن سورس ایران بی سابقه بوده و حقیقتا به تمام کسانی که بی‌دریغ حمایت کردن مدیونیم و با تمام قوا رو به جلو پیش می‌ریم تا بتونیم این حمایت‌ها رو جبران کنیم ??

سرتونو درد نیاریم؛ چون این معرفی به اندازه کافی طولانی هست (ولی قول میدیم جذاب باشه!).

اول بیاین با جواب دادن به چند تا سوال شروع کنیم.

«هزار» دقیقا چیه؟

«هزار» یک کتابخونه و فریم‌وورک برای به کارگیری مدل‌ها و الگوریتم‌های مبتنی بر هوش مصنوعی برای زبان فارسیه و برای کاربرد‌های مختلفی از جمله پردازش متن، تصویر و صوت مدل‌های مختلفی داره.

از جمله مدل‌هایی که در هزار برای کاربرد‌های مختلف وجود داره میشه به موارد زیر اشاره کرد:

  • دسته بندی متن (تشخیص احساسات، دسته‌بندی موضوعی و …)
  • تولید متن (خلاصه‌سازی، ترجمه و …)
  • مدل زبانی
  • نویسه خوان (OCR)
  • توصیف عکس (Image captioning)
  • تبدیل گفتار به متن
  • تشخیص موجودیت معنادار
  • بردار تعبیه (Embedding)

البته هزار فقط محدود به مدل‌ها نیست بلکه انواع روش‌های پیش پردازش داده مثل توکنایزر، استخراج ویژگی، نرمالایزر و … و همچنین تکنیک‌های مختلف آموزش مدل و پیاده‌سازی‌های آماده اجزای مختلف یک خط لوله آموزش مدل و … رو هم شامل میشه.

آدرس گیت‌هاب هزار:‌ https://github.com/hezarai/hezar (استار⭐ یادتون نره?)

آدرس مستندات هزار: https://hezarai.github.io/hezar

کانال تلگرام هزار:‌ https://t.me/hezarai

اصلا چرا «هزار» ساخته شد؟

اگر تو حوزه هوش مصنوعی فعال باشید و تجربه کار با دیتای فارسی رو داشته باشید حتما حس کردید که متاسفانه این حوزه تو ایران کویره (حداقل از نظر منابع متن‌باز و آزاد). منکر این نیستیم که کارهای خیلی خفنی در همین چند سال اخیر در این حوزه انجام شده و در دسترس عموم قرار گرفته اما باز هم میشه گفت که منابع پراکنده هستند و دسترسی و پیدا کردن بعضیاشون خیلی سخته. بعضی از این منابع هم قدیمی هستند و دیگه پشتیبانی نمیشن! از طرفی هم هر منبعی با یک دست خطی نوشته شده و اگر به فرض یه روزی بخواید مدل‌های آماده فلان تسک رو از جاهای مختلف پیدا کنید و همه رو دونه دونه تست کنید کلی دردسر دارید!

هزار با این ایده شروع شد که خیلی خوب میشه اگه یه بستری ایجاد بشه که به کمک اون تمام کارهای خفن هوش مصنوعی که برای فارسی‌زبان‌ها انجام شده (یا در آینده انجام میشه) رو به راحتی استفاده کرد یا توسعه داد. این کار از چند جهت مفیده:

  • استفاده از مدل‌های هوش مصنوعی برای تازه کار‌ها خیلی راحت میشه
  • حتی خبره‌های این حوزه هم برای تست کردن مدل‌های مختلف دردسر کمتری دارن
  • این بستر مرجعی میشه برای اینکه به راحتی همه بتونن بهترین مدل‌ها رو برای هر تسکی که میخوان پیدا کنن
  • مدلی دارین که منتشر هم کردین ولی اونجور که باید شناخته نشده؟ این کتابخونه کمک میکنه اگر کسی میخواد مدلی که خودش آموزش داده سریع‌تر شناخته بشه با اشتراک گذاشتن اون توی مدلای هزار به این هدف برسه.
  • با وجود همچین کتابخونه‌ای، خیلی بهتر میشه از به روز بودن مدل‌ها و سازگاریشون با پکیجای مختلف در طول زمان مطمئن شد (قطعا براتون پیش اومده که یه کدی پیدا کردین که مال ۵ سال پیشه و استفاده ازش با پکیج‌های به روز مشکله و از طرفی سازنده‌ش خیلی وقته که دیگه ساپورت نمی‌کنه)
  • وقتی یه جامعه بزرگی با کمک هم تمام تمرکزشون رو روی یک بستر واحد بذارن انرژی و هزینه خیلی کمتری صرف میشه، افراد بیشتر از همدیگه یاد میگیرن و در نهایت کل اون حوزه بهتر پیشرفت می‌کنه
  • و در نهایت فرهنگ توسعه متن‌باز نرم‌افزار بیشتر جا می‌افته (یکی از مهم‌ترین عوامل پیشرفت سریع نرم‌افزار نسبت به هر صنعت دیگه‌ای همین قابلیت دسترسی به منابع متن باز هست و اگر بخوایم هوش مصنوعی برای فارسی پیشرفت کنه قطعا مهم‌ترین قدم، رشد جامعه متن باز و اشتراک رایگان دانش در این حوزه‌ست.)

چرا اسمش شد «هزار»؟

اولین اسمی که تو ذهنمون بود «myriad» بود (صرفا چون اسم باحالی بود) که واحد شمارش ده‌ هزارتاییه. بعدا تغییر داده شد به «chiliad» («کیلیاد») که واحد شمارش هزارتاییه و بعدتر بخاطر اینکه اساس این کتابخونه برای زبان فارسی هست، یه اسم فارسی نیاز داشت که نهایتا به «هزار» ختم شد. از طرفی این اسم، یک کمیت و اندازه نسبتا بزرگی رو نشون میده و تقریبا نمایانگر هدف اصلی این پروژه یعنی گسترش دانش هوش مصنوعی با توسعه و انتشار مدل‌های متعدد هست.

خب دیگه وقتشه که بریم سراغ یه دموی کلی از قابلیت‌های هزار.

نحوه استفاده

برای یک آموزش جامع از نحوه استفاده از همه جوانب مختلف هزار، به صفحه داکیومنت‌‌ها مراجعه کنید.

https://hezarai.github.io/hezar/tutorial/index.html

نصب هزار

هزار یک پکیج پایتون روی PyPi داره و میتونید مثل هر پکیج دیگه‌ای رو پایتون به این شکل نصبش کنید.

pip install hezar

اگرم احیانا خواستین آخرین نسخه‌ای که داریم توسعه میدیم رو از روی سورس نصب کنید میتونید این شکلی انجامش بدید.

pip install git+https://github.com/hezarai/hezar.git

استفاده از مدل‌های آماده

اولین و مهم‌ترین کاربرد هزار، توی استفاده از مدل‌های از پیش آماده هست. تنها کاری که نیازه اینه که برید داخل مدل هاب هزار روی Hugging Face و مدل مدنظرتون رو انتخاب کنید. نام مدل‌ها بر اساس معماری یا نام مدل اصلی و تسک اون مدل قابل شناسایی هست. یعنی مثلا مدل hezarai/vit-roberta-fa-image-captioning-flickr30k یک مدل برای image captioning هست که با معماری ترکیبی ViT + RoBERTa و روی دیتاست flickr30k آموزش داده شده. حالا چطور میشه مدل‌ها رو استفاده کرد؟ هر مدلی که روی هاب میبینید رو با کد زیر میتونید لود کنید:

from hezar.models import Model
model = Model.load('hezarai/<MODEL PATH>')

این دستور در پس زمینه، وزن‌های مدل و تمام محتویات موردنیاز مثل کانفیگ و فایل‌های پیش‌پردازش و توکنایزر و ... رو لود می‌کنه و مدل رو برای inference آماده می‌کنه و از اینجا میشه با استفاده از دستور `()predict.` خروجی مدل روی ورودی مدنظر رو گرفت.

from hezar.models import Model

example = ['هزار، کتابخانه‌ای کامل برای به کارگیری آسان هوش مصنوعی']
model = Model.load('hezarai/bert-fa-sentiment-dksf')
outputs = model.predict(example)
print(outputs)

خروجی هر مدل نسبت به تسک اون مدل متفاوته. مثلا خروجی مثال بالا که یک مدل دسته بندی هست به این شکله:

[[{'label': 'positive', 'score': 0.812910258769989}]]

چند نمونه دیگه برای مثال ببینید:

  • تشخیص موجودیت (NER)
from hezar.models import Model

ner_model = Model.load('hezarai/bert-fa-ner-arman')  # Named entity recognition
inputs = ['شرکت هوش مصنوعی هزار']
ner_outputs = ner_model.predict(inputs)
print(f'NER: {ner_outputs}')
NER: [[{'token': 'شرکت', 'label': 'B-org'}, {'token': 'هوش', 'label': 'I-org'}, {'token': 'مصنوعی', 'label': 'I-org'}, {'token': 'هزار', 'label': 'I-org'}]]
  • نقش کلمات (Part of speech tagging)
from hezar.models import Model

pos_model = Model.load('hezarai/bert-fa-pos-lscp-500k')  # Part-of-speech
inputs = ['شرکت هوش مصنوعی هزار']
pos_outputs = pos_model.predict(inputs)
print(f'POS: {pos_outputs}')
POS: [[{'token': 'شرکت', 'label': 'Ne'}, {'token': 'هوش', 'label': 'Ne'}, {'token': 'مصنوعی', 'label': 'AJe'}, {'token': 'هزار', 'label': 'NUM'}]]
  • مدل زبانی (پر کردن ماسک)
from hezar.models import Model

roberta_mlm = Model.load('hezarai/roberta-fa-mlm')
inputs = ['سلام بچه ها حالتون <mask>']
outputs = roberta_mlm.predict(inputs)
print(outputs)
[[{'token': 'چطوره', 'sequence': 'سلام بچه ها حالتون چطوره', 'token_id': 34505, 'score': 0.2230483442544937}]]
  • تشخیص گفتار
from hezar.models import Model

whisper = Model.load('hezarai/whisper-small-fa')
transcripts = whisper.predict('examples/assets/speech_example.mp3')
print(transcripts)
[{'text': 'و این تنها محدود به محیط کار نیست'}]
  • نویسه خوان (OCR)
from hezar.models import Model

model = Model.load('hezarai/crnn-base-fa-64x256')
texts = model.predict('examples/assets/ocr_example.jpg')
print(f'CRNN Output: {texts}')
CRNN Output: [{'text': 'چه میشه کرد، باید صبر کنیم'}]
  • پلاک خوان (License Plate Recognition)
from hezar.models import Model

model = Model.load('hezarai/crnn-fa-64x256-license-plate-recognition')
plate_text = model.predict('assets/license_plate_ocr_example.jpg')
print(plate_text)  # Persian text of mixed numbers and characters might not show correctly in the console
[{'text': '۵۷س۷۷۹۷۷'}]
  • توصیف عکس (Image captioning)
from hezar.models import Model

model = Model.load('hezarai/vit-roberta-fa-image-captioning-flickr30k')
texts = model.predict('examples/assets/image_captioning_example.jpg')
print(texts)
[{'text': 'سگی با توپ تنیس در دهانش می دود.'}]
  • مدل‌های تعبیه کلمات (Word Embeddings)
from hezar.embeddings import Embedding

fasttext = Embedding.load('hezarai/fasttext-fa-300')
most_similar = fasttext.most_similar('هزار')
print(most_similar)
[{'score': 0.7579, 'word': 'میلیون'},
{'score': 0.6943, 'word': '21هزار'},
{'score': 0.6861, 'word': 'میلیارد'},
{'score': 0.6825, 'word': '26هزار'},
{'score': 0.6803, 'word': '٣هزار'}]

دیتاست‌ها

شاید بشه گفت مهم‌ترین عاملی که باعث میشه برای یک زبان، مدل‌های خوبی تولید بشه، تعداد و تنوع دیتاست‌ها برای اون زبان هست. هزار بستری برای فراهم‌سازی و به کارگیری ساده دیتاست‌ها هم در خودش داره. دیتاست ‌های هزار هم داخل هاگینگ فیس هستن و هر دیتاستی رو می‌تونید هم به فرمت هاگینگ فیس (که دیتاست خام هست) و هم به فرمت هزار (که یک کلاس شسته رفته پایتورچی و آماده استفاده برای آموزش بهتون میده) لود کنید.

from hezar.data import Dataset  # For Hezar dataset format
from datasets import load_dataset  # For Hugging Face dataset 

# Hugging Face
dataset = load_dataset('hezarai/xlsum-fa')
# Hezar
dataset = Dataset.load('hezarai/xlsum-fa')  # Returns a `TextSummarizationDataset` instance

برای مشاهده همه دیتاست‌ها اینجا کلیک کنید.

آموزش مدل‌ها

آموزش مدل‌های هزار با استفاده از دیتاست‌های هزار بسیار ساده و سر راسته! در حال حاضر به این شکل می‌تونید یک مدل رو روی یک دیتاست از داخل هاب آموزش بدید.

مدلی که می‌خوایم آموزش بدیم (در واقع فاین تون کنیم) مدل DistilBERT برای تسک دسته‌بندی متن (تشخیص احساسات در این مثال) روی دیتاست ترکیبی کامنت‌های دیجی‌کالا و اسنپ‌فود هست. اول، همه چیزایی که نیازه رو ایمپورت می‌کنیم:

from hezar.models import DistilBertTextClassification, DistilBertTextClassificationConfig
from hezar.trainer import Trainer, TrainerConfig
from hezar.data import Dataset
from hezar.preprocessors import Preprocessor

حالا آدرس دیتاست روی هاب و همینطور مدل پایه‌ای که می‌خوایم فاین-تیونش کنیم رو تعریف می‌کنیم.

DATASET_PATH = 'hezarai/sentiment-dksf'  # dataset path on the Hub
BASE_MODEL_PATH = 'hezarai/distilbert-base-fa'  # used as model backbone weights and tokenizer

حالا کلاس دیتاست‌های آموزش و ارزیابی رو لود می‌کنیم که خروجیش از جنس PyTorch Dataset هست.

train_dataset = Dataset.load(DATASET_PATH, split='train', tokenizer_path=BASE_MODEL_PATH)
eval_dataset = Dataset.load(DATASET_PATH, split='test', tokenizer_path=BASE_MODEL_PATH)

حالا بریم مدل و پیش‌پردازش‌گر مناسب مدل رو لود کنیم.

model = DistilBertTextClassification(
 BertTextClassificationConfig(id2label=train_dataset.config.id2label)
)
preprocessor = Preprocessor.load(BASE_MODEL_PATH)

مدلمون از کلاس DistilBertTextClassification هست و داخل کانفیگ هم نیازه که id2label رو تعیین کنیم تا لایه آخر به درستی ساخته بشه که مقدارش رو از دیتاست برمی‌داریم. پیش پردازش‌گر این مدل هم فقط یک توکنایزر هست که درواقع با مدل پایه که دیستیل‌برت هست یکیه.

دیتاست و مدل و پیش‌پردازشگر آماده‌ست. الان باید یک کانفیگ برای آموزش تعیین کنیم که تنظیمات آموزش مدل رو مشخص می‌کنه.

train_config = TrainerConfig(
    task='text_classification',
    device='cuda',
    init_weights_from=base_model_path,
    batch_size=8,
    num_epochs=5,
    checkpoints_dir='checkpoints/',
    metrics=['f1'],
)

پارامتر‌هایی که تعیین کردیم به این شرح هستن:

  • پارامتر task: این پارامتر اجباریه و به Trainer می‌گه که مدلی که قرار آموزش بدیم برای چه تسکی هست. (اگر این پارامتر رو اشتباه تعیین کنید یک ارور میده و بهتون میگه که چه مقادیری مجاز هستن)
  • پارامتر device: که تعیین کننده اینه که روی کدوم سخت‌افزار برای پردازش‌ها استفاده بشه که اینجا از cuda استفاده می‌کنیم که همون کارت گرافیکمون هست.
  • پارامتر init_weights_from: مقدار این پارامتر باید آدرس مدلی باشه که از روی اون می‌خوایم فاین تیون کنیم.
  • پارامتر batch_size: که نیاز به توضیح نداره :)
  • پارامتر num_epochs: اینم نیاز به توضیح نداره :)
  • پارامتر checkpoints_dir: تمام چکپوینت‌ها که شامل وزن‌های ذخیره شده، فایل‌های دیگه مدل و ... در این آدرس ذخیره می‌شن.
  • پارامتر metrics: یک لیست از معیار‌های ارزیابی مدل هست. این پارامتر باید بر اساس تسکی که مدنظره تعیین بشه.
  • پارامتر‌های دیگه هم قابل تنظیم هستن ولی برای این مثال نیازی بهشون نیست.

در مرحل نهایی آبجکت Trainer رو می‌سازیم و آموزش رو انجام می‌دیم. (پارامتر‌های اجباری Trainer مواردی هستند که در این قطعه کد می‌بینید.)

trainer = Trainer(
    config=train_config,
    model=model,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    data_collator=train_dataset.data_collator,
    preprocessor=preprocessor,
)
trainer.train()
Epoch: 1/5      100%|####################################| 3576/3576 [07:07<00:00,  8.37batch/s, f1=0.732, loss=0.619]
Evaluating...   100%|####################################| 290/290 [00:07<00:00, 38.64batch/s, f1=0.8, loss=0.473]
Epoch: 2/5      100%|####################################| 3576/3576 [07:00<00:00,  8.50batch/s, f1=0.807, loss=0.47]
Evaluating...   100%|####################################| 290/290 [00:07<00:00, 39.87batch/s, f1=0.838, loss=0.419]
Epoch: 3/5      100%|####################################| 3576/3576 [07:01<00:00,  8.48batch/s, f1=0.864, loss=0.348]
Evaluating...   100%|####################################| 290/290 [00:07<00:00, 39.97batch/s, f1=0.875, loss=0.346]
Epoch: 4/5      100%|####################################| 3576/3576 [06:57<00:00,  8.56batch/s, f1=0.919, loss=0.227]
Evaluating...   100%|####################################| 290/290 [00:07<00:00, 38.84batch/s, f1=0.875, loss=0.381]
Epoch: 5/5      100%|####################################| 3576/3576 [07:02<00:00,  8.46batch/s, f1=0.943, loss=0.156]
Evaluating...   100%|####################################| 290/290 [00:07<00:00, 39.71batch/s, f1=0.887, loss=0.446]

بعد از هر ایپاک لاگ معیار‌ها هم در Tensorboard و هم در یک فایل csv ذخیره می‌شه.

اگر دوست داشتید می‌تونید همه محتویات آموزش شامل کانفیگ‌ها و مدل و پیش‌پردازش‌گر و لاگ‌ها رو به هاب اپلود کنید.

trainer.push_to_hub('<your-hf-username>/distilbert-fa-sentiment-dksf')

چند مرتبه عمیق‌تر

«هزار» حقیقتا پروژه بزرگیه و به دلیل اینکه ابعاد بسیار زیادی داره، خیلی خیلی وسواسانه نوشته شده و علاوه بر رعایت اصل سادگی استفاده برای کاربر، برای توسعه دهندگان این فریموورک هم خیلی راحت و سرراسته. معماری «هزار» طوریه که همواره سعی شده روی بهترین ابزار‌های موجود سوار باشه تا هم چرخ اضافی‌ای اختراع نشه و هم استفاده از هر جزئی برای عموم راحت و آشنا باشه. تمام مدل‌های هزار با فریموورک PyTorch ساخته شدن و هر مدلی که تو هزار هست کاملا رفتار یک مدل عادی پایتورچ رو داره. بقیه موارد از جمله دیتاست‌ها، پیش پردازشگر‌ها و ... هم بر پایه ابزار‌هایی هستند که اکثریت باهاش آشنایی دارن. از طرفی سعی شده تا حد امکان از کامپوزیشن توی معماری استفاده نشه تا به راحتی هر کس بتونه یه تیکه از کد رو کپی کنه و هر جور خواست استفاده کنه! برای اطلاعات بیشتر راجع به معماری هزار در لایه‌های پایین‌تر به قسمت Developer Guides مراجعه کنید.

اهداف و مسیر آینده

مهم‌ترین هدف هزار دموکراتیزه کردن هوش مصنوعی برای فارسی‌زبانان هست. به شکل جزئی‌تر اهداف هزار عبارتند از:

  • هموارکردن راه برای تازه‌وارد‌ها و علاقه‌مندان هوش مصنوعی
  • مرجعی برای به اشتراک‌گذاری پیشرفته‌ترین مدل‌های هوش مصنوعی برای زبان فارسی
  • سرعت بخشیدن به پیشرفت هوش مصنوعی برای زبان فارسی به واسطه فرهنگ متن باز و اشتراک رایگان دانش

تا به اینجای کار، قسمت اعظم توسعه این پروژه متمرکز بر مباحث زیرساختی و معماری این فریموورک بوده و مدل‌هایی که منتشر شده ظرف بازه بسیار کوتاهی آموزش داده شدن. این مدل‌ها بسیار جای پیشرفت دارن و تیم هزار همواره در این جهت تلاش می‌کنه. بعد از استیبل شدن کلی «هزار»، برنامه‌های زیادی برای توسعه مدل‌های بسیار بزرگ‌تر و پیچیده‌تر داریم و در این راه قطعا از هر کمک، حمایت و مشارکتی استقبال ویژه می‌کنیم.

مشارکت و حمایت

بزرگترین انگیزه تیم هزار برای ادامه، حمایت و مشارکت جامعه توسعه دهندگان فارسیه. مشارکت برای همه افراد آزاد هست و شامل موارد زیر میشه:

  • توسعه فیچر‌های مختلف و قابلیت‌های جدید
  • اضافه‌کردن مدل‌ها
  • آموزش مدل‌ها
  • نوشتن داکیومنت
  • درخواست فیچر یا مدل جدید
  • گزارش باگ‌ها
  • مشارکت در حل باگ‌ها و ایشوهای گیت‌هاب
  • تبلیغ و معرفی به دوستان و در سوشال مدیا
  • حمایت مالی و سرمایه‌گذاری

ارتباط با ما

اگر پیام یا درخواست تکنیکال دارید راه ارتباطی پیشنهادی ما issue یا discussion زدن روی گیت‌هابه اما اگر دوست دارید شخصا در تماس باشید می‌تونید از طریق ایمیل یا لینکدین هم پیام بدین ?