تولید متن با LLMها در Keras
این پست از فصل 16 کتاب DEEP LEARNING with Python ویرایش 3 ترجمه شده است.
محتویات
- تاریخچه مختصر تولید توالی
- آموزش یک mini-GPT
- استفاده از یک LLM از پیش آموزشدیده
- پیشرفت بیشتر با LLMها
- LLMها به کجا میروند؟
- خلاصه
- تاریخچه مختصر مدلسازی تولیدی
- آموزش یک مدل GPT کوچک از صفر
- استفاده از یک مدل Transformer از پیش آموزشدیده برای ساخت یک چتبات
- ساخت یک مدل چندوجهی که میتواند تصاویر را به زبان طبیعی توصیف کند
امروزه ابزارهای هوش مصنوعی مولد اکنون افزونههای رایجی در پردازندههای متن، ویرایشگرهای تصویر و محیطهای توسعه هستند. جوایز معتبر به ادبیات و هنری که با مدلهای تولیدی ایجاد شدهاند اعطا میشود که البته با بحث و جدل و مناقشه قابل توجهی همراه بوده است.
از نظر عملی، هوش مصنوعی به هیچ وجه نزدیک به رقابت با فیلمنامهنویسان، نقاشان یا آهنگسازان انسانی نیست. اما جایگزینی انسانها نباید و نباید هدف باشد. در بسیاری از زمینهها، به خصوص در زمینههای خلاق، مردم از هوش مصنوعی برای تقویت قابلیتهای خود استفاده خواهند کرد – بیشتر هوش تقویتشده تا هوش مصنوعی.
بخش زیادی از خلق هنری شامل تشخیص الگو و مهارت فنی است. روشهای ادراکی، زبان و آثار هنری ما همگی ساختار آماری دارند، و مدلهای یادگیری عمیق در یادگیری این ساختار عالی هستند. مدلهای یادگیری ماشین میتوانند فضاهای نهفته آماری تصاویر، موسیقی و داستانها را یاد بگیرند و سپس از این فضاها نمونهگیری کنند و آثار هنری جدیدی با ویژگیهای مشابه با آنچه مدل در دادههای آموزشی خود دیده است ایجاد کنند.
تاریخچه مختصر تولید توالی
تا همین اواخر، ایده تولید توالی از یک مدل یک موضوع فرعی در یادگیری ماشین بود و شبکههای بازگشتی مولد تنها در سال ۲۰۱۶ به جریان اصلی حوزه راه یافتند. با این حال، این تکنیکها تاریخچه نسبتاً طولانی دارند که با توسعه الگوریتم LSTM در سال ۱۹۹۷ شروع شد.
در سال ۲۰۰۲، داگلاس اک (Douglas Eck) برای اولین بار LSTM را برای تولید موسیقی به کار برد، با نتایج امیدوارکننده. اک محقق گوگل برین شد و در سال ۲۰۱۶، یک گروه تحقیقاتی جدید به نام Magenta را راهاندازی کرد که بر استفاده از تکنیکهای مدرن یادگیری عمیق برای تولید موسیقی جذاب متمرکز بود. گاهی اوقات، ایدههای خوب ۱۵ سال طول میکشد تا شروع شوند.
در اواخر دهه ۲۰۰۰ و اوایل دهه ۲۰۱۰، الکس گریوز (Alex Graves) پیشگام استفاده از شبکههای بازگشتی برای انواع جدید تولید داده توالی بود. به طور خاص، برخی کار او در سال ۲۰۱۳ درباره استفاده از شبکههای چگالی مخلوط بازگشتی (recurrent mixture density network) برای تولید دستخط شبیه انسان با استفاده از سریهای زمانی موقعیتهای قلم را به عنوان نقطه عطف میدانند.
در سال ۲۰۱۸، یک سال پس از مقاله “Attention Is All You Need”، گروهی از محققان در سازمانی به نام OpenAI مقاله جدیدی با عنوان “بهبود درک زبان با پیشآموزش تولیدی” منتشر کردند. آنها چند مؤلفه را ترکیب کردند:
- پیشآموزش بدون نظارت یک مدل زبانی – اساساً آموزش یک مدل برای “حدس زدن توکن بعدی” در یک توالی
- معماری Transformer
- دادههای متنی در موضوعات مختلف از طریق هزاران کتاب خودمنتشرشده
نویسندگان نشان دادند که چنین مدل از پیش آموزشدیدهای میتواند برای دستیابی به عملکرد پیشرفته در طیف گستردهای از وظایف طبقهبندی متن – از سنجش شباهت دو جمله تا پاسخ به یک سؤال چندگزینهای – تنظیم دقیق شود. آنها این مدل از پیش آموزشدیده را GPT نامیدند، مخفف Generative Pretrained Transformer.
GPT با هیچ پیشرفت مدلسازی یا آموزشی همراه نبود. آنچه در مورد نتایج جالب بود این بود که چنین راهاندازی آموزشی عمومی میتوانست تکنیکهای پیچیدهتر را در تعدادی از وظایف شکست دهد. نرمالسازی پیچیده متن وجود نداشت، نیازی به سفارشیسازی معماری مدل یا دادههای آموزشی برای هر معیار نبود، فقط مقدار زیادی داده پیشآموزش و محاسبات.
در سالهای بعد، OpenAI با تمرکز یکدنده به مقیاسبندی این ایده پرداخت. معماری مدل تنها کمی تغییر کرد. طی چهار سال، OpenAI سه نسخه از GPT را منتشر کرد که به صورت زیر مقیاسبندی شدند:
- GPT-1 (منتشرشده در ۲۰۱۸): ۱۱۷ میلیون پارامتر و آموزش بر روی ۱ میلیارد توکن
- GPT-2 (منتشرشده در ۲۰۱۹): ۱.۵ میلیارد پارامتر و آموزش بر روی بیش از ۱۰ میلیارد توکن
- GPT-3 (منتشرشده در ۲۰۲۰): ۱۷۵ میلیارد پارامتر و آموزش بر روی حدود نیم تریلیون توکن
راهاندازی مدلسازی زبان به هر یک از این مدلها امکان تولید متن را میداد، و توسعهدهندگان در OpenAI متوجه شدند که با هر جهش در مقیاس، کیفیت این خروجی تولیدی به طور قابل توجهی افزایش مییابد.
آموزش یک mini-GPT
برای شروع پیشآموزش mini-GPT خود، به مقدار زیادی داده متنی نیاز خواهیم داشت. GPT-1 از مجموعه دادهای به نام BooksCorpus استفاده کرد که شامل تعدادی کتاب خودمنتشرشده رایگان بود که بدون اجازه صریح نویسندگان به مجموعه داده اضافه شده بودند. مجموعه داده از آن زمان توسط ناشران آن حذف شده است.
ما از یک مجموعه داده پیشآموزش جدیدتر به نام “Colossal Clean Crawled Corpus” (C4) استفاده خواهیم کرد که توسط گوگل در سال ۲۰۲۰ منتشر شد. با ۷۵۰ گیگابایت، بسیار بزرگتر از آن است که بتوانیم به طور معقول برای یک مثال کتاب بر روی آن آموزش دهیم، بنابراین از کمتر از ۱٪ کل مجموعه استفاده خواهیم کرد.
import keras
import pathlib
extract_dir = keras.utils.get_file(
fname="mini-c4",
origin=(
"https://hf.co/datasets/mattdangerw/mini-c4/resolve/main/mini-c4.zip"
),
extract=True,
)
extract_dir = pathlib.Path(extract_dir) / "mini-c4"
اجرای کد در این فصل
مدلهای زبانی تولیدی بزرگ هستند و برای اجرا به محاسبات زیادی نیاز دارند. در حالی که ما برای قابل دسترس کردن کد در این فصل تلاش کردهایم، این همچنان محاسباتیترین فصل در این کتاب است.
اگر میخواهید، میتوانید همه چیز را در runtime رایگان GPU Colab (یک GPU T4 در زمان نوشتن این مطلب) اجرا کنید، اما آماده باشید که منتظر بمانید! این مثال mini-GPT حدود ۶ ساعت برای آموزش طول میکشد و باید runtime Colab خود را در وسط نوتبوک مجدداً راهاندازی کنید تا حافظه GPU را قبل از بارگذاری یک مدل از پیش آموزشدیده بزرگتر آزاد کنید.
ما ۵۰ قطعه از داده متنی داریم که هر کدام حدود ۷۵ مگابایت متن خام دارند. هر خط شامل یک سند در خزش با newlineهای escape شده است. بیایید به یک سند در اولین قطعه خود نگاه کنیم:
>>> with open(extract_dir / "shard0.txt", "r") as f:
>>> print(f.readline().replace("\\n", "\n")[:100])
Beginners BBQ Class Taking Place in Missoula!
Do you want to get better at making delicious BBQ? You
برای پیشپردازش دادههای زیادی که برای اجرای پیشآموزش یک LLM نیاز داریم، حتی یک LLM کوچک مانند آنچه در حال آموزش هستیم، استفاده از یک روال توکنسازی سریع برای پیشپردازش اسناد منبع ما به توکنهای صحیح میتواند زندگی ما را ساده کند.
ما از SentencePiece استفاده خواهیم کرد، یک کتابخانه برای توکنسازی زیرکلمهای دادههای متنی. تکنیک توکنسازی واقعی همان توکنسازی جفتبایت است که خودمان در فصل ۱۴ ساختیم، اما کتابخانه به زبان C++ برای سرعت نوشته شده است و یک تابع detokenize() اضافه میکند که صحیحها را به رشتهها معکوس و آنها را به هم میپیوندد.
import keras_hub
import numpy as np
vocabulary_file = keras.utils.get_file(
origin="https://hf.co/mattdangerw/spiece/resolve/main/vocabulary.proto",
)
tokenizer = keras_hub.tokenizers.SentencePieceTokenizer(vocabulary_file)
میتوانیم از این tokenizer برای نگاشت دوطرفه از متن به توالیهای int استفاده کنیم:
>>> tokenizer.tokenize("The quick brown fox.")
array([ 450, 4996, 17354, 1701, 29916, 29889], dtype=int32)
>>> tokenizer.detokenize([450, 4996, 17354, 1701, 29916, 29889])
"The quick brown fox."
بیایید از این لایه برای توکنسازی متن ورودی خود استفاده کنیم و سپس از tf.data برای پنجرهبندی ورودی ما به توالیهایی با طول ۲۵۶ استفاده کنیم.
import tensorflow as tf
batch_size = 64
sequence_length = 256
suffix = np.array([tokenizer.token_to_id("<|endoftext|>")])
def read_file(filename):
ds = tf.data.TextLineDataset(filename)
# Restores newlines
ds = ds.map(lambda x: tf.strings.regex_replace(x, r"\\n", "\n"))
# Tokenizes data
ds = ds.map(tokenizer, num_parallel_calls=8)
# Adds the <|endoftext|> token
return ds.map(lambda x: tf.concat([x, suffix], -1))
files = [str(file) for file in extract_dir.glob("*.txt")]
ds = tf.data.Dataset.from_tensor_slices(files)
# Combines our file shards into a single dataset
ds = ds.interleave(read_file, cycle_length=32, num_parallel_calls=32)
# Windows tokens into even samples of 256 tokens
ds = ds.rebatch(sequence_length + 1, drop_remainder=True)
# Splits labels, offset by one
ds = ds.map(lambda x: (x[:-1], x[1:]))
ds = ds.batch(batch_size).prefetch(8)
ما ۵۸,۷۴۶ batch داریم. با ۶۴ نمونه در هر batch و ۲۵۶ توکن در هر نمونه، این کمی کمتر از یک میلیارد توکن داده است. بیایید ۵۰۰ batch را به عنوان یک مجموعه اعتبارسنجی سریع جدا کنیم و آماده شروع پیشآموزش هستیم:
num_batches = 58746 num_val_batches = 500 num_train_batches = num_batches - num_val_batches val_ds = ds.take(num_val_batches).repeat() train_ds = ds.skip(num_val_batches).repeat()
ساخت مدل
مدل GPT اصلی، Transformer توالی به توالی که در فصل قبل دیدیم را ساده میکند. به جای دریافت یک توالی منبع و هدف با یک encoder و decoder، همانطور که برای مدل ترجمه خود انجام دادیم، رویکرد GPT encoder را به طور کامل حذف میکند و فقط از decoder استفاده میکند. این بدان معناست که اطلاعات فقط میتوانند از چپ به راست در یک توالی حرکت کنند.
این یک شرط جالب از سوی توسعهدهندگان GPT بود. یک مدل فقط decoder همچنان میتواند مسائل توالی به توالی مانند پاسخ به سؤال را مدیریت کند. با این حال، به جای تغذیه سؤال و پاسخ به عنوان ورودیهای جداگانه، باید هر دو را در یک توالی واحد ترکیب کنیم تا آن را به مدل خود بدهیم.
from keras import layers
class TransformerDecoder(keras.Layer):
def __init__(self, hidden_dim, intermediate_dim, num_heads):
super().__init__()
key_dim = hidden_dim // num_heads
# Self-attention layers
self.self_attention = layers.MultiHeadAttention(
num_heads, key_dim, dropout=0.1
)
self.self_attention_layernorm = layers.LayerNormalization()
# Feedforward layers
self.feed_forward_1 = layers.Dense(intermediate_dim, activation="relu")
self.feed_forward_2 = layers.Dense(hidden_dim)
self.feed_forward_layernorm = layers.LayerNormalization()
self.dropout = layers.Dropout(0.1)
def call(self, inputs):
# Self-attention computation
residual = x = inputs
x = self.self_attention(query=x, key=x, value=x, use_causal_mask=True)
x = self.dropout(x)
x = x + residual
x = self.self_attention_layernorm(x)
# Feedforward computation
residual = x
x = self.feed_forward_1(x)
x = self.feed_forward_2(x)
x = self.dropout(x)
x = x + residual
x = self.feed_forward_layernorm(x)
return x
در مرحله بعد، میتوانیم لایه PositionalEmbedding را از فصل ۱۵ کپی کنیم. به یاد بیاورید که این لایه به ما یک راه ساده برای یادگیری یک embedding برای هر موقعیت در یک توالی میدهد و آن را با token embeddingهای ما ترکیب میکند.
یک ترفند جالب وجود دارد که میتوانیم در اینجا برای صرفهجویی در برخی حافظه GPU به کار ببریم. بزرگترین وزنها در یک مدل Transformer، token embeddingهای ورودی و لایه dense پیشبینی خروجی هستند زیرا آنها با فضای واژگان ما سروکار دارند.
from keras import ops
class PositionalEmbedding(keras.Layer):
def __init__(self, sequence_length, input_dim, output_dim):
super().__init__()
self.token_embeddings = layers.Embedding(input_dim, output_dim)
self.position_embeddings = layers.Embedding(sequence_length, output_dim)
def call(self, inputs, reverse=False):
if reverse:
token_embeddings = self.token_embeddings.embeddings
return ops.matmul(inputs, ops.transpose(token_embeddings))
positions = ops.cumsum(ops.ones_like(inputs), axis=-1) - 1
embedded_tokens = self.token_embeddings(inputs)
embedded_positions = self.position_embeddings(positions)
return embedded_tokens + embedded_positions
بیایید مدل خود را بسازیم. ما هشت لایه decoder را در یک مدل “mini” GPT واحد قرار خواهیم داد.
ما همچنین یک تنظیم Keras به نام دقت مختلط (mixed precision) را برای تسریع آموزش روشن خواهیم کرد. این به Keras اجازه میدهد برخی از محاسبات مدل را با فدا کردن برخی وفاداری عددی بسیار سریعتر اجرا کند.
# Enables mixed precision (see chapter 18)
keras.config.set_dtype_policy("mixed_float16")
vocab_size = tokenizer.vocabulary_size()
hidden_dim = 512
intermediate_dim = 2056
num_heads = 8
num_layers = 8
inputs = keras.Input(shape=(None,), dtype="int32", name="inputs")
embedding = PositionalEmbedding(sequence_length, vocab_size, hidden_dim)
x = embedding(inputs)
x = layers.LayerNormalization()(x)
for i in range(num_layers):
x = TransformerDecoder(hidden_dim, intermediate_dim, num_heads)(x)
outputs = embedding(x, reverse=True)
mini_gpt = keras.Model(inputs, outputs)
این مدل ۴۱ میلیون پارامتر دارد که برای مدلهای این کتاب بزرگ است اما در مقایسه با بیشتر LLMهای امروزی که از چند میلیارد تا تریلیونها پارامتر دارند، کاملاً کوچک است.
پیشآموزش مدل
آموزش یک Transformer بزرگ به طور معروف سخت است – مدل به مقداردهی اولیه پارامترها و انتخاب بهینهساز حساس است. زمانی که بسیاری از لایههای Transformer روی هم قرار میگیرند، آسان است که از گرادیانهای انفجاری رنج ببریم، جایی که پارامترها خیلی سریع بهروز میشوند و تابع loss ما همگرا نمیشود.
class WarmupSchedule(keras.optimizers.schedules.LearningRateSchedule):
def __init__(self):
# Peak learning rate
self.rate = 2e-4
self.warmup_steps = 1_000.0
def __call__(self, step):
step = ops.cast(step, dtype="float32")
scale = ops.minimum(step / self.warmup_steps, 1.0)
return self.rate * scale
ما مدل خود را با استفاده از یک بار عبور از ۱ میلیارد توکن خود آموزش خواهیم داد، که در هشت epoch تقسیم شده است تا بتوانیم گاهی اوقات loss و accuracy مجموعه اعتبارسنجی خود را بررسی کنیم.
num_epochs = 8
# Set these to a lower value if you don't want to wait for training.
steps_per_epoch = num_train_batches // num_epochs
validation_steps = num_val_batches
mini_gpt.compile(
optimizer=keras.optimizers.Adam(schedule),
loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=["accuracy"],
)
mini_gpt.fit(
train_ds,
validation_data=val_ds,
epochs=num_epochs,
steps_per_epoch=steps_per_epoch,
validation_steps=validation_steps,
)
logit چیست؟
هنگامی که مدل خود را compile میکنیم، متوجه یک مقدار جدید برای loss میشوید: SparseCategoricalCrossentropy(from_logits=True). logit چیست؟
پروژکشن خروجی در انتهای مدل transformer ما شامل activation معمول softmax نیست. میتوانید به این خروجی به عنوان یک دسته “احتمالات لگاریتمی نرمالنشده” برای هر توکن فکر کنید. اگر هر مقدار خروجی را تواندار کنید و همه مقدارها را نرمال کنید تا مجموع آنها ۱ شود (این همان کاری است که تابع softmax انجام میدهد)، یک مقدار احتمال خواهید گرفت. یک اصطلاح رایج برای یک “احتمال لگاریتمی نرمالنشده”، logit است.
پس از آموزش، مدل ما میتواند توکن بعدی در یک توالی را حدود ۳۶٪ از زمان در مجموعه اعتبارسنجی ما پیشبینی کند، اگرچه چنین معیاری فقط یک heuristic خام است.
رمزگشایی تولیدی
برای نمونهگیری برخی خروجی از مدل خود، میتوانیم رویکردی را که برای تولید شکسپیر یا ترجمههای اسپانیایی در فصل ۱۵ استفاده کردیم دنبال کنیم.
def generate(prompt, max_length=64):
tokens = list(ops.convert_to_numpy(tokenizer(prompt)))
prompt_length = len(tokens)
for _ in range(max_length - prompt_length):
prediction = mini_gpt(ops.convert_to_numpy([tokens]))
prediction = ops.convert_to_numpy(prediction[0, -1])
tokens.append(np.argmax(prediction).item())
return tokenizer.detokenize(tokens)
بیایید این را با یک prompt متنی امتحان کنیم:
>>> prompt = "A piece of advice" >>> generate(prompt) A piece of advice, and the best way to get a feel for yourself is to get a sense of what you are doing. If you are a business owner, you can get a sense of what you are doing. You can get a sense of what you are doing, and you can get a sense of what
def compiled_generate(prompt, max_length=64):
tokens = list(ops.convert_to_numpy(tokenizer(prompt)))
prompt_length = len(tokens)
# Pads tokens to the full sequence length
tokens = tokens + [0] * (max_length - prompt_length)
for i in range(prompt_length, max_length):
prediction = mini_gpt.predict(np.array([tokens]), verbose=0)
prediction = prediction[0, i - 1]
tokens[i] = np.argmax(prediction).item()
return tokenizer.detokenize(tokens)
بیایید ببینیم این تابع جدید چقدر سریع است:
>>> import timeit >>> tries = 10 >>> timeit.timeit(lambda: compiled_generate(prompt), number=tries) / tries 0.4866470648999893
فراخوانی تولید ما با کامپایل از دقایق به کمتر از یک ثانیه رسید. این بهبود کاملاً چشمگیری است.
استراتژیهای نمونهگیری
یکی دیگر از مشکلات آشکار با خروجی تولیدی ما این است که مدل ما اغلب خود را تکرار میکند. در run آموزشی خاص ما، مدل گروه کلمات “get a sense of what you are doing” را بارها و بارها تکرار میکند.
استفاده از محتملترین خروجی در هر مرحله تولید را جستجوی حریصانه (greedy search) مینامند. این سادهترین رویکرد برای استفاده از پیشبینیهای مدل است، اما به سختی تنها رویکرد است.
def compiled_generate(prompt, sample_fn, max_length=64):
tokens = list(ops.convert_to_numpy(tokenizer(prompt)))
prompt_length = len(tokens)
tokens = tokens + [0] * (max_length - prompt_length)
for i in range(prompt_length, max_length):
prediction = mini_gpt.predict(np.array([tokens]), verbose=0)
prediction = prediction[0, i - 1]
next_token = ops.convert_to_numpy(sample_fn(prediction))
tokens[i] = np.array(next_token).item()
return tokenizer.detokenize(tokens)
def greedy_search(preds):
return ops.argmax(preds)
compiled_generate(prompt, greedy_search)
def random_sample(preds, temperature=1.0):
preds = preds / temperature
return keras.random.categorical(preds[None, :], num_samples=1)[0]
>>> compiled_generate(prompt, random_sample) A piece of advice, just read my knees and stick with getables and a hello to me. However, the bar napkin doesn't last as long. I happen to be waking up close and pull it up as I wanted too and I still get it, really, shouldn't be a reaction
>>> from functools import partial >>> compiled_generate(prompt, partial(random_sample, temperature=2.0)) ... >>> compiled_generate(prompt, partial(random_sample, temperature=0.8)) ... >>> compiled_generate(prompt, partial(random_sample, temperature=0.2)) ...
def top_k(preds, k=5, temperature=1.0):
preds = preds / temperature
top_preds, top_indices = ops.top_k(preds, k=k, sorted=False)
choice = keras.random.categorical(top_preds[None, :], num_samples=1)[0]
return ops.take_along_axis(top_indices, choice, axis=-1)
استفاده از یک LLM از پیش آموزشدیده
حالا که یک مدل زبانی کوچک را از صفر آموزش دادهایم، بیایید از یک مدل از پیش آموزشدیده یک میلیارد پارامتری استفاده کنیم و ببینیم چه کاری میتواند انجام دهد.
تولید متن با مدل Gemma
برای بارگذاری این مدل از پیش آموزشدیده، میتوانیم از KerasHub استفاده کنیم، همانطور که در فصلهای قبلی انجام دادهایم.
import kagglehub kagglehub.login()
gemma_lm = keras_hub.models.CausalLM.from_preset(
"gemma3_1b",
dtype="float32",
)
>>> gemma_lm.compile(sampler="greedy")
>>> gemma_lm.generate("A piece of advice", max_length=40)
A piece of advice from a former student of mine:
“I’m not sure if you’ve heard of it, but I’ve been told that the best way to learn >>> gemma_lm.generate(“How can I make brownies?”, max_length=40) How can I make brownies? [User 0001] I’m trying to make brownies for my son’s birthday party. I’ve never made brownies before.
تنظیم دقیق دستورالعمل
import json
PROMPT_TEMPLATE = """"[instruction]\n{}[end]\n[response]\n"""
RESPONSE_TEMPLATE = """{}[end]"""
dataset_path = keras.utils.get_file(
origin=(
"https://hf.co/datasets/databricks/databricks-dolly-15k/"
"resolve/main/databricks-dolly-15k.jsonl"
),
)
data = {"prompts": [], "responses": []}
with open(dataset_path) as file:
for line in file:
features = json.loads(line)
if features["context"]:
continue
data["prompts"].append(PROMPT_TEMPLATE.format(features["instruction"]))
data["responses"].append(RESPONSE_TEMPLATE.format(features["response"]))
>>> data["prompts"][0] [instruction] Which is a species of fish? Tope or Rope[end] [response] >>> data["responses"][0] Tope[end]
انطباق کمرتبه (LoRA)
class LoraLinear(keras.Layer):
def __init__(self, input_dim, output_dim, rank):
super().__init__()
self.kernel = self.add_weight(
shape=(input_dim, output_dim), trainable=False
)
self.alpha = self.add_weight(shape=(input_dim, rank))
self.beta = self.add_weight(shape=(rank, output_dim))
def call(self, inputs):
frozen = ops.matmul(inputs, self.kernel)
update = ops.matmul(ops.matmul(inputs, self.alpha), self.beta)
return frozen + update
gemma_lm.backbone.enable_lora(rank=8)
gemma_lm.compile(
loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
optimizer=keras.optimizers.Adam(5e-5),
weighted_metrics=[keras.metrics.SparseCategoricalAccuracy()],
)
gemma_lm.fit(train_ds, validation_data=val_ds, epochs=1)
>>> gemma_lm.generate( ... "[instruction]\nHow can I make brownies?[end]\n" ... "[response]\n", ... max_length=512, ... ) [instruction] How can I make brownies?[end] [response] You can make brownies by mixing together 1 cup of flour, 1 cup of sugar, 1/2 cup of butter, 1/2 cup of milk, 1/2 cup of chocolate chips, and 1/2 cup of chocolate chips. Then, you can bake it in a 9x13 pan for 30 minutes at 350 degrees Fahrenheit. You can also add a little bit of vanilla extract to the batter to make it taste better.[end]
پیشرفت بیشتر با LLMها
یادگیری تقویتی با بازخورد انسانی (RLHF)
for prompts in dataset:
# Takes an action
responses = model.generate(prompts)
# Receives a reward
rewards = reward_model.predict(responses)
good_responses = []
for response, score in zip(responses, rewards):
if score > cutoff:
good_responses.append(response)
# Updates the model parameters. We do not update the reward model.
model.fit(good_responses)
gemma_lm = keras_hub.models.CausalLM.from_preset(
"gemma3_instruct_4b",
dtype="bfloat16",
)
PROMPT_TEMPLATE = """user
{}
model
"""
>>> prompt = "Why can't you assign values in Jax tensors? Be brief!" >>> gemma_lm.generate(PROMPT_TEMPLATE.format(prompt), max_length=512) user Why can't you assign values in Jax tensors? Be brief! model Jax tensors are designed for efficient automatic differentiation. Directly assigning values disrupts this process, making it difficult to track gradients correctly. Instead, Jax uses operations to modify tensor values, preserving the differentiation pipeline.
LLMهای چندوجهی
import matplotlib.pyplot as plt
image_url = (
"https://github.com/mattdangerw/keras-nlp-scripts/"
"blob/main/learned-python.png?raw=true"
)
image_path = keras.utils.get_file(origin=image_url)
image = np.array(keras.utils.load_img(image_path))
plt.axis("off")
plt.imshow(image)
plt.show()
>>> # Limits the maximum input size of the model
>>> gemma_lm.preprocessor.max_images_per_prompt = 1
>>> gemma_lm.preprocessor.sequence_length = 512
>>> prompt = "What is going on in this image? Be concise!"
>>> gemma_lm.generate({
... "prompts": PROMPT_TEMPLATE.format(prompt),
... "images": [image],
... })
user
What is going on in this image? Be concise!
model
A snake wearing glasses is sitting in a leather armchair, surrounded by a large
bookshelf, and reading a book. It's a whimsical, slightly surreal image.
مدلهای “استدلالی”
prompt = """Judy wrote a 2-page letter to 3 friends twice a week for 3 months. How many letters did she write? Be brief, and add "ANSWER:" before your final answer.""" # Turns on random sampling to get a diverse range of outputs gemma_lm.compile(sampler="random")
>>> gemma_lm.generate(PROMPT_TEMPLATE.format(prompt)) user Judy wrote a 2-page letter to 3 friends twice a week for 3 months. How many letters did she write? Be brief, and add "ANSWER:" before your final answer. model Here's how to solve the problem: * **Letters per week:** 3 friends * 2 letters/week = 6 letters/week * **Letters per month:** 6 letters/week * 4 weeks/month = 24 letters/month * **Letters in 3 months:** 24 letters/month * 3 months = 72 letters * **Total letters:** 72 letters * 2 = 144 letters ANSWER: 144
LLMها به کجا میروند؟
با توجه به مسیر LLMها که در ابتدای این فصل بحث شد، ممکن است واضح به نظر برسد که LLMها به کجا خواهند رفت. پارامترهای بیشتر! عملکرد حتی بهتر! به طور کلی، احتمالاً صحیح است، اما مسیر ما ممکن است چندان خطی نباشد.
اگر یک بودجه ثابت برای پیشآموزش داشته باشید، بگویید یک میلیون دلار، میتوانید تقریباً به آن به عنوان خرید مقدار ثابتی از محاسبات یا عملیات اعشاری فکر کنید. میتوانید آن flops را یا صرف آموزش با دادههای بیشتر یا آموزش یک مدل بزرگتر کنید.
تحقیقات اخیر اشاره کرده است که GPT-3، با ۱۷۵ میلیارد پارامتر، برای بودجه محاسباتی خود بسیار بزرگ بود. آموزش یک مدل کوچکتر با دادههای بیشتر منجر به عملکرد بهتر مدل میشد. بنابراین اخیراً، اندازه مدلها مسطحتر شده است در حالی که اندازه دادهها رو به افزایش بوده است.
خلاصه
- مدلهای زبانی بزرگ یا LLMها ترکیبی از چند مؤلفه کلیدی هستند:
- معماری Transformer
- یک وظیفه مدلسازی زبان (پیشبینی توکن بعدی بر اساس توکنهای گذشته)
- مقدار زیادی داده متنی بدون برچسب
- یک LLM یک توزیع احتمال برای پیشبینی توکنهای فردی میآموزد. این میتواند با یک استراتژی نمونهگیری برای تولید یک رشته طولانی از متن ترکیب شود.
- LLMها از میلیاردها پارامتر استفاده میکنند و بر روی تریلیونها کلمه متن آموزش داده میشوند.
- خروجی LLM غیرقابل اعتماد است و همه LLMها گاهی اطلاعات واقعی نادرست را توهم میبینند.
- LLMها میتوانند برای دنبال کردن دستورالعملها در یک دیالوگ چت تنظیم دقیق شوند.
- رایجترین گلوگاه منبع هنگام کار با LLMها حافظه شتابدهنده است.
- LoRA تکنیکی برای کاهش استفاده از حافظه است با فریز کردن بیشتر پارامترهای Transformer و فقط بهروزرسانی یک تجزیه کمرتبه از وزنهای پروژکشن attention.
- LLMها میتوانند دادهها را از روشهای مختلف ورودی یا خروجی کنند اگر بتوانید بفهمید چگونه این ورودیها یا خروجیها را به عنوان توالی در یک مسئله پیشبینی توالی قالببندی کنید.
- یک مدل پایه یک اصطلاح کلی برای مدلهای هر روشی است که با استفاده از خودنظارت برای طیف گستردهای از وظایف downstream آموزش داده شدهاند.
منبع: یادگیری عمیق با پایتون، ویرایش سوم نوشته فرانسوا شوله
دیدگاهتان را بنویسید