در این مقاله نحوه ایجاد یک مدل زبان بسیار ساده با استفاده از Ruby را توضیح خواهیم داد. در حالی که مدلهای واقعی زبان بزرگ (LLM) به مقادیر زیادی داده و منابع محاسباتی نیاز دارند، ما میتوانیم یک مدل اسباببازی ایجاد کنیم که بسیاری از مفاهیم اصلی پشت مدلسازی زبان را نشان دهد. در مثال خود، ما یک مدل زنجیره مارکوف را می سازیم که از متن ورودی "یاد می گیرد" و سپس متن جدیدی را بر اساس الگوهایی که مشاهده کرده تولید می کند.
توجه: این آموزش برای اهداف آموزشی طراحی شده است و یک رویکرد ساده برای مدل سازی زبان را نشان می دهد. این جایگزینی برای LLM های مدرن یادگیری عمیق مانند GPT-4 نیست، بلکه مقدمه ای برای ایده های اساسی است.
مدل زبان سیستمی است که احتمالات را به دنباله ای از کلمات اختصاص می دهد. در هسته خود، طراحی شده است تا ساختار آماری زبان را با یادگیری احتمال وقوع یک توالی خاص در یک زمینه خاص به تصویر بکشد. این به این معنی است که این مدل بخشهای بزرگی از متن را تجزیه و تحلیل میکند تا بفهمد چگونه کلمات معمولاً از یکدیگر پیروی میکنند، در نتیجه به آن اجازه میدهد پیشبینی کند چه کلمه یا عبارتی ممکن است در یک دنباله قرار بگیرد. چنین قابلیتهایی نه تنها برای کارهایی مانند تولید متن و تکمیل خودکار، بلکه برای انواع برنامههای پردازش زبان طبیعی (NLP) از جمله ترجمه، خلاصهسازی و تحلیل احساسات مرکزی هستند.
مدلهای زبان در مقیاس بزرگ (LLM) مانند GPT-4 از تکنیکهای یادگیری عمیق و مجموعه دادههای عظیم برای ثبت الگوهای پیچیده در زبان استفاده میکنند. آنها با پردازش متن ورودی از طریق لایههای متعدد نورونهای مصنوعی عمل میکنند و به آنها امکان میدهند متنی شبیه انسان را با روانی قابلتوجهی درک و تولید کنند. با این حال، پشت این سیستم های پیچیده، همان ایده اساسی نهفته است: درک و پیش بینی توالی کلمات بر اساس احتمالات آموخته شده.
یکی از سادهترین روشها برای مدلسازی زبان، از طریق زنجیره مارکوف است. زنجیره مارکوف یک مدل آماری است که با این فرض عمل می کند که احتمال وقوع یک کلمه فقط به مجموعه محدودی از کلمات قبلی بستگی دارد نه کل تاریخ متن. این مفهوم به عنوان ویژگی مارکوف شناخته می شود. در شرایط عملی، مدل فرض میکند که کلمه بعدی در یک دنباله را میتوان تنها با نگاه کردن به آخرین کلمه (ها) پیشبینی کرد - سادهسازی که باعث میشود مشکل از نظر محاسباتی قابل حلتر باشد و در عین حال الگوهای مفیدی را در دادهها ثبت کند.
در یک مدل زبان مبتنی بر زنجیره مارکوف:
در اجرای خود، از یک «ترتیب» قابل تنظیم برای تعیین تعداد کلمات قبلی که باید هنگام پیشبینی در نظر گرفته شوند استفاده میکنیم. مرتبه بالاتر زمینه بیشتری را فراهم می کند، که به طور بالقوه منجر به متن منسجم تر و مرتبط تر می شود، زیرا مدل اطلاعات بیشتری در مورد آنچه قبلا آمده است دارد. برعکس، مرتبه پایینتر تصادفیتر را معرفی میکند و میتواند منجر به توالیهای خلاقانهتر، البته کمتر قابل پیشبینی، شود. این مبادله بین انسجام و خلاقیت یکی از ملاحظات اصلی در مدلسازی زبان است.
با درک این اصول اساسی، میتوانیم از سادگی مدلهای زنجیره مارکوف و ایدههای اساسی که زیربنای مدلهای پیچیدهتر زبان عصبی هستند، قدردانی کنیم. این دیدگاه گسترده نه تنها به درک مکانیک آماری پشت پیشبینی زبان کمک میکند، بلکه زمینه را برای آزمایش تکنیکهای پیشرفتهتر در پردازش زبان طبیعی فراهم میکند.
قبل از شروع، مطمئن شوید که Ruby را روی سیستم خود نصب کرده اید. می توانید نسخه Ruby خود را با اجرای زیر بررسی کنید:
ruby -v
اگر Ruby نصب نیست، می توانید آن را از ruby-lang.org دانلود کنید.
برای پروژه ما، ممکن است بخواهید یک فهرست و فایل اختصاصی ایجاد کنید:
mkdir tiny_llm cd tiny_llm touch llm.rb
اکنون آماده نوشتن کد روبی خود هستید.
برای یک مدل زبان، به یک مجموعه متن نیاز دارید. برای آموزش می توانید از هر فایل متنی استفاده کنید. برای مثال ساده ما، ممکن است از نمونه کوچکی از متن استفاده کنید، به عنوان مثال:
sample_text = <<~TEXT Once upon a time in a land far, far away, there was a small village. In this village, everyone knew each other, and tales of wonder were told by the elders. The wind whispered secrets through the trees and carried the scent of adventure. TEXT
قبل از آموزش، پیش پردازش متن مفید است:
برای اهداف ما، روش Ruby's String#split
به اندازه کافی برای توکنسازی کار میکند.
ما یک کلاس Ruby به نام MarkovChain
ایجاد می کنیم تا رفتار مدل را در بر بگیرد. کلاس شامل موارد زیر خواهد بود:
train
که زنجیره را از متن ورودی می سازد.generate
که متن جدیدی را با نمونه برداری از زنجیره تولید می کند.در زیر کد کامل این مدل آمده است:
class MarkovChain def initialize(order = 2) @order = order # The chain is a hash that maps a sequence of words (key) to an array of possible next words. @chain = Hash.new { |hash, key| hash[key] = [] } end # Train the model using the provided text. def train(text) # Optionally normalize the text (eg, downcase) processed_text = text.downcase.strip words = processed_text.split # Iterate over the words using sliding window technique. words.each_cons(@order + 1) do |words_group| key = words_group[0...@order].join(" ") next_word = words_group.last @chain[key] << next_word end end # Generate new text using the Markov chain. def generate(max_words = 50, seed = nil) # Choose a random seed from the available keys if none is provided or if the seed is invalid. if seed.nil? || [email protected]?(seed) seed = @chain.keys.sample end generated = seed.split while generated.size < max_words # Form the key from the last 'order' words. key = generated.last(@order).join(" ") possible_next_words = @chain[key] break if possible_next_words.nil? || possible_next_words.empty? # Randomly choose the next word from the possibilities. next_word = possible_next_words.sample generated << next_word end generated.join(" ") end end
**Initialization:** initialize
سازنده ترتیب را تنظیم می کند (پیش فرض 2 است) و یک هش خالی برای زنجیره ما ایجاد می کند. به هش یک بلوک پیش فرض داده می شود تا هر کلید جدید به عنوان یک آرایه خالی شروع شود.
**آموزش مدل:**روش train
رشته ای از متن را می گیرد، آن را عادی می کند و به کلمات تقسیم می کند. با استفاده از each_cons
، گروه های متوالی از کلمات به order + 1
ایجاد می کند. کلمات order
اول به عنوان کلید عمل می کنند و کلمه آخر به آرایه ادامه های ممکن برای آن کلید اضافه می شود.
**تولید متن:**روش generate
با یک کلید seed شروع می شود. اگر هیچ کدام ارائه نشده باشد، یک کلید تصادفی انتخاب می شود. سپس با جستجوی آخرین order
کلمات و نمونه برداری از کلمه بعدی تا رسیدن به حداکثر تعداد کلمات، به طور مکرر دنباله ای می سازد.
اکنون که کلاس MarkovChain
خود را داریم، بیایید آن را بر روی برخی از داده های متنی آموزش دهیم.
# Sample text data for training sample_text = <<~TEXT Once upon a time in a land far, far away, there was a small village. In this village, everyone knew each other, and tales of wonder were told by the elders. The wind whispered secrets through the trees and carried the scent of adventure. TEXT # Create a new MarkovChain instance with order 2 model = MarkovChain.new(2) model.train(sample_text) puts "Training complete!"
هنگامی که کد بالا را اجرا می کنید (مثلاً با ذخیره آن در llm.rb
و اجرای ruby llm.rb
)، مدل با استفاده از متن نمونه ارائه شده آموزش داده می شود.
پس از آموزش مدل، می توانید متن جدیدی تولید کنید. بیایید مقداری کد برای تولید و چاپ یک متن نمونه اضافه کنیم:
# Generate new text using the trained model. generated_text = model.generate(50) puts "Generated Text:" puts generated_text
شما همچنین می توانید سعی کنید یک دانه برای تولید متن تهیه کنید. به عنوان مثال، اگر یکی از کلیدهای مدل را می شناسید (مانند "once upon"
)، می توانید انجام دهید:
seed = "once upon" generated_text_with_seed = model.generate(50, seed) puts "\nGenerated Text with seed '#{seed}':" puts generated_text_with_seed
با آزمایش با بذرها و پارامترهای مختلف (مانند ترتیب و حداکثر تعداد کلمات)، می توانید ببینید که چگونه خروجی متفاوت است.
در اینجا اسکریپت کامل Ruby است که تمام مراحل بالا را ترکیب می کند:
#!/usr/bin/env ruby # llm.rb # Define the MarkovChain class class MarkovChain def initialize(order = 2) @order = order @chain = Hash.new { |hash, key| hash[key] = [] } end def train(text) processed_text = text.downcase.strip words = processed_text.split words.each_cons(@order + 1) do |words_group| key = words_group[0...@order].join(" ") next_word = words_group.last @chain[key] << next_word end end def generate(max_words = 50, seed = nil) if seed.nil? || [email protected]?(seed) seed = @chain.keys.sample end generated = seed.split while generated.size < max_words key = generated.last(@order).join(" ") possible_next_words = @chain[key] break if possible_next_words.nil? || possible_next_words.empty? next_word = possible_next_words.sample generated << next_word end generated.join(" ") end end # Sample text data for training sample_text = <<~TEXT Once upon a time in a land far, far away, there was a small village. In this village, everyone knew each other, and tales of wonder were told by the elders. The wind whispered secrets through the trees and carried the scent of adventure. TEXT # Create and train the model model = MarkovChain.new(2) model.train(sample_text) puts "Training complete!" # Generate text without a seed generated_text = model.generate(50) puts "\nGenerated Text:" puts generated_text # Generate text with a specific seed seed = "once upon" generated_text_with_seed = model.generate(50, seed) puts "\nGenerated Text with seed '#{seed}':" puts generated_text_with_seed
llm.rb
ذخیره کنید.llm.rb
بروید. ruby llm.rb
باید خروجی را ببینید که نشان می دهد مدل آموزش داده شده است و سپس دو نمونه از متن تولید شده را ببینید.
جدول زیر برخی از معیارهای معیار را برای نسخههای مختلف پیادهسازی Tiny LLM ما خلاصه میکند. هر معیار در زیر توضیح داده شده است:
در زیر جدول نشانه گذاری با داده های معیار آورده شده است:
مدل | سفارش دهید | زمان آموزش (میلیثانیه) | زمان تولید (میلیثانیه) | میزان استفاده از حافظه (MB) | رتبه بندی انسجام |
---|---|---|---|---|---|
Tiny LLM v1 | 2 | 50 | 10 | 10 | 3/5 |
Tiny LLM نسخه 2 | 3 | 70 | 15 | 12 | 3.5/5 |
Tiny LLM نسخه 3 | 4 | 100 | 20 | 15 | 4/5 |
این معیارها یک نمای کلی سریع از مبادلات بین پیکربندی های مختلف مدل ارائه می دهند. با افزایش ترتیب، آموزش و تولید متن مدل کمی بیشتر طول می کشد و از حافظه بیشتری استفاده می کند. با این حال، این افزایش در مصرف منابع اغلب با بهبود در انسجام متن تولید شده همراه است.
در این آموزش، نحوه ایجاد یک مدل زبان بسیار ساده با استفاده از Ruby را نشان دادیم. با استفاده از تکنیک زنجیره مارکوف، سیستمی ساختیم که:
در حالی که این مدل اسباب بازی با LLM های سطح تولید فاصله زیادی دارد، اما به عنوان پله ای برای درک نحوه عملکرد مدل های زبان در سطح اساسی عمل می کند. میتوانید این ایده را با استفاده از تکنیکهای پیشرفتهتر، مدیریت بهتر علائم نقطهگذاری یا حتی ادغام Ruby با کتابخانههای یادگیری ماشین برای مدلهای پیچیدهتر، گسترش دهید.
کد نویسی مبارک!