Как построить модель детектора фраз Малазанской империи

Теперь я не очень люблю большие слова, я верю в объяснение вещей в моем собственном понимании, и я обнаружил, что люди (новички) склонны понимать концепцию лучше/быстрее, когда новичок объясняет концепцию так, как он ее понимает, тем самым разрушая ее до его уровня. Но те, кто стремится к большому техническому определению, могут заняться исследованиями, они есть во всем Интернете.

Что такое детектор фраз

Детектор фраз — это реализованный алгоритм, который использует несколько техник, самой популярной из которых является счетная свертка (именно эта техника используется в gensim). Эта техника определяет общие слова, которые всегда встречаются вместе с минимальной предопределенной частотой или, согласно gensim, пороговой оценкой, где чем выше пороговое значение, тем строже процесс отбора.

Эта модель используется для выявления фраз (биграмм), которые присутствуют в ваших текстах, и особенно полезна при построении векторов слов. Поскольку она существенно снижает вычислительную сложность за счет уменьшения количества словарей в вашем векторе слов, она делает это путем объединения слов, которые часто встречаются вместе, в одно слово.

import os
import re
from typing import List
from itertools import islice

from gensim import utils
from gensim.models.phrases import Phrases, ENGLISH_CONNECTOR_WORDS
from nltk.tokenize import NLTKWordTokenizer, PunktSentenceTokenizer
view rawmodel.py
Вход в полноэкранный режим Выход из полноэкранного режима

Эта модель обучена на всей серии «Малазанской книги павших», это не только отличный ресурс для обучения вашей модели, но и гораздо более отличное чтение, или это могут быть любые [или все] книги, которые в настоящее время находятся в вашем компьютере. Книги должны быть в формате .txt [или преобразованы в него] для удобства загрузки, и все они должны находиться в папке под названием «Книги» без вложенных папок, содержащих другие текстовые файлы.

class CustomPathLineSentences:
    """Custom implementaion of gensim.models.word2vec.PathLineSentences

    It differs from gensim implementation in that it replaces the default
    tokenizer with a more powerful tokenizer, while also adding more
    functionalities to it.

    Functionalities
    1) Break the block of text into sentences using PunktSentenceTokenizer()
       as each text is split on n
    2) For each sentence
        a) Tokenize sentence using NLTKWordTokenizer()
            i) Clean each tokens 

        b) Join words that constitute phrases into a single word if a 
           phrase detector model is passed as argument

        c) yield up the preprocessed tokens for further processing
    2) 

    Parameters

    source: str
        File path of the folder containing the text file
    limit: int
        The maximum number of characters to read in each text block
    include_phrase: bool
        If True group words that constitue phrase into a single word, 
        this should only be set to True if a phrase detector model has
        been trained
    phrase_model: phrase detector model
        The model used in detecting phrases in text
        if include_phrase is True and phrase_model is None, a ValueError
        is raised,
    """
    def __init__(self, source, limit=None, 
                 include_phrase=False, phrase_model=None):
        self.source = source
        self.limit = limit
        self.include_phrase = include_phrase
        self.word_tokenizer = NLTKWordTokenizer()
        self.sentence_tokenizer = PunktSentenceTokenizer()

        if self.include_phrase and phrase_model is not None:
            self.phrase_model = phrase_model
        elif self.include_phrase and phrase_model is None:
            raise ValueError("phrase model detector not provided")

        if os.path.isfile(self.source):
            print('This is a file, use a folder next time')
            self.input_files = [self.source]
        elif os.path.isdir(self.source):
            self.source = os.path.join(self.source, '')
            self.input_files = os.listdir(self.source)
            self.input_files = [self.source + fname 
                                    for fname in self.input_files]
            self.input_files.sort()
        else:
            raise ValueError('input is neither a file or a directory')

    def __word_cleaner(self, word, cleaned_word_tokens, punctuation) -> List[str]:
        """For each word if any punctuation is still found in the 
        beginning and ending, further split them, ignore any 
        punctuation found in between the alphabet

        """
        beginning_punc = None
        ending_punc = None

        if len(word) > 1:
            if word[0] in punctuation:
                beginning_punc = word[0]
                word = word[1:]
            if word[-1] in punctuation:
                ending_punc = word[-1]
                word = word[:-1]

        if beginning_punc is not None:
            cleaned_word_tokens.append(beginning_punc)

        # For Some reason Jupyter notebook keep restarting
        # because of this recursive code

#         if word[0] in punctuation or word[-1] in punctuation:
#             cleaned_word_tokens = self.__word_cleaner(word, cleaned_word_tokens, 
#                                                       punctuation)
#         else:
#             cleaned_word_tokens.append(word)

        cleaned_word_tokens.append(word)
        if ending_punc is not None:
            cleaned_word_tokens.append(ending_punc)

        return cleaned_word_tokens

    def clean_token_words(self, sentence) -> List[str]:
        """Split a sentence into tokens for further preprocessing"""
        word_tokens: list = sentence.split()
        cleaned_word_tokens = []
        punctuation = string.punctuation + "’" + "‘"

        for word in word_tokens:
            if not self.include_phrase:
                cleaned_word_tokens.append(word.strip(punctuation))
            else:
                self.__word_cleaner(word, cleaned_word_tokens, punctuation)

        return cleaned_word_tokens          

    def __iter__(self):
        """Iterate through the files"""
        pattern = re.compile("[‘’]")

        total_count = 0

        for fname in self.input_files:
            with utils.open(fname, 'rb') as fin:
                # iterate through the text using the inbuilt
                # readline function
                for line in islice(fin, self.limit):
                    line = utils.to_unicode(line).strip()
                    if line:
                        # text broken at the line break point may contain
                        # many sentences in it, use a sentence segmenter
                        # to further break them into sentences
                        sentences = self.sentence_tokenizer.tokenize(line)

                        # for each of those sentences break them into tokens
                        for sentence in sentences:
                            sentence = pattern.sub("'", sentence)
                            word_tokens = self.clean_token_words(sentence)
                            if not self.include_phrase:
                                yield word_tokens
                            else:
                                # combine detected words that consitutes phrases
                                # into a single word
                                generator = self.phrase_model.analyze_sentence(word_tokens)
                                yield [word[0] for word in generator]
                    to

    def __len__(self):
        counts = 0
        for sentences in self.__iter__():
            counts += 1
        return counts
Вход в полноэкранный режим Выход из полноэкранного режима

Хорошо, это было весело, вы только что создали и добавили удобный инструмент в свой пояс инструментов, он пригодится нам в нескольких сценариях [особенно при построении вектора слов или модели стилевого вывода], поэтому сохраните его где-нибудь в текстовом файле python и назовите файл utils.py.

Я немного схитрил, я создал функцию CustomPathLineSentences, чтобы она была общей и имела много вариантов использования, не специфичных только для этого проекта, как вы увидите, когда я буду использовать ее при построении вектора слов и обучении модели стилевого анализа.

Вкратце этот класс выполняет следующие функции: он становится итератором для нас при инстанцировании, итерируя наши текстовые файлы и одновременно препроцессируя их для нас, оставляя нам более сложную задачу обучения модели детектора фраз. Чем мы и займемся ниже;

# train a phrase detector
def train_phrase_detector(*, threshold=400, reduce_model_memory_size=False):
    sentences_iterator = CustomPathLineSentences('Books')
    print("List of iles that will be analyzed for word phrase (bigrams)")
    for file in sentences_iterator.input_files:
        print(file)

    phrases = Phrases(sentences_iterator, threshold=threshold, 
                     connector_words=ENGLISH_CONNECTOR_WORDS)

    print("Training completed")
    return (phrases.freeze(), sentences_iterator) if reduce_model_memory_size 
                else (phrases, sentences_iterator)
Вход в полноэкранный режим Выйти из полноэкранного режима

Мы определили функцию, которая будет выполнять для нас задачу обучения модели, используя заданные и стандартные параметры. Далее мы перейдем к обучению модели, выполнив функцию.

threshold = 400
reduce_model_memory_size = False
phrase_model, sentences_iterator = train_phrase_detector(
               threshold=threshold,
                                 reduce_model_memory_size=reduce_model_memory_size)
# saving the trained model
fname = "malaz_phrase_detector"
phrase_model = phrase_model.save(fname)
Вход в полноэкранный режим Выход из полноэкранного режима

Хорошо, мы закончили обучение модели и сохранили ее на диск для дальнейшего использования, когда нам понадобится построить вектор слов и модель стилевого вывода, давайте посмотрим, чему научилась модель, и проверим, может ли она обнаруживать словосочетания в текстах.

# print how many phrases the model detected in the trainng text
print(f"Total number of phrases (bigrams) detected: {len(phrase_model)}")
text = """The Foolish Dog Clan will join your companies on the other side,' Coltaine said. 'You and the Weasel Clan shall guard this side while the wounded and the refugees cross"""
# preprocess the text in the same way the training
# text was preprocessed
text_cleaned = sentences_iterator.clean_token_words(text)
# detect phrases (bigrams) in text
phrases_detected = phrase_model.analyze_sentence(text_cleaned)
print("Detected phrases")
for key, values in phrases_detected.items():
    if values > 0:
        print(key)
Вход в полноэкранный режим Выход из полноэкранного режима

Мы успешно построили модель детектора фраз, модель была протестирована на тексте и смогла успешно обнаружить фразы в модели.

Это важно, данная модель может быть достаточно общей для обнаружения фраз, которые следуют шаблону обучающего текста [например, следующая серия авторского романа, если модель была обучена на предыдущей серии]. Но если модель будет предназначена для обнаружения фраз на совершенно другом образце текста, который даже не содержит той же лексики, что и учебный текст, модель потерпит серьезное фиаско.

Бог любит тебя!

Оцените статью
Procodings.ru
Добавить комментарий