반응형

GreaseLM 배경 설명

  • GreaseLM은 2022년 Stanford에서 나온 ICLR 논문이다.
  • 사실 KG에 대해, 전문적인 지식은 없지만, 최근 Language Model에 KG 정보 등을 이용해서 성능을 높이려는 방식이 많이 사용되고 있는 것 같아 흥미가 생긴다.
  • 이 논문은 KG를 단순 LM의 학습을 도와주는 용도가 아니라, 두 modality 간의 정보를 섞는 fusion 개념으로 KG와 LM을 사용하였기에 굉장히 가치가 있는 논문이라고 생각한다.  

Abstract

  • 복잡한 텍스트 내러티브 질문에 대답하기 위해서는 Context와 그 안에 숨겨진 지식들 모두에 대한 추론이 필요하다.
  • 현재(그 당시) QA 시스템들에 많이 사용되는 pretrained Language Model(LM)은 concept 들 간의 관계를 robust 하게 표현해주지 못한다. 
  • Knowledge Graph(KG)은 구조화된(관계에 대한) representation들을 가지고 있기 때문에, LM과 함께 사용되곤 한다.
  • 하지만, KG representations들과 language context 정보들을 어떻게 효과적으로 융합할 수 있는지에 대해서는 미지수이다. 
  • 이 논문에서는 GreaseLM이라는 LM에서 추출된 representations(laguage context 정보)와 GNN의 정보들(KG 그래프 정보)을  융합해서 사용하는 새로운 모델을 제시한다. 
  • 이 모델에서는 각 modal 들이 다른 modal에게 정보들을 전달하는 구조로 정보를 융합한다.  

 Introduction

[Language Model]

  • QA task에서는 textual context 정보뿐 아니라, 세상에 대한 지식(박학다식을  이렇게 표현해 놓았다.)이 필요하다. 
  • 최근에는 (그 당시) large pretrained LM을 QA 분야에 사용하는 것이 주류가 되었다. pretrained LM의 경우에는 pre-training 과정에서 수많은 text 데이터들을 학습하기 때문에, 그 과정에서 텍스트들에 함축된 knowledge 들을 학습하게 된다. 
  • 이러한 pretrained LM 모델들은 좋은 성능을 보이지만, fine-tuning 단계에서 학습한 데이터와 다른 유형의 문제를 풀 때는 어려움을 겪는다. 
  • 그것은 이러한 모델들이 Question과 Answer 사이에 pattern에 의존하지, 그 사이의 reasoning에는 많이 의존하지 않기 때문이다. 이러한 reasoning은 context 데이터와 implicit external knowledge가 합쳐진 정보이다. 

[Knowledge Graph]

  • 기존의 연구들중 KG를 도입해서 구조화된 reasoning과 query answering에 효과를 본 연구들이 있다.
  • 하지만, text 문장으로 구성된 question & answer와 KG의 knowledge를 어떻게 결합할 것인지에 대해서는 아직 정답이 없다.
  • 좋은 reasoning을 위해, 두 modal 정보를 함께 사용하기 위한 연구들이 있었다. 하지만, 그 연구들은 얕고 non-interactive 한 방식(각 modal의 정보를 각각 encoding 하고 prediction 결과를 섞거나, 한 modal의 정보를 활용하기 위해 다른 modal을 사용하는 방식)을 사용하였다.
  • 결과적으로, 이러한 방법들은 두 modal 간의 유용한 정보들을 어떻게 섞을 것인지에 대한 방법을 고민하게 하였다. 

[Grease LM]

  • 이 논문에서는 GreaseLM이라는 LM과 KG가 여러 layer에 거쳐서 정보를 fusion하고 exchange 할 수 있는 새로운 구조를 제안한다. 
  • GreaseLM은 context를 처리하는 LM과 KG를 처리하는 GNN으로 구성된다. 각각 LM와 GNN Layer를 거친 후, 각 modality끼리 정보를 교환할 수 있는 bidirectional interactive schema를 통해, interaction representation을 담게 된다.
  • 이를 위해, LM을 위한 Interaction Token과 GNN을 위한 Interaction Node를 사용한다. 
  • GreaseLM은 다른 LM 구조에 비해 QA에서 좋은 성능을 보인다. (기존에 KG를 같이 사용하던 모델도 포함해서)
  • 특히, GreaseLM은 효과적인 Reasoning이 필요한 질문들에서 매우 좋은 성능을 보인다.

Related Work

  • KG 정보를 사용하는 것은 QA 분야에서 각광받고 있다.
  • 몇몇 연구들은 text 처리를 위한 LM과 knowledge 처리를 위한 graph를 사용해서 정보를 융합하는 방법을 사용한다.
  • 다른 연구들은 한 KG 정보를 text 데이터를 활용하는데 도움을 주는 용도로 사용한다. (KG를 활용한 QA example Augmentation 등)
  • 반대로 text 데이터를 활용하여 KG를 뽑아내는 데 사용하는 연구들도 있다.

→ 정리하자면, 기존에도 KG와 text 데이터를 같이 사용하는 연구들은 많았으나, 한 modal의 데이터를 다른 modal에 간접적으로 사용하는 등, 효과적으로 두 정보를 결합하지 못했다.
 

  • 최근에는 두 modality들의 정보의 deeper integration을 위한 방법들이 연구되고 있다.
  • 어떤 연구는 LM이 implicit knowledge(Embedding을 의미하는 것 같다.)을 만드는 것을 학습하기 위해, KG를 사용한다.  하지만, 이 방법은 LM을 학습할 때를 제외하고는 KG 정보를 사용하지 않기 때문에 reasoning을 guide 할 수 있는 중요한 정보를 사용하지 못한다. (실제 KG 정보를 사용하지는 않는다.)
  • 더 최근에는, QA-GNN이라는 모델이 LM과 GNN이 message passing을 통해, 같이 학습하는 방법을 제안하였다. 하지만, 이 논문에서는 LM의 textual component를 표현하는데 single pooled representation을 이용하여, text representation에 대한 update에 한계가 있다.
  • 기존 방법들과 다르게, 이 논문에서는 LM의 각 token representations들과 GNN의 여러 layer들의 정보가 섞일 수 있어, 각 modality에서 다른 modality의 정보를 반영할 수 있다. 
  • 동시에 각 modality들의 구조를 유지하여 함께 사용한다.

→ 정리하자면, 그래도 최근에는 LM과 QA의 정보를 효율적으로 사용하는 구조를 제안해 보았지만, 아직은 제한적으로 사용되고 있다. 이 논문에서는 text 내의 token과 실제 KG의 연결 정보가 잘 결합될 수 있는 구조를 제안한다. 
 

  • 어떤 연구들은 KG와 LM을 pretraining 단계에서 같이 활용하기도 한다.
  • 하지만, QA에서와 비슷하게 multiple layer들에서의 interaction을 고려한 것이 아닌, knodwledge를 language에 이용하는 형식으로 사용된다.

GreassLM

  • 이 논문에서는 lareg-scale LM을 KG를 이용한 grpah reasoning 모듈로 augment 하였다.
  • GreaseLM은 2개의 component들로 구성되어 있다. 1) unimodal LM layers: input token(text 데이터)으로만 학습함 2) upper cross-modal GreaseLM layers: lanugage sequence들과 linked KG로 학습되어, 두 modality의 정보를 함께 사용할 수 있음. 논문에서는 LM layer들을 N개, GreaseLM layer를 M개 사용해서, 총 N+M개로 이뤄진다고 말하고 있다.
  • Notation : multiple choice question answering에서 context paragraph는 c, question은 q, candidate answer set은 A이고, 모두 text로 구성되어 있다. 이 논문에서는 external knowledge graph(KG)를 G로 정의하여 content에 대한 background knowledge를 제공하는 데 사용한다. QA 문제는 c, q, A, G가 있을 때, A에 속하는 a를 찾는 것이 목표이다. 일반성을 위해, 본 논문에서는 정답을 a로, natural language의 sequence의 각 token을 w로 1부터 T까지 나타낸다. KG의 각 노드는 e로 1부터 J까지 나타낸다.  
  • Input  Representation
    • 우선 context와 question, answer를 separator token 등을 이용해서 concatenate 한다.(BERT에서 사용하던 방법이다.) 이 token을 tokenize 해서 combined sequence를 구성한다. {w1,..., wT} 
    • Input sequence를 KG에서 subgraph(현재 Question과 관련 있는 정보를 제공)를 뽑는 데 사용한다. subgraph는 {ㄷe1,..., eJ}
    • KG Retrieval : QA context가 있을 때, subgraph를 뽑기 위해 기존 다른 논문(QA-GNN: 나중에 읽어봐야겠다.)의 방법을 사용한다. subgraph의 각 Node는 context, question, answer와 연결되어 있는지 또는 해당 Node의 이웃으로 연결되었는지에 따라 유형이 할당된다. 
    • Interaction Bottlenecks : cross-modal GreaseLM layers에서 두 modality들 간의 정보가 섞인다. 이를 위해 special interaction token을 사용하는데, 이것을 w_int로, special interaction node를 e_int로 정의한다. 
  • Language Pre-Encoding
    • unimodal encoding component에는 token과 segment와 positional embeddins들을 합해서 input으로 사용하여, LM layer에 통과시킨다. l번째 layer를 거친 pretrained representations들은 아래와 같이 정의된다. LM-Layer들의 parameter들은 pretrained model을 사용하여 이미 학습되어 있는 상태이다.
    • 앞서 언급한 대로, LM-layer의 총개수는 N개이다.
  • GreaseLM
    • GreaseLM은 cross-modal fusion component를 사용한다.
    • GreaseLM layer는 각 정보를 독립적으로 encode 하고, 그 정보들을 spectial token과 node의 bottleneck을 통해서 fuse 한다. 
    • 3가지 component로 구성되어 있다.
      • transformer LM encoder block : language context를 encoding 함.
      • GNN layer : KG entitie들과 relation들의 정보를 담음
      • modality interaction layer : interaction token과 interaction node 간 정보를 교환함. 

[Language Representation]

  • l번째 GreaseLM layer의 feature는 Language Pre-Encoding 된 representations에 추가적으로 l번의 transformer LM encoder를 거친 정보이다. 
  • GreaseLM Layer의 l번째 embeddings는 다음과 같이 나타난다.  
  • 뒤에서 추가적으로 언급하겠지만, h_int는 KG의 representation을 encode 하는 역할을 한다. 

[Graph Representation]

  • GreaseLm layer는 QA example과 관련된 local KG 정보도 함께 encoding 한다. 
  • Graph를 뽑기 위해, 처음으로 initial node embeddings를 pretraned KG embeddings를 통해 뽑는다. 이때, iteraction node, e_int의 initial embedding은 random 하게 초기화된다. 
  • 그러고 나서, GNN의 각 layer는 현재 node embeddings들을 입력으로 받아, information propagation을 수행하고, 이를 통해 fuse 된 node embedding을 생성한다. 
  • 이때, 사용되는 GNN은 QA-GNN에서 사용된 방법을 따른다. 

N: e_j의 neighborhood, m_sj:e_s가 e_j에게 보내는 message, a_sj:message에 대한 attention, f_n: 2 layer MLP

  • Entity들 간 message는 relation과 node type을 이용해 다음과 같이 정의된다.  

f_r : 2 layer MLP, r_hat_sj: relation embedding, u_s, u_j : node type embedding

  • message를 어느 비중으로 보낼 것인지, 결정하는 a_sj는 다음과 같이 결정된다. 

f_q, g_k : linear transformation

→ 해석하자면, GreaseLM의 node representation은 전 단계 layer의 node들과 attention을 적용한 neigbor node들이 보낸 message들의 합으로 나타난다.
이때, message는 1) enitity들의 node type embedding과 relation embedding을 이용한 MLP output과, 2) neiborhood의 node type embedding에 두 entity 간 relation representations, 3) neighborhood의 l-1번째 LM embedding representation을 linear transformation 한 값으로 구해지고, 
message는 query(neighborhood의 l-1번째 LM embedding representation과 그의 node type embedding의 linear transformations)와 key(현 entity의 l-1번째 LM embedding representation과 그의 node type embedding과 neighborhood 간의 relation을 linear transformation)한 값으로 구해진다.
이때, 두 사이의 relation 값의 비중은 q와 k의 곱으로 구해지고(consine similarity 같은 개념인가 보다.) 이것을 neighborhood 간 normalization을 통해 0~1 사이의 가중치를 구한다. 
(자세한 내용은 QA-GNN을 참고하는 편이 좋아 보인다. 그래도 천천히 읽다 보면 어떤 걸 의도하는 이해가 간다.)
 
[Modality Interaction]

  • LM과 GNN이 각각 정볼르 embedding 한 이후에, modality interaction layer(MInt)를 통해 두 modality들의 정보가 interaction token과 interaction node 간의 bottleneck을 통해 섞이길 바란다.
  • 이때, l번째 MInt에서는 interaction node의 embedding과 interaction token의 embedding을 concate 한 값을 Input으로 받아서 처리하고, output은 그 결과를 split 해서 각각 가져간다. 
  • MInt로는 2 layer MLP를 사용한다. interaction token과 interaction node를 제외한 다른 token 및 node들은 이 단계에서 사용되지 않는다.  하지만, 직접적으로 MInt의 Input으로 사용되지는 않더라도, interaction node와 interatction token에는 각각 다른 token 및 node의 정보가 담겨있다. (interaction node는 relation을 통해, 다른 entitiy들의 영향을 포함하고, interaction token은 transformer의 encoding 단계 중, 다른 token 정보를 포함하기 때문에 그런 것이다. 이 부분에서 아이디어가 매우 좋다는 생각이 들었다.)

Experiments

  • CommonsenseQA와 OpenBook QA에서 기존 모델들 (LM only or LM + KG) 보다 좋은 성능을 보여준다. 

Conclusion

  • 이 논문에서는 GreaseLM이라는 knowledge graph와 language model 간의 정보를 교환할 수 있는 새로운 구조를 제안했다.
  • 실험결과는 기존의 KG+LM의 구조나 LM 단독으로 사용된 것들에 비해 좋은 성능을 보여준다. 
  • 특히, 뉘앙스 등의 reasoning이 포함된 문제에서 더욱 효과적이다. 

출처

Greaselm: Graph reasoning enhanced language modelsX Zhang, A Bosselut, M Yasunaga, H Ren, P Liang, CD Manning, ...International conference on learning representations, 2022

총평

평소 word embedding을 보면서, 저절로 만들어지는 KG 아니야? 하는 생각을 가지고 있었다. 그만큼 KG와 LM은 비슷한 구조이면서, 서로를 보완해 줄 수 있는 데이터인 것 같다. 사실 두 정보를 함께 사용하는 논문이 이미 많이 나왔을 줄 알았는데, 그만큼 매우 어려운 것 같기도 하고, 역시 transformer의 위대함이 아닌가 싶다. 

반응형

BERT 배경 설명

  • BERT는 Google에서 2018년 10월에 나온 NLP 논문이다.
  • 사실 지금은, Chat-GPT 때문에 GPT가 자연어 처리의 대명사가 되었지만, GPT 전에는 BERT가 자연어 처리의 대표 모델로 불리곤 했었다. 
  • BERT는 성능이 매우 좋아서, 아직도 많은 NLP Task에서 사용되고 있다.
  • 개인적으로 이 논문을 읽으면서, 2018년 6월에 나온 GPT-1 논문을 굉장히 많이 신경 쓰고 있다는 인상을 받았다. 

Abstract

  • 이 논문에서는 BERT(Bidirctional Encoder Representations form Transformers)라는 새로운 모델을 소개한다.
  • 기존의 (그 당시) 유행하는 모델들(특히 GPT-1)과 달리 BERT는 단어의 양방향 데이터(이전 데이터와 이후 데이터 모두)를 사용한다.  
  • 이러한 구조로 BERT는 별도의 task-specific한 변형 없이, 하나의 layer만 추가해도 대다수 NLP task(11개)에서 좋은 성능을 보여준다.

 Introduction

[문제 제기]

  • 기존의 pre-trained language representations들을 specific 한 task에 적용하는 방식은 feature-basedfine-tuning으로 크게 2가지로 나뉘어진다. 
    • Feature-based : task-specific한 구조를 가지고 있고, pre-trained 된 representations들을 추가적인 feature로만 사용한다. (ELMo)
    • Fine-tuning : 최소한의 task-specific한 parameter들을 가지고, 모든 pre-trained parameter들을 fine-tuning 해서 사용한다. (GPT)
  • 하지만, 기존의 방식들은 pre-trained model을 학습하는 과정에서 이전 데이터들만 사용하는 unidirectional launguage models (단방향 모델)이다. 
  • 이러한 방식은 pre-trained representations들의 효과를 감쇠한다. 특히, fine-tuning model에서 이런 감쇠 효과는 더 크다. 

[모델 제시]

  • 이 논문에서는 "BERT"라는 모델을 제시하여, fine-tuning 방식의 pre-trained language model의 성능을 향상 시킨다.
  • BERT는 "masked language model(MLM)" pre-training objective를 이용하여, 단방향 데이터만을 사용하는 기존의 한계를 경감한다. 
  • 은 input 데이터의 token들에 randomly 하게
  • 기존 left-to-right language model pre-training과 달리, MLM은 left와 right context 정보를 모두 활용할 수 있다. 
  • 추가적으로 "next sentence prediction"을 통해, text-pair 들의 representation들을 학습한다. 

 Model

  • BERT는 기존의 Fine-tuning 방법들(특히 GPT-1)처럼 2개의 step으로 구성된다.  (1) pre-training (2) fine-tuning

  • Model Architecture : BERT의 모델 아키텍처는 Transformer를 그대로 사용했다. Paper에서는 두 버전의 BERT 모델을 소개한다. 첫 번째로, GPT와 비교하기 위해, 동일 모델 사이즈를 가지고 있는 BERT BASE(12개의 Layer, 768 Dimension, 16개 Self-Attention)이다. 두번째로, BERT LARGE(24개의 Layer, 1024 Dimension, 16개의 Self-Attention) 이다. 
  • Input/Output Representations : BERT는 WordPiece Embeddings를 사용한다. BERT는 다양한 NLP task에 응용할 수 있도록, 단일 문장이나 문장의 짝 모두를 input으로 사용할 수 있도록 한다. 모든 문장의 맨 첫 token은 special token인 "[CLS]"로 시작하고(해당 Token 등은 sentence 단위의 classification에 활용된다.), 두 문장이 Input으로 들어올 때는 두 문장 사이에 "[SEP]" token을 넣어 구분하고, 어느 문장에 소속된 token인지 구분할 수 있는 learned embedding을 문장을 이루는 각 token에 추가했다.(Segment embeddings)

아래 그림은 BERT의 input representations를 나타내는데, token 자체의 embeddings와 어느 문장에 속하는지를 나타내주는 Segment embeddings, token의 문장 내 위치를 가르쳐주는 Position embeddings로 구성되어 있다. 

 

 

  • BERT의 Pre-Training 단계
    • 논문 내내 강조하는 것이, BERT는 단방향 모델이 아닌, 양방향 Language model을 사용한다는 것이다. 
    • Masked LM 
      • 직관적으로 생각해도(수능 빈칸 추론 문제만 생각해 봐도) 단어를 추정할 때, 그 단어의 앞부분만 보는 것이 아닌 뒷부분에서 힌트를 얻을 수 있다. 하지만, 기존 모델들은 한쪽 방향의 단어들만으로 Language model을 학습했다. BERT는 지금껏 계속 강조해 온 대로, 양방향의 데이터를 모두 활용하기 위해 Masked LM을 제시한다. 
      • Masked LM은 일정한 확률로 무작위로 input token을 가리고("[MASK]" token으로 대체), 문장 내 다른 단어들을 통해, 해당 token을 추정하는 방식(기존의 LM과 동일하게 cross-entropy)으로 학습된다
      •  이런 Masked LM에는 한 가지 문제가 있는데, pre-training에 빈번하게 등장하는 "[MASK]" token이 실제 fine-tuning 과정에서는 없다는 것이다.(pre-training 학습을 위해 임의로 넣어주었기 때문에) 이를 해결하기 위해, 논문에서는 token을 무조건 [MASK]로 대체하는 것이 아닌, 확률적으로 바꿔주는 스킬을 사용한다. 따라서, 한 문장에서 15% 정도의 token의 위치를 1) 80% 확률로 [MASK] token으로 대체, 2) 10% 정도 random 한 token으로 대체, 3) 10%는 바꾸지 않고 원래 단어로 둔다. → 특정 token 들에 의지해서 masked 된 token을 추정하는 것을 방지해 주는 Augmentation 효과도 있을 것이다.  
    • Next Sentence Prediction
      • 앞부분까지는 한 문장 내에서 단어를 추정하기 위한 방법이었다. 하지만, 많은 NLP task들은 문장 간의 관계가 중요한 경우가 많다. 이러한 문장 간의 관계는 기존 Language model로는 잡 포착하기 어려웠다.
      • 문장 간의 관계를 학습하기 위해, BERT에서는 next sentence prediction task를 이용하였다. 
      • 앞서, 문장의 Embeddings 중 Segment Embedding이 존재하였는데, 실제 데이터들은 한 문장 뒤에 다음 문장이 오는 구조로 되어있다. (실제 문장이든, QA 문장이든 선후 관계가 존재한다.) 
      • next sentence prediction task에서는 실제 데이터에서 뒤에 오는 문장을 임의로 변경하여, false 데이터를 만들어서 두 문장 간의 선후 or 인과 관계에 대한 binary classification을 학습한다.  
      • 이러한 구조는 매우 간단하지만, QA 등의 문장 간의 인과 관계가 중요한 task에서 매우 효과적인 성능 향상을 보인다고 한다.
  • BERT의 Fine-tuning 단계
    • BERT의 fine-tuning 과정은 Transformer 구조를 그대로 이용하였고, Input의 형태가 단일 문장이던, 문장의 짝이던 동일하기 때문에 매우 직관적이다. 
    • 언급한 대로, Input의 형태는 task에 상관없이 모두 동일하고, Output은 앞서 문장 앞에 넣어주었던 [CLS] token을 classification을 위한 output layer의 input으로 넣어 학습하면 된다.
    • Pre-training 과정은 매우 많은 시간과 H/W 리소스가 필요하지만, fine-tuning은 구조가 간단하고 simple하기 때문에 inexpensive 한 과정이라고 한다. (사실 이 특징 때문에, AI의 패러다임이 모델 중심에서 데이터 중심으로 바뀐 것 아닌가 싶다.) 

 

Experiments

  • BERT를 이용해서 11개의 NLP task를 실험했다. 
  • GLUE(General Language Understanding Evaluation)를 포함한 다양한 언어 모델에서 다른 모델들을 능가하는 performance를 보여준다. 
  • 실험에서 놀랄만한 점은, BERT가 인간보다 높은 성능을 보이는 테스트도 있다는 것이다. 

→ BERT도 GPT-1과 마찬가지로, 논문 자체가 실용성에 초점을 맞추고 있다 보니, 학습 부분을 자세히 설명해 놓았다. 자세한 내용은 논문을 직접 참고하는 게 좋을 것 같다. 

 

Conclusion

  • 최근에(그 당시에) 수많은 unlabeled 데이터를 통해, unsupervised pre-training을 진행하는 것이 NLP 분야에 엄청난 발전을 이뤘다. 
  • 이 논문의 가장 큰 contribution은 이러한 방법을 통합하는 bidirectional 구조를 제안했다는 것이고, 이러한 pre-trainin g구조가 다양한 NLP 분야에 활용할 수 있다는 점이다.   

출처

Jacob Devlin, Ming-Wei Chang, Kenton Lee, and Kristina Toutanova. 2019. BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. In Proceedings of the 2019 Conference of the North American Chapter of the Association for Computational Linguistics: Human Language Technologies, Volume 1 (Long and Short Papers), pages 4171–4186, Minneapolis, Minnesota. Association for Computational Linguistics.

 

총평

지금 생각하면 당연한 것인데, Bidirectional 구조를 제안하고, 실제 NLP 분야에서 좋은 성능을 보여줬다는 것이 신기하다. 개인적으로 논문 전체가 GPT를 신경 쓰고 있다는 느낌이 들어, 역시 Google 사람들은 혜안이 있구나 하는 생각이 들었다. 아직 BERT 뒤에 논문들을 읽어보지 못했지만, 전체적으로 NLP 논문들이 작은 단위(근처 단어)를 보다가, 큰 단위(이 논문에서는 next sentence prediction으로 인접 문장까지) 봤다는 것을 봐서, 점점 참조하는 범위가 늘어나겠구나라는 것을 유추해 볼 수 있을 것 같다.  

반응형

GPT-1 배경 설명

  • GPT는 최근 가장 유명한 딥러닝 모델 중 하나다. GPT-1은 2018년 OpenAI에서 발표한 자연어 생성 모델로 다양한 자연어 처리 Task에서도 좋은 성능을 보여준다. 
  • GPT-1은 2017년에 나온 Transformer 아키텍쳐를 기반으로 만들어졌다. 
  • 개인적인 생각으로는 이 논문이 과거 모델 중심의 딥러닝 발전 방향에서 지금의 학습 & 데이터 중심의 방향으로 변하는 계기가 되지 않았나 싶다.  

Abstract

  • 자연어 처리는 이전까지(GPT-1 생성까지) 다양한 분야에서 발전을 이뤘다. 
  • 하지만, labeling 되지 않은 corpora(말뭉치) 데이터는 풍부하지만, 특정 자연어 처리 task 들을 학습하기 위한 label 데이터는 많지 않다.
  • "GPT-1"에서는 다양한 labeling되지 않은 다양한 텍스트 데이터들을 통해, 언어 모델을 "generativew pre-training" 하고,  각 task에 맞는 discriminative fine-tuning"을 하는 구조를 제안한다. 
  •  "GPT-1"에서는 fine-tuning 과정에서 "task-aware input transformation"을 사용해서 model 구조를 최소한으로 바꾸면서 효과적인 fine-tuning을 가능하게 한다고 한다. (뒤에서 무슨 말인지 확인해 보자)
  • "GPT-1"은 12개 task 중 9개 task에서, 애초에 그 목적으로 학습한 모델들을 넘어서 SOTA를 달성했다고 한다. 

Introduction

  • 기존 딥러닝 모델들에서 학습이 까다로웠던 이유는 labeling 된 데이터를 수집하는데 한계가 있기 때문이다. (기존 딥러닝 모델들이 실생활에 적용하기 까다로운 이유이기도 했다.)
  • 단순, 특정 task 학습을 위한 labeling된 데이터뿐 아니라, 풍부한 unlabeled 데이터를 함께 사용해서 언어 모델을 학습하는 것은 다양한 text의 representation을 학습하여 언어 모델의 성능을 향상할 수 있다. (word embedding 등등)
  • 하지만, unlabeled text에서 word-level의 information을 학습하는 것은 2가지 어려움이 있다. 
    • transfer를 위한 좋은 text representations을 뽑기 위해, 어떻게 학습하는 것이 효율적인지 알 수 없다.
    • 이렇게 학습된 representations들을 target task에 전달하기 위해 가장 효율적인 방법이 무엇인지 알 수 없다. 
  • 이 논문에서는, 언어 모델 학습을 위해 unsupervised pre-training과 supervised fine-tuning을 잘 조합해서 언어 모델의 성능을 향상 시킬 수 있는 방법을 제시한다.
  • GPT-1의 목표는 조금의 task adaptation만으로 광범위한 task들을 커버할 수 있는 universal representation들을 학습하는 것이다. 
  • GPT-1의 학습은 2가지 과정으로 진행된다.
    1. language modeling을 통해서 unlabeled 데이터를 모델에 학습한다.
    2. supervised 학습을 이용해서, target task에 맞도록 모델의 파라미터를 tuning 한다. 
  • 이를 위해, GPT-1에서는 "Transformer"를 이용한다. (Transformer의 메모리 제약이 적다는 점이 다양한 task에 적합하다고 한다.) 
  • GPT-1은 12개의 자연어 처리 task들 중 9개에서 SOTA를 달성할 정도로 광범위하고, 좋은 성능을 보인다. 

Framework

  • GPT의 학습은 Introduction에 언급하대로 1) unsupervised learning으로 unlabeled 데이터의 pre-training 하는 과정과 2) Task에 맞는 labeld 데이터로 fine-tuning하는 과정으로 진행된다.
  • Unsupervised pre-training 과정

Unlabeled 데이터로 모델을 pre-training하는 과정에서는, 일반적인 language model의 objective function을 따른다. (이전 단어들을 통해, 다음 단어들을 추측할 확률이 높도록 학습)

 

k: context window, T_i : i번째 Text의 단어 수, N: 문서 수  

 

 이 Paper에서는 multi-layer Transformer decoder를 SGD를 이용해서 pre-training을 학습했다고 한다. 

이 Paper에서 사용한 모델은 Transformer의 Decoder 부분만을 사용해서 학습한 방식을 따랐다고 한다. (Generating wikipedia by summarizing long sequences)

U: tokens들의 context vector, W_e : Token Embedding Matrix, W_p: position embedding matrix, n: layer 개수

→ pre-training 과정을 요약하자면, Transformer의 Decoder 모델을 이용하여, 일반적인 언어모델 학습(이전 단어들로 다음 단어를 잘 추정하도록 학습) 한다. 이 과정은 별도의 Labeling이 필요 없이, 단어 간의 context 정보를 Mapping 할 수 있도록 해준다. 

 

  • Supervised fine-tuning 과정

Unsupervised pre-training 과정 후에, 각 task에 맞는 역할을 수행하도록 parameter를 fine-tuning 하는 과정이다. fine tuning 된 모델의 마지막 단에 linear layer를 하나 추가해서, task에 목적에 맞는 학습을 진행한다.

Labeled 데이터가 y이고, pretrained transformer의 마지막 block의 값이 h_l일 때, objective function은 다음과 같다.

즉, pre-training 된 모델 마지막 부분에 layer를 추가적으로 달아서, 원하는 task의 objective function을 따르도록 학습하면 된다는 것이다.

GPT에서는 (1) supervied model의 일반화 향상 (2) 빠른 convergence를 위해, 추가적으로 auxiliary objective를 추가해서 학습한다. 

C : labeled 데이터

Task에 맞는 supervised 모델을 학습하면서, labeled 데이터를 이용해서 language model 학습을 같이 진행한다. (이론상으로는 pre-training 과정에서는 labeled 데이터는 사용하지 않은 상태이다.)  

 

  • Task-specific input transformations
  • Text Classification처럼 간단한 Task 들은 위처럼 fine-tuning을 진행하면 된다. 하지만, 몇 가지 다른 Task들은 fine-tuning 시, input을 조금 변형해서 넣어줘야 한다.
  • 특히, pre-training 단계에서는 order 적 개념을 학습한다. (전 단어들로 다음 단어를 추정하는 등.. ) 이러한 order 관계가 필요 없는 task들에서는 input을 order 형으로 변형해 주는 과정이 필요하다.
  • 이 부분은 모델을 최소한으로 건들면서, 다양한 Task들을 커버하기 위한 방법이다. 

 

Task  Input 구성 방법
Textual Entailment premise와 hypothesis 간 delimiter tocken($)를 사용함
Similarity 각각 독립적으로 Transformer에 넣은 뒤, 두 feature를 element-wise add하여 final linear layer의 input feature로 넣음
Question Answering & Commonsense Reasoning context, answer를 붙여서 input을 구성한 뒤, 각 question들을 각각 linear layer에 태운 뒤, softmax 함수에서 normalization을 한다.

Experiments

→ 아무래도, 논문 자체가 실용성에 초점을 맞추고 있다 보니, 학습 부분을 자세히 설명해 놓았다. 자세한 내용은 논문을 직접 참고하는 게 좋을 것 같다. 

  • Unsupervised Pre-training Setup 
    • Dataset : Unsupervised Pre-training을 위해, BooksCorpus dataset을 사용했다. 
    • Model : original transformer 모델을 따랐다. transformer의 12 layer의 decoder를 이용하였다. position-wise feed-forward 네트워크로 3072 dimmension의 inner states를 사용했다. Optimizer로는 Adam, Learning rate는 2.5e-4로 학습했다. L2 regularization도 도입했고, Gaussian Error Linear Unit을 activation function으로 사용했다고 한다. 기존 Transformer 논문과 달리, siunsoidal을 사용하지 않고 position embeddings을 사용했다. Tokenizer로는 spaCy를 사용했다. 
  • 실험 결과

→ 이 부분에서 각 Task의 사전 결과들에 대한 자세한 부분(모델 & 학습 데이터 & 성능이 의미하는 바)에 대해서 세세하게 잘 알지 못해서, 이 부분은 논문을 직접 참조하는 편이 좋을 것 같다. 

 

전체적으로 다양한 NLP 분야의 task에서 좋은 성능을 거두었다.(12개 task들 중, 9개에서 SOTA 성능이다.) 

 

 

Conclusion 

  • 이 논문에서는 unlabeled 데이터로 pre-training을 진행하고, 각 task에 맞는 labeled 데이터를 통해 supervised learning으로 좋은 성능을 보여주는 학습 방법에 대해 제시한다. 
  • Pre-training 단계에서는 다양한 word 간의 관계와 long-range dependencies 등이 학습되고, 이 정보들이 Fine-tuning 과정을 통해, 각 task들의 학습에 유용하게 사용된다.
  • 이러한 학습 방법은 12개의 NLP task 중 9개에서 SOTA를 기록할 정도로 powerful 하다. 

출처

Improving Language Understanding with Unsupervised Learning (lec Radford, Karthik Narasimhan, Tim Salimans, and Ilya Sutskever)

 

총평

이 논문에서는 복잡한 수식이나, 새로운 모델을 제시한 것은 아니다. 하지만, NLP 분야에서 unsupervised 방법으로 pre-training 하고, supervised 방법으로 모델을 학습하는 개념을 장착시켜, 현재의 Chat-GPT까지 만들 정도로 NLP 분야의 매우 중요한 이정표가 된 것 같다. 

반응형

Transformer 배경 설명

  • Transformer는 Google Brain이 2017년 "Attention is All You Need"라는 논문에서 제안된 딥러닝 모델이다.  
  • Transformer는 기존 자연어 처리 분야에서 주로 사용되던 RNN, LSTM 같은 순환 신경망 모델 중심의 처리 방법의 대안을 제공하여, 현재는 자연어 처리 분야에서 가장 널리 사용되는 모델 중 하나가 되었다.

사전 지식

  • 기존의 순환 신경망을 사용한 자연어 처리는 아래와 같이 Encoder를 이용해서 Context를 생성하고, Decoder를 따르는 구조를 가졌다. 

Abstract

  • 기존의(당시) 자연어 처리 분야의 논문에서는 Encoder와 Decoder에 복잡한 순환 모델이나 CNN 구조를 적용하는 방법이 지배적 이었다. 
  • 이 논문에서는 Transformer라는 Attention 메커니즘만 사용한 모델을 제안한다.
  • 실험에서 Transformer는 기존 모델에 비해 병렬적으로 학습하여, 더 빠른 시간에 학습하였음에도, 번역 분야에서 압도적인 성능을 보여준다. 

Introduction

  • 순환 모델에서는 일반적으로 Sequence를 처리하기 위해, 각 시간축을 따라 데이터를 참조한다. (즉, t 지점의 Feature를 생성하기 위해서는 t-1 까지의 값을 모두 참조해야한다.)
  • 이러한 구조는 전시점의 데이터들을 함께 필요로하기 때문에, 긴 sequence를 처리할 때(Sequential computation), 메모리 제약이 많이 걸린다. (학습 시, 병렬 처리가 어렵다.)
  • Sequential computation을 효율적으로 수행하기 위해, 여러 방법(Factorization trick, Conditional computation, 보통은 참조하는 시간 값을 줄이거나 뽑는 방법을 사용함) 등의 방법이 나왔지만, 근본적인 순환 모델의 한계(Sequential 구조때문에 메모리 제약이 큼, 병렬 처리가 어려움)는 극복하지 못한다. 
  • 이 논문에서는 순환 모델이 아닌, 전체를 Attention 메커니즘으로 처리하여, input과 output간 global 의존성을 모델링하는 "Transformer" 구조를 제안한다.  

Background 

  • Sequential computation을 줄이기 위해, CNN을 사용한 여러 논문들이 있었지만, 이 구조들로는 Input과 Output의 관계를  모델링하기는 어려움.
    • Transformer에는 "Multi-Head Attention" 메커니즘을 사용해서 여러 sequence의 Attention을 독립적으로 계산하고, 이를 결합해서, input과 output간 global 의존성을 모델링한다. 
  • "Self-attention" ("infra-attention"이라고도 함, input sequence의 각 위치에서 다른 위치들과의 상관 관계를 계산하는 기법)을 사용함. 
  • "End-to-end memory network" 구조로 구성된다. 

 

Model Architecture

  • 기본적으로, Transformer의 Encoder와 Decoder의 각 Layer들은 1) self-attention과 2) point-wise fully connected layer들로 구성된다.

  • Encoder
    •  Encoder는 동일한 6개의 layer들로 구성되어 있다. (그림에서 N=6)
    • 각 layer들은 2개의 sub layer들로 구성되어 있고, 각각 multi-header self-attention layer와 position-wise fully connected layer이다. 
    • 각 sub-layer들에는 residual connection을 연결해주었고, Layer Normalization(각 시점마다의 Normalization을 수행, 각 시점마다의 데이터 분포가 달라지는 것을 방지해줌)을 처리했다.
  • Decoder
    • Decoder도 동일한 6개의 layer들로 구성되어 있다.
    • Encoder의 2개의 sub layer(multi-header self-attention layer와 position-wise fully connected layer)에 추가적으로 encoder들의 output에 multi-head attention을 처리해줄 layer를 추가하여, Decoder의 각 layer를 구성한다. 
    • Encoder와 마찬가지로 각 sub-layer들에는 residual connection과 Layer Normalization 과정이 포함된다.
    • Decoder는 후속 데이터를 참조하면 안되기 때문에(실제 데이터에는 후속 데이터를 볼 수 없기 때문), self-attention sub-layer를 개조하여,  masking을 구현했다.
  • Transformer에서 사용되는 Attention
  • Scaled Dot-Product Attention : Query와 Key 사이의 유사도에 기반하여 Attention을 구하는 방식을 사용한다. 유사도 계산은 Attention Function에서 자주 사용하는 Dot Product를 기반해서 구한다. (빠르고, 공간 효율적이여서) scaling factor인 sqrt(d_k)를 나눠주는 이유는 d_k가 큰 값을 가질 때, Dot Product 값이 너무 커져서, Gradient가 매우 작아질 수 있기 떄문이다. 

→ 의미 : Query가 Key와 얼마나 유사한지에 따라 Value에 Attention을 가하겠다. (유사할수록 많이)

 

  • Multi-Head Attention : Query, Key, Value를 그냥 사용하는 것보다 각각 학습된 Weight들을 곱해준(Linearly Projection) 값을 사용하는 것이 효율적이라고 한다.(논문에서) Query, Key, Value를 Linearly Projection한 값으로 Scaled Dot-Product Attention을 구한 후, 각 값들을 concatenate 하고, 다시 그것에 Weight를 곱해서 Multi-Head Attention을 구한다.  

  • Transformer에서 Attention은 어떻게 사용되나?
    • Transformer에는 3가지 방식으로 multi-head attention을 사용한다. 
      1. "Encoder-Decoder Attention" : Decoder의 이전 시전 값과 현재 시점 값으로 구한 self-attention 값을 query로, Encoder들의 output을 이용하여 key, value를 구해서 multi-head attention을 적용한다. Decoder의 각 위치가 Input Sequence의 모든 위치들을 참조하도록 도와준다. 
      2. Encoder는 self-attention layer들을 가지고 있다. Key, Query, Value는 모두 Encoder의 전 Layer의 Output이다. Encoder의 각 위치가 다른 위치들의 값을 참조하도록 도와준다.  
      3. Decoder 단에도 self-attention layer들이 있다. Decoder의 각 위치가 다른 포지션을 참조하도록 해준다. (다만, 다음 시점의 데이터들은 참조하면 안되기 때문에 masking한다. )
    • 특히, 2,3번의 self-attention은 RNN을 사용하지 않고도, Sequence 데이터 처리에서 다른 시점의 데이터들을 참조할 수 있도록 한다. 
    • Attention을 정리하면 다음과 같다. 

Attention 인자 의미
1. Encoder-Decoder Attention Q : Decoder 단의 Vector
K : Encoder 단의 Vector
V : Encoder 단의 Vector
현시점의 Decoder의 Vector 값이 Encoder 단에서의 Vector 값과의 유사도 만큼, Encoder 값을 참조하는 가중치를 조정하겠다는 의미
2. Encoder Self-Attention Q : Encoder단의 Vector
K : Encoder 단의 Vector
V : Encoder 단의 Vector
현시점의 Encoder의 Vector 값과, Sequence 내 다른 Encoder 단의 Vector 값과 유사도를 측정하여 참조하는 가중치를 조정하겠다는 의미 → Sequence 내 다른 값도 함께 참조 가능 (RNN 기능을 self-attention으로 구현)
3. Decoder Self-Attention Q : Decoder 단의 Vector
K : Decoder 단의 Vector
V : Decoder 단의 Vector
현시점의 Decoder 의 Vector 값과, 이전 시점의 Decoder Vector 값과 유사도를 측정하여 참조하는 가중치를 조정하겠다는 의미 → Sequence 내 다른 Decoder 값도 함께 참조 가능
  • Position-wise Feed-Forward Networks : 앞서 말한대로, Encoder의 2번째, Decoder의 3번째 sub-layer는아래와 같은 fully-connected layer와 Relu로 구성되어 있다. 

  • Embeddings and Softmax : Embedding으로는 학습된 Embedding을 사용함. Decoder Output을 다음 Token의 확률로 변환하기 위해 Linear Transformation과 Softmax를 이용한다. 
  • Position Encoding : Input Sequence의 단어 위치 정보를 Embedding에 추가해서, 단어의 순서 정보를 이용할 수 있도록 Position Encoding을 사용. Position Encoding을 단어의 Embedding Vector에 더해서 사용.

Results

  • 기계 번역 : WMT 2014 English-to-German translation, English-to-French translation에서 State-of-the-arts 달성
  • 영어 문장 구문 분석 : 언어 모델의 일반화를 위한 실험, Task 튜닝 없이도 거의 SOTA에 근접한 성능 달성

 

출처

Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., ... & Polosukhin, I. (2017). Attention is all you need. In Advances in neural information processing systems (pp. 5998-6008).

반응형

PCA는 차원 축소의 대표적인 기법이다. 다루고자 하는 데이터의 차원이 많을때, 보통 PCA를 먼저 생각하게 된다. 수업에서 배운 기억이 남아있는데, 너무 오래되어, 다시 한번 공부해보기로 한다.


PCA 란?

  • PCA(Principal Component Analysis)는 이름 그대로, 데이터에서 주성분(Principal Component)을 추출하여, 주성분만으로 원 데이터를 표현하는 방법이다. 
  • PCA는 다차원의 데이터셋 내에서 변수들간의 상관관계를 이용하여, 이를 새로운 좌표계로 변환하여 차원을 축소한다. 
  • PCA는 다음과 같은 이유로 많이 사용된다.
    • 데이터의 차원 축소 : 실제 데이터 분석에서 데이터의 Dimension은 고차원인 경우가 많다. 데이터의 모든 Dimension을 하나 하나 분석하기는 매우 어렵다. 이런 경우 PCA를 이용하여, 저차원으로 축소하여 분석하는 경우가 많다.
    • 데이터의 잡음 제거 :  PCA에서는 주성분을 추출하는 과정을 거치기 때문에, 이 과정에서 데이터의 Noise를 제거할 수 있다. 
    • 시각화 : PCA를 통해, 데이터를 3차원 이하로 줄이면, 데이터의 패턴이나 구조를 눈으로 확인 할 수 있다. 
    • 계산 효율성 : PCA를 활용하여, 저차원으로 데이터를 분석하면 계산 효율성이 크게 향상된다. 머신러닝 기법에서 데이터 전처리로 PCA를 많이 활용하는 경우도 많다.
  •  데이터 분석 시, PCA를 마구 사용하는 경우가 많은데, PCA 사용 시, 다음과 같은 점을 유의해야한다.
    •  해석력 감소 : PCA는 고차원의 데이터를 저차원의 새로운 축으로 다시 표현하는데, 이때 저차원에서의 각 component가 원래 데이터의 어느 요소와 연관성이 있는지 해석이 어렵다.
    • 정보 손실 : 정보 손실을 최소화하는 쪽으로, 차원을 축소하지만, 이 과정에서 많은 정보가 유실된다.

PCA의 원리

  • PCA의 원리를 한마디로 표현하자면, 변수들의 Covariance Matrix에서 Eigenvector와 Eigenvalue를 구한 후, 원하는 만큼의 Eigenvector만 사용하여 변수를 표현하겠다는 것이다. 
  • Covariance Matrix로 선형 변환한다는 것이 중요한데, 각 차원의 변수들을 다른 변수들과의 상관관계를 표현해서 나타내겠다는 의미이다. 
  • 예를 들어, 아래와 같이 선형 변환을 한다고하면, 선형 변환으로 구해진 새로운 변수들은 기존 변수들의 선형적 관계를 통해 구해진다. 이를 통해서, 새로운 차원의 변수는 기존 데이터의 여러 차원의 정보를 동시에 지니게 된다. 

[Covariance 란?]

  • Covariance는 두 변수가 함께 변화하는 정도로, 두 변수 간의 관계를 나타내는 통계값이다. 
  • Variance와 달리,  두 변수 간의 상관 관계를 나타내기 때문에, 방향의 개념도 포함한다. (양수 : 두 변수가 양의 상관관계, 음수: 두 변수가 음의 상관관계)

[Covariance Matrix란?]

  • 다차원 변수에서 각 차원의 변수 간 Convariance를 Matrix 형태로 나타낸 것이다.
  • N차원의 데이터는 N X N 형태의 Convariance Matrix로 나타나게된다. 
  • k X k의 대각 성분은 Variance를 의미한다. 

[Eigenvector & Eigenvalue란?]

  • Eigenvector는 특정 행렬이 곱해져도, 방향이 변하지 않는 벡터를 의미한다. 즉, PCA에서 Covariance Matrix를 이용해서, 선형 변환을 했을때도 방향이 변하지 않는 행렬을 의미한다.
  • Eigenvalue는 Eigenvector로 선형 변환하였을때의 길이의 비율을 의미한다. 
  • PCA에서 Eigenvalue는 주어진 데이터셋의 주성분 중 얼마나 많은 variance를 설명할 수 있는지에 대한 수치이다. (즉, Eigenvalue가 클수록 중요한 정보를 많이 담고 있다고 해석된다.)
  • N차원의 데이터에서는 N개의 Eigenvector & Eigenvalue가 나온다. 

 

이것을 그림으로 이해해보자.

아래 그림과 같은 2차원의 데이터 분포가 있다.

해당 데이터에서 각 차원의 평균이 원점이 되는 새로운 축을 그린다. (Conviance에서 mean shift하는 과정을 의미한다.)

이때, 우리는 분산(새로운 원점인 기존 데이터들의 평균부터 각 데이터까지의 거리의 합)이 최대가 되는 직선을 구할 것이다.)

이 부분이 약간 헷갈릴 수 있는데, 피타고라스 정리를 생각하면 된다. 데이터를 새로운 축에서 가장 잘 표현하기 위해서는 기존 데이터와 새로운 축에서의 데이터 간의 거리가 가장 작은 선을 축으로 삼아야한다.)

아래의 그림에서 c는 데이터 포인트와 평균 간의 거리기 때문에 고정이다. 피타고라스 정리에 의해서 c가 고정되어 있을때, b(원 데이터와의 거리)가 최소인 값을 구하려면 a가 최대가 되어야한다. 

 

 

이때, a가 최대가 되는 선은, 분산이 최대가 최대가 되는 선으로 Eigenvector이다. 

첫번째 구한 Eigenvector와 수직인 직선을 구하면, 두번째 Eigenvector가 된다.

PCA 파이썬 구현

  • PCA는 파이썬의 scikit-learn을 통해 쉽게 사용 가능하다. 
  • PCA 수행 시, n_components에 몇번째 차원까지의 주성분을 사용할지를 결정한다. 
import numpy as np
from sklearn.decomposition import PCA

if __name__ == '__main__':
    # 2차원 랜덤 데이터 생성
    np.random.seed(1)
    x = 5*np.random.rand(100, 2)

    # 첫 번째 특성에 대해 랜덤한 선형적 상관관계 부여
    X[:, 1] = 0.3 * X[:, 0] + 0.1 * np.random.randn(100)

    # PCA 모델 생성
    pca = PCA(n_components=1)

    # PCA 모델 학습
    pca.fit(X)

    # PCA 수행
    transformed_data = pca.transform(X)
    # 차원 변화 확인
    print(transformed_data.shape)
    # 주성분 확인
	print(pca.components_)
  • Covariance Matrix와 Eigenvalue, Eigenvector를 사용하기 위해서는 numpy에 내장되어 있는 함수들을 사용하면 된다. 
import numpy as np

if __name__ == '__main__':
    # 2차원 랜덤 데이터 생성
    np.random.seed(1)
    x = 5*np.random.rand(100, 2)

    # 첫 번째 특성에 대해 랜덤한 선형적 상관관계 부여
    X[:, 1] = 0.3 * X[:, 0] + 0.1 * np.random.randn(100)
    
    # Covariance Matrix 구하기
    cov_mat = np.cov(X.T)
    print(cov_mat)
    
    # Eigenvalue & Eigenvector 구하기
    eigenvalue, eigenvector = np.linalg.eig(cov_mat)
    print(eigenvalue, eigenvector)
    
    # 차원 변화 확인 (데이터 변환된 값)
    transformed_data = eigenvector.T.dot((X - X.mean()).T).T
    n_component = 1
    pca_data = transformed_data[:,:n_component]
    print(pca_data.shape)
반응형

t-SNE는 딥러닝 모델에서 feature의 유사도를 파악하기 위해 시각화할 때, 정말 많이 사용했던 방법이다. 단순 차원축소를 해주는 알고리즘이다라고만 이해하고 있었는데,  이번 기회에 완벽히 이해해보고자 한다. 


t-SNE 이란?

  • t-SNE(t-distributed Stochastic Neighbor Embedding)는 고차원 데이터를 저차원 영역으로 표현하기 위한 비선형 차원 축소 기법이다.
  • 여러 Feature 들의 차원 중에서 의미가 큰 차원을 선택하는 Feature Selection과 달리, 고차원 데이터의 구조와 패턴을 유지하면서, 차원 축소를 가능하게 한다.  
  • 딥러닝 등의 중간 Layer의 Output Feature 들은 대체적으로 고차원의 영역의 데이터이다. 이러한 데이터들은 직관적으로 이해하기가 어렵기 때문에, 저차원으로 시각화하여 Visualization을 진행하는데, t-SNE가 자주 사용된다.
  • PCA(주성분 분석)과 차원축소의 개념에서는 비슷하지만, 목적과 방식이 달라, 혼용해서 보완 사용하기도 한다.
  t-SNE PCA
목적 고차원 데이터를 저차원으로 바꿔, 시각화
(유사한 데이터는 가깝게, 다른 데이터는 멀게)
고차원 데이터를 저차원으로 바꿔, 데이터의 구조와 패턴을 파악 
방법 확률 분포를 이용하여 고차원 데이터와 저차원 데이터 간의 유사도를 계산하고, 최적화함. 데이터의 분산을 최대한 보존하는 축을 찾아서 차원을 축소함 (고유값 분해)
알맞은 데이터 유형
선형적 & 비선형적 데이터 모두 (데이터 간 유사도가 극명하면 유리) 데이터가 선형적으로 구성되어 있는 경우 
주의점 저차원에서의 유사도 최적화 과정이 포함되어서, PCA보다 computation cost가 높음
최적화 과정이 있기 때문에, 데이터셋 구성에 따라 결과가 달라짐
비선형적 데이터에 대해서는 성능이 떨어짐

t-SNE 알고리즘

  • t-SNE의 원리는 쉽게 말해서, 고차원 공간에서 가까운 것은 저차원에서도 가깝게, 고차원에서 먼 것은 저차원에서도 멀게 유지하는 것이다.
  • 기본적으로 t-SNE는 고차원 데이터 포인트들간 유클리디안 거리를 이용해서, 유사도를 조건부 확률로 바꿔서, 유사도를 나타내겠다는 SNE를 개선한 방법이다.
  • SNE의 유사도를 조건부 확률로 바꾸는 것이 처음에 잘 이해가 안 되는데, 쉽게 생각하면, Gaussian 분포의 PDF를 생각하면 된다. 이 식에서 평균이 데이터 포인트 i라고 하면, 평균이 i 포인트인 Gaussian 분포를 생각하면 된다. 즉, 한 데이터 포인트를 중심으로 다른 데이터 포인트 간의 거리는 정규 분포를 따른다고 생각하면 된다. 

  • 우선, t-SNE를 이해하기 위해 SNE 원리를 이해해보자.  

 

[SNE 원리]

1. 각 데이터 포인트간 Euclidean Distance를 구한다.

2.  두 데이터 포인트 간 거리를 d라고 했을때, 두 데이터 포인트 사이의 거리가 d 일 확률은 다음과 같은 정규분포의 조건부 확률로 나타난다. 즉, 거리를 다음과 같이 나타낸다. (p(i|j)와 p(j|i)가 다르다는 점을 주목해야한다.)

3. SNE의 원리는 고차원의 거리를 그대로 유지하는 저차원에서의 모델을 찾는 것이다. 저차원에서 σ의 제곱(분산)이 1/2 값을 갖는 분포를 가정하면, 저차원에서 데이터 분포 간의 거리는 다음과 같이 나타낼 수 있다.  

4. 학습의 목적은 고차원에서 데이터 포인트간의 거리를 나타내는 분포 p를 제일 잘 표현할 수 있는 저차원의 근사분포 q를 찾는 것이다. qp와 비슷한 분포가 되기 위해, 두 분포간의 KL(Kullback-Leibler) Divergence가 작아지도록 학습한다. (Gradient Descent를 이용, 두 분포가 완전히 같아졌을때, KL divergence는 0)

 

  • SNE도 좋은 방법이지만, t-SNE는 SNE보다 다음과 같은 면을 수정했다.

 

1. 비대칭성 → 대칭성

조건부 확률 기반에서, 고차원의 두 데이터 포인트 i와 j 사이의 거리인 p(i|j)와 p(j|i)는 다르다.(Sigma가 다르다) t-SNE에서는 둘 사이의 거리를 정의하는 확률을 아래와 같이 수정하여 대칭성을 부여하였다. (이로 인해, 최적화 속도가 빨라졌다. → 어느 방향에서도 동일하게 수렴 가능하기 때문에 안정적이다.)

2. Gaussian 분포 → t-분포

고차원을 저차원으로 축소하다 보면, 고차원에서 데이터가 많이 분포하는 구간에서 축소된 데이터들은 서로 많이 뭉치게 된다. 10차원에서 봤을 때는 다양한 값들을 가진 데이터들이 2차원으로 차원 축소가 되면, 거의 비슷하게 보일 수 있다. (RGB 이미지에서 구분 잘되던, 그림들이 흑백에서 구분이 잘 안 되는 걸 생각하면 된다.) 이를 완화하기 위해서는 데이터의 분포가 고르게 퍼져있는 구조가 유리하다. t-SNE에서는 거리 분포를 Gaussian 분포 대신에 t 분포를 도입하여, 데이터를 퍼뜨렸다. 

t-분포

v: 자유도, B : 베타 함수

[t-SNE]

1. 각 데이터 포인트간 Euclidean Distance를 구한다.

2.  두 데이터 포인트 사이의 거리가d일 확률은 다음과 같은 조건부 확률로 나타난다. 다만, 앞에 말했던 대로, 대칭성 확보를 위해 두 데이터 포인트 사이의 거리를 다음과 같이 정의한다. (고차원의 거리 분포는 Gaussian 분포를 그대로 유지한다.)

3. t-SNE는 SNE와 달리, 저차원에서 분포를 t-분포로 가정한다. 따라서, 데이터 포인트 간 거리를 다음과 같이 나타낼 수 있다. (일반적으로 자유도가 1인 t-분포를 사용한다.)

 

4. t-SNE도 마찬가지로, 학습의 목적은 고차원에서 데이터 포인트 간의 거리를 나타내는 분포 p를 제일 잘 표현할 수 있는 저차원의 근사분포 q를 찾는 것이다. q p와 비슷한 분포가 되기 위해, 두 분포간의 KL Divergence가 작아지도록 학습한다. (Gradient Descent를 이용)

t-SNE 파이썬 구현

  • scikit-learn의 TSNE를 사용하면, 쉽게 TSNE를 사용 가능하다. 
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.manifold import TSNE

if __name__ == '__main__':
    # Data Load (MNIST: 64 dim)
    digits = datasets.load_digits()
    X = digits.data
    y = digits.target

    # t-SNE(64 to 2)
    tsne = TSNE(n_components=2, random_state=1)
    X_tsne = tsne.fit_transform(X)

    # t-SNE Visualization
    plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y)
    plt.show()

반응형

💬 한국어 텍스트 데이터 전처리

  • 텍스트 데이터는 보통 그 자체로 사용하기보다, 의미의 단위로 나눠서 활용 여부나 사이 연관 관계를 찾는다.
  • 저번 장에서 확인한 대로, 데이터셋의 텍스트 데이터는 한국어 문장으로 구성되어 있다.
  • 학습할 때마다 한국어 형태소 분리를 실행해도 되지만, 시간이 너무 많이 걸려서, 텍스트 데이터를 전처리 해놓기로 한다. 

한국어 텍스트 데이터 전처리 방법

  • 텍스트 데이터의 전처리 단계는 다음과 같다.
1. 텍스트 데이터를 형태소 단위로 분리한다.
2. 분리된 데이터 중, 불용어를 제거한다. (Optional)
3. 동의어를 mapping 할 수 있다면, 동의어를 mapping한다. (Optional)
4. word dictionary를 생성
5. word를 정수 인코딩한다.

1. 한국어 형태소 분리 (Tokenization)

  • 한국어의 경우에는 영어와 달리, 의미의 단위가 띄어쓰기와 정확히 일치하지 않는다.
  • 과거부터 한국어 형태소 분리가 연구되어 여러 방법들이 존재한다.
  • 파이썬은 "konlpy" 라이브러리에서 다양한 형태소 분석기를 제공한다. (자세한 내용은 https://konlpy.org/ko/latest/index.html 참조)
  • konlpy에서는 다양한 형태소 분석기를 제공해 주지만, 그중 "Okt"(Twitter에서 개발한 오픈소스 한국어 처리기)를 사용하여 한국어 형태소 분리 처리를 하기로 한다. (선택한 이유는 속도 때문이다.)
처리 전 처리 후
"아버지가 방에 들어가신다."  ["아버지","가","방","에","들어가신다","."]

2. 불용어 처리

  • 불용어(Stopword)는 분석에 필요하지 않거나, 분석 결과에 영향을 미치는 단어를 말한다. (예시: 은,는,이,가)
  • 자연어 처리에서는 불용어 제거가 매우 중요하다. 불용어는 실제 분석에는 이용되지 않지만, 일반적으로 문장에서 등장하는 빈도수가 높아져서, 해당 단어들이 중요한 단어로 인식될 수가 있다. 
  • 또한, 불용어 제거는 전처리 과정에서 처리할 텍스트 데이터의 양이 줄어서 처리 속도 향상을 위해 꼭 필요하다. 
  • 다만, 불용어는 분석의 목적에 따라 달라지는 상대적인 개념이기 때문에, 분석에 영향을 미치지 않는 단어만 넣도록 한다. 예를 들어, 일반적으로 '?'는 Elastic Search 등의 텍스트 검색을 위한 처리에서 불용어 처리가 될 수 있지만, 우리가 다루고자 하는 비윤리적 텍스트 검출에서는 상대를 비꼬는 문장을 찾을 수 있는 중요한 단서가 되기도 한다. 
  • 일반적으로 특수문자는 문장에서 제거한 후에, 한국어 형태소 분리하지만, 해당 Task에서는 특수문자가 분류에 많이 사용될 것으로 생각되어서, 실제 사용되지 않을 것으로 보이는 특수문자만 불용어로 처리하였다.  
불용어 예시 : 

stopwords = ['','','','','','','','','','','으로','','하다','!','?','<','>','(',')','[',']','|','#','.']

3. 동의어 처리

  • 동의어 처리는 일반적으로 텍스트 검색 기능에서 유사한 단어를 찾기 위해 자주 사용된다. 
  • 비윤리적 텍스트 문장 검출 데이터셋에서는 일반적인 단어를 특수문자나 축약어로 표현해 놓은 데이터가 많다. (예시: ㅇㅋ, Ok, 오키, 옿키)
  • 좋은 성능의 검출 모델을 만들기 위해서 동의어 처리도 매우 중요할 것으로 생각되지만, 현실적으로 공수가 너무 많이 소요되어, 별도의 동의어 처리는 하지 않았다. 

4. Word Dictionary 생성 

  • 학습 데이터셋을 형태소 분리하고, 불용어와 동의어 처리까지 처리한 후, 학습 데이터를 기반으로 워드 딕셔너리를 생성한다.
  • 실사용 시, Word Dictionary에 포함되지 않는 단어가 등장했을 경우에는 모델은 해당 단어에 대한 정보를 사용할 수 없다. (자연어 처리 시, 다양하고 풍부한 학습 데이터가 필요한 이유이기도 하다.) 
  • 각 단어에 대한 고유의 번호를 지정한다. 
  • 모든 단어를 사용하는 것이 다양성 측면에서는 좋겠지만, 속도나 성능을 고려하면, word dictionary의 크기를 무작정 늘리는 것은 좋지 않다. (일반적으로 최대 단어 개수를 지정한다. )
  • 정수 인코딩과 모델 테스트 시 빠른 사용을 위해, 인덱싱(key: 숫자, value: word)과 역인덱싱(key: word, value: 숫자)을 모두 진행해 놓는 것이 좋다.  
문장 형태소 분리 Word Dictionary 인덱싱
"아버지가 방에 들어가신다." ["아버지","가","방","에","들어가신다","."]  {<unk>:0,<pad>:1,"아버지":2, "방":3, "들어가신다":4} {'0':<unk>,'1':<pad>,'2': "아버지", '3':"방", '4':"들어가신다"}

5. 텍스트의 Word를 정수 인코딩

  • 모델의 학습을 위해, 텍스트를 정수로 인코딩해주는 작업이 필요하다. 
  • Word Dictionary를 기반으로 학습 데이터의 각 단어들을 정수로 변환한다.
  • Word Dictionary에 포함되지 않은 불용어 등은 "<unk>"라는 wildcard로 치환한다. 이를 통해, 모델이 입력받는 word 데이터의 종류는 Word Dictionary에 존재하는 단어 개수로 제한된다. 
  • 정수 인코딩을 진행하면, 문장마다의 인코딩 벡터의 길이는 전부 다르다. 학습을 위해 데이터를 정형화하는 편이 좋기 때문에, 인코딩 벡터의 끝부분에 "<pad>"값을 넣어, 벡터의 길이를 모두 같게 만들어준다. 
처리 전 처리 후
"아버지가 방에 들어가신다."  2,0,3,0,4,0,1,1,1,1

 

데이터 전처리 코드 구현

  • 전처리 과정을 사전에 진행해 놓기 위한, 코드를 구현하였다. 다만, 학습과 테스트 시 코드 통일성을 위해, 정수 인코딩 부분은 모델 데이터셋 정의 과정에 넣었다. (테스트 데이터도 정수 인코딩은 진행해야 하기 때문에, Dataset 구성 파트에서 설명 예정)
  • 자연어 Dataset 처리를 용이하게 하기 위해, "torchtext"라는 pytorch에서 제공해 주는 자연어 처리용 패키지를 사용하였다. (하지만, pytorch는 데이터셋의 종류에 따른 전처리를 모두 통일하기 위해 현재는 torch를 사용하도록 권장하고 있다. )
  • Okt가 빠르긴 하지만, 처리 데이터가 많기 때문에 전처리에 시간이 많이 소요된다. 
  • 데이터 전처리 단계를 대략적으로 구성하였지만, 실사용에서는 불용어 지정이나 어느 종류의 형태소 분석기를 사용할 것인지, word dictionary를 어떻게 구성할 것인지 등이 성능을 결정하는 매우 중요한 단계이다. 
from konlpy.tag import *
from torchtext import data 
import json

import pandas as pd

tokenizer = Okt()
stopwords = ['의','가','에','들','는','잘','걍','과','도','를','으로','한','하다','!','?','<','>','(',')','[',']','|','#','.']

# 텍스트 전처리 함수
def norm_morphs(x):
    x = tokenizer.normalize(x) # 텍스트 Normalization
    x = tokenizer.morphs(x) # 형태소 분리
    x = [word for word in x if not word in stopwords] #불용어 처리
    return x


if __name__ =='__main__':
    # 데이터셋 위치 지정
    data_dir = r"..\korean_language\data"

    # ID: 문서의 번호, TEXT: 문장 데이터(전처리 함수를 지정할 수 있음), LABEL: 윤리성 유무를 나타내는 LABEL 
    ID = data.Field(sequential=False, use_vocab=False)
    TEXT = data.Field(sequential=True, use_vocab=True, tokenize = norm_morphs, batch_first=True, tokenizer_language='ko')
    LABEL = data.Field(sequential=False, use_vocab=False, is_target=True)

    # Torch Text의 splits를 이용해서, 데이터를 한번에 불러올 수 있다. 
    train_data, test_data = data.TabularDataset.splits(path=data_dir, train='train', test='test', format='tsv', fields=[('id',ID), ('label',LABEL),('temp1',None),('temp2',None),('temp3',None),('text',TEXT)], skip_header=True)

    # word dictionary를 만듬 (최대 크기와, 최소 빈도수를 지정)
    TEXT.build_vocab(train_data, min_freq=2, max_size=100000)

    # word dictionary를 저장
    with open('./dictionary.json','w') as f:
        json.dump(TEXT.vocab.stoi, f, ensure_ascii=False, indent=4)

    # Index dictionary를 저장 
    index_dict = {v: k for k, v in TEXT.vocab.stoi.items()}
    with open('./index_dictionary.json','w') as f:
        json.dump(index_dict, f, ensure_ascii=False, indent=4)


    id_list = []
    text_list = []
    label_list = []
    df = pd.DataFrame()

    for id, data_dict in enumerate(train_data):
        id_list.append(id)
        text_list.append('|'.join(data_dict.text))
        label_list.append(data_dict.label)

    df['id'] = id_list
    df['text'] = text_list
    df['label'] = label_list
    df.to_csv('train.csv', index=False,sep = '#')

    id_list = []
    text_list = []
    label_list = []
    df = pd.DataFrame()

    for id, data_dict in enumerate(test_data):
        id_list.append(id)
        text_list.append('|'.join(data_dict.text))
        label_list.append(data_dict.label)

    df['id'] = id_list
    df['text'] = text_list
    df['label'] = label_list

    df.to_csv('test.csv', index=False,sep = '#')


    print("Train Data :",len(train_data))
    print("Test Data :",len(test_data))

 

전처리를 진행하였으니, Dataset을 정의하고, 모델을 만들어볼 차례이다!

반응형

Logistic Regression

Logistic Regression의 원리는 이진분류에서 다뤘다. 하지만, 실제 데이터 분석 시에는 이진 분류보다는 다중 클래스 사이에서 데이터가 어느 클래스에 속하는지를 분류하는 문제가 많다. 사실 다중 분류를 위한 로지스틱 회귀는 이진 분류와 내용 차이가 크게 없지만, 많이 사용하는 만큼 따로 나눠서 소개를 하고 한다. 


다중 Logistic Regression 이란?

  • 3개 이상의 클래스 중, 하나의 클래스에 속하는지를 예측하는 문제이다.
  • 이진 분류와 가장 다른 점은, 이진 분류는 분류 문제의 정답이 '참'일 확률(p)만 고려하여, '참'과 '참이 아님'을 분류하면 되지만, 다중 분류는 여러 가지 클래스 중, 예측 모델이 속할 확률이 가장 높은 클래스를 찾는 문제이다.
  • 즉, 정답이 이진 분류에서는 정답 예측을 한 차원('참'일 확률 p)에서만 끝낼 수 있었지만, 다중 분류의 예측은 클래스의 개수만큼의 예측 결과가 필요하다. 
  • 이러한 다중 분류를 위해 다중 로지스틱 회귀 모델에서는 일반적으로 Softmax 함수를 사용한다. 

※ Softmax 함수
-  K개의 클래스가 있는 다중 분류 문제에서 j번째 softmax 함수 결과는 아래와 같이 나타난다.

 

-  Softmax 함수는 Logistic 함수의 일반화된 형태이다. 
-  Softmax 함수는 각 클래스에 속할 확률(p)을 각 클래스들에 속할 확률들의 합으로 나눠서, 0부터 1 사이로 Normalization 한 형태이다. 
-  일반적으로 Softmax 함숫값이 가장 큰 클래스로 예측 모델의 결과를 낸다. 

 

다중 Logistic Regression의 학습 방법

  • 다중 Logistic Regression의 학습을 위해서도 최대우도방법(MLE, Maximum Likelihood Estimation)을 사용한다.
  • 다중 Logistic Regression의 학습을 위해서, 학습에 사용되는 정답을 One-hot vector 형식으로 나타내야 한다. 
  • 다중 Logistic Regression의 학습을 위해서는 일반적으로 크로스 엔트로피(Cross Entropy) 함수를 사용하여, 목적 함수를 정의한다. 

[크로스 엔트로피]

  • 크로스 엔트로피는 정보 이론에서 사용되는 개념으로, 두 확률 분포가 얼마나 다른지를 측정하는 방법이다. 
  • 크로스 엔트로피 식은 다음과 같다.

p: 실제 확률, q: 예측 확률, n: 분포의 원소 개수

  • 크로스 엔트로피의 그래프를 확인해 보면, 예측 확률 q가 실제 확률 p과 동일한 지점에서 최솟값을 나타냄을 확인할 수 있다. 
  • 즉, 크로스 엔트로피가 최솟값을 가지는 구간이 실제 확률과 가장 비슷한 예측을 하였다고 할 수 있다.
  • 분류 문제에는 종속 변수가 범주형(각 클래스에 속할 확률이 0 or 1)으로 나타나기 때문에(One-Hot vector), 첫 번째 그래프처럼 실제 분포를 정확히 예측하였을 때, '0' 값을 갖는다.

[One-Hot Vector]

  • One-Hot vector는 범주형 데이터를 다루기 위해, 사용되는 벡터 표현 방법이다. 
  • 클래스에 정수형 범주를 붙인다면, 클래스 간의 대소 관계와 순서가 모델의 학습과정에서 고려되어, 숫자형 범주 자체를 '중요도'로 오해하여 학습될 수 있다. 이를 막기 위해 One-Hot vector를 이용하여 정답 레이블을 표시한다.
  • K개의 클래스가 있는 범주형 데이터가 있는 분류 문제에서, 해당 데이터가 실제로 i번째 클래스에  속해있다고 하면, i번째 데이터를 제외한 K-1개 클래스는 0으로, i번째 클래스는 1의 값을 갖는다.
  • One-Hot vector는 해당 클래스에 속할 확률을 나타낸다고 생각할 수 있다. 

[다중 로지스틱 회귀 목적함수]

    • 다중 로지스틱 회귀를 이용한 분류 문제의 목적은 실제 데이터가 속한 클래스와 비슷한 분포를 예측하는 모델을 만드는 것이다.
    • 위의 크로스 엔트로피 식에서 p를 실제 데이터의 분포를 One-Hot vector로 변환한 값, q를 모델이 예측한 분포라고하면, 크로스 엔트로피 값이 최소인 지점이 모델이 실제 데이터를 가장 잘 예측하였을 때라고 생각할 수 있다.
    •  결국 다중 로지스틱 회귀 모델의 학습의 목적은 Softmax 함수의 형태로 구해진 예측 모델의 결과가 실제 정답의 분포에 가장 유사한 형태를 갖도록, 크로스 엔트로피 값을 최소화할 수 있는 모델 파라미터를 찾는 것이다.  

y : 실제 정답 레이블(one-hot vector 형태), K: 클래스 개수, N: 데이터 개수 

  • 다중 로지스틱 회귀 목적함수는 다음과 같다. 

Logistic Regression의 Python 구현

  • 다중 Logistic Regression은 Python의 Sklearn을 이용하여 쉽게 구현 가능하다.
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score


if __name__ == "__main__":
    # 데이터 Load (iris 데이터 사용, X :꽃의 길이와 너비, y: 꽃의 종류, 3개의 class)
    iris = load_iris()
    X = iris.data[:, :2]
    y = iris.target
        
    # 데이터 분할
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=5)

    # 모델 학습
    clf = LogisticRegression(random_state=1)
    clf.fit(X_train, y_train)

    # 모델 예측
    y_pred = clf.predict(X_test)

    # 정확도 계산
    acc = accuracy_score(y_test, y_pred)
    print("Accuracy:", acc)

 

+ Recent posts