ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • (1) 자연어 처리 개요
    자연어처리 2023. 7. 10. 20:05
    728x90

    1. 자연어

    • 정의: 프로그래밍 언어와 같이 인공적으로 만든 기계 언어와 대비되는 단어로 우리가 일상에서 주로 사용하는 언어이다.

    1-1. 자연어 처리

    • 컴퓨터가 한국어나 영어와 같은 인간의 자연어를 읽고 이해할 수 있도록 돕는 인공지능의 한 분야
    • 자연어에서 의미 있는 정보를 추출하여 활용
    • 기계가 자연어의 의미를 이해하게 한다. 
    • 기계가 사람의 언어로 소통할 수 있게 한다.

    1-2. 자연어 처리의 활용

    • 문서 분류, 스팸 처리와 같은 분류 문제부터 검색어 추천과 같은 추천 기능, 음성 인식, 질의 응답, 번역 등의 다양한 분야에서 사용되고 있다.
    • 반복 업무 자동화
    • 검색 효율 향상 및 검색 엔진 최적화
    • 대규모 문서 분석 및 정리
    • 소셜 미디어 분석

    1-3. 용어 정리

    • 자연어이해(NLU)
      • 자연어 처리의 하위 집합 중 하나이다.
      • 자연어 이해 기술의 목적은 일반적으로 기계가 자연어의 실제 의미, 의도나 감정, 질문등을 사람처럼 이해하도록 돕는 것
      • 기계가 다양한 텍스트의 숨겨진 의미를 해석하려면 사전 처리 작업들과 추가 학습이 필요하다.
      • 텍스트에 명시적으로 나타나는 표지적인 정보 이외에 숨겨진 뜻을 파악
      • 비 언어적인 신호(표정, 손짓, 몸짓)도 힌트로 사용될 수 있다.
      • 텍스트에서 의미있는 정보를 추출하는 기술과 상황을 통계적으로 학습시킬 수 있는 다량의 데이터가 필요하다.
    • 자연어 생성(NLG)
      • 기계가 사람의 언어를 직접 생성하도록 돕는 기술
      • 자연어 처리의 하위 집합 중 하나이다.
      • NLG는 기계가 일련의 계산 결과를 사람의 언어로 표현하도록 도와줌

    2. 자연어처리 다양한 task

     

    Two minutes NLP — 33 important NLP tasks explained

    Information Retrieval, Knowledge Bases, Chatbots, Text Generation, Text-to-Data, Text Reasoning, etc.

    medium.com

    2-1. Text Classification

    • 단어, 문장, 문서 단위의 텍스트에 사전 정의된 카테고리를 할당하는 작업
      • Sentiment Analysis: 주어진 문장의 감정을 분류
      • Abusing Detection: 주어진 문장의 어뷰징(악용) 여부를 판별

    2-2. Information Retrieval and Document Ranking

    • 두 문서나 문장 간 유사도를 결정하는 작업
    • Text Similarity Task는 document DB가 있을 때 query text에 대해서 가장 유사한 문서를 반환하는 것을 목표로 하는 retrieval 또는 ranking 작업으로 확장 될 수 있다.

    2-3. Text to Text Generation

    • 텍스트를 입력으로 받아 목표를 달성하는 텍스트를 생성하는 작업
      • 소스 언어의 텍스트를 의미를 유지한채 타겟 언어의 텍스트로 번역하는 작업
      • 여러 문서들의 의미를 유지한채 더 짧은 버전의 텍스트로 요약하는 작업
      • 포괄적인 관점에서 사람이 작성한 것 같은 텍스트를 생성하는 작업

    2-4. Knowledge bases, Entities and Relations

    • 지식 기반, 의미론적인 Entity나 관계를 파악하는 자연어 처리 분야
    • 예시

    OpenAI는 2023년 5월 ChatGPT4 인공지능 봇을 공개하였다.

    OpenAI(조직) 2023년 5월(날짜) ChatGPT4(제품) 인공지능 봇(제품)

    2-5. Topics and Keywords

    • 문서 혹은 문장 내의 주제나 키워드를 파악하는 자연어 처리 분야

    2-6. Chatbots

    • 음성이나 문자를 통한 인간과의 대화를 통해서 특정한 작업을 수행하도록 제작된 컴퓨터 프로그램
    • 정해진 규칙에 맞춰서 메세지를 입력하면 발화를 출력하는 규칙 기반 챗봇부터 문맥을 입력으로 받아 적절한 답변을 생성 및 검색하는 인공지능 기반 챗봇

    2-7. Text Reasoning

    • 주어진 지식이나 상식을 활용하여 일련의 추론 작업을 수행하는 작업
    • 간단한 수학 문제들을 푼다고 생각해보면 일련의 계산 과정에 의해 답을 도출하게 되는데 그러한 일련의 계산 과정을 추론 과정이라고 한다.

    2-8. Fake News and Hate Speech Detection

    • 허위 혹은 오해의 소지가 있는 정보가 포함된 텍스트를 감지하고 필터링 하는 작업
    • 소셜 미디어 혹은 배포 중인 제품에서 발생하는 어뷰징 콘텐츠들을 필터링하기 위해 사용한다.

    2-9. Text to Data and vice-versa

    • 자연어 처리 작업 단일 모달인 텍스트 관련 작업 뿐만 아니라 입출력의 모달을 다양하게 활용할 수 있다.
    • 음성을 텍스트(STT)로 혹은 텍스트를(TTS)로 변환하는 작업이나, 텍스트를 이미지(Text to Image)로 변환하는 작업 등이 실무 혹은 학계에서 많이 논의된다.

    3. 자연어 처리 진행 순서

    3-1. 문제 정의

    • 문제에 대한 솔루션이 있어야 하고, 명확하고 구체적일 수록 알맞는 자연어 처리 기술을 찾을 수 있다.

    3-2. 데이터 수집 및 분석

    • 다양한 학습 데이터를 수집하기 위해 공개된 데이터셋, 유료 데이터셋 또는 웹 크롤링을 사용하여 수집
    • https://paperswithcode.com/datasets?mod=texts&task=question-answering
      • 다만 만들어진 데이터라서 실제 프로젝트로 적용하는데에는 거리감이 있을 것이다.
    • 웹 크롤링을 통해 데이터를 수집했다면 EDA 및 분석 작업을 통해 데이터를 철저하게 검증해야 한다. (탐색적 데이터 분석)
    • 정답 레이블이 필요하다면 수집한 데이터에 레이블을 붙여야 한다. (M-Turk, SELECTSTART)
     

    Papers with Code - Machine Learning Datasets

    269 datasets • 100516 papers with code.

    paperswithcode.com

    3-3. 데이터 전처리

    • 학습에 용이하게 데이터를 수정/보완하는 작업
    • 자연어 처리 진행 과정에서 데이터가 차지하는 비중이 매우 높기 때문에 데이터를 수집하고 전처리 하는 과정이 매우 중요하다.
    • 토큰화(Tokenization): 주어진 데이터셋에서 문장이나 문서들을 토큰이라 불리는 단위로 나뉘는 작업
    • 정제(Cleaning): 갖고 있는 데이터셋으로부터 노이즈 데이터(이상치, 편향 등)을 제거하는 작업
    • 정규화(normalization): 표현 방법이 다른 데이터들을 통합시켜서 같은 항목으로 합친다.

    3-4. 모델링

    • 자연어 처리 작업은 대부분 단어 토큰들을 결과로 표현한다.
    • 언어 모델을 사용하며 문장 혹은 단어에 확률을 할당하여 컴퓨터가 처리할 수 있도록 한다.
    • 자연어 처리 분야에는 많은 언어 모델들이 있다.
      • 어떤 언어 모델이 내가 풀고자 하는 문제에 가장 적합한지를 찾아야 한다.
    • 자연어 작업 처리에 특화된 세부적인 테그틱들이 다 다르므로 SOTA 모델들을 확인해야 한다.
     

    Papers with Code - Natural Language Processing

    Browse 607 tasks • 1818 datasets • 2102

    paperswithcode.com

    3-5. 모델 학습 및 평가

    • 데이터가 준비되어 있고 모델 구조와 학습 방법을 결정 했다면 언어 모델을 학습시킨다.
    • GPU 환경에서 진행한다.
    • 가용할 수 있는 인프라에 맞춰서 학습 parameter를 설정하고 학습을 시작하면 된다.
    • 학습 도중, 학습 종료 후 평가
      • 학습 도중: 중간 중간마다 train, validation에서의 정확도 등을 출력해서 확인하는 방법
      • 학습 종료: test data를 이용해서 평가를 했을 때 만족할 만한 결과가 나오는가
    • 정량 평가, 정성 평가

    3-6. 실무에서의 평가 진행 과정

    1. 준비된 데이터셋을 Train/Valid/Test 데이터셋으로 분할
    2. Train 데이터셋으로 모델을 학습하고, 중간 중간 Valid 데이터셋으로 학습 진행 상황 체크
    3. 문제 없이 학습이 종료 되었다면 Test 데이터셋과 추가 정량 평가 데이터셋들로 최종 모델에 대한 정량 성능 지표를 측정한다.
    4. 정성 평가를 수행하기 위해 정성 평가 데이터셋을 만들고 평가자를 모집하여 블라인드 테스트를 진행한다.
    5. 정량 평가 및 정성 평가 결과에 따라 모델 사용 여부를 결정

    4. Huggingface

    • 기계 학습을 사용하여 어플리케이션을 구축하기 위한 도구를 개발하는 회사
    • 자연어 처리 애플리케이션용으로 구축된 Transformers 라이브러리와 사용자가 기계 학습 모델 및 데이터셋을 공유 할 수 있는 플랫폼으로 유명하다
    • Huggingface에 업로드된 모델들은 기본적으로 PretrainedModel 클래스를 상속받고 있다.
    • https://huggingface.co/
     

    Hugging Face – The AI community building the future.

    The AI community building the future. Build, train and deploy state of the art models powered by the reference open source in machine learning.

    huggingface.co

    # 사용하기 위한 라이브러리 다운로드
    !pip install transformers
     
    !pip install huggingface_hub
    from transformers import AutoModel, AutoTokenizer, BertTokenizer
    from getpass import getpass
    from huggingface_hub import HfApi
    # AutoModel: 모델에 관한 정보를 처음부터 명시하지 않아도 됨
    # 예) BERT 모델을 사용하는 경우 모델의 상세정보를 확인할 필요도 없이 Model ID만으로 손쉽게 모델 구성이 가능하다.
    # 손쉽게 모델 구성이 가능하다.
    access_token = '토큰값'
    bert_model = AutoModel.from_pretrained("bert-base-cased", use_auth_token=access_token)
    bert_tokenizer = AutoTokenizer.from_pretrained('bert-base-cased')
    # 단어를 분절해주는 역할을 한다.
    print(bert_tokenizer.vocab_size)

    for i, key in enumerate(bert_tokenizer.get_vocab()):
      print(key)
      if i > 10:
        break

    sample_1 = 'welcome to the natural language class'
    sample_2 = 'welcometothenaturallanguageclass'
    tokenized_input_text = bert_tokenizer(sample_1, return_tensors='pt')
    # return_tensors: Token을 어떤 type으로 반환할지 설정(tf, pt, np)
    # tf = tensorflow
    # pt = pytorch용 tensor로 return 된다.
    # np = numpy ndarray

    for key, value in tokenized_input_text.items():
      print('{}:\n\t {}'.format(key, value))

    # 영어는 분절을 할 때 웬만하면 띄어쓰기를 기준으로 한다.
    # 101, 102는 특별한 key를 가진다(시작과 끝)
    # 나머지 6개(7236, 1106, 1103, 2379, 1846, 1705)는 각 단어에 대한 index를 나타낸다.


    # attention mask
    # 어텐션을 적용해야 하는 토큰은 1로 표시되고, 어텐션을 적용하지 않아야 하는 토큰은 0으로 표시

    tokenized_input_text = bert_tokenizer(sample_2, return_tensors='pt')
    # return_tensors: Token을 어떤 type으로 반환할지 설정(tf, pt, np)
    # tf = tensorflow
    # pt = pytorch용 tensor로 return 된다.
    # np = numpy ndarray

    for key, value in tokenized_input_text.items():
      print('{}:\n\t {}'.format(key, value))

    # sample_1과 sample_2가 결과가 다르게 나온다.
    # input_ids에서 101, 102를 제외하고는 10개 이므로 10개의 단어로 나뉘었다는 것을 알 수 있다.
    # 10681, 24226, 12602, 19514처럼 10000 이상인 경우에는 나중에 추가되었다고 생각할 수 있다.

    print(tokenized_input_text['input_ids'])
    print(tokenized_input_text.input_ids)

    print(tokenized_input_text['token_type_ids'])
    print(tokenized_input_text.token_type_ids)

    print(tokenized_input_text['attention_mask'])
    print(tokenized_input_text.attention_mask)

    tokenized_text = bert_tokenizer.tokenize(sample_1)
    print(tokenized_text)
    print(type(tokenized_text))

    input_ids = bert_tokenizer.encode(sample_1)
    print(input_ids) # 번호가 나온다.
    print(type(input_ids))
    # 여기서 숫자는 8개가 나오는데
    # 제일 앞에 있는 101은 CLS, 뒤에 있는 102는 SEP가 된다.

    decoded_ids = bert_tokenizer.decode(input_ids)
    print(decoded_ids)

    tokenized_text = bert_tokenizer.tokenize(sample_2)
    print(tokenized_text)
    print(type(tokenized_text))

    input_ids = bert_tokenizer.encode(sample_2)
    print(input_ids) # 번호가 나온다.
    print(type(input_ids))
    # 여기서 숫자는 8개가 나오는데
    # 제일 앞에 있는 101은 CLS, 뒤에 있는 102는 SEP가 된다.

    decoded_ids = bert_tokenizer.decode(input_ids)
    print(decoded_ids)

    tokenized_text = bert_tokenizer.tokenize(sample_1, add_special_tokens=False)
    print(tokenized_text)
    print(type(tokenized_text))

    input_ids = bert_tokenizer.encode(sample_1, add_special_tokens=False)
    print(input_ids) # 번호가 나온다.
    print(type(input_ids))

    decoded_ids = bert_tokenizer.decode(input_ids)
    print(decoded_ids)

    # add_special_tokens=False를 적용시키면 CLS와 SEP가 사라진다.
    # decode의 경우 애초에 input_ids가 이미 add_special_tokens=False를 적용시켰기 때문에 할 필요가 없다.

    # max_length 설정
    tokenized_text = bert_tokenizer.tokenize(
        sample_1,
        add_special_tokens=False,
        max_length=4,
        truncation=True
    )
    # 5개씩 읽어서 tokenize 시켜라
    print(tokenized_text)
    # 5일 경우
    # ['welcome', 'to', 'the', 'natural', 'language']

    # 4일 경우
    # ['welcome', 'to', 'the', 'natural']
    print(type(tokenized_text))

    input_ids = bert_tokenizer.encode(
        sample_1,
        add_special_tokens=False,
        max_length=5,
        truncation=True
    )
    # 5개씩 읽어서 tokenize 시켜라
    print(input_ids)

    decoded_ids = bert_tokenizer.decode(input_ids)
    print(decoded_ids)

    tokenized_text = bert_tokenizer.tokenize(
        sample_1,
        add_special_tokens=False,
        max_length=20,
        padding='max_length'
    )
    print(tokenized_text)

    # max_length를 20으로 했다 하더라도 add_special_tokens=False 때문에 별 차이가 없다.

    # padding='max_length'를 적용시켰다면
    # [7236, 1106, 1103, 2379, 1846, 1705, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    # 부족한 부분을 pad라는 특별한 값으로 채우게 되었다.

    input_ids = bert_tokenizer.encode(
        sample_1,
        add_special_tokens=False,
        max_length=20,
        padding='max_length'
    )
    # 5개씩 읽어서 tokenize 시켜라
    print(input_ids)
    # [7236, 1106, 1103, 2379, 1846, 1705, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

    decoded_ids = bert_tokenizer.decode(input_ids)
    print(decoded_ids)
    # welcome to the natural language class [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD]
    # decoding을 하게 되면 pad로 채워진 부분(0)은 PAD로 채워진다.

    print(bert_tokenizer.pad_token)
    print(bert_tokenizer.pad_token_id)
    # [PAD]
    # 0

    kor_text = '아직도 목요일이네'
    tokenized_text = bert_tokenizer.tokenize(
        kor_text,
        add_special_tokens=False,
        max_length=20,
        padding='max_length'
    )
    print(tokenized_text)
    # ['[UNK]', '[UNK]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]']
    # 모르는 값은 [UNK]로 대체한다.

    tokenized_input_text = bert_tokenizer(kor_text, return_tensors='pt')
    for key, value in tokenized_input_text.items():
      print('{}:\n\t {}'.format(key, value))

    # UNK는 100번이라는 것을 알 수 있다.

    tokenized_text = bert_tokenizer.tokenize(kor_text)
    print(tokenized_text)
    print(type(tokenized_text))

    input_ids = bert_tokenizer.encode(kor_text)
    print(input_ids) # 번호가 나온다.
    print(type(input_ids))

    decoded_ids = bert_tokenizer.decode(input_ids)
    print(decoded_ids)

    한국어 텍스트 모델

    multi_bert_model = AutoModel.from_pretrained('bert-base-multilingual-cased')
    multi_bert_model_tokenizer = AutoTokenizer.from_pretrained('bert-base-multilingual-cased')
    print(multi_bert_model_tokenizer.vocab_size)

    text = '한국인이 알아볼 수 있는 한국어를 사용합니다'
    tokenized_text = multi_bert_model_tokenizer.tokenize(text)
    print(tokenized_text)
    print(type(tokenized_text))

    input_ids = multi_bert_model_tokenizer.encode(text)
    print(input_ids) # 번호가 나온다.
    print(type(input_ids))

    decoded_ids = multi_bert_model_tokenizer.decode(input_ids)
    print(decoded_ids)

    unk_text = '한꾺인이 알아뽈 쑤 있뉸 한귝어를 샤용합뉘다'
    tokenized_text = multi_bert_model_tokenizer.tokenize(unk_text)
    print(tokenized_text)
    print(type(tokenized_text))

    input_ids = multi_bert_model_tokenizer.encode(unk_text)
    print(input_ids) # 번호가 나온다.
    print(type(input_ids))

    decoded_ids = multi_bert_model_tokenizer.decode(input_ids)
    print(decoded_ids)

    added_token_num = multi_bert_model_tokenizer.add_tokens(['한꾺인','알아뽈','있뉸'])
    print(added_token_num)
    # 3
    tokenized_text = multi_bert_model_tokenizer.tokenize(unk_text, add_special_tokens=False)
    print(tokenized_text)

    input_ids =multi_bert_model_tokenizer.encode(unk_text,add_special_tokens=False)
    print(input_ids)

    decoded_ids =multi_bert_model_tokenizer.decode(input_ids)
    print(decoded_ids)

    special_token_text = "[DAD]아빠[/DAD]가 방에 들어가신다"

    tokenized_text = multi_bert_model_tokenizer.tokenize(special_token_text, add_special_tokens=False)
    print(tokenized_text)

    input_ids =multi_bert_model_tokenizer.encode(special_token_text,add_special_tokens=False)
    print(input_ids)

    special_token_text = "[DAD]아빠[/DAD]가 방에 들어가신다"

    added_token_num = multi_bert_model_tokenizer.add_special_tokens({"additional_special_tokens":["[DAD]","[/DAD]"]})
    tokenized_text = multi_bert_model_tokenizer.tokenize(special_token_text, add_special_tokens=False)
    print(tokenized_text)

    input_ids =multi_bert_model_tokenizer.encode(special_token_text,add_special_tokens=False)
    print(input_ids)

    decoded_ids =multi_bert_model_tokenizer.decode(input_ids)
    print(decoded_ids)

    decoded_ids = multi_bert_model_tokenizer.decode(input_ids, skip_special_tokens=True)
    print(decoded_ids)

    print(added_token_num)
    # 2
    # 입력을 문장의 리스트로 구성하여 tokenizer의 입력으로 사용하면 출력 결과도 배열로 저장됨

    sample_list = ['아빠가 방에 들어가신다','[DAD]아빠[/DAD]가방에들어가신다']

    tokens = multi_bert_model_tokenizer(
        sample_list,
        padding = True
    )

    for i in range(2):
      print('Tokens (int) : {}'.format(tokens['input_ids'][i]))
      print('Tokens (str) : {}'.format([multi_bert_model_tokenizer.convert_ids_to_tokens(s) for s in tokens['input_ids']][i]))
      print('Tokens (attn_mask): {}'.format(tokens['attention_mask'][i]))
      print()

    # [MASK] 토큰 예측
    masked_text = "아빠가 [MASK] 들어가신다"
    tokenized_text = multi_bert_model_tokenizer.tokenize(masked_text)

    print(tokenized_text)

    from transformers import pipeline
     
    nlp_fill = pipeline('fill-mask', model = 'bert-base-multilingual-cased')
    nlp_fill(masked_text)

    댓글

Designed by Tistory.