GPT2 برای طبقه بندی متن با استفاده از ترانسفورماتورهای صورت در آغوش گرفته

گره منبع: 809063

طبقه بندی متن

این نوت بوک برای تنظیم دقیق مدل GPT2 برای طبقه بندی متن استفاده می شود در آغوش کشیدن صورت ترانسفورماتور کتابخانه بر روی یک مجموعه داده سفارشی

Hugging Face برای ما بسیار خوب است که همه عملکردهای مورد نیاز برای استفاده از GPT2 در کارهای طبقه بندی را شامل می شود. با تشکر از شما در آغوش کشیدن صورت!

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

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

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

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

از آنجایی که ما فقط به اولین نشانه در برت اهمیت می‌دادیم، به سمت راست می‌رفتیم. اکنون در GPT2 از آخرین نشانه برای پیش‌بینی استفاده می‌کنیم، بنابراین باید در سمت چپ قرار دهیم. به دلیل ارتقای خوب HuggingFace Transformers، می‌توانیم Tokenizer GPT2 را برای انجام این کار پیکربندی کنیم.

برای این نوت بوک چه چیزی باید بدانم؟

از آنجایی که من از PyTorch برای تنظیم دقیق مدل های ترانسفورماتور خود استفاده می کنم، هرگونه دانش در مورد PyTorch بسیار مفید است.

دانستن کمی در مورد ترانسفورماتور کتابخانه نیز کمک می کند.

چگونه از این نوت بوک استفاده کنیم؟

مانند هر پروژه ای، من این نوت بوک را با قابلیت استفاده مجدد ساختم.

همه تغییرات در بخش پردازش داده اتفاق می‌افتد، جایی که باید مجموعه داده PyTorch، جمع‌آوری داده‌ها و DataLoader را متناسب با نیازهای داده‌ای خود سفارشی کنید.

تمام پارامترهای قابل تغییر در زیر هستند واردات بخش. هر پارامتر به خوبی توضیح داده شده و ساختاری دارد که تا حد امکان بصری باشد.

مجموعه داده

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

توضیحات ارائه شده در وب سایت استنفورد:

این مجموعه داده ای برای طبقه بندی احساسات باینری است که حاوی داده های قابل ملاحظه ای بیشتر از مجموعه داده های معیار قبلی است. ما مجموعه ای از 25,000 نقد فیلم بسیار قطبی را برای آموزش و 25,000 برای آزمایش ارائه می دهیم. داده های بدون برچسب اضافی نیز برای استفاده وجود دارد. قالب‌های متن خام و کیسه‌ای از کلمات پردازش شده ارائه شده است. برای جزئیات بیشتر به فایل README موجود در نسخه مراجعه کنید.

چرا این مجموعه داده؟ من معتقدم یک مجموعه داده برای طبقه بندی آسان برای درک و استفاده است. من فکر می کنم که داده های احساسات همیشه کار با آنها سرگرم کننده است.

برنامه نویسی

حالا بیایید کمی کدنویسی کنیم! ما از طریق هر سلول کدنویسی در نوت بوک مرور خواهیم کرد و توضیح می دهیم که چه کاری انجام می دهد، کد چیست و چه زمانی مرتبط است - خروجی را نشان می دهیم.

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

وقتی از یک آموزش یاد می‌گیرم، همیشه سعی می‌کنم نتایج را تکرار کنم. من معتقدم اگر کد را در کنار توضیحات داشته باشید، پیگیری آن آسان است.

دانلود

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

Download the dataset.
!wget -q -nc http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
Unzip the dataset.
!tar -zxf /content/aclImdb_v1.tar.gz

نصب می کند

  • ترانسفورماتور برای استفاده از همه کدهای عالی Hugging Face باید کتابخانه نصب شود. برای دریافت آخرین نسخه آن را مستقیماً از GitHub نصب خواهم کرد.
  • ml_ چیزها کتابخانه ای که برای کارهای مختلف مرتبط با یادگیری ماشین استفاده می شود. من این کتابخانه را ایجاد کردم تا مقدار کدی را که برای هر پروژه یادگیری ماشینی باید بنویسم کاهش دهم.
# Install transformers library.
!pip install -q git+https://github.com/huggingface/transformers.git
# Install helper functions.
!pip install -q git+https://github.com/gmihaila/ml_things.git
Installing build dependencies ... done Getting requirements to build wheel ... done Preparing wheel metadata ... done |████████████████████████████████| 2.9MB 6.7MB/s |████████████████████████████████| 890kB 48.9MB/s |████████████████████████████████| 1.1MB 49.0MB/s Building wheelfor transformers (PEP 517) ... done Building wheel for sacremoses (setup.py) ... done |████████████████████████████████| 71kB 5.2MB/s Building wheel for ml-things (setup.py) ... done Building wheel for ftfy (setup.py) ... done

واردات

تمام کتابخانه های مورد نیاز را برای این نوت بوک وارد کنید. پارامترهای استفاده شده برای این نوت بوک را اعلام کنید:

  • set_seed(123) - همیشه خوب است که یک دانه ثابت برای تکرارپذیری تنظیم کنید.
  • epochs - تعداد دوره های آموزشی (نویسندگان بین 2 تا 4 را توصیه می کنند).
  • batch_size - تعداد دسته ها - بسته به حداکثر طول توالی و حافظه GPU. برای طول 512 سکانس، یک دسته 10 تایی معمولاً بدون مشکل حافظه متفاوت کار می کند. برای طول دنباله کوچک می توانید دسته ای از 32 یا بالاتر را امتحان کنید. max_length – توالی های متن را به طول خاصی اضافه یا کوتاه کنید. برای سرعت بخشیدن به تمرین، آن را روی 60 تنظیم می کنم.
  • device – به دنبال gpu برای استفاده باشید. اگر gpu پیدا نشد به طور پیش فرض از cpu استفاده می کند.
  • model_name_or_path – نام مدل ترانسفورماتور – از مدل از پیش آموزش دیده استفاده خواهد شد. مسیر مدل ترانسفورماتور - مدل خود را از دیسک محلی بارگیری می کند. در این آموزش استفاده خواهم کرد gpt2 مدل.
  • labels_ids - فرهنگ لغت برچسب ها و شناسه آنها - برای تبدیل برچسب های رشته ای به اعداد استفاده می شود.
  • n_labels - از چند برچسب در این مجموعه داده استفاده می کنیم. این برای تعیین اندازه سر طبقه بندی استفاده می شود.
import io
import os
import torch
from tqdm.notebook import tqdm
from torch.utils.data import Dataset, DataLoader
from ml_things import plot_dict, plot_confusion_matrix, fix_text
from sklearn.metrics import classification_report, accuracy_score
from transformers import (set_seed, TrainingArguments, Trainer, GPT2Config, GPT2Tokenizer, AdamW, get_linear_schedule_with_warmup, GPT2ForSequenceClassification) # Set seed for reproducibility.
set_seed(123) # Number of training epochs (authors on fine-tuning Bert recommend between 2 and 4).
epochs = 4 # Number of batches - depending on the max sequence length and GPU memory.
# For 512 sequence length batch of 10 works without cuda memory issues.
# For small sequence length can try batch of 32 or higher.
batch_size = 32 # Pad or truncate text sequences to a specific length
# if `None` it will use maximum sequence of word piece tokens allowed by model.
max_length = 60 # Look for gpu to use. Will use `cpu` by default if no gpu found.
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # Name of transformers model - will use already pretrained model.
# Path of transformer model - will load your own model from local disk.
model_name_or_path = 'gpt2' # Dictionary of labels and their id - this will be used to convert.
# String labels to number ids.
labels_ids = {'neg': 0, 'pos': 1} # How many labels are we using in training.
# This is used to decide size of classification head.
n_labels = len(labels_ids)

توابع کمکی

من دوست دارم تمام کلاس‌ها و توابعی را که در این نوت‌بوک استفاده می‌شود، در این بخش نگه دارم تا به حفظ ظاهری تمیز از نوت‌بوک کمک کند:

MovieReviewsDataset (مجموعه داده)

اگر قبلاً با PyTorch کار کرده اید، این کاملاً استاندارد است. ما به این کلاس نیاز داریم تا در مجموعه داده خود بخوانیم، آن را تجزیه کنیم و متون را با برچسب های مرتبط خود برگردانیم.

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

من تمام متون و برچسب ها را در لیست ها اضافه می کنم.

سه بخش اصلی از این کلاس مجموعه داده PyTorch وجود دارد:

  • init() جایی که در مجموعه داده می خوانیم و متن و برچسب ها را به اعداد تبدیل می کنیم.
  • len () که در آن باید تعداد نمونه هایی را که می خوانیم برگردانیم. این مورد هنگام فراخوانی len (MovieReviewsDataset()) استفاده می شود.
  • getitem() همیشه یک مقدار int را به عنوان ورودی می گیرد که نشان می دهد کدام مثال از نمونه های ما باید از مجموعه داده ما بازگردانده شود. اگر مقدار 3 ارسال شود، نمونه داده‌های خود را در موقعیت 3 برمی‌گردانیم.
class MovieReviewsDataset(Dataset): r"""PyTorch Dataset class for loading data. This is where the data parsing happens. This class is built with reusability in mind: it can be used as is as. Arguments: path (:obj:`str`): Path to the data partition. """ def __init__(self, path, use_tokenizer): # Check if path exists. if not os.path.isdir(path): # Raise error if path is invalid. raise ValueError('Invalid `path` variable! Needs to be a directory') self.texts = [] self.labels = [] # Since the labels are defined by folders with data we loop # through each label. for label in ['pos', 'neg']: sentiment_path = os.path.join(path, label) # Get all files from path. files_names = os.listdir(sentiment_path)#[:10] # Sample for debugging. # Go through each file and read its content. for file_name in tqdm(files_names, desc=f'{label} files'): file_path = os.path.join(sentiment_path, file_name) # Read content. content = io.open(file_path, mode='r', encoding='utf-8').read() # Fix any unicode issues. content = fix_text(content) # Save content. self.texts.append(content) # Save encode labels. self.labels.append(label) # Number of exmaples. self.n_examples = len(self.labels) return def __len__(self): r"""When used `len` return the number of examples. """ return self.n_examples def __getitem__(self, item): r"""Given an index return an example from the position. Arguments: item (:obj:`int`): Index position to pick an example to return. Returns: :obj:`Dict[str, str]`: Dictionary of inputs that contain text and asociated labels. """ return {'text':self.texts[item], 'label':self.labels[item]}

Gpt2ClassificationCollator

من از این کلاس برای ایجاد Data Collator استفاده می کنم. این در DataLoader برای ایجاد حمام داده هایی که به مدل تغذیه می شوند استفاده می شود. من از رمزگذار و رمزگذار برچسب در هر دنباله برای تبدیل متون و برچسب ها به عدد استفاده می کنم.

خوش شانس ما، Hugging Face به همه چیز فکر کرد و توکنایزر را وادار کرد که تمام کارهای سنگین را انجام دهد (تقسیم متن به نشانه، padding، کوتاه کردن، کدگذاری متن به اعداد) و استفاده از آن بسیار آسان است!

دو بخش اصلی از این کلاس جمع‌آوری داده وجود دارد:

  • init() جایی که توکنایزری را که قصد استفاده از آن را داریم، مقداردهی اولیه می کنیم، چگونه برچسب های خود را رمزگذاری کنیم و اگر نیاز داریم طول دنباله را روی مقدار دیگری تنظیم کنیم.
  • زنگ زدن() به عنوان جمع‌آوری تابع استفاده می‌شود که مجموعه‌ای از نمونه‌های داده را به عنوان ورودی می‌گیرد. باید یک شی با قالبی که می تواند به مدل ما داده شود را برگرداند. خوشبختانه توکنایزر ما این کار را برای ما انجام می دهد و یک فرهنگ لغت از متغیرها را به شکل آماده برای تغذیه به مدل برمی گرداند: model(**inputs). از آنجایی که ما در حال تنظیم دقیق مدل هستیم، برچسب ها را نیز اضافه کردم.
class Gpt2ClassificationCollator(object): r""" Data Collator used for GPT2 in a classificaiton rask. It uses a given tokenizer and label encoder to convert any text and labels to numbers that can go straight into a GPT2 model. This class is built with reusability in mind: it can be used as is as long as the `dataloader` outputs a batch in dictionary format that can be passed straight into the model - `model(**batch)`. Arguments: use_tokenizer (:obj:`transformers.tokenization_?`): Transformer type tokenizer used to process raw text into numbers. labels_ids (:obj:`dict`): Dictionary to encode any labels names into numbers. Keys map to labels names and Values map to number associated to those labels. max_sequence_len (:obj:`int`, `optional`) Value to indicate the maximum desired sequence to truncate or pad text sequences. If no value is passed it will used maximum sequence size supported by the tokenizer and model. """ def __init__(self, use_tokenizer, labels_encoder, max_sequence_len=None): # Tokenizer to be used inside the class. self.use_tokenizer = use_tokenizer # Check max sequence length. self.max_sequence_len = use_tokenizer.model_max_length if max_sequence_len is None else max_sequence_len # Label encoder used inside the class. self.labels_encoder = labels_encoder return def __call__(self, sequences): r""" This function allowes the class objesct to be used as a function call. Sine the PyTorch DataLoader needs a collator function, I can use this class as a function. Arguments: item (:obj:`list`): List of texts and labels. Returns: :obj:`Dict[str, object]`: Dictionary of inputs that feed into the model. It holddes the statement `model(**Returned Dictionary)`. """ # Get all texts from sequences list. texts = [sequence['text'] for sequence in sequences] # Get all labels from sequences list. labels = [sequence['label'] for sequence in sequences] # Encode all labels using label encoder. labels = [self.labels_encoder[label] for label in labels] # Call tokenizer on all texts to convert into tensors of numbers with # appropriate padding. inputs = self.use_tokenizer(text=texts, return_tensors="pt", padding=True, truncation=True, max_length=self.max_sequence_len) # Update the inputs with the associated encoded labels as tensor. inputs.update({'labels':torch.tensor(labels)}) return inputs

قطار (بارگذار داده، بهینه ساز_، زمانبند_، دستگاه_)

من این تابع را برای انجام یک عبور کامل از شی DataLoader ایجاد کردم (شیء DataLoader از شی نوع Dataset* ما با استفاده از کلاس **MovieReviewsDataset ایجاد می شود). این اساساً یک قطار دوره ای از کل مجموعه داده است.

دیتالودر از PyTorch DataLoader ایجاد شده است که شی ایجاد شده از کلاس MovieReviewsDataset را می گیرد و هر نمونه را به صورت دسته ای قرار می دهد. به این ترتیب ما می توانیم دسته ای از داده های مدل خود را تغذیه کنیم!

optimizer_ و scheduler_ در PyTorch بسیار رایج هستند. آنها باید پارامترهای مدل ما را به روز کنند و میزان یادگیری ما را در طول آموزش به روز کنند. خیلی بیشتر از این وجود دارد اما من وارد جزئیات نمی شوم. این در واقع می تواند یک سوراخ خرگوش بزرگ باشد زیرا در پشت این عملکردها چیزهای زیادی اتفاق می افتد که نیازی به نگرانی نیست. با تشکر از PyTorch!

در این فرآیند، برچسب‌های واقعی و برچسب‌های پیش‌بینی‌شده را همراه با ضرر پیگیری می‌کنیم.

def train(dataloader, optimizer_, scheduler_, device_): r""" Train pytorch model on a single pass through the data loader. It will use the global variable `model` which is the transformer model loaded on `_device` that we want to train on. This function is built with reusability in mind: it can be used as is as long as the `dataloader` outputs a batch in dictionary format that can be passed straight into the model - `model(**batch)`. Arguments: dataloader (:obj:`torch.utils.data.dataloader.DataLoader`): Parsed data into batches of tensors. optimizer_ (:obj:`transformers.optimization.AdamW`): Optimizer used for training. scheduler_ (:obj:`torch.optim.lr_scheduler.LambdaLR`): PyTorch scheduler. device_ (:obj:`torch.device`): Device used to load tensors before feeding to model. Returns: :obj:`List[List[int], List[int], float]`: List of [True Labels, Predicted Labels, Train Average Loss]. """ # Use global variable for model. global model # Tracking variables. predictions_labels = [] true_labels = [] # Total loss for this epoch. total_loss = 0 # Put the model into training mode. model.train() # For each batch of training data... for batch in tqdm(dataloader, total=len(dataloader)): # Add original labels - use later for evaluation. true_labels += batch['labels'].numpy().flatten().tolist() # move batch to device batch = {k:v.type(torch.long).to(device_) for k,v in batch.items()} # Always clear any previously calculated gradients before performing a # backward pass. model.zero_grad() # Perform a forward pass (evaluate the model on this training batch). # This will return the loss (rather than the model output) because we # have provided the `labels`. # The documentation for this a bert model function is here: # https://huggingface.co/transformers/v2.2.0/model_doc/bert.html#transformers.BertForSequenceClassification outputs = model(**batch) # The call to `model` always returns a tuple, so we need to pull the # loss value out of the tuple along with the logits. We will use logits # later to calculate training accuracy. loss, logits = outputs[:2] # Accumulate the training loss over all of the batches so that we can # calculate the average loss at the end. `loss` is a Tensor containing a # single value; the `.item()` function just returns the Python value # from the tensor. total_loss += loss.item() # Perform a backward pass to calculate the gradients. loss.backward() # Clip the norm of the gradients to 1.0. # This is to help prevent the "exploding gradients" problem. torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) # Update parameters and take a step using the computed gradient. # The optimizer dictates the "update rule"--how the parameters are # modified based on their gradients, the learning rate, etc. optimizer.step() # Update the learning rate. scheduler.step() # Move logits and labels to CPU logits = logits.detach().cpu().numpy() # Convert these logits to list of predicted labels values. predictions_labels += logits.argmax(axis=-1).flatten().tolist() # Calculate the average loss over the training data. avg_epoch_loss = total_loss / len(dataloader) # Return all true labels and prediction for future evaluations. return true_labels, predictions_labels, avg_epoch_loss

اعتبارسنجی (داده‌بار، دستگاه_)

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

من از DataLoader به روشی مشابه قطار استفاده می‌کنم تا دسته‌هایی را بیرون بیاورم تا به مدل خود تغذیه کنیم.

در این فرآیند، برچسب‌های واقعی و برچسب‌های پیش‌بینی‌شده را همراه با ضرر پیگیری می‌کنم.

def validation(dataloader, device_): r"""Validation function to evaluate model performance on a separate set of data. This function will return the true and predicted labels so we can use later to evaluate the model's performance. This function is built with reusability in mind: it can be used as is as long as the `dataloader` outputs a batch in dictionary format that can be passed straight into the model - `model(**batch)`. Arguments: dataloader (:obj:`torch.utils.data.dataloader.DataLoader`): Parsed data into batches of tensors. device_ (:obj:`torch.device`): Device used to load tensors before feeding to model. Returns: :obj:`List[List[int], List[int], float]`: List of [True Labels, Predicted Labels, Train Average Loss] """ # Use global variable for model. global model # Tracking variables predictions_labels = [] true_labels = [] #total loss for this epoch. total_loss = 0 # Put the model in evaluation mode--the dropout layers behave differently # during evaluation. model.eval() # Evaluate data for one epoch for batch in tqdm(dataloader, total=len(dataloader)): # add original labels true_labels += batch['labels'].numpy().flatten().tolist() # move batch to device batch = {k:v.type(torch.long).to(device_) for k,v in batch.items()} # Telling the model not to compute or store gradients, saving memory and # speeding up validation with torch.no_grad(): # Forward pass, calculate logit predictions. # This will return the logits rather than the loss because we have # not provided labels. # token_type_ids is the same as the "segment ids", which # differentiates sentence 1 and 2 in 2-sentence tasks. # The documentation for this `model` function is here: # https://huggingface.co/transformers/v2.2.0/model_doc/bert.html#transformers.BertForSequenceClassification outputs = model(**batch) # The call to `model` always returns a tuple, so we need to pull the # loss value out of the tuple along with the logits. We will use logits # later to to calculate training accuracy. loss, logits = outputs[:2] # Move logits and labels to CPU logits = logits.detach().cpu().numpy() # Accumulate the training loss over all of the batches so that we can # calculate the average loss at the end. `loss` is a Tensor containing a # single value; the `.item()` function just returns the Python value # from the tensor. total_loss += loss.item() # get predicitons to list predict_content = logits.argmax(axis=-1).flatten().tolist() # update list predictions_labels += predict_content # Calculate the average loss over the training data. avg_epoch_loss = total_loss / len(dataloader) # Return all true labels and prediciton for future evaluations. return true_labels, predictions_labels, avg_epoch_loss

مدل بارگذاری و توکنایزر

بارگیری سه بخش اساسی ترانسفورماتور GPT2 از پیش آموزش دیده: پیکربندی، توکنایزر و مدل.

برای این مثال استفاده خواهم کرد gpt2 از ترانسفورماتورهای از پیش آموزش دیده HuggingFace. شما می توانید از هر گونه تنوع GP2 که می خواهید استفاده کنید.

در ایجاد model_config من تعداد برچسب هایی را که برای کار طبقه بندی خود نیاز دارم ذکر می کنم. از آنجایی که من فقط دو احساس را پیش بینی می کنم: مثبت و منفی، فقط به دو برچسب برای آن نیاز دارم num_labels.

ایجاد tokenizer هنگام استفاده از کتابخانه Transformers بسیار استاندارد است. پس از ایجاد توکنایزر، تنظیم padding در سمت چپ برای این آموزش بسیار مهم است tokenizer.padding_side = "left" و توکن padding را مقداردهی کنید tokenizer.eos_token که رمز اصلی پایان توالی GPT2 است. این ضروری ترین بخش این آموزش است زیرا GPT2 از آخرین نشانه برای پیش بینی استفاده می کند، بنابراین باید به سمت چپ صفحه را وارد کنیم.

HuggingFace در حال حاضر بیشتر کارها را برای ما انجام داده و یک لایه طبقه بندی به مدل GPT2 اضافه کرده است. در ایجاد مدلی که استفاده کردم GPT2ForSequenceClassification. از آنجایی که ما یک توکن padding سفارشی داریم، باید آن را برای مدل مورد استفاده مقداردهی اولیه کنیم model.config.pad_token_id. در نهایت باید مدل را به دستگاهی که قبلا تعریف کردیم منتقل کنیم.

# Get model configuration.
print('Loading configuraiton...')
model_config = GPT2Config.from_pretrained(pretrained_model_name_or_path=model_name_or_path, num_labels=n_labels) # Get model's tokenizer.
print('Loading tokenizer...')
tokenizer = GPT2Tokenizer.from_pretrained(pretrained_model_name_or_path=model_name_or_path)
# default to left padding
tokenizer.padding_side = "left"
# Define PAD Token = EOS Token = 50256
tokenizer.pad_token = tokenizer.eos_token # Get the actual model.
print('Loading model...')
model = GPT2ForSequenceClassification.from_pretrained(pretrained_model_name_or_path=model_name_or_path, config=model_config) # resize model embedding to match new tokenizer
model.resize_token_embeddings(len(tokenizer)) # fix model padding token id
model.config.pad_token_id = model.config.eos_token_id # Load model to defined device.
model.to(device)
print('Model loaded to `%s`'%device)
Loading configuraiton... Loading tokenizer... Loading model... Some weights of GPT2ForSequenceClassification were not initialized from the model checkpoint at gpt2 and are newly initialized: ['score.weight'] You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference. Model loaded to `cuda`

مجموعه داده و جمع‌آور

اینجاست که من مجموعه داده PyTorch و Data Loader را با آبجکت های Data Collator ایجاد می کنم که برای تغذیه داده ها به مدل ما استفاده می شود.

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

از آنجایی که باید اعداد را به مدل خود وارد کنیم، باید متون و برچسب ها را به اعداد تبدیل کنیم. این هدف یک جمع کننده است! داده‌های خروجی توسط مجموعه داده PyTorch را می‌گیرد و از تابع Data Collator عبور می‌کند تا دنباله‌ای را برای مدل ما خروجی دهد.

من توکنایزر را از مجموعه داده PyTorch دور نگه می‌دارم تا کد را تمیزتر و ساختارمندتر کنم. بدیهی است که می‌توانید از توکنایزر داخل مجموعه داده PyTorch و توالی‌های خروجی استفاده کنید که می‌توانند مستقیماً در مدل بدون استفاده از جمع‌آوری داده استفاده شوند.

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

جمع‌آوری داده برای قالب‌بندی خروجی‌های PyTorch Dataset برای مطابقت با ورودی‌های مورد نیاز برای GPT2 استفاده می‌شود.

# Create data collator to encode text and labels into numbers.
gpt2_classificaiton_collator = Gpt2ClassificationCollator(use_tokenizer=tokenizer, labels_encoder=labels_ids, max_sequence_len=max_length) print('Dealing with Train...')
# Create pytorch dataset.
train_dataset = MovieReviewsDataset(path='/content/aclImdb/train', use_tokenizer=tokenizer)
print('Created `train_dataset` with %d examples!'%len(train_dataset)) # Move pytorch dataset into dataloader.
train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, collate_fn=gpt2_classificaiton_collator)
print('Created `train_dataloader` with %d batches!'%len(train_dataloader)) print() print('Dealing with Validation...')
# Create pytorch dataset.
valid_dataset = MovieReviewsDataset(path='/content/aclImdb/test', use_tokenizer=tokenizer)
print('Created `valid_dataset` with %d examples!'%len(valid_dataset)) # Move pytorch dataset into dataloader.
valid_dataloader = DataLoader(valid_dataset, batch_size=batch_size, shuffle=False, collate_fn=gpt2_classificaiton_collator)
print('Created `eval_dataloader` with %d batches!'%len(valid_dataloader))
Dealing with Train... pos files: 100%|████████████████████████████████|12500/12500 [01:17<00:00, 161.19it/s] neg files: 100%|████████████████████████████████|12500/12500 [01:05<00:00, 190.72it/s] Created `train_dataset` with 25000 examples! Created `train_dataloader` with 782 batches! Reading pos files... pos files: 100%|████████████████████████████████|12500/12500 [00:54<00:00, 230.93it/s] neg files: 100%|████████████████████████████████|12500/12500 [00:42<00:00, 291.07it/s] Created `valid_dataset` with 25000 examples! Created `eval_dataloader` with 782 batches!

قطار

من در آموزش استفاده از بهینه ساز و زمانبندی توسط PyTorch را ایجاد کردم. من از رایج ترین پارامترهای مورد استفاده در مدل های ترانسفورماتور استفاده کردم.

من از طریق تعداد دوره های تعریف شده حلقه زدم و با آن تماس گرفتم قطار و اعتبار سنجی توابع.

من سعی می کنم پس از هر دوره اطلاعات مشابه Keras را ارائه کنم: train_loss: — val_loss: — train_acc: — valid_acc.

پس از آموزش، منحنی‌های کاهش اعتبار و صحت را ترسیم کنید تا نحوه آموزش را بررسی کنید.

توجه داشته باشید: نمودارهای آموزشی ممکن است کمی عجیب به نظر برسند: دقت اعتبار سنجی بالاتر از دقت آموزش شروع می شود و از دست دادن اعتبار سنجی کمتر از ضرر آموزش شروع می شود. به طور معمول این برعکس خواهد بود. من فرض می‌کنم تقسیم داده‌ها برای بخش اعتبارسنجی آسان‌تر یا برای بخش آموزشی یا هر دو بسیار سخت است. از آنجایی که این آموزش در مورد استفاده از GPT2 برای طبقه بندی است، من زیاد نگران نتایج مدل نخواهم بود.

# Note: AdamW is a class from the huggingface library (as opposed to pytorch) # I believe the 'W' stands for 'Weight Decay fix"
optimizer = AdamW(model.parameters(), lr = 2e-5, # default is 5e-5, our notebook had 2e-5 eps = 1e-8 # default is 1e-8. ) # Total number of training steps is number of batches * number of epochs.
# `train_dataloader` contains batched data so `len(train_dataloader)` gives # us the number of batches.
total_steps = len(train_dataloader) * epochs # Create the learning rate scheduler.
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps = 0, # Default value in run_glue.py num_training_steps = total_steps) # Store the average loss after each epoch so we can plot them.
all_loss = {'train_loss':[], 'val_loss':[]}
all_acc = {'train_acc':[], 'val_acc':[]} # Loop through each epoch.
print('Epoch')
for epoch in tqdm(range(epochs)): print() print('Training on batches...') # Perform one full pass over the training set. train_labels, train_predict, train_loss = train(train_dataloader, optimizer, scheduler, device) train_acc = accuracy_score(train_labels, train_predict) # Get prediction form model on validation data. print('Validation on batches...') valid_labels, valid_predict, val_loss = validation(valid_dataloader, device) val_acc = accuracy_score(valid_labels, valid_predict) # Print loss and accuracy values to see how training evolves. print(" train_loss: %.5f - val_loss: %.5f - train_acc: %.5f - valid_acc: %.5f"%(train_loss, val_loss, train_acc, val_acc)) print() # Store the loss value for plotting the learning curve. all_loss['train_loss'].append(train_loss) all_loss['val_loss'].append(val_loss) all_acc['train_acc'].append(train_acc) all_acc['val_acc'].append(val_acc) # Plot loss curves.
plot_dict(all_loss, use_xlabel='Epochs', use_ylabel='Value', use_linestyles=['-', '--']) # Plot accuracy curves.
plot_dict(all_acc, use_xlabel='Epochs', use_ylabel='Value', use_linestyles=['-', '--'])
Epoch 100%|████████████████████████████████|4/4 [15:11<00:00, 227.96s/it] Training on batches... 100%|████████████████████████████████|782/782 [02:42<00:00, 4.82it/s] Validation on batches... 100%|████████████████████████████████|782/782 [02:07<00:00, 6.13it/s] train_loss: 0.54128 - val_loss: 0.38758 - train_acc: 0.75288 - valid_acc: 0.81904 Training on batches... 100%|████████████████████████████████|782/782 [02:36<00:00, 5.00it/s] Validation on batches... 100%|████████████████████████████████|782/782 [01:41<00:00, 7.68it/s] train_loss: 0.36716 - val_loss: 0.37620 - train_acc: 0.83288 -valid_acc: 0.82912 Training on batches... 100%|████████████████████████████████|782/782 [02:36<00:00, 5.00it/s] Validation on batches... 100%|████████████████████████████████|782/782 [01:24<00:00, 9.24it/s] train_loss: 0.31409 - val_loss: 0.39384 - train_acc: 0.86304 - valid_acc: 0.83044 Training on batches... 100%|████████████████████████████████|782/782 [02:36<00:00, 4.99it/s] Validation on batches... 100%|████████████████████████████████|782/782 [01:09<00:00, 11.29it/s] train_loss: 0.27358 - val_loss: 0.39798 - train_acc: 0.88432 - valid_acc: 0.83292
قطار و از دست دادن اعتبار.
دقت آموزش و اعتبارسنجی

ارزیابی

هنگام پرداختن به طبقه بندی، توجه به فراخوانی دقیق و امتیاز F1 مفید است.

یک سنج خوب برای ارزیابی یک مدل، ماتریس سردرگمی است.

# Get prediction form model on validation data. This is where you should use
# your test data.
true_labels, predictions_labels, avg_epoch_loss = validation(valid_dataloader, device) # Create the evaluation report.
evaluation_report = classification_report(true_labels, predictions_labels, labels=list(labels_ids.values()), target_names=list(labels_ids.keys()))
# Show the evaluation report.
print(evaluation_report) # Plot confusion matrix.
plot_confusion_matrix(y_true=true_labels, y_pred=predictions_labels, classes=list(labels_ids.keys()), normalize=True, magnify=0.1, );
Training on batches... 100%|████████████████████████████████|782/782 [01:09<00:00, 11.24it/s] precision recall f1-score support neg 0.84 0.83 0.83 12500 pos 0.83 0.84 0.83 12500 accuracy 0.83 25000 macro avg 0.83 0.83 0.83 25000 weighted avg 0.83 0.83 0.83 25000
ماتریس سردرگمی نرمال شد.

نکته آخر

اگر تا اینجا پیش رفتی تبریک! 🎊 و متشکرم! 🙏 برای علاقه شما به آموزش من!

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

البته دنبال کردن آن برای من آسان است زیرا آن را ساخته ام. به همین دلیل است که از هرگونه بازخورد استقبال می شود و به من کمک می کند تا آموزش های آینده ام را بهبود بخشم!

اگر مشکلی دیدید، لطفاً با باز کردن یک موضوع در من، به من اطلاع دهید ml_things مخزن GitHub!

بسیاری از آموزش‌های موجود در آنجا عمدتاً یکبار مصرف هستند و نگهداری نمی‌شوند. من قصد دارم تا جایی که بتوانم آموزش هایم را به روز نگه دارم.

این مقاله در اصل در تاریخ منتشر شد وب سایت شخصی جورج میهایلا  و با اجازه نویسنده مجدداً در TOPBOTS منتشر شد.

از این مقاله لذت می برید؟ برای به روز رسانی های بیشتر هوش مصنوعی ثبت نام کنید.

زمانی که آموزش فنی بیشتری را منتشر کنیم به شما اطلاع خواهیم داد.

منبع: https://www.topbots.com/gpt2-text-classification-using-hugging-face-transformers/

تمبر زمان:

بیشتر از TOPBOTS