paint-brush
Как да изградите малък езиков модел (TLM) в Ruby: Ръководство стъпка по стъпкаот@davidesantangelo
520 показания
520 показания

Как да изградите малък езиков модел (TLM) в Ruby: Ръководство стъпка по стъпка

от Davide Santangelo10m2025/02/03
Read on Terminal Reader

Твърде дълго; Чета

В тази статия ще разгледаме как да създадем много прост езиков модел с помощта на Ruby. Ще изградим основен модел на веригата на Марков, който „се учи“ от въведен текст и след това генерира нов текст въз основа на наблюдаваните модели.
featured image - Как да изградите малък езиков модел (TLM) в Ruby: Ръководство стъпка по стъпка
Davide Santangelo HackerNoon profile picture
0-item

В тази статия ще разгледаме как да създадем много прост езиков модел с помощта на Ruby. Докато истинските големи езикови модели (LLM) изискват огромни количества данни и изчислителни ресурси, ние можем да създадем модел играчка, който демонстрира много от основните концепции зад езиковото моделиране. В нашия пример ще изградим основен модел на Марковска верига, който се „учи“ от въведен текст и след това генерира нов текст въз основа на наблюдаваните модели.


Забележка: Този урок е предназначен за образователни цели и илюстрира опростен подход към езиковото моделиране. Това не е заместител на съвременните LLMs за дълбоко обучение като GPT-4, а по-скоро въведение в основните идеи.


Съдържание

  1. Разбиране на основите на езиковите модели
  2. Настройване на вашата Ruby среда
  3. Събиране на данни и предварителна обработка
  4. Изграждане на модела на веригата на Марков
  5. Обучение на модела
  6. Генериране и тестване на текст
  7. Заключение

Разбиране на основите на езиковите модели

Езиковият модел е система, която присвоява вероятности на последователности от думи. В основата си той е предназначен да улови статистическата структура на езика чрез изучаване на вероятността определена последователност да се появи в даден контекст. Това означава, че моделът анализира големи части от текст, за да разбере как думите обикновено следват една след друга, като по този начин му позволява да предвиди коя дума или фраза може да дойде следващата в последователността. Такива възможности са централни не само за задачи като генериране на текст и автоматично довършване, но и за различни приложения за обработка на естествен език (NLP), включително превод, обобщение и анализ на настроението.

Съвременните широкомащабни езикови модели (LLM) като GPT-4 използват техники за задълбочено обучение и масивни набори от данни за улавяне на сложни модели в езика. Те работят, като обработват въведен текст чрез множество слоеве от изкуствени неврони, което им позволява да разбират и генерират човешки текст със забележителна плавност. Въпреки това, зад тези сложни системи се крие същата фундаментална идея: разбиране и прогнозиране на последователности от думи въз основа на научени вероятности.

Един от най-простите методи за моделиране на език е чрез верига на Марков . Веригата на Марков е статистически модел, който работи при предположението, че вероятността думата да се появи зависи само от ограничен набор от предходни думи, а не от цялата история на текста. Тази концепция е известна като свойство на Марков. От практическа гледна точка, моделът предполага, че следващата дума в последователност може да бъде предвидена единствено чрез разглеждане на най-новата дума(и) - опростяване, което прави проблема изчислително по-податлив, като същевременно улавя полезни модели в данните.

В езиков модел, базиран на Маркова верига:

  • Бъдещото състояние (следваща дума) зависи само от текущото състояние (предишни думи): Това означава, че след като знаем последните няколко думи (определени от реда на модела), имаме достатъчно контекст, за да предвидим какво може да последва. Не е необходимо да се разглежда цялата история на разговора или текста, което намалява сложността.
  • Ние изграждаме вероятностно разпределение за това коя дума идва след като се има предвид предходната дума(и): Тъй като моделът се обучава върху корпус от текст, той научава вероятността различни думи да следват дадена последователност. След това това разпределение на вероятностите се използва по време на фазата на генериране, за да се избере следващата дума в последователността, като обикновено се използва процес на произволна извадка, който зачита научените вероятности.

В нашата реализация ще използваме конфигурируем "ред", за да определим колко предишни думи трябва да се вземат предвид, когато се правят прогнози. По-високият ред осигурява повече контекст, което потенциално води до по-последователен и контекстуално подходящ текст, тъй като моделът има повече информация за това, което е било преди. Обратно, по-нисък ред въвежда повече произволност и може да доведе до по-креативни, макар и по-малко предвидими, последователности от думи. Този компромис между съгласуваност и креативност е централно съображение при езиковото моделиране.

Като разберем тези основни принципи, можем да оценим както простотата на моделите на веригата на Марков, така и основополагащите идеи, които са в основата на по-сложни невронни езикови модели. Този разширен изглед не само помага за разбирането на статистическата механика зад езиковата прогноза, но също така полага основите за експериментиране с по-напреднали техники в обработката на естествен език.


Настройване на вашата Ruby среда

Преди да започнете, уверете се, че имате инсталиран Ruby на вашата система. Можете да проверите вашата версия на Ruby, като стартирате:

 ruby -v

Ако Ruby не е инсталиран, можете да го изтеглите от ruby-lang.org .

За нашия проект може да искате да създадете специална директория и файл:

 mkdir tiny_llm cd tiny_llm touch llm.rb

Сега сте готови да напишете вашия Ruby код.


Събиране на данни и предварителна обработка

Събиране на данни за обучение

За езиков модел се нуждаете от текстов корпус. Можете да използвате всеки текстов файл за обучение. За нашия прост пример можете да използвате малка извадка от текст, например:

 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

Предварителна обработка на данните

Преди обучение е полезно да обработите предварително текста:

  • Токенизация: Разделяне на текст на думи.
  • Нормализация: По избор преобразувайте текст в малки букви, премахване на пунктуация и т.н.

За нашите цели методът String#split на Ruby работи достатъчно добре за токенизиране.


Изграждане на модела на веригата на Марков

Ще създадем 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

Обяснение на Кодекса


  • **Инициализация: **Конструкторът initialize задава реда (по подразбиране е 2) и създава празен хеш за нашата верига. Хешът получава блок по подразбиране, така че всеки нов ключ да започва като празен масив.


  • **Обучение на модела: **Методът train взема низ от текст, нормализира го и го разделя на думи. Използвайки each_cons , той създава последователни групи от думи с order + 1 . Думите от първия order служат като ключ, а последната дума се добавя към масива от възможни продължения за този ключ.


  • **Генериране на текст: **Методът generate започва с начален ключ. Ако не е предоставен такъв, се избира произволен ключ. След това итеративно изгражда последователност, като търси думите от последния 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

Като експериментирате с различни семена и параметри (като ред и максимален брой думи), можете да видите как изходът варира.


Пълен пример: Обучение и тестване на малък LLM

Ето пълния 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

Изпълнение на скрипта

  1. Запазете скрипта като llm.rb
  2. Отворете вашия терминал и отидете до директорията, съдържаща llm.rb
  3. Стартирайте скрипта, като използвате:
 ruby llm.rb

Трябва да видите изход, показващ, че моделът е обучен и след това два примера за генериран текст.


Бенчмарк

Следната таблица обобщава някои сравнителни показатели за различни версии на нашите реализации на Tiny LLM. Всеки показател е обяснен по-долу:

  • Модел: Името или идентификаторът на версията на езиковия модел.
  • Ред: Броят на предишните думи, използвани във веригата на Марков за предсказване на следващата дума. По-висок ред обикновено означава, че се използва повече контекст, което потенциално увеличава кохерентността.
  • Време за обучение (ms): Приблизителното време, необходимо за обучение на модела върху предоставените текстови данни, измерено в милисекунди.
  • Време за генериране (ms): Времето, необходимо за генериране на изходен примерен текст, измерено в милисекунди.
  • Използване на памет (MB): Количеството памет, консумирано от модела по време на обучение и генериране.
  • Оценка на съгласуваност: Субективна оценка (от 5), показваща колко съгласуван или контекстуално подходящ е генерираният текст.

По-долу е таблицата с маркдаун с референтните данни:

Модел

ред

Време за тренировка (ms)

Време за генериране (ms)

Използване на паметта (MB)

Оценка на съгласуваност

Малък LLM v1

2

50

10

10

3/5

Малък LLM v2

3

70

15

12

3,5/5

Малък LLM v3

4

100

20

15

4/5

Тези показатели осигуряват бърз преглед на компромисите между различните конфигурации на моделите. Тъй като редът се увеличава, моделът обикновено отнема малко повече време за обучение и генериране на текст и използва повече памет. Въпреки това, тези увеличения на потреблението на ресурси често са придружени от подобрения в съгласуваността на генерирания текст.

Заключение

В този урок демонстрирахме как да създадем много прост езиков модел с помощта на Ruby. Използвайки техниката на веригата на Марков, ние изградихме система, която:

  • Обучава върху примерен текст, като научава преходите между думите.
  • Генерира нов текст въз основа на научени модели.

Въпреки че този модел играчка е далеч от LLMs на производствено ниво, той служи като стъпало за разбиране на това как работят езиковите модели на основно ниво. Можете да разширите тази идея, като включите по-напреднали техники, по-добре боравите с пунктуацията или дори интегрирате Ruby с библиотеки за машинно обучение за по-сложни модели.

Приятно кодиране!

L O A D I N G
. . . comments & more!

About Author

Davide Santangelo HackerNoon profile picture
Davide Santangelo@davidesantangelo
Software Engineer - dad. APIs specialist, In love with #ruby, #go and #python - developer at sevio.it

ЗАКАЧВАЙТЕ ЕТИКЕТИ

ТАЗИ СТАТИЯ Е ПРЕДСТАВЕНА В...