وبلاگ رسانگار
با ما حرفه ای باشید

سرور مجازی NVMe

پایتون برای NLP: تولید متن یادگیری عمیق با Keras

0 35
زمان لازم برای مطالعه: 9 دقیقه


این بیست و یکمین مقاله از سری مقالات من است روی پایتون برای NLP. در مقاله قبلی، روش استفاده از کتابخانه FastText فیس بوک را برای یافتن شباهت معنایی و طبقه بندی متن توضیح دادم. در این مقاله روش تولید متن از طریق تکنیک یادگیری عمیق در پایتون با استفاده از کتابخانه کراس.

تولید متن یکی از پیشرفته ترین کاربردهای NLP است. تکنیک های یادگیری عمیق برای انواع وظایف تولید متن مانند نوشتن شعر، تولید فیلمنامه برای فیلم ها و حتی برای ساخت موسیقی استفاده می شود. با این حال، در این مقاله یک مثال بسیار ساده از تولید متن را مشاهده خواهیم کرد که در آن با یک رشته ورودی از کلمات، کلمه بعدی را پیش‌بینی می‌کنیم. ما از متن خام رمان معروف شکسپیر “مکبث” استفاده خواهیم کرد و از آن برای پیش‌بینی کلمه بعدی با توجه به دنباله‌ای از کلمات ورودی استفاده خواهیم کرد.

پس از تکمیل این مقاله، شما قادر خواهید بود با استفاده از مجموعه داده انتخابی خود، تولید متن را انجام دهید. بنابراین، بیایید بدون بحث بیشتر شروع کنیم.

واردات کتابخانه ها و مجموعه داده ها

اولین قدم این است که import کتابخانه های مورد نیاز برای اجرای اسکریپت های این مقاله به همراه مجموعه داده ها. کد زیر کتابخانه های مورد نیاز را وارد می کند:

import numpy as np
from keras.models import Sequential, load_model
from keras.layers import Dense, Embedding, LSTM, Dropout
from keras.utils import to_categorical
from random import randint
import re

مرحله بعدی دانلود مجموعه داده است. ما از کتابخانه NLTK پایتون برای دانلود مجموعه داده استفاده خواهیم کرد. ما استفاده خواهیم کرد مجموعه داده گوتنبرگکه شامل 3036 کتاب انگلیسی نوشته 142 نویسنده از جمله “مکبث” اثر شکسپیر است.

اسکریپت زیر مجموعه داده گوتنبرگ را دانلود می کند و نام تمام فایل های موجود در مجموعه داده را چاپ می کند.

import nltk
nltk.download('gutenberg')
from nltk.corpus import gutenberg as gut

print(gut.fileids())

شما باید خروجی زیر را ببینید:

('austen-emma.txt', 'austen-persuasion.txt', 'austen-sense.txt', 'bible-kjv.txt', 'blake-poems.txt', 'bryant-stories.txt', 'burgess-busterbrown.txt', 'carroll-alice.txt', 'chesterton-ball.txt', 'chesterton-brown.txt', 'chesterton-thursday.txt', 'edgeworth-parents.txt', 'melville-moby_dick.txt', 'milton-paradise.txt', 'shakespeare-caesar.txt', 'shakespeare-hamlet.txt', 'shakespeare-macbeth.txt', 'whitman-leaves.txt')

پرونده shakespeare-macbeth.txt حاوی متن خام برای رمان “مکبث”. برای خواندن متن از این فایل، raw روش از gutenberg کلاس قابل استفاده است:

macbeth_text = nltk.corpus.gutenberg.raw('shakespeare-macbeth.txt')

اجازه دهید print 500 کاراکتر اول از مجموعه داده:

print(macbeth_text(:500))

در اینجا خروجی است:

(The Tragedie of Macbeth by William Shakespeare 1603)


Actus Primus. Scoena Prima.

Thunder and Lightning. Enter three Witches.

  1. When shall we three meet againe?
In Thunder, Lightning, or in Raine?
  2. When the Hurley-burley's done,
When the Battaile's lost, and wonne

   3. That will be ere the set of Sunne

   1. Where the place?
  2. Vpon the Heath

   3. There to meet with Macbeth

   1. I come, Gray-Malkin

   All. Padock calls anon: faire is foule, and foule is faire,
Houer through

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

پیش پردازش داده ها

برای حذف علائم نگارشی و کاراکترهای خاص، تابعی به نام تعریف می کنیم preprocess_text():

def preprocess_text(sen):
    
    sentence = re.sub('(^a-zA-Z)', ' ', sen)

    
    sentence = re.sub(r"\s+(a-zA-Z)\s+", ' ', sentence)

    
    sentence = re.sub(r'\s+', ' ', sentence)

    return sentence.lower()

را preprocess_text تابع یک رشته متن را به عنوان پارامتر می پذیرد و یک رشته متن پاک شده را با حروف کوچک برمی گرداند.

بیایید اکنون و دوباره متن خود را پاک کنیم print 500 کاراکتر اول:

macbeth_text = preprocess_text(macbeth_text)
macbeth_text(:500)

در اینجا خروجی است:

the tragedie of macbeth by william shakespeare actus primus scoena prima thunder and lightning enter three witches when shall we three meet againe in thunder lightning or in raine when the hurley burley done when the battaile lost and wonne that will be ere the set of sunne where the place vpon the heath there to meet with macbeth come gray malkin all padock calls anon faire is foule and foule is faire houer through the fogge and filthie ayre exeunt scena secunda alarum within enter king malcom

تبدیل کلمات به اعداد

مدل های یادگیری عمیق مبتنی هستند روی الگوریتم های آماری از این رو، برای کار با مدل های یادگیری عمیق، باید کلمات را به اعداد تبدیل کنیم.

در این مقاله از یک روش بسیار ساده استفاده خواهیم کرد که در آن کلمات به اعداد صحیح منفرد تبدیل می شوند. قبل از اینکه بتوانیم کلمات را به اعداد صحیح تبدیل کنیم، باید متن خود را به کلمات جداگانه تبدیل کنیم. برای انجام این کار، word_tokenize() روش از nltk.tokenize می توان از ماژول استفاده کرد.

اسکریپت زیر متن موجود در مجموعه داده ما را نشانه گذاری می کند و سپس تعداد کل کلمات موجود در مجموعه داده و همچنین تعداد کل کلمات منحصر به فرد در مجموعه داده را چاپ می کند:

from nltk.tokenize import word_tokenize

macbeth_text_words = (word_tokenize(macbeth_text))
n_words = len(macbeth_text_words)
unique_words = len(set(macbeth_text_words))

print('Total Words: %d' % n_words)
print('Unique Words: %d' % unique_words)

خروجی به شکل زیر است:

Total Words: 17250
Unique Words: 3436

متن ما در مجموع دارای 17250 کلمه است که از این تعداد 3436 کلمه منحصر به فرد است. برای تبدیل کلمات رمز شده به اعداد، Tokenizer کلاس از keras.preprocessing.text می توان از ماژول استفاده کرد. باید با fit_on_texts روش و آن را به لیست کلمات ارسال کنید. یک فرهنگ لغت ایجاد می شود که در آن کلیدها کلمات را نشان می دهند، در حالی که اعداد صحیح مقادیر متناظر فرهنگ لغت را نشان می دهند.

به اسکریپت زیر نگاه کنید:

from keras.preprocessing.text import Tokenizer
tokenizer = Tokenizer(num_words=3437)
tokenizer.fit_on_texts(macbeth_text_words)

برای دسترسی به فرهنگ لغت حاوی کلمات و نمایه های مربوط به آنها، word_index ویژگی از tokenizer شی را می توان استفاده کرد:

vocab_size = len(tokenizer.word_index) + 1
word_2_index = tokenizer.word_index

اگر طول فرهنگ لغت را بررسی کنید، حاوی 3436 کلمه است که تعداد کل کلمات منحصر به فرد در مجموعه داده ما است.

حالا بیایید print پانصدمین کلمه منحصر به فرد به همراه مقدار صحیح آن از word_2_index فرهنگ لغت.

print(macbeth_text_words(500))
print(word_2_index(macbeth_text_words(500)))

در اینجا خروجی است:

comparisons
1456

در اینجا به کلمه “مقایسه” مقدار صحیح 1456 اختصاص داده شده است.

تغییر شکل داده ها

تولید متن در دسته مشکلات توالی چند به یک قرار می گیرد زیرا ورودی دنباله ای از کلمات و خروجی یک کلمه واحد است. ما استفاده خواهیم کرد شبکه حافظه کوتاه مدت بلند مدت (LSTM)، که نوعی شبکه عصبی بازگشتی برای ایجاد مدل تولید متن ما است. LSTM داده ها را در قالب 3 بعدی (تعداد نمونه ها، تعداد مراحل زمانی، ویژگی ها در هر مرحله زمانی) می پذیرد. از آنجایی که خروجی یک کلمه خواهد بود، شکل خروجی 2 بعدی (تعداد نمونه، تعداد کلمات منحصر به فرد در مجموعه) خواهد بود.

اسکریپت زیر شکل توالی های ورودی و خروجی های مربوطه را تغییر می دهد.

input_sequence = ()
output_words = ()
input_seq_length = 100

for i in range(0, n_words - input_seq_length , 1):
    in_seq = macbeth_text_words(i:i + input_seq_length)
    out_seq = macbeth_text_words(i + input_seq_length)
    input_sequence.append((word_2_index(word) for word in in_seq))
    output_words.append(word_2_index(out_seq))

در اسکریپت بالا، دو لیست خالی را اعلام می کنیم input_sequence و output_words. را input_seq_length روی 100 تنظیم شده است، به این معنی که دنباله ورودی ما از 100 کلمه تشکیل شده است. در مرحله بعد، یک حلقه را اجرا می کنیم که در آن در اولین تکرار، مقادیر صحیح برای 100 کلمه اول متن به آن اضافه می شود. input_sequence فهرست کلمه 101 به الحاق شده است output_words فهرست در طول تکرار دوم، دنباله ای از کلمات که از کلمه دوم در متن شروع می شود و به کلمه 101 ختم می شود در ذخیره می شود. input_sequence لیست، و کلمه 102 در ذخیره می شود output_words آرایه و غیره روی. در مجموع 17150 دنباله ورودی ایجاد خواهد شد زیرا 17250 کلمه در مجموعه داده وجود دارد (100 کمتر از کل کلمات).

حالا بیایید print مقدار اولین دنباله در input_sequence لیست:

print(input_sequence(0))

خروجی:

(1, 869, 4, 40, 60, 1358, 1359, 408, 1360, 1361, 409, 265, 2, 870, 31, 190, 291, 76, 36, 30, 190, 327, 128, 8, 265, 870, 83, 8, 1362, 76, 1, 1363, 1364, 86, 76, 1, 1365, 354, 2, 871, 5, 34, 14, 168, 1, 292, 4, 649, 77, 1, 220, 41, 1, 872, 53, 3, 327, 12, 40, 52, 1366, 1367, 25, 1368, 873, 328, 355, 9, 410, 2, 410, 9, 355, 1369, 356, 1, 1370, 2, 874, 169, 103, 127, 411, 357, 149, 31, 51, 1371, 329, 107, 12, 358, 412, 875, 1372, 51, 20, 170, 92, 9)

بیایید دنباله های ورودی خود را با تقسیم اعداد صحیح در دنباله ها بر بزرگترین مقدار صحیح، عادی سازی کنیم. اسکریپت زیر نیز خروجی را به فرمت 2 بعدی تبدیل می کند.

X = np.reshape(input_sequence, (len(input_sequence), input_seq_length, 1))
X = X / float(vocab_size)

y = to_categorical(output_words)

اسکریپت زیر شکل ورودی ها و خروجی های مربوطه را چاپ می کند.

print("X shape:", X.shape)
print("y shape:", y.shape)

خروجی:

X shape: (17150, 100, 1)
y shape: (17150, 3437)

آموزش مدل

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

ما سه لایه LSTM با 800 نورون ایجاد خواهیم کرد. یک لایه متراکم نهایی با 1 نورون اضافه می شود تا شاخص کلمه بعدی را پیش بینی کند، همانطور که در زیر نشان داده شده است:

model = Sequential()
model.add(LSTM(800, input_shape=(X.shape(1), X.shape(2)), return_sequences=True))
model.add(LSTM(800, return_sequences=True))
model.add(LSTM(800))
model.add(Dense(y.shape(1), activation='softmax'))

model.summary()

model.compile(loss='categorical_crossentropy', optimizer='adam')

از آنجایی که کلمه خروجی می تواند یکی از 3436 کلمه منحصر به فرد باشد، مشکل ما یک مسئله طبقه بندی چند کلاسه است، از این رو categorical_crossentropy تابع ضرر استفاده می شود. در صورت طبقه بندی باینری، binary_crossentropy تابع استفاده می شود. پس از اجرای اسکریپت بالا، باید خلاصه مدل را ببینید:

Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
lstm_1 (LSTM)                (None, 100, 800)          2566400
_________________________________________________________________
lstm_2 (LSTM)                (None, 100, 800)          5123200
_________________________________________________________________
lstm_3 (LSTM)                (None, 800)               5123200
_________________________________________________________________
dense_1 (Dense)              (None, 3437)              2753037
=================================================================
Total params: 15,565,837
Trainable params: 15,565,837
Non-trainable params: 0

برای آموزش مدل، به سادگی می توانیم از آن استفاده کنیم fit() روش.

model.fit(X, y, batch_size=64, epochs=10, verbose=1)

در اینجا دوباره، می توانید با مقادیر مختلف بازی کنید batch_size و epochs. آموزش این مدل ممکن است کمی طول بکشد.

پیشگویی

برای پیش‌بینی، دنباله‌ای را به‌طور تصادفی از میان انتخاب می‌کنیم input_sequence لیست کنید، آن را به یک شکل 3 بعدی تبدیل کنید و سپس به آن منتقل کنید predict() روش مدل آموزش دیده مدل یک آرایه رمزگذاری شده یک داغ را برمی گرداند که در آن شاخصی که حاوی 1 است، مقدار شاخص کلمه بعدی خواهد بود. سپس مقدار شاخص به index_2_word فرهنگ لغت، که در آن کلمه شاخص به عنوان یک کلید استفاده می شود. را index_2_word دیکشنری کلمه ای را که متعلق به فهرستی است که به عنوان کلید به فرهنگ لغت منتقل می شود، برمی گرداند.

اسکریپت زیر به طور تصادفی دنباله ای از اعداد صحیح را انتخاب می کند و سپس دنباله مربوط به کلمات را چاپ می کند:

random_seq_index = np.random.randint(0, len(input_sequence)-1)
random_seq = input_sequence(random_seq_index)

index_2_word = dict(map(reversed, word_2_index.items()))

word_sequence = (index_2_word(value) for value in random_seq)

print(' '.join(word_sequence))

برای فیلمنامه در این مقاله، دنباله زیر به طور تصادفی انتخاب شد. توالی ایجاد شده برای شما به احتمال زیاد متفاوت از این خواهد بود:

amen when they did say god blesse vs lady consider it not so deepely mac but wherefore could not pronounce amen had most need of blessing and amen stuck in my throat lady these deeds must not be thought after these wayes so it will make vs mad macb me thought heard voyce cry sleep no more macbeth does murther sleepe the innocent sleepe sleepe that knits vp the rauel sleeue of care the death of each dayes life sore labors bath balme of hurt mindes great natures second course chiefe nourisher in life feast lady what doe you meane

در اسکریپت بالا، index_2_word فرهنگ لغت به سادگی با معکوس کردن ایجاد می شود word_2_index فرهنگ لغت. در این مورد، معکوس کردن یک فرهنگ لغت به آن اشاره دارد process تعویض کلیدها با مقادیر

بعد، ما خواهیم کرد print 100 کلمه بعدی که از دنباله کلمات بالا پیروی می کنند:

for i in range(100):
    int_sample = np.reshape(random_seq, (1, len(random_seq), 1))
    int_sample = int_sample / float(vocab_size)

    predicted_word_index = model.predict(int_sample, verbose=0)

    predicted_word_id = np.argmax(predicted_word_index)
    seq_in = (index_2_word(index) for index in random_seq)

    word_sequence.append(index_2_word( predicted_word_id))

    random_seq.append(predicted_word_id)
    random_seq = random_seq(1:len(random_seq))

را word_sequence متغیر اکنون شامل توالی کلمات ورودی ما به همراه 100 کلمه پیش‌بینی‌شده بعدی است. را word_sequence متغیر شامل دنباله ای از کلمات در قالب یک لیست است. همانطور که در زیر نشان داده شده است، می‌توانیم به سادگی کلمات موجود در لیست را به هم بپیوندیم تا دنباله خروجی نهایی را بدست آوریم:

final_output = ""
for word in word_sequence:
    final_output = final_output + " " + word

print(final_output)

در اینجا خروجی نهایی است:

amen when they did say god blesse vs lady consider it not so deepely mac but wherefore could not pronounce amen had most need of blessing and amen stuck in my throat lady these deeds must not be thought after these wayes so it will make vs mad macb me thought heard voyce cry sleep no more macbeth does murther sleepe the innocent sleepe sleepe that knits vp the rauel sleeue of care the death of each dayes life sore labors bath balme of hurt mindes great natures second course chiefe nourisher in life feast lady what doe you meane and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and

خروجی هنوز خیلی خوب به نظر نمی رسد و به نظر می رسد که مدل ما فقط از کلمه آخر یاد می گیرد and. با این حال، شما این ایده را در مورد روش ایجاد یک مدل تولید متن با Keras دریافت می کنید. برای بهبود نتایج، توصیه های زیر را برای شما دارم:

  • پارامترهای hyper، از جمله اندازه و تعداد لایه های LSTM و تعداد دوره ها را تغییر دهید تا ببینید آیا نتایج بهتری دریافت می کنید.
  • سعی کنید کلمات توقف مانند را حذف کنید is، am، are از مجموعه آموزشی برای تولید کلماتی غیر از کلمات توقف در مجموعه آزمایشی (اگرچه این بستگی دارد روی نوع کاربرد).
  • یک مدل تولید متن در سطح کاراکتر ایجاد کنید که آینده را پیش بینی کند N شخصیت ها.

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

نتیجه

در این مقاله روش ایجاد یک مدل تولید متن با استفاده از یادگیری عمیق با کتابخانه Keras Python را دیدیم. اگرچه مدل توسعه‌یافته در این مقاله بی‌نقص نیست، اما این مقاله ایده چگونگی تولید متن با یادگیری عمیق را بیان می‌کند.

(برچسب‌ها به ترجمه)# python



منتشر شده در 1403-01-20 07:39:04

1/5 (1 رای)
دیدگاه شما در خصوص مطلب چیست ؟

آدرس ایمیل شما منتشر نخواهد شد.

لطفا دیدگاه خود را با احترام به دیدگاه های دیگران و با توجه به محتوای مطلب درج کنید