Практическое глубокое обучение 8.2 Простая предварительная обработка текста

глубокое обучение PyTorch

Примите участие в 25-м дне испытания ноябрьского обновления и узнайте подробности события:Вызов последнего обновления 2021 г.


Эта статья о том, как сделать простую предварительную обработку текста, действительно очень простую. Мы собираемся сделать следующие четыре шага:

  1. Загрузить текст в память в виде строки.
  2. Разбить строку на токены (например, слова и символы).
  3. Создайте словарь, который сопоставляет разделенные токены с числовыми индексами.
  4. Преобразование текста в последовательность числовых индексов для упрощения работы с моделью.

Это действительно самая простая предварительная обработка текста.За исключением «Learning Deep Learning by Hand», первая предварительная обработка была такой же, когда я читал Yushu. Таким образом, он должен быть подходящим для новичков, чтобы взглянуть.

import collections
import re
from d2l import torch as d2l

чтение набора данных

d2l.DATA_HUB['time_machine'] = (d2l.DATA_URL + 'timemachine.txt',
                                '090b5e7e70c295757f55df93cb0a180b9691891a')

def read_time_machine():
    with open(d2l.download('time_machine'), 'r') as f:
        lines = f.readlines()
    return [re.sub('[^A-Za-z]+', ' ', line).strip().lower() for line in lines]

lines = read_time_machine()
print(f'# text lines: {len(lines)}')
print(lines[0])
print(lines[10])

Этот код от H.G.Wellмашина времениЗагрузка текста в формате , представляет собой небольшой набор из 3w слов.

  • будет отображаться во время загрузки

    Downloading ..\data\timemachine.txt from 2-данные — это 3-ускорение. Amazon AWS.com/time machine…...

  • Сколько рейсов выводится после завершения загрузки и содержимое строк 0 и 10.

    >>
    # text lines: 3221
    the time machine by h g wells
    twinkled and his usually pale face was flushed and animated the
    
  • read_time_machine()Это прочитать предложение из загруженного файла, удалить другие символы, кроме прописных и строчных букв, и сохранить его в списке. После этого шага в списке остаются только строчные буквы и пробелы.

    • for line in linesявляется объектом генератора
      • [for line in lines]состоит в том, чтобы вернуть объект генератора в список

      • [对line进行操作 for line in lines]состоит в том, чтобы работать с каждым элементом в строках списка

      • re.sub('[^A-Za-z]+', ' ', line)Используйте регулярное выражение, чтобы заменить в строке элементы, отличные от букв, и заменить их пробелами.

        • re.sub(*pattern*, *repl*, *string*, *count=0*, *flags=0*)

          использовать replзаменить вstringпоявление вpatternи вернуть строку результата.

          replМожет быть строкой или функцией; если это строка, то будут обработаны любые escape-последовательности обратной косой черты в ней. Это,\nбудет преобразовано в новую строку,\rпреобразуется в возврат каретки и так далее.

          необязательные параметрыcountмаксимальное количество замен;countДолжно быть неотрицательным целым числом. Если этот параметр опущен или установлен в 0, все совпадения будут заменены.

      • .strip()Удалить пробелы с обоих концов строки

      • .lower()Преобразование прописных букв в строчные

лемматизация

Это разделить текст на список слов.Размер является основной единицей текста.

def tokenize(lines, token='word'): 
    if token == 'word':
        return [line.split() for line in lines]
    elif token == 'char':
        return [list(line) for line in lines]
    else:
        print('错误:未知词元类型:' + token)

Разделит ли этот шаг текст на слова (или пробелы) или на отдельные буквы (или пробелы),

  • token = wordэто разделить на слова
  • token = charэто разбить его на буквы

попробуйtokenizeЭффект функции:

  • word

    tokens = tokenize(lines)
    for i in range(10,13):
        print(f"\nline[{i}]:",lines[i])
        print(f"\ntokens[{i}]:",tokens[i])
    
    >>
    line[10]: twinkled and his usually pale face was flushed and animated the
    
    tokens[10]: ['twinkled', 'and', 'his', 'usually', 'pale', 'face', 'was', 'flushed', 'and', 'animated', 'the']
    
    line[11]: fire burned brightly and the soft radiance of the incandescent
    
    tokens[11]: ['fire', 'burned', 'brightly', 'and', 'the', 'soft', 'radiance', 'of', 'the', 'incandescent']
    
    line[12]: lights in the lilies of silver caught the bubbles that flashed and
    
    tokens[12]: ['lights', 'in', 'the', 'lilies', 'of', 'silver', 'caught', 'the', 'bubbles', 'that', 'flashed', 'and']
    
  • char

    tokens = tokenize(lines, 'char')
    for i in range(10,13):
        print(f"\nline[{i}]:",lines[i])
        print(f"\ntokens[{i}]:",tokens[i])
    
    >>
    line[10]: twinkled and his usually pale face was flushed and animated the
    
    tokens[10]: ['t', 'w', 'i', 'n', 'k', 'l', 'e', 'd', ' ', 'a', 'n', 'd', ' ', 'h', 'i', 's', ' ', 'u', 's', 'u', 'a', 'l', 'l', 'y', ' ', 'p', 'a', 'l', 'e', ' ', 'f', 'a', 'c', 'e', ' ', 'w', 'a', 's', ' ', 'f', 'l', 'u', 's', 'h', 'e', 'd', ' ', 'a', 'n', 'd', ' ', 'a', 'n', 'i', 'm', 'a', 't', 'e', 'd', ' ', 't', 'h', 'e']
    
    line[11]: fire burned brightly and the soft radiance of the incandescent
    
    tokens[11]: ['f', 'i', 'r', 'e', ' ', 'b', 'u', 'r', 'n', 'e', 'd', ' ', 'b', 'r', 'i', 'g', 'h', 't', 'l', 'y', ' ', 'a', 'n', 'd', ' ', 't', 'h', 'e', ' ', 's', 'o', 'f', 't', ' ', 'r', 'a', 'd', 'i', 'a', 'n', 'c', 'e', ' ', 'o', 'f', ' ', 't', 'h', 'e', ' ', 'i', 'n', 'c', 'a', 'n', 'd', 'e', 's', 'c', 'e', 'n', 't']
    
    line[12]: lights in the lilies of silver caught the bubbles that flashed and
    
    tokens[12]: ['l', 'i', 'g', 'h', 't', 's', ' ', 'i', 'n', ' ', 't', 'h', 'e', ' ', 'l', 'i', 'l', 'i', 'e', 's', ' ', 'o', 'f', ' ', 's', 'i', 'l', 'v', 'e', 'r', ' ', 'c', 'a', 'u', 'g', 'h', 't', ' ', 't', 'h', 'e', ' ', 'b', 'u', 'b', 'b', 'l', 'e', 's', ' ', 't', 'h', 'a', 't', ' ', 'f', 'l', 'a', 's', 'h', 'e', 'd', ' ', 'a', 'n', 'd']
    

Глоссарий

После описанной выше обработки токен, который мы получаем, имеет строковый тип, а ввод, требуемый моделью, — это число, поэтому нам нужно пронумеровать каждый токен, чтобы модель могла использовать номер.

построитьСловарьСловарь, который сопоставляет токены строкового типа с числовыми индексами, начинающимися с 0.

def count_corpus(tokens): 
    if len(tokens) == 0 or isinstance(tokens[0], list):
        # 将词元列表展平成使用词元填充的一个列表
        tokens = [token for line in tokens for token in line]
    return collections.Counter(tokens)

Эта функция используется для подсчета частоты токенов.

Все документы в обучающей выборке объединяются вместе, подсчитываются их уникальные токены, а полученные статистические результаты называются корпусом. Затем каждому уникальному токену присваивается числовой индекс в зависимости от того, как часто он встречается.

  • if len(tokens) == 0 or isinstance(tokens[0], list)Возвращает true, когда токены представляют собой пустой список или двумерный список (конечно, трехмерный и четырехмерный также возвращают true, но мы определили, что для предыдущей операции с токенами он не более чем двумерный).
  • tokens = [token for line in tokens for token in line]Используется для выравнивания списка, преобразования исходного двумерного в одномерный.
  • наконец вернуться кcollections.Counter.
    • class collections.Counter([*iterable-or-mapping*])

      Один Counter Является dictподкласс

      Это коллекция, в которой элементы хранятся как ключи словаря, а их счетчики хранятся как значения. Количество может быть любым целым числом, включая 0 и отрицательные числа. CounterКлассы немного похожи на сумки или мультимножества в других языках.

      c = collections.Counter('gallahad')   
      print(c)
      c = collections.Counter({'red': 4, 'blue': 2})
      print(c)
      c = collections.Counter(['eggs', 'ham'])
      print(c)
      
      >>
      Counter({'a': 3, 'l': 2, 'g': 1, 'h': 1, 'd': 1})
      Counter({'red': 4, 'blue': 2})
      Counter({'eggs': 1, 'ham': 1})
      

      Если указанный ключ не имеет записей, верните 0 вместо того, чтобы выталкиватьKeyError

      c = collections.Counter('gallahad')   
      print(c['z'])
      
      >>
      0
      

При обработке ожиданий удаляются менее часто встречающиеся слова, что может снизить сложность обработки.

.

Мы также можем добавить список для хранения зарезервированных маркеров, например: маркеры заполнения («»); маркеры начала последовательности («»); маркеры конца последовательности («»).

Теперь напишите класс для реализации функции текстового словаря:

class Vocab:
    def __init__(self, tokens=None, min_freq=0, reserved_tokens=None):
        if tokens is None:
            tokens = []
        if reserved_tokens is None:
            reserved_tokens = [] 
        # 按出现频率排序
        counter = count_corpus(tokens)
        self.token_freqs = sorted(counter.items(), key=lambda x: x[1],
                                  reverse=True)
        # 未知词元的索引为0
        self.unk, uniq_tokens = 0, ['<unk>'] + reserved_tokens
        uniq_tokens += [token for token, freq in self.token_freqs
                        if freq >= min_freq and token not in uniq_tokens]
        self.idx_to_token, self.token_to_idx = [], dict()
        for token in uniq_tokens:
            self.idx_to_token.append(token)
            self.token_to_idx[token] = len(self.idx_to_token) - 1

    def __len__(self):
        return len(self.idx_to_token)

    def __getitem__(self, tokens):
        if not isinstance(tokens, (list, tuple)):
            return self.token_to_idx.get(tokens, self.unk)
        return [self.__getitem__(token) for token in tokens]

    def to_tokens(self, indices):
        if not isinstance(indices, (list, tuple)):
            return self.idx_to_token[indices]
        return [self.idx_to_token[index] for index in indices]
  • параметр:

    • токен: ваш текст классифицируется по слову или символу
    • min_freq: установить порог и игнорировать определенные слова, если их частота слишком низкая
    • зарезервированные_токены: токен, с которого начинается или заканчивается предложение.
  • Начните с двух операторов if, если это неприемлемоtokensилиreserved_tokensПросто установите его пустым, чтобы предотвратить ошибки.

  • использоватьcounterПринять корпус с хорошей статистикой частоты слов

  • self.token_freqsполучить словарь, отсортированный по частоте в порядке убывания

    • sorted(iterable, key=None, reverse=False)

      Описание параметра:

      • iterable — итерируемый объект.
      • key -- в основном используется для сравнения элемента, параметр всего один, параметр конкретной функции берется из итерируемого объекта, а для сортировки указывается элемент в итерируемом объекте.
      • reverse -- сортировка, reverse=True по убыванию, reverse=False по возрастанию (по умолчанию).
    • используя счетчик.items()Сортировка, то есть кортеж пар ключ-значение. ключ установлен наx[1], Кортеж каждой пары ключ-значение рассматривается как x, а x[1] сортируется в соответствии со следующими значениями.reverse = TrueОтсортируйте их в порядке убывания.

  • Последняя часть — написать self.idx_to_token и self.token_to_idx, чтобы получить его частоту слов или слов.


  1. Эта статья представляет собой примечания к чтению версии pytorch «Обучение глубокому обучению вручную». Другие статьи из этой серии можно найти здесь:Колонка «Практическое глубокое обучение» (juejin.cn)

  2. Примечания Адрес Github:DeepLearningNotes/d2l(github.com)

Все еще в процессе обновления......