본문 바로가기

AI Theory/NLP

[케창딥] ch11 텍스트를 위한 딥러닝

[케창딥] ch11 텍스트를 위한 딥러닝

텍스트 데이터 준비

  • 딥러닝 모델은 수치 텐서만 처리할 수 있으므로 원시 텍스트에 대해 텍스트 벡터화를 수행해야 함
  • 텍스트 벡터화란 텍스트를 수치 텐서로 바꾸는 과정
  • 케라스의 TextVectorizeation 층을 통해 빠르고 효율적으로 사용 가능

텍스트 벡터화의 단계

텍스트 벡터화의 단계(출처: 케창딥)

1. 텍스트 표준화(standardization)

  • 소문자로 바꾸거나 구두점 제거
  • (고급) 어간 추출(stemming): 어형이 변형된 단어를 하나의 표현으로 바꾸기
  • 표준화를 통해 모델에 필요한 훈련 데이터가 줄어들고 일반화가 잘되는 장점이 있으나, 일정량의 정보를 삭제할 수 있다는 단점이 있다.

2. 텍스트 토큰화(텍스트 분할)

  • 텍스트 표준화 진행 후 텍스트를 벡터화하기 위한 단위(토큰)로 분할
  • 크게 단어수준토큰화, n-gram 토큰화, 문자수준토큰화 3가지 방법으로 나뉨
  • 일반적으로 단어수준토큰화, N-gram 토큰화를 많이 사용
    • 단어수준토큰화: 단어 순서 고려하는 시퀸스 모델
    • n-gram토큰화: 입력 단어 순서 무시하고 집합으로 다루는 BoW모델(bag of words model)
    • 문자수준토큰화: 음성인식, 텍스트생성 모델

단어 수준 토큰화

공백 또는 구두점으로 구분되도록 토큰화

문장: "나는 오늘 영화를 보러 갔다."
단어수준 토큰화: ["나는", "오늘", "영화를", "보러", "갔다."]

문장: "과일은 맛있고 건강하다."
단어수준 토큰화: ["과일은", "맛있고", "건강하다."]

가능한 경우 단어를 부분단어(subword)로 나누는 방법도 사용할 수 있다.

단어: "unbelievable"
Subword 토큰화: ["un", "beli", "ev", "able"]

단어: "disappear"
Subword 토큰화: ["dis", "appear"]

단어: "incredible"
Subword 토큰화: ["in", "cred", "ible"]

N-gram 토큰화

N개의 연속된 단어 그룹으로 토큰 생성

문장: "나는 오늘 학교에 갔다."
2-gram 토큰화: ["나는", "는 오", "오늘", "늘 학", "학교", "교에", "에 갔", "갔다", "다."]

문장: "사과와 바나나는 맛있다."
2-gram 토큰화: ["사과", "과와", "와 바", "바나", "나나", "나는", "는 맛", "맛있", "있다", "다."]

문장: "Hello, world!"
2-gram 토큰화: ["Hello,", "world!"]

문장: "I love programming"
2-gram 토큰화: ["I love", "love programming"]

문장: "Artificial intelligence is fascinating"
3-gram 토큰화: ["Artificial intelligence is", "intelligence is fascinating"]

문장: "Learning new things"
3-gram 토큰화: ["Learning new things"]

문자 수준 토큰화

각 문자가 하나의 토큰이 됨

텍스트 생성, 음성인식과 같은 특별한 작업에서만 사용됨

문장: "안녕하세요!"
문자수준 토큰화: ["안", "녕", "하", "세", "요", "!"]

문장: "Hello, world!"
문자수준 토큰화: ["H", "e", "l", "l", "o", ",", " ", "w", "o", "r", "l", "d", "!"]

문장: "The quick brown fox jumps over the lazy dog."
3-gram 토큰화: ["The", "he ", "e q", " qu", "qui", "uic", "ick", "ck ", "k b", " br", "bro", "row", "own", "wn ", "n f", " fo", "fox", "ox ", "x j", " ju", "jum", "ump", "mps", "ps ", "s o", " ov", "ove", "ver", "er ", "r t", " th", "the", "he ", "e l", " la", "laz", "azy", "zy ", "y d", " do", "dog", "og."]

3. 토큰 인덱싱: 각 토큰을 수치 벡터로 변환해 토큰 인덱스 생성

  • 텍스트를 토큰으로 나눈 후 각 토큰을 수치 표현으로 인코딩
  • 훈련 데이터에 있는 모든 토큰의 인덱스를 만들어 어휘 사전의 각 항목에 고유한 정수 할당
  • 일반적으로 가장 많이 등장하는 2~3만개 단어로 어휘사전 제한
  • 예외 어휘 인덱스(out of vocabulary index, OOV 인덱스)
    • 어휘사전에 없는 모든 토큰과 대응
    • 어휘사전에서 일반적으로 1을 인덱스로 사용, 단어로 디코딩할 때는 "[UNK]"로 디코딩
  • 마스킹 토큰
    • 단어가 아니라 무시할 수 있는 토큰
    • 시퀸스 데이터를 패딩하기 위해 사용
    • 어휘사전의 인덱스 0 사용
vocabulary = {}
for text in dataset:
    text = standardize(text)
    tokens = tokenize(text)
    for token in tokens:
        if token not in vocabulary:
            vocabulary[token] = len(vocabulary)

4. 토큰 인덱스를 원핫 인코딩 또는 임베딩

원핫 인코딩

단어 임베딩(word embedding)


단어 그룹을 표현하는 2가지 방법

단어를 문장으로 구성하기 위해 단어 순서를 인코딩할 때 어떤 방법을 사용할 수 있을까?

1. Bow 모델

  • 순서를 무시하고 텍스트를 토큰의 (순서없는) 집합으로 처리

  • 개별단어(unigram)을 사용하거나 연속된 토큰 그룹(n gram)으로 국부적인 순서 정보를 유지할 수 있다.

  • 초기 머신러닝에 많이 사용

  • 이진 인코딩을 사용한 유니그램

    • 전체 텍스트를 하나의 벡터로 표현할 수 있다.
    • 벡터의 각 원소는 한 단어의 존재 유무를 표시한다
문장: the cat sat on the mat
유니그램: {'cat', 'mat', 'sat', 'on', 'the'}
  • 이진 인코딩을 사용한 바이그램
  • TF-IDF 인코딩을 사용한 바이그램
    • 개별 단어나 N-grma의 등장 횟수를 카운트한 정보를 추가할 수 있다.

2. 시퀸스 모델

  • 단어를 시퀸스로 처리하기: 시퀸스 모델 방식
  • 순서 기반의 특성을 수동으로 만드는 대신 원시 단어 시퀸스를 모델에 전달하여 스스로 특성을 학습하도록 함
  • 과정
  1. 입력 샘플을 정수 인덱스의 시퀸스로 표현
  2. 각 정수를 벡터로 매핑하여 벡터 시퀸스 얻음
  3. 벡터 시퀸스를 RNN, transformer 등 인접한 벡터의 특징을 비교할 수 있는 층에 전달

원핫인코딩된 벡터 시퀸스로 모델 제작

원핫 인코딩된 벡터 시퀸스로 시퀸스 모델을 훈련할 경우 매우 느리고 이진 유니그램 모델보다 성능이 나쁘다. 따라서 원핫 인코딩이 아니라 단어 임베딩으로 단어를 벡터화해야 한다.

원핫 인코딩 대신 워드 임베딩을 사용한 모델 제작

word embedding
  • 자연어처리에서 단어를 벡터 형태로 표시하는 기법
  • 단어들 간 의미적 유사성을 보존하면서 각 단어를 고차원에서 저차원 벡터로 표현
  • 핵심 가설: 분포가설 - 단어는 주변 단어와 유사하게 사용된다
  • 저차원의 부동 소수점 밀집 벡터로 많은 정보를 더 적은 차원으로 압축

원핫 인코딩을 사용한 모델보다 훨씬 빠르고 테스트 정확도가 비슷하다. 그러나 여전히 바이그램 모델보다 성능이 낮다. 약간 적은 데이터를 사용하고, 600개 단어 이후 시퀸스를 잘라버리기 때문이다.

패딩과 마스킹

시퀸스 모델에서 토큰의 길이는 같아야 한다. 예를 들어 max_length=600인 경우 토큰이 600개 이상인 문장은 잘리고, 이하인 문장은 0으로 패딩된다. 그런데 이렇게 패딩을 적용할 경우 RNN은 마지막에 의미없는 토큰만 반복처리하면서 정보 손실이 일어난다.

rnn층이 이러한 패딩을 건너뛰게 하기 위해서 embedding층에 마스킹(masking) 을 생성할 수 있다. 마스킹은 1과 0으로 이루어진 (batch_size, sequence_length) 크기의 텐서이다. 0또는 1을 갖는 mask[i, t]는 샘플 i의 타입스텝 t를 건너뛸지 말지를 결정한다.

마스킹은 기본적으로 활성화되어있지 않으며 활성화하기 위해서는 embedding 층에 mask_zero=True로 지정해야한다.이후 해당 레이어에 대해 compute_mask()를 사용할 경우 마스킹을 추출할 수 있다.

사전 훈련된 단어 임베딩 사용하기

  • 훈련 데이터가 부족한 경우 사전훈련된 임베딩 공간의 임베딩 벡터를 로드해 사용
  • word2vec, glove 등

트랜스포머

트랜스포머 아키텍처

  • "attention is all you need"
  • 순환 층이나 합성곱 층을 사용하지 않고 뉴럴 어텐션이라고 불리는 간단한 메커니즘을 사용해서 강력한 시퀸스 모델 제작

셀프 어텐션

  • 데이터의 일련의 특성에 대한 중요도 점수 계산. 관련성이 높은 특성은 점수가 높고 관련성이 적은 특성은 점수가 낮다.
  • 이러한 매커니즘을 사용해 문맥 인식 특성을 만들 수 있다.
  • 셀프 어텐션은 시퀸스에 있는 관련된 토큰의 표현을 사용하여 한 토큰의 표현을 조절하는 것이 목적이다.

셀프 어텐션 알고리즘

  1. 목적 단어와 시퀸스에 있는 다른 모든 단어 사이 어텐션 점수 계산하고 어텐션 점수를 사용해 단어 벡터에 가중치를 부여하여 새로운 목적 단어 벡터 만듦
  2. 소프트맥스, 스케일조정, 곱셈을 통해 토큰 벡터에 가중치 적용
  3. 더해서 문맥을 고려한 벡터 생성

일반화된 셀프 어텐션: 쿼리-키-값 모델

  • 트랜스포머는 한 시퀸스를 다른 시퀸스로 변환하기 위해 고안된 시퀸스-투-시퀸스 모델
  • 3개의 시퀸스 query, key, value로 '쿼리에 있는 모든 원소가 키에 있는 모든 원소에 얼마나 관련되어 있는지 계산하고, 이 점수를 사용해 value에 있는 모든 원수의 가중치 합 계산'
outputs = sum(values * pairwise_scores(query, keys))

query = "dogs in the beach" # 찾고있는 것을 설명하는 참조 시퀸스
key = ["cat", "dog", "party" ...] # value 설명
value = ["beach, dog, tree] # 정보를 추출할 지식의 본체

1. query와 key를 비교해 매칭 점수 계산. 이 경우 dog와의 매칭점수 1, cat과의 매칭점수 0
2. 매칭 점수에 따라 value 순서를 매긴 후 가장 잘 매칭된 상위 n개의 사진을 반환
3

멀티 헤드 어텐션

  • 셀프 어텐션 메커니즘의 변형
  • 멀티헤드라는 이름은 셀프 어텐션의 출력 공간이 독립적으로 학습되는 부분공간으로 나뉘어진다는 것을 의미
  • [쿼리, 키, 값] --(독립적인 3개의 밀집투영 통과)---> 3개의 별개 벡터
  • 각 벡터는 뉴런 어텐션으로 처리되고 이 출력이 하나의 출력 시퀸스로 연결됨
  • 학습가능한 밀집 투영 덕분에 이 층이 실제로 무언가를 학습할 수 있다.
  • 독립적인 헤드가 있으면 층이 토큰마다 다양한 특성 그룹을 학습하는 데 도움이 됨

트랜스포머 인코더

  • 텍스트 데이터를 입력받아 텍스트의 잠재적인 의미와 특징 추출

  • 인코더 부분을 텍스트 분류에 사용할 수 있다

  • 셀프 어텐션 (Self-Attention): 텍스트 내의 단어들 간의 관계를 학습하기 위해 사용되는 메커니즘입니다. 각 단어는 다른 모든 단어들과 어텐션을 수행하여 자신과 유사한 단어에 더 많은 가중치를 부여하게 됩니다. 이를 통해 단어 간의 문맥 정보를 포착할 수 있습니다.

  • 멀티헤드 어텐션 (Multi-Head Attention): 셀프 어텐션을 여러 개의 헤드로 나누어 병렬로 수행한 후 결과를 결합합니다. 각 헤드는 서로 다른 관점에서 정보를 추출하고, 이를 통해 더 풍부한 특징을 학습할 수 있습니다.

  • 피드포워드 신경망 (Feedforward Neural Network): 셀프 어텐션의 결과를 이용하여 텍스트의 특징을 더 의미 있는 표현으로 변환합니다. 주로 다층 퍼셉트론(MLP) 구조로 구성되며, 비선형성을 추가하여 텍스트의 추상적인 특징을 잘 잡을 수 있습니다.

  • 트랜스포머 인코더는 시퀸스 모델의 형태가 아니다. 시퀸스 토큰을 독립적으로 처리하는 밀집층과 토큰을 집합으로 보는 어텐션 층으로 구성되어 있다. 즉 시퀸스에 있는 토큰 순서를 바꿔도 정확히 동일한 어텐션 점수와 문맥이 고려된 표현을 얻는다.

  • 그런데 왜 트랜스포머는 시퀸스 모델일까? 트랜스포머는 기술적으로 순서에 구애받지는 않고 모델이 처리하는 표현에 대해 순서 정보를 수동으로 주입하는 위치 인코딩 을 수행하는 하이브리드 방식의 모델이다.

위치 인코딩

  • 모델에 단어 순서 정보를 제공하기 위해 문장의 단어 위치를 각 단어 임베딩에 추가
  • 단어 임베딩은 특정 문맥에 독립적으로 단어를 표현하는 일반적인 단어 임베딩, 현재 문장의 단어 위치를 표현하는 위치 벡터 두 부분으로 구성됨
  • 위치 벡터의 경우 위치 임베딩을 통해 단어 임베딩에 추가됨
    • 단어 인덱스의 임베딩을 학습하는 것처럼 위치 임베딩 벡터 학습하고, 위치 임베딩을 해당하는 단어임베딩에 추가함

위 모델의 결과는 88.3%로 지금까지의 시퀸스 모델 중 가장 뛰어나지만 여전히 bow보다 성능이 낮다. 그렇다면 bow 모델 대신 언제 시퀸스 모델을 사용할 수 있을까?

새로운 텍스트 분류 작업을 시도할 때, 훈련 데이터에 있는 샘플 개수와 샘플에 있는 평균 단어 개수 사이의 비율을 고려해야 한다.

  • 이 비율이 1500보다 작을경우 >> bow 사용
  • 이 비율이 1500보다 큰 경우 >> 시퀸스모델 사용

즉 시퀸스 모델은 훈련 데이터가 많고 샘플 길이가 비교적 짧은 경우 잘 동작한다.

시퀸스 투 시퀸스 학습

  • 입력으로 시퀸스를 받아 이를 다른 시퀸스로 바꾼다.
    • 기계번역
    • 텍스트 요약
    • 질문답변
    • 챗봇
    • 텍스트 생성

시퀸스 투 시퀸스 모델의 구조

인코더가 소스 시퀸스를 처리하여 디코더로 보내고 디코더는 지금까지의 타깃 시퀸스를 보고 한 스텝 미래의 타깃 시퀸스를 예측한다. 추론 단계에서는 한번에 하나의 타깃 시퀸스를 생성해 다시 디코더에 주입한다.

  1. 인코더
  • 모델이 소스 시퀸스를 중간 표현으로 바꿈
  1. 디코더
  • 0에서 i-1까지의 이전 토큰과 인코딩된 소스 시퀸스를 보고 타깃 시퀸스에 있는 다음 토큰 i를 예측하도록 훈련
  1. 추론과정
  • 인코더가 소스 시퀸스 인코딩
  • 디코더가 인코딩된 소스 시퀸스와 초기 시드 토큰을 사용해 시퀸스의 첫번째 토큰 예측
  • 지금까지 예측된 시퀸스를 디코더에 다시 주입하고 다음 토큰을 생성하는 것을 종료 토큰 생성시까지 반복

시퀸스 투 시퀸스를 활용한 기계번역

모델 제작

rnn을 사용한 seq to seq 모델

  • rnn(인코더)를 사용해 전체 소스 문장을 하나의 벡터 집합으로 바꿈

  • 벡터 집합을 다른 rnn(디코더)의 초기 상태로 사용

  • 인코더, 디코더 순환 층을 여러개 쌓거나, lstm을 사용하는 등으로 개선 가능

  • 그러나 근본적인 제약 존재

    • 소스 시퀸스가 인코더 상태 벡터로 완전하게 표현되어야 함. 이는 번역할 수 있는 문장의 크기, 복잡도에 큰 제약이 됨
    • rnn의 장기기억소실

트랜스포머를 사용한 시퀸스 투 시퀸스