반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형

15.6. Subword Embedding — Dive into Deep Learning 1.0.3 documentation (d2l.ai)

 

15.6. Subword Embedding — Dive into Deep Learning 1.0.3 documentation

 

d2l.ai

 

15.6. Subword Embedding

 

In English, words such as “helps”, “helped”, and “helping” are inflected forms of the same word “help”. The relationship between “dog” and “dogs” is the same as that between “cat” and “cats”, and the relationship between “boy” and “boyfriend” is the same as that between “girl” and “girlfriend”. In other languages such as French and Spanish, many verbs have over 40 inflected forms, while in Finnish, a noun may have up to 15 cases. In linguistics, morphology studies word formation and word relationships. However, the internal structure of words was neither explored in word2vec nor in GloVe.

 

영어에서 "helps", "helped" 및 "helping"과 같은 단어는 동일한 단어 "help"의 변형 형태입니다. 'dog'와 'dogs'의 관계는 'cat'와 'cats'의 관계와 같고, 'boy'과 'boyfriend'의 관계는 'girl'와 'girlfriend'의 관계와 같습니다. 프랑스어와 스페인어와 같은 다른 언어에서는 많은 동사에 40개 이상의 변화형이 있는 반면, 핀란드어에서는 명사가 최대 15개의 경우를 가질 수 있습니다. 언어학에서 형태론은 단어 형성과 단어 관계를 연구합니다. 그러나 word2vec이나 GloVe에서는 단어의 내부 구조가 탐색되지 않았습니다.

 

Recall how words are represented in word2vec. In both the skip-gram model and the continuous bag-of-words model, different inflected forms of the same word are directly represented by different vectors without shared parameters. To use morphological information, the fastText model proposed a subword embedding approach, where a subword is a character n-gram (Bojanowski et al., 2017). Instead of learning word-level vector representations, fastText can be considered as the subword-level skip-gram, where each center word is represented by the sum of its subword vectors.

 

word2vec에서 단어가 어떻게 표현되는지 기억해 보세요. 스킵그램 모델과 continuous  bag-of-words 모델 모두에서 동일한 단어의 다양한 활용 형태는 공유 매개변수 없이 다양한 벡터로 직접 표현됩니다. 형태학적 정보를 사용하기 위해 fastText 모델은 하위 단어가 문자 n-gram인 하위 단어 임베딩 접근 방식을 제안했습니다(Bojanowski et al., 2017). 단어 수준 벡터 표현을 학습하는 대신 fastText는 하위 단어 수준 건너뛰기 그램으로 간주될 수 있습니다. 여기서 각 중심 단어는 해당 하위 단어 벡터의 합으로 표시됩니다.

 

Let’s illustrate how to obtain subwords for each center word in fastText using the word “where”. First, add special characters “<” and “>” at the beginning and end of the word to distinguish prefixes and suffixes from other subwords. Then, extract character n-grams from the word. For example, when n=3, we obtain all subwords of length 3: “<wh”, “whe”, “her”, “ere”, “re>”, and the special subword “<where>”.

 

"where"라는 단어를 사용하여 fastText의 각 중심 단어에 대한 하위 단어를 얻는 방법을 살펴보겠습니다. 먼저, 접두어와 접미어를 다른 하위 단어와 구별하기 위해 단어의 시작과 끝 부분에 특수 문자 “<” “>”를 추가합니다. 그런 다음 단어에서 문자 n-그램을 추출합니다. 예를 들어 n=3이면 길이가 3인 모든 하위 단어인 "<wh", "whe", "her", "ere", "re>" 및 특수 하위 단어 "<where>"를 얻습니다.

 

In fastText, for any word w, denote by gw the union of all its subwords of length between 3 and 6 and its special subword. The vocabulary is the union of the subwords of all words. Letting zg be the vector of subword g in the dictionary, the vector vw for word was a center word in the skip-gram model is the sum of its subword vectors:

 

fastText에서 임의의 단어 w에 대해 길이가 3에서 6 사이인 모든 하위 단어와 특수 하위 단어의 결합을 gw로 표시합니다. 어휘는 모든 단어의 하위 단어의 결합입니다. zg를 사전에 있는 하위 단어 g의 벡터로 두면 단어에 대한 벡터 vw는 스킵 그램 모델의 중심 단어였으며 해당 하위 단어 벡터의 합입니다.

 

The rest of fastText is the same as the skip-gram model. Compared with the skip-gram model, the vocabulary in fastText is larger, resulting in more model parameters. Besides, to calculate the representation of a word, all its subword vectors have to be summed, leading to higher computational complexity. However, thanks to shared parameters from subwords among words with similar structures, rare words and even out-of-vocabulary words may obtain better vector representations in fastText.

 

fastText의 나머지 부분은 Skip-gram 모델과 동일합니다. Skip-gram 모델과 비교하면 fastText의 어휘량이 더 많아 모델 매개변수가 더 많아집니다. 게다가, 단어의 표현을 계산하려면 모든 하위 단어 벡터를 합산해야 하므로 계산 복잡도가 높아집니다. 그러나 유사한 구조를 가진 단어들 사이에서 하위 단어의 공유 매개변수 덕분에 희귀한 단어와 심지어 어휘에 포함되지 않은 단어도 fastText에서 더 나은 벡터 표현을 얻을 수 있습니다.

 

fastText란?

 

fastText is a popular library and approach in natural language processing (NLP) that focuses on word embeddings and text classification. Developed by Facebook's AI Research (FAIR) team, fastText extends the concept of word embeddings introduced by Word2Vec and provides a more efficient and powerful way of representing words in a continuous vector space.

 

fastText는 자연어 처리(NLP)에서 널리 사용되는 라이브러리 및 접근 방식으로, 단어 임베딩과 텍스트 분류에 중점을 둡니다. 페이스북의 인공지능 연구(Facebook AI Research, FAIR) 팀에서 개발한 fastText는 Word2Vec에 소개된 단어 임베딩 개념을 확장하여 단어를 연속 벡터 공간에 효과적으로 표현하는 방법을 제공하며 더 효율적이고 강력한 접근 방식을 제공합니다.

 

The key features of fastText include:

 

fastText의 주요 특징은 다음과 같습니다:

 

  1. Subword Embeddings: Unlike traditional word embeddings, which treat words as atomic units, fastText breaks words into smaller subword units called "character n-grams." This allows it to capture morphological and semantic information from subword components, making it particularly effective for handling out-of-vocabulary words and morphologically rich languages.

    서브워드 임베딩: 전통적인 단어 임베딩과 달리 fastText는 단어를 더 작은 "문자 n-그램"이라 불리는 서브워드 단위로 분해합니다. 이를 통해 형태소 및 의미 정보를 서브워드 구성 요소에서 캡처할 수 있어, 어휘에 없는 단어나 형태론적으로 풍부한 언어를 처리하는 데 효과적입니다.

  2. Efficiency: fastText is designed to be highly efficient both in terms of training time and memory usage. Its subword-based approach reduces the vocabulary size and allows it to handle rare or unseen words effectively.

    효율성: fastText는 훈련 시간과 메모리 사용량 면에서 높은 효율성을 가지도록 설계되었습니다. 서브워드 기반 접근 방식을 사용하여 어휘 크기를 줄이고 희귀한 단어나 처음 보는 단어를 효과적으로 다룰 수 있습니다.

  3. Text Classification: In addition to word embeddings, fastText also excels at text classification tasks. It can classify documents, sentences, or shorter text snippets into predefined categories or labels. This makes it suitable for tasks like sentiment analysis, topic classification, and more.

    Text 분: 단어 임베딩 외에도 fastText는 텍스트 분류 작업에도 탁월합니다. 문서, 문장 또는 짧은 텍스트 조각을 미리 정의된 카테고리나 레이블로 분류할 수 있습니다. 따라서 감정 분석, 주제 분류 등과 같은 작업에 적합합니다..

  4. Pretrained Models: fastText provides pre-trained word vectors that can be readily used for various downstream tasks. These pre-trained vectors capture semantic information about words and can be fine-tuned or incorporated into other models.

    미리 훈련된 모델: fastText는 미리 훈련된 단어 벡터를 제공하여 다양한 하위 작업에 쉽게 활용할 수 있습니다. 이러한 미리 훈련된 벡터는 단어에 관한 의미 정보를 캡처하며 다른 모델에 미세 조정하거나 통합할 수 있습니다.

  5. Hierarchical Softmax and Negative Sampling: fastText employs techniques like hierarchical softmax and negative sampling to speed up training and make it feasible to train on large datasets.

    계층화된 소프트맥스와 네거티브 샘플링: fastText는 계층화된 소프트맥스와 네거티브 샘플링과 같은 기술을 사용하여 훈련 속도를 높이고 대규모 데이터셋에서 훈련할 수 있게 합니다.

  6. Open-Source: fastText is open-source software, which means researchers and developers can freely access its code, use pre-trained models, and even modify the library to suit their needs.

    오픈 소스: fastText는 오픈 소스 소프트웨어로, 연구원과 개발자는 코드에 자유롭게 접근하고, 미리 훈련된 모델을 사용하며, 라이브러리를 수정하여 필요에 맞게 사용할 수 있습니다.

Overall, fastText's unique subword embeddings and its focus on efficiency make it a valuable tool in the field of NLP, especially for tasks involving limited training data, morphologically complex languages, and text classification.

총론적으로 fastText의 독특한 서브워드 임베딩과 효율성에 중점을 두어서, 특히 훈련 데이터가 제한적인 경우, 형태론적으로 복잡한 언어, 텍스트 분류와 관련된 작업에서 가치 있는 도구로 사용됩니다.

15.6.2. Byte Pair Encoding

 

In fastText, all the extracted subwords have to be of the specified lengths, such as 3 to 6, thus the vocabulary size cannot be predefined. To allow for variable-length subwords in a fixed-size vocabulary, we can apply a compression algorithm called byte pair encoding (BPE) to extract subwords (Sennrich et al., 2015).

 

fastText에서는 추출된 모든 하위 단어가 3~6과 같이 지정된 길이여야 하므로 어휘 크기를 미리 정의할 수 없습니다. 고정 크기 어휘에서 가변 길이 하위 단어를 허용하기 위해 BPE(바이트 쌍 인코딩)라는 압축 알고리즘을 적용하여 하위 단어를 추출할 수 있습니다(Sennrich et al., 2015).

 

Byte pair encoding performs a statistical analysis of the training dataset to discover common symbols within a word, such as consecutive characters of arbitrary length. Starting from symbols of length 1, byte pair encoding iteratively merges the most frequent pair of consecutive symbols to produce new longer symbols. Note that for efficiency, pairs crossing word boundaries are not considered. In the end, we can use such symbols as subwords to segment words. Byte pair encoding and its variants has been used for input representations in popular natural language processing pretraining models such as GPT-2 (Radford et al., 2019) and RoBERTa (Liu et al., 2019). In the following, we will illustrate how byte pair encoding works.

 

바이트 쌍 인코딩은 훈련 데이터 세트의 통계 분석을 수행하여 임의 길이의 연속 문자와 같은 단어 내의 공통 기호를 찾습니다. 길이 1의 기호부터 시작하여 바이트 쌍 인코딩은 가장 빈번한 연속 기호 쌍을 반복적으로 병합하여 새로운 더 긴 기호를 생성합니다. 효율성을 위해 단어 경계를 넘는 쌍은 고려되지 않습니다. 결국 우리는 하위 단어와 같은 기호를 사용하여 단어를 분할할 수 있습니다. 바이트 쌍 인코딩과 그 변형은 GPT-2(Radford et al., 2019) 및 RoBERTa(Liu et al., 2019)와 같은 인기 있는 자연어 처리 사전 학습 모델의 입력 표현에 사용되었습니다. 다음에서는 바이트 쌍 인코딩이 작동하는 방식을 설명합니다.

 

First, we initialize the vocabulary of symbols as all the English lowercase characters, a special end-of-word symbol '_', and a special unknown symbol '[UNK]'.

 

먼저 기호의 어휘를 모두 영어 소문자, 특수 단어 끝 기호 '_', 특수 미지 기호 '[UNK]'로 초기화합니다.

 

import collections

symbols = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
           'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
           '_', '[UNK]']

이 코드는 다양한 기호를 포함하는 리스트인 symbols를 정의하는 부분입니다.

  1. import collections:
    • 파이썬 내장 모듈인 collections를 가져옵니다. 이 모듈은 데이터 컨테이너를 위한 유용한 클래스와 함수를 제공합니다.
  2. symbols = ['a', 'b', 'c', ..., '[UNK]']:
    • symbols라는 리스트를 정의하고 초기화합니다.
    • 이 리스트에는 알파벳 소문자 'a'부터 'z'까지의 문자, 언더스코어 '_', 그리고 '[UNK]'라는 특수 기호가 포함되어 있습니다.
    • '[UNK]'는 "unknown"을 의미하며, 텍스트에서 잘못된 문자 등을 대체하는 용도로 사용될 수 있습니다.

이 코드는 다양한 문자와 특수 기호를 포함하는 symbols 리스트를 정의하고 초기화하는 역할을 합니다.

 

Since we do not consider symbol pairs that cross boundaries of words, we only need a dictionary raw_token_freqs that maps words to their frequencies (number of occurrences) in a dataset. Note that the special symbol '_' is appended to each word so that we can easily recover a word sequence (e.g., “a taller man”) from a sequence of output symbols ( e.g., “a_ tall er_ man”). Since we start the merging process from a vocabulary of only single characters and special symbols, space is inserted between every pair of consecutive characters within each word (keys of the dictionary token_freqs). In other words, space is the delimiter between symbols within a word.

 

단어의 경계를 넘는 기호 쌍을 고려하지 않기 때문에 단어를 데이터 세트의 빈도(발생 횟수)에 매핑하는 사전 raw_token_freqs만 필요합니다. 특수 기호 '_'가 각 단어에 추가되어 출력 기호 시퀀스(예: "a_ Taller_ Man")에서 단어 시퀀스(예: "a Taller Man")를 쉽게 복구할 수 있습니다. 단일 문자와 특수 기호로만 구성된 어휘에서 병합 프로세스를 시작하므로 각 단어 내의 모든 연속 문자 쌍(사전 token_freqs의 키) 사이에 공백이 삽입됩니다. 즉, 공백은 단어 내 기호 사이의 구분 기호입니다.

 

raw_token_freqs = {'fast_': 4, 'faster_': 3, 'tall_': 5, 'taller_': 4}
token_freqs = {}
for token, freq in raw_token_freqs.items():
    token_freqs[' '.join(list(token))] = raw_token_freqs[token]
token_freqs

이 코드는 원시 토큰 빈도 정보를 가공하여 토큰을 수정하고, 새로운 형식으로 빈도 정보를 저장하는 과정을 나타내고 있습니다.

  1. raw_token_freqs = {'fast_': 4, 'faster_': 3, 'tall_': 5, 'taller_': 4}:
    • raw_token_freqs라는 딕셔너리를 정의하고 초기화합니다. 각 토큰과 해당 토큰의 빈도를 나타냅니다.
  2. token_freqs = {}:
    • 빈 딕셔너리 token_freqs를 초기화합니다. 수정된 토큰과 빈도 정보를 저장할 예정입니다.
  3. for token, freq in raw_token_freqs.items()::
    • raw_token_freqs 딕셔너리의 각 토큰과 빈도에 대해 반복합니다.
  4. token_freqs[' '.join(list(token))] = raw_token_freqs[token]:
    • 해당 토큰을 공백으로 분리하여 리스트로 만든 다음, 다시 공백을 이어붙여 하나의 문자열로 만듭니다.
    • 수정된 토큰을 token_freqs 딕셔너리의 키로 설정하고, 해당 토큰의 빈도를 raw_token_freqs 딕셔너리에서 가져와 값으로 설정합니다.
  5. token_freqs:
    • 수정된 토큰과 해당 토큰의 빈도로 이루어진 token_freqs 딕셔너리를 출력합니다.

이 코드는 원시 토큰의 빈도 정보를 가공하여 토큰을 수정하고, 수정된 토큰과 빈도 정보를 새로운 형식으로 저장하는 과정을 보여줍니다.

{'f a s t _': 4, 'f a s t e r _': 3, 't a l l _': 5, 't a l l e r _': 4}

We define the following get_max_freq_pair function that returns the most frequent pair of consecutive symbols within a word, where words come from keys of the input dictionary token_freqs.

 

단어 내에서 가장 빈번한 연속 기호 쌍을 반환하는 다음 get_max_freq_pair 함수를 정의합니다. 여기서 단어는 입력 사전 token_freqs의 키에서 나옵니다.

 

def get_max_freq_pair(token_freqs):
    pairs = collections.defaultdict(int)
    for token, freq in token_freqs.items():
        symbols = token.split()
        for i in range(len(symbols) - 1):
            # Key of `pairs` is a tuple of two consecutive symbols
            pairs[symbols[i], symbols[i + 1]] += freq
    return max(pairs, key=pairs.get)  # Key of `pairs` with the max value

이 코드는 주어진 토큰 빈도 정보에서 두 연속된 심볼의 페어 중 빈도가 가장 높은 페어를 찾아 반환하는 함수를 정의하고 있습니다.

  1. def get_max_freq_pair(token_freqs)::
    • token_freqs라는 인자를 받는 함수 get_max_freq_pair를 정의합니다.
    • token_freqs는 토큰과 해당 토큰의 빈도 정보가 저장된 딕셔너리입니다.
  2. pairs = collections.defaultdict(int):
    • collections.defaultdict 객체인 pairs를 생성합니다. 이 객체는 기본값으로 정수 0을 갖습니다.
    • 이 객체는 연속된 심볼 페어와 그 빈도를 저장할 용도로 사용됩니다.
  3. for token, freq in token_freqs.items()::
    • token_freqs 딕셔너리의 각 토큰과 빈도에 대해 반복합니다.
  4. symbols = token.split():
    • 현재 토큰을 공백을 기준으로 분리하여 symbols라는 리스트로 만듭니다.
  5. for i in range(len(symbols) - 1)::
    • symbols 리스트의 길이에서 1을 뺀 범위 내에서 반복합니다.
  6. pairs[symbols[i], symbols[i + 1]] += freq:
    • pairs 딕셔너리에 페어의 키인 (symbols[i], symbols[i + 1])에 빈도 freq를 더합니다.
  7. return max(pairs, key=pairs.get):
    • pairs 딕셔너리에서 값이 가장 큰 키를 반환합니다. 즉, 빈도가 가장 높은 페어의 키를 반환합니다.

이 함수는 주어진 토큰 빈도 정보에서 빈도가 가장 높은 연속된 심볼 페어를 찾아 반환하는 기능을 수행합니다.

 

As a greedy approach based on frequency of consecutive symbols, byte pair encoding will use the following merge_symbols function to merge the most frequent pair of consecutive symbols to produce new symbols.

 

연속 기호의 빈도를 기반으로 한 탐욕적 접근 방식으로 바이트 쌍 인코딩은 다음 merge_symbols 함수를 사용하여 가장 빈번한 연속 기호 쌍을 병합하여 새 기호를 생성합니다.

 

def merge_symbols(max_freq_pair, token_freqs, symbols):
    symbols.append(''.join(max_freq_pair))
    new_token_freqs = dict()
    for token, freq in token_freqs.items():
        new_token = token.replace(' '.join(max_freq_pair),
                                  ''.join(max_freq_pair))
        new_token_freqs[new_token] = token_freqs[token]
    return new_token_freqs

이 코드는 가장 높은 빈도를 갖는 연속된 심볼 페어를 병합하고, 토큰 빈도 정보를 업데이트하는 함수를 나타내고 있습니다.

  1. def merge_symbols(max_freq_pair, token_freqs, symbols)::
    • max_freq_pair, token_freqs, symbols라는 세 개의 인자를 받는 함수 merge_symbols를 정의합니다.
    • max_freq_pair는 가장 높은 빈도를 갖는 연속된 심볼 페어를 나타내는 튜플입니다.
    • token_freqs는 토큰과 해당 토큰의 빈도 정보가 저장된 딕셔너리입니다.
    • symbols는 기존 심볼을 저장한 리스트입니다.
  2. symbols.append(''.join(max_freq_pair)):
    • max_freq_pair 튜플의 심볼을 이어붙여서 하나의 문자열로 만든 다음, symbols 리스트에 추가합니다.
    • 이렇게 만들어진 문자열은 더 이상 나누어지지 않는 단일 심볼로써 추가됩니다.
  3. new_token_freqs = dict():
    • 빈 딕셔너리 new_token_freqs를 초기화합니다. 업데이트된 토큰 빈도 정보를 저장할 예정입니다.
  4. for token, freq in token_freqs.items()::
    • token_freqs 딕셔너리의 각 토큰과 빈도에 대해 반복합니다.
  5. new_token = token.replace(' '.join(max_freq_pair), ''.join(max_freq_pair)):
    • 현재 토큰에서 max_freq_pair 튜플의 심볼을 하나의 문자열로 바꾸어 새로운 토큰을 생성합니다.
    • 이렇게 생성된 새로운 토큰은 병합된 연속된 심볼을 포함하도록 됩니다.
  6. new_token_freqs[new_token] = token_freqs[token]:
    • 업데이트된 토큰과 해당 토큰의 빈도 정보를 new_token_freqs 딕셔너리에 추가합니다.
  7. return new_token_freqs:
    • 업데이트된 토큰 빈도 정보가 저장된 new_token_freqs 딕셔너리를 반환합니다.

이 함수는 가장 높은 빈도를 갖는 연속된 심볼 페어를 병합하고, 해당 페어가 병합된 토큰 빈도 정보를 업데이트하는 기능을 수행합니다.

 

 

Now we iteratively perform the byte pair encoding algorithm over the keys of the dictionary token_freqs. In the first iteration, the most frequent pair of consecutive symbols are 't' and 'a', thus byte pair encoding merges them to produce a new symbol 'ta'. In the second iteration, byte pair encoding continues to merge 'ta' and 'l' to result in another new symbol 'tal'.

 

이제 사전 token_freqs의 키에 대해 바이트 쌍 인코딩 알고리즘을 반복적으로 수행합니다. 첫 번째 반복에서 가장 빈번한 연속 기호 쌍은 't'와 'a'이므로 바이트 쌍 인코딩은 이를 병합하여 새로운 기호 'ta'를 생성합니다. 두 번째 반복에서는 바이트 쌍 인코딩이 계속해서 'ta'와 'l'을 병합하여 또 다른 새로운 기호 'tal'을 생성합니다.

 

num_merges = 10
for i in range(num_merges):
    max_freq_pair = get_max_freq_pair(token_freqs)
    token_freqs = merge_symbols(max_freq_pair, token_freqs, symbols)
    print(f'merge #{i + 1}:', max_freq_pair)

 

merge #1: ('t', 'a')
merge #2: ('ta', 'l')
merge #3: ('tal', 'l')
merge #4: ('f', 'a')
merge #5: ('fa', 's')
merge #6: ('fas', 't')
merge #7: ('e', 'r')
merge #8: ('er', '_')
merge #9: ('tall', '_')
merge #10: ('fast', '_')

이 코드는 주어진 빈도 정보와 심볼을 사용하여 심볼을 반복적으로 병합하는 과정을 나타내고 있습니다.

  1. num_merges = 10:
    • num_merges 변수에 10을 할당합니다. 이 변수는 병합을 반복할 횟수를 나타냅니다.
  2. for i in range(num_merges)::
    • 0부터 num_merges - 1까지의 범위에서 반복합니다.
  3. max_freq_pair = get_max_freq_pair(token_freqs):
    • get_max_freq_pair 함수를 사용하여 현재 가장 높은 빈도를 갖는 연속된 심볼 페어를 가져옵니다.
    • 이를 max_freq_pair 변수에 할당합니다.
  4. token_freqs = merge_symbols(max_freq_pair, token_freqs, symbols):
    • merge_symbols 함수를 사용하여 심볼을 병합하고, 토큰 빈도 정보를 업데이트합니다.
    • 업데이트된 토큰 빈도 정보를 token_freqs 변수에 할당합니다.
  5. print(f'merge #{i + 1}:', max_freq_pair):
    • 현재 반복 횟수와 병합된 심볼 페어를 출력합니다.
    • 출력 형식은 "merge #1: (심볼1, 심볼2)"와 같이 됩니다.

이 코드는 주어진 빈도 정보와 심볼을 사용하여 심볼을 반복적으로 병합하고, 각 반복마다 병합된 심볼 페어를 출력하는 과정을 나타내고 있습니다.

 

After 10 iterations of byte pair encoding, we can see that list symbols now contains 10 more symbols that are iteratively merged from other symbols.

 

바이트 쌍 인코딩을 10번 반복한 후 이제 목록 기호에 다른 기호에서 반복적으로 병합된 기호가 10개 더 포함되어 있음을 확인할 수 있습니다.

 

print(symbols)
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '_', '[UNK]', 'ta', 'tal', 'tall', 'fa', 'fas', 'fast', 'er', 'er_', 'tall_', 'fast_']

 

For the same dataset specified in the keys of the dictionary raw_token_freqs, each word in the dataset is now segmented by subwords “fast_”, “fast”, “er_”, “tall_”, and “tall” as a result of the byte pair encoding algorithm. For instance, words “faster_” and “taller_” are segmented as “fast er_” and “tall er_”, respectively.

 

raw_token_freqs 사전의 키에 지정된 동일한 데이터 세트의 경우 이제 데이터 세트의 각 단어는 바이트 쌍의 결과로 하위 단어 "fast_", "fast", "er_", "tall_" 및 "tall"로 분할됩니다. 인코딩 알고리즘. 예를 들어, "faster_" 및 "taller_"라는 단어는 각각 "fast er_" 및 "tall er_"로 분할됩니다.

 

print(list(token_freqs.keys()))
['fast_', 'fast er_', 'tall_', 'tall er_']

Note that the result of byte pair encoding depends on the dataset being used. We can also use the subwords learned from one dataset to segment words of another dataset. As a greedy approach, the following segment_BPE function tries to break words into the longest possible subwords from the input argument symbols.

 

바이트 쌍 인코딩의 결과는 사용되는 데이터세트에 따라 달라집니다. 또한 한 데이터세트에서 학습된 하위 단어를 사용하여 다른 데이터세트의 단어를 분할할 수도 있습니다. 탐욕적인 접근 방식으로, 다음 세그먼트_BPE 함수는 입력 인수 기호에서 단어를 가능한 가장 긴 하위 단어로 나누려고 시도합니다.

 

def segment_BPE(tokens, symbols):
    outputs = []
    for token in tokens:
        start, end = 0, len(token)
        cur_output = []
        # Segment token with the longest possible subwords from symbols
        while start < len(token) and start < end:
            if token[start: end] in symbols:
                cur_output.append(token[start: end])
                start = end
                end = len(token)
            else:
                end -= 1
        if start < len(token):
            cur_output.append('[UNK]')
        outputs.append(' '.join(cur_output))
    return outputs

이 코드는 주어진 토큰과 심볼을 사용하여 BPE (Byte-Pair Encoding) 알고리즘을 통해 토큰을 하위 단어로 분할하는 함수를 나타내고 있습니다.

  1. def segment_BPE(tokens, symbols)::
    • tokens와 symbols라는 두 개의 인자를 받는 함수 segment_BPE를 정의합니다.
    • tokens는 분할할 토큰들이 저장된 리스트입니다.
    • symbols는 BPE 알고리즘에서 사용할 심볼들을 저장한 리스트입니다.
  2. outputs = []:
    • 빈 리스트 outputs를 초기화합니다. 분할된 결과를 저장할 예정입니다.
  3. for token in tokens::
    • tokens 리스트의 각 토큰에 대해 반복합니다.
  4. start, end = 0, len(token):
    • start와 end를 초기화합니다. 이 변수들은 토큰의 하위 단어 분할을 위한 인덱스를 나타냅니다.
  5. cur_output = []:
    • 빈 리스트 cur_output을 초기화합니다. 현재 토큰의 분할 결과를 저장할 예정입니다.
  6. while start < len(token) and start < end::
    • start가 토큰의 길이보다 작고, start가 end보다 작은 동안 반복합니다.
    • 토큰의 하위 단어 분할을 수행합니다.
  7. if token[start: end] in symbols::
    • symbols 리스트에 현재 부분 토큰이 존재하면 (가장 긴 하위 단어라면):
    • cur_output 리스트에 현재 부분 토큰을 추가하고, start를 end로 설정합니다.
    • 그리고 end를 토큰의 길이로 설정하여 더 이상 하위 단어 분할을 시도하지 않도록 합니다.
  8. else::
    • 그렇지 않으면 (현재 부분 토큰이 symbols에 없으면):
    • end를 하나 줄여 다음으로 더 짧은 부분 토큰을 검사하도록 합니다.
  9. if start < len(token)::
    • 만약 start가 토큰의 길이보다 작다면 (아직 분할되지 않은 부분이 남았다면):
    • '[UNK]'라는 특수 토큰을 cur_output 리스트에 추가합니다.
  10. outputs.append(' '.join(cur_output)):
    • 현재 토큰의 분할 결과인 cur_output 리스트를 공백으로 연결하여 하나의 문자열로 만들고, 이를 outputs 리스트에 추가합니다.
  11. return outputs:
    • 분할된 결과가 저장된 outputs 리스트를 반환합니다.

이 함수는 BPE 알고리즘을 사용하여 주어진 토큰들을 하위 단어로 분할하는 기능을 수행합니다.

 

In the following, we use the subwords in list symbols, which is learned from the aforementioned dataset, to segment tokens that represent another dataset.

 

다음에서는 앞서 언급한 데이터 세트에서 학습한 목록 기호의 하위 단어를 사용하여 다른 데이터 세트를 나타내는 토큰을 분할합니다.

 

tokens = ['tallest_', 'fatter_']
print(segment_BPE(tokens, symbols))

이 코드는 주어진 토큰들을 BPE 알고리즘을 이용하여 하위 단어로 분할하는 함수를 호출하고, 그 결과를 출력하는 과정을 나타내고 있습니다.

  1. tokens = ['tallest_', 'fatter_']:
    • tokens 리스트에 두 개의 토큰인 'tallest_'와 'fatter_'를 저장합니다.
  2. print(segment_BPE(tokens, symbols)):
    • segment_BPE 함수를 호출하여 주어진 토큰들을 하위 단어로 분할합니다.
    • symbols 리스트는 앞서 정의된 심볼 리스트입니다.
    • 분할된 결과를 출력합니다.

이 코드는 주어진 토큰들을 BPE 알고리즘을 이용하여 하위 단어로 분할한 후, 그 결과를 출력합니다.

['tall e s t _', 'fa t t er_']

 

Byte Pair Encoding (BPE) 란?

 

바이트 페어 인코딩(Byte Pair Encoding 또는 BPE)은 자연어 처리에서 텍스트 압축 및 토큰화에 사용되는 기술입니다. 이 기술은 텍스트 데이터를 작은 단위로 쪼개어 단어 및 서브워드의 어휘를 구축하는 방법을 의미합니다.

 

BPE의 주요 아이디어는 빈도 기반으로 텍스트 데이터 내에서 가장 자주 나타나는 바이트 또는 문자열 단위를 식별하고 이를 하나의 토큰으로 결합하여 새로운 어휘를 생성하는 것입니다. 이렇게 하면 텍스트 데이터 내에서 자주 사용되는 단어와 단어 구성 요소를 캡처하면서 어휘 크기를 줄일 수 있습니다.

 

BPE 알고리즘의 작동 방식은 다음과 같습니다:

 

  1. 빈도 계산: 텍스트 데이터 내에서 모든 바이트 또는 문자열 단위의 빈도를 계산합니다.
  2. 가장 빈도가 높은 바이트 결합 식별: 가장 자주 나타나는 바이트나 문자열의 쌍을 식별합니다. 이러한 바이트 쌍은 어휘 내의 새로운 토큰으로 결합됩니다.
  3. 토큰 결합: 가장 빈도가 높은 바이트 쌍을 하나의 토큰으로 결합하여 어휘를 업데이트합니다. 이 단계에서 중복되는 바이트 쌍을 찾아 처리합니다.
  4. 반복: 토큰 결합 단계를 여러 번 반복하여 텍스트 데이터의 빈도 기반 어휘를 구축합니다. 이렇게 하면 단어와 서브워드의 어휘가 생성됩니다.

 

BPE를 사용하면 희소성을 줄이고 미등록 단어에 대한 처리를 향상시킬 수 있습니다. 또한, 어휘 크기를 줄이는 효과를 가져와 모델 학습 및 토큰화 속도를 향상시킬 수 있습니다. 이 기술은 특히 기계 번역, 텍스트 생성, 감정 분석 등 다양한 자연어 처리 작업에서 유용하게 활용됩니다.

15.6.3. Summary

 

  • The fastText model proposes a subword embedding approach. Based on the skip-gram model in word2vec, it represents a center word as the sum of its subword vectors.

    fastText 모델은 하위 단어 임베딩 접근 방식을 제안합니다. word2vec의 스킵 그램 모델을 기반으로 중앙 단어를 하위 단어 벡터의 합으로 나타냅니다.

  • Byte pair encoding performs a statistical analysis of the training dataset to discover common symbols within a word. As a greedy approach, byte pair encoding iteratively merges the most frequent pair of consecutive symbols.

    바이트 쌍 인코딩은 훈련 데이터 세트의 통계 분석을 수행하여 단어 내의 공통 기호를 찾습니다. 욕심 많은 접근 방식으로 바이트 쌍 인코딩은 가장 빈번한 연속 기호 쌍을 반복적으로 병합합니다.

  • Subword embedding may improve the quality of representations of rare words and out-of-dictionary words.

    하위 단어 임베딩은 희귀 단어 및 사전에 없는 단어 표현의 품질을 향상시킬 수 있습니다.

 

15.6.4. Exercises

  1. As an example, there are about 3×10**8 possible 6-grams in English. What is the issue when there are too many subwords? How to address the issue? Hint: refer to the end of Section 3.2 of the fastText paper (Bojanowski et al., 2017).
  2. How to design a subword embedding model based on the continuous bag-of-words model?
  3. To get a vocabulary of size m, how many merging operations are needed when the initial symbol vocabulary size is n?
  4. How to extend the idea of byte pair encoding to extract phrases?
반응형