RNN یا شبکه عصبی بازگشتی، برای پردازش دنباله از حالتی استفاده میکند که از گام قبل به گام بعد میرسد. در نتیجه، خروجی یک گام میتواند هم به ورودی فعلی و هم به اثر ورودیهای پیشین وابسته باشد. این «حالت پنهان» با ذخیره پرونده مشتری، تاریخچه رابط چت یا تغییر وزن مدل یکسان نیست.
یک حالت عددی، سه ورودی
برای تمرین، h_t = tanh(۰٫۸×x_t +۰٫۵×h_previous +۰٫۱) را انتخاب میکنیم. حالت آغازین صفر و دنباله ورودی [۱،۰،−۱] است. وزنها ثابت و انتخاب آموزشی ما هستند. هیچ داده یا مدل گفتاری بارگذاری نمیشود و محاسبه، آموزش شبکه نیست.
tanh مقدار ترکیب خطی را به بازهای محدود میبرد؛ اما آن مقدار احتمال رخداد یا خلاصه قابل خواندن جمله نیست. در شبکههای واقعی، حالت میتواند یک بردار باشد. اینجا عمداً فقط یک عدد داریم تا نقش انتقال حالت دیده شود.
جدول عبور از دنباله
| گام | ورودی | حالت پیشین | حالت تازه تقریبی |
|---|---|---|---|
| 1 | 1 | 0 | ۰٫۷۱۶۲۹۸ |
| 2 | 0 | ۰٫۷۱۶۲۹۸ | ۰٫۴۲۸۵۷۴ |
| 3 | −۱ | ۰٫۴۲۸۵۷۴ | −۰٫۴۵۰۸۰۷ |
در گام دوم، با آنکه ورودی صفر است، حالت تازه صفر نمیشود. مقدار قبلی در ضریب ۰٫۵ وارد ترکیب شده است. در گام سوم هم فقط tanh منفی ۰٫۷ را نداریم؛ اثر حالت گام دوم در نتیجه دیده میشود.
ترتیب و ریستکردن را جدا آزمایش کنیم
اگر ورودیها را برعکس کنیم، ترتیب [−۱،۰،۱] میشود و معمولاً حالت نهایی دیگری به دست میآید. اگر قبل از هر ورودی حالت را صفر کنیم، دیگر همان دنباله را با همان قرارداد پردازش نکردهایم؛ هر عدد مستقل دیده شده است. کد هر سه حالت را کنار هم چاپ میکند تا این اختلاف عملی روشن باشد.
import math
def recurrent(xs, initial=0.0):
h = initial
result = []
for x in xs:
h = math.tanh(0.8*x+0.5*h+0.1)
result.append(h)
return result
xs = [1.0, 0.0, -1.0]
forward = recurrent(xs)
reverse = recurrent(xs[::-1])
reset_each = [recurrent([x])[0] for x in xs]
print('sequence', [round(x, 6) for x in forward])
print('reversed', [round(x, 6) for x in reverse])
print('reset every item', [round(x, 6) for x in reset_each])
assert abs(forward[0]-0.7162978701990244) < 1e-12
assert abs(forward[-1]+0.450807140833709) < 1e-12
assert abs(forward[-1]-reverse[-1]) > 0.5
assert forward[1] != reset_each[1]در خروجی اصلی، سه حالت حدود ۰٫۷۱۶۲۹۸، ۰٫۴۲۸۵۷۴ و منفی ۰٫۴۵۰۸۰۷ هستند. اینها امتیاز کیفیت یا درصد درک گفتار نیستند. تغییر حالت در زمان اجرا به معنی تغییر وزنهای ۰٫۸ و ۰٫۵ هم نیست؛ آن دو در همه گامهای کد ثابتاند.
حالت پنهان چه نوع حافظهای نیست؟
یک عدد، تاریخچه کامل ورودی را بهصورت پرونده بازیابیپذیر نگه نمیدارد. برای نمونه، از حالت آخر همین شبکه نمیتوان بدون اطلاعات دیگر گفت هر سه ورودی دقیقاً چه بودهاند. نگهداشتن حالت میان دو دنباله مستقل نیز تصمیمی جداست؛ اگر ریست لازم را فراموش کنیم، خروجی دنباله دوم به اولی وابسته میشود.
پنجره زمینه و حافظه دستیار سه لایه برنامه و ذخیره را جدا میکند. موضوع اینجا عملیات عددی در معماری RNN است؛ وجود تاریخچه در یک برنامه شاهد استفاده آن از RNN نیست. برای فهم تغییر پارامتر در آموزش نیز مثال پسانتشار را ببینید.
برای آزمایش خودتان چه چیزی ثبت کنید؟
ترتیب ورودی، حالت آغازین، مرز دنباله و وزنهای ثابت را بنویسید. سپس فقط یکی را عوض کنید. مقایسه دو اجرای دارای ترتیب یا حالت آغازین متفاوت را به تصادفیبودن مدل نسبت ندهید. برای یک سامانه واقعی، حفظ وابستگیهای بلند، کیفیت و خطای وظیفه باید جدا با داده نماینده سنجیده شوند؛ سه گام این مثال چیزی درباره آنها ثابت نمیکند.
اگر هدف شما ادامه درست مکالمه مشتری است، چند نمونه مجاز و اطلاعاتی را که باید در هر نوبت دیده شوند برای بررسی راهکار اپرا آماده کنید. این راهنما استفاده از RNN یا حافظه دائمی در محصولات اپرا را اعلام نمیکند.
فایل تمرین و منابع
دریافت کد کامل این تمرین؛ این فایل فقط از کتابخانه استاندارد پایتون استفاده میکند. ورودیهای آن ساختگی و برای بازتولید محاسبهاند؛ اجرای آموزشی آن نتیجه یک محصول یا مشتری را نشان نمیدهد.
تاریخ بررسی منابع: ۳ نوامبر ۲۰۲۶. منابع، مرجع روشاند؛ دادهها، اعداد و کد مثال برای همین راهنما طراحی شدهاند.