Torchtext 0.7 показывает, что поле устарело. Какова альтернатива?

#pytorch #torchtext

#pytorch #текст факела

Вопрос:

Похоже, что предыдущая парадигма объявления полей, примеров и использования BucketIterator устарела и перейдет к устаревшей версии 0.8. Однако, похоже, я не могу найти пример новой парадигмы для пользовательских наборов данных (например, не тех, которые включены в torch.datasets), которая не использует Field . Кто-нибудь может указать мне на актуальный пример?

Ссылка на устаревание:

https://github.com/pytorch/text/releases

Ответ №1:

Мне потребовалось некоторое время, чтобы найти решение самостоятельно. Новая парадигма аналогична so для готовых наборов данных:

 from torchtext.experimental.datasets import AG_NEWS
train, test = AG_NEWS(ngrams=3)
  

или примерно так для пользовательских наборов данных:

 from torch.utils.data import DataLoader
def collate_fn(batch):
    texts, labels = [], []
    for label, txt in batch:
        texts.append(txt)
        labels.append(label)
    return texts, labels
dataloader = DataLoader(train, batch_size=8, collate_fn=collate_fn)
for idx, (texts, labels) in enumerate(dataloader):
    print(idx, texts, labels)
  

Я скопировал примеры из Источника

Комментарии:

1. Привет, Стивен, спасибо тебе. В любом случае, вы нашли какой-нибудь фрагмент о том, как мы создаем vocab, токенизацию и т.д.?

2. @SatrioAdiPrabowo Лично я бы посоветовал использовать huggingface . Huggingface в настоящее время является стандартом defacto практически для всех вещей NLP на данный момент, от создания словарей до токенизации и даже моделей. В качестве альтернативы вы можете создать свой собственный, что потребует больше усилий.

3. Это немного запоздало, но я действительно думаю, что это отвечает на заданный вопрос. Похоже, некоторые функции предварительной обработки, на которые я надеялся в отношении Vocab / tokenization, просто не встроены, как я мог бы надеяться.

4. Эй, Пако, может быть, в следующий раз спросишь более широко, поскольку вопрос о том, какова альтернатива в отношении устаревания, подразумевает, что ты хочешь продолжать использовать torchtext и хочешь использовать не устаревшую альтернативу в torchtext. В отличие от более общего вопроса о том, что я должен использовать для предварительной обработки и работы в NLP. Обратите внимание, что задавание слишком широких вопросов может привести к блокировке вопроса при переполнении стека.

Ответ №2:

Просматривая torchtext репозиторий GitHub, я наткнулся на README в устаревшем каталоге, который не задокументирован в официальных документах. README ссылается на выпуск GitHub, в котором объясняется обоснование изменения, а также на руководство по миграции.

Если вы просто хотите сохранить свой существующий код, работающий с torchtext 0.9.0, где устаревшие классы были перенесены в legacy модуль, вам необходимо скорректировать свой импорт:

 # from torchtext.data import Field, TabularDataset
from torchtext.legacy.data import Field, TabularDataset
  

В качестве альтернативы вы можете импортировать весь torchtext.legacy модуль, как torchtext предложено README:

 import torchtext.legacy as torchtext
  

Ответ №3:

По этому поводу есть сообщение. Вместо устаревших классов Field и BucketIterator он использует TextClassificationDataset вместе с collator и другой предварительной обработкой. Он считывает текстовый файл и создает набор данных, за которым следует модель. Внутри поста есть ссылка на полный рабочий блокнот. Сообщение находится по адресу: https://mmg10.github.io/pytorch/2021/02/16/text_torch.html . Но вам нужна «разработка» (или ночная сборка) PyTorch, чтобы это сработало.

По ссылке выше:

После токенизации и создания словаря вы можете создать набор данных следующим образом

 def data_to_dataset(data, tokenizer, vocab):
    
    data = [(text, label) for (text, label) in data]
    
    text_transform = sequential_transforms(tokenizer.tokenize,
                                                  vocab_func(vocab),
                                                  totensor(dtype=torch.long)
                                          )
    label_transform = sequential_transforms(lambda x: 1 if x =='1' else (0 if x =='0' else x),
                                                  totensor(dtype=torch.long)
                                          )
    
    
    transforms = (text_transform, label_transform)
    
    dataset = TextClassificationDataset(data, vocab, transforms)
    
    return dataset
  

Собиратель выглядит следующим образом:

     def __init__(self, pad_idx):
        
        self.pad_idx = pad_idx
        
    def collate(self, batch):
        text, labels = zip(*batch)
        labels = torch.LongTensor(labels)
        text = nn.utils.rnn.pad_sequence(text, padding_value=self.pad_idx, batch_first=True)
        return text, labels
  

Затем вы можете создать загрузчик данных с типичным torch.utils.data.DataLoader использованием collate_fn аргумента.

Комментарии:

1. Привет! Не могли бы вы, пожалуйста, подробно описать подход вместо описания того, что находится в записной книжке? Таким образом, если когда-либо notebook станет недоступен, люди все равно смогут извлечь выгоду из вашего ответа 🙂

2. @Proko. Я добавил важный сегмент кода.

Ответ №4:

Ну, похоже, что конвейер может быть таким:

     import torchtext as TT
    import torch
    from collections import Counter
    from torchtext.vocab import Vocab

    # read the data

    with open('text_data.txt','r') as f:
        data = f.readlines()
    with open('labels.txt', 'r') as f:
        labels = f.readlines()

    
    tokenizer = TT.data.utils.get_tokenizer('spacy', 'en') # can remove 'spacy' and use a simple built-in tokenizer
    train_iter = zip(labels, data)
    counter = Counter()
    
    for (label, line) in train_iter:
        counter.update(tokenizer(line))
        
    vocab = TT.vocab.Vocab(counter, min_freq=1)

    text_pipeline = lambda x: [vocab[token] for token in tokenizer(x)]
    # this is data-specific - adapt for your data
    label_pipeline = lambda x: 1 if x == 'positiven' else 0
    
    class TextData(torch.utils.data.Dataset):
        '''
        very basic dataset for processing text data
        '''
        def __init__(self, labels, text):
            super(TextData, self).__init__()
            self.labels = labels
            self.text = text
            
        def __getitem__(self, index):
            return self.labels[index], self.text[index]
        
        def __len__(self):
            return len(self.labels)
    
    
    def tokenize_batch(batch, max_len=200):
        '''
        tokenizer to use in DataLoader
        takes a text batch of text dataset and produces a tensor batch, converting text and labels though tokenizer, labeler
        tokenizer is a global function text_pipeline
        labeler is a global function label_pipeline
        max_len is a fixed len size, if text is less than max_len it is padded with ones (pad number)
        if text is larger that max_len it is truncated but from the end of the string
        '''
        labels_list, text_list = [], []
        for _label, _text in batch:
            labels_list.append(label_pipeline(_label))
            text_holder = torch.ones(max_len, dtype=torch.int32) # fixed size tensor of max_len
            processed_text = torch.tensor(text_pipeline(_text), dtype=torch.int32)
            pos = min(200, len(processed_text))
            text_holder[-pos:] = processed_text[-pos:]
            text_list.append(text_holder.unsqueeze(dim=0))
        return torch.FloatTensor(labels_list), torch.cat(text_list, dim=0)
    
    train_dataset = TextData(labels, data)
    
    train_loader = DataLoader(train_dataset, batch_size=2, shuffle=False, collate_fn=tokenize_batch)
    
    lbl, txt = iter(train_loader).next()