<jupyter_start><jupyter_text>"[Do it 자연어] 1. 문장을 작은 단위로 쪼개기"- author: <NAME> - categories: [book, jupyter, Do it, natural language, GPT, BERT, token]  패키지 다운/구글 연동<jupyter_code>!pip install ratsnlp
from google.colab import drive
drive.mount('/gdrive', force_remount=True)
from Korpora import Korpora
nsmc = Korpora.load('nsmc', force_download=True)<jupyter_output>Korpora 는 다른 분들이 연구 목적으로 공유해주신 말뭉치들을
    손쉽게 다운로드, 사용할 수 있는 기능만을 제공합니다.

    말뭉치들을 공유해 주신 분들에게 감사드리며, 각 말뭉치 별 설명과 라이센스를 공유 드립니다.
    해당 말뭉치에 대해 자세히 알고 싶으신 분은 아래의 description 을 참고,
    해당 말뭉치를 연구/상용의 목적으로 이용하실 때에는 아래의 라이센스를 참고해 주시기 바랍니다.

    # Description
    Author : <EMAIL>
    Repository : https://github.com/e9t/nsmc
    References : www.lucypark.kr/docs/2015-pyconkr/#39

    Naver sentiment movie corpus v1.0
    This is a movie review dataset in the Korean language.
    Reviews were scraped from Naver Movies.

    The dataset construction is based on the method noted in
    [Large movie review dataset][^1] from Maas et al., 2011.

    [^1]: http://ai.stanford.edu/~amaas/data/sentiment/

    # License
    CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
    Details in https://creativecommons.org/publicdomain/zero/1.0/<jupyter_text>NSMC는 네이버 영화 리뷰자료 입니다.<jupyter_code>import os
def write_lines(path, lines):
    with open(path, 'w', encoding = 'utf-8') as f:
        for line in lines:
            f.write(f'{line}\n')

write_lines('/root/train.txt', nsmc.train.get_all_texts())
write_lines('/root/test.txt', nsmc.test.get_all_texts())<jupyter_output><empty_output><jupyter_text>영화 리뷰들을 순수 텍스트 형태로 저장했습니다.<jupyter_code>!head /root/train.txt<jupyter_output>아 더빙.. 진짜 짜증나네요 목소리
흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나
너무재밓었다그래서보는것을추천한다
교도소 이야기구먼 ..솔직히 재미는 없다..평점 조정
사이몬페그의 익살스런 연기가 돋보였던 영화!스파이더맨에서 늙어보이기만 했던 커스틴 던스트가 너무나도 이뻐보였다
막 걸음마 뗀 3세부터 초등학교 1학년생인 8살용영화.ㅋㅋㅋ...별반개도 아까움.
원작의 긴장감을 제대로 살려내지못했다.
별 반개도 아깝다 욕나온다 이응경 길용우 연기생활이몇년인지..정말 발로해도 그것보단 낫겟다 납치.감금만반복반복..이드라마는 가족도없다 연기못하는사람만모엿네
액션이 없는데도 재미 있는 몇안되는 영화
왜케 평점이 낮은건데? 꽤 볼만한데.. 헐리우드식 화려함에만 너무 길들여져 있나?<jupyter_text>리뷰 앞 내용입니다.  GPT 토크나이저 구축<jupyter_code>import os
os.makedirs('/gdrive/My Drive/nlpbook/bbpe', exist_ok= True)<jupyter_output><empty_output><jupyter_text>저장용 디렉터리를 만들었습니다.<jupyter_code>from tokenizers import ByteLevelBPETokenizer
bytebpe_tokenizer = ByteLevelBPETokenizer()
bytebpe_tokenizer.train(
    files=["/root/train.txt", "/root/test.txt"], # 학습 말뭉치를 리스트 형태로
    vocab_size=10000, # 어휘 집합 크기 조절
    special_tokens=["[PAD]"] # 특수 토큰 추가
)
bytebpe_tokenizer.save_model("/gdrive/My Drive/nlpbook/bbpe")<jupyter_output><empty_output><jupyter_text>코드가 실행되면 vocab.json, merges.txt가 생성됩니다.전자는 바이트 수준 BPE 어휘집합, 후자는 바이그램 쌍과 병합우선순위가 있습니다.<jupyter_code>!cat /gdrive/My\ Drive/nlpbook/bbpe/vocab.json
!head /gdrive/My\ Drive/nlpbook/bbpe/merges.txt<jupyter_output>#version: 0.2 - Trained by `huggingface/tokenizers`
Ġ ì
Ġ ë
ì Ŀ
ë ĭ
í ķ
ê °
. .
ìĿ ´
ëĭ ¤<jupyter_text>BPE 어휘집합과 바이그램 쌍/병합우선순위 일부를 출력했습니다.  BERT 토크나이저 구축<jupyter_code>import os
os.makedirs('/gdrive/My Drive/nlpbook/wordpiece', exist_ok= True)
from tokenizers import BertWordPieceTokenizer
wordpiece_tokenizer = BertWordPieceTokenizer(lowercase = False)
wordpiece_tokenizer.train(
    files=['/root/train.txt', '/root/test.txt'],
    vocab_size = 10000,
)
wordpiece_tokenizer.save_model('/gdrive/My Drive/nlpbook/wordpiece')<jupyter_output><empty_output><jupyter_text>워드피스 방식입니다. BPE와 차이점은 단순히 빈도를 기준으로 병합하는 것이 아니라 병합했을 때 말뭉치의 우도를 높이는 쌍을 병합합니다.<jupyter_code>!head /gdrive/My\ Drive/nlpbook/wordpiece/vocab.txt<jupyter_output>[PAD]
[UNK]
[CLS]
[SEP]
[MASK]
!
"
%
&
'<jupyter_text>워드피스 수행 결과의 일부 입니다.  토큰화하기 - GPT<jupyter_code>from transformers import GPT2Tokenizer
tokenizer_gpt = GPT2Tokenizer.from_pretrained('/gdrive/My Drive/nlpbook/bbpe')
tokenizer_gpt.pad_token = '[PAD]'
sentences = [
    "아 더빙.. 진짜 짜증나네요 목소리",
    "흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나",
    "별루 였다..",
]
tokenized_sentences = [tokenizer_gpt.tokenize(sentence) for sentence in sentences]
tokenized_sentences<jupyter_output><empty_output><jupyter_text>GPT 토크나이저로 토큰화 해봤는데요. 알수 없는 언어들이 출력됩니다.이는 GPT 모델은 바이트 기준 BPE를 적용하기 때문입니다.<jupyter_code>batch_inputs = tokenizer_gpt(
    sentences,
    padding = 'max_length', # 문장 최대 길이에 맞춰 패딩
    max_length = 12, # 문장 토큰 기준 최대 길이
    truncation = True, # 문장 잘림 허용 옵션
)
batch_inputs.keys()<jupyter_output><empty_output><jupyter_text>실제 모델 입력값 입니다. 결과는 input_ids, attention_mask 두개로 나옵니다.<jupyter_code>batch_inputs['input_ids']<jupyter_output><empty_output><jupyter_text>input_ids는 토큰화 결과를 가지고 각 토큰을 인덱스로 바꾼 것 입니다.여기서 모든 문장의 길이가 12로 맞춰줬는데 앞선 max_length 인자에 12를 넣었기 때문입니다.[PAD] 토큰은 인덱스 0이며 더미 토큰입니다. 즉 위 값 중 0이 있으면 문장이 짧아 토큰 길이를 맞춰준 것으로 생각할 수 있습니다.문장 잘림을 허용하는 옵션 때문에 문장2는 토큰길이가 원래 15였는데 12안에 들어왔습니다.<jupyter_code>batch_inputs['attention_mask']<jupyter_output><empty_output><jupyter_text>attention_mask는 일반 토큰이 자리한 곳(1)과 패딩 토큰이 자리한 곳(0)을 구분해주는 장치입니다.  토큰화하기 - BERT<jupyter_code>from transformers import BertTokenizer
tokenizer_bert = BertTokenizer.from_pretrained(
    '/gdrive/My Drive/nlpbook/wordpiece',
    do_lower_case = False,
)
sentences = [
    "아 더빙.. 진짜 짜증나네요 목소리",
    "흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나",
    "별루 였다..",
]
tokenized_sentences = [tokenizer_bert.tokenize(sentence) for sentence in sentences]
tokenized_sentences<jupyter_output><empty_output><jupyter_text>토큰 일부에 있는 은 해당 토큰이 어절의 시작이 아님을 나타냅니다.<jupyter_code>batch_inputs = tokenizer_bert(
    sentences,
    padding = 'max_length',
    max_length = 12,
    truncation = True,
)
batch_inputs.keys()<jupyter_output><empty_output><jupyter_text>코드 적합시 input_ids, token_type_ids, attention_mask 총 3개의 출력물이 나옵니다.<jupyter_code>batch_inputs['input_ids']<jupyter_output><empty_output><jupyter_text>모든 문장 시작시 2, 끝날 때 3이 붙은 것을 알 수 있습니다.여기서 2는 [CLS], 3은 [SEP]라는 토큰에 대응하는 인덱스입니다.<jupyter_code>batch_inputs['attention_mask']<jupyter_output><empty_output><jupyter_text>attention_mask은 GPT와 마찬가지로 일반 토큰이 차지한 부분을 구분하는 역할을 합니다.<jupyter_code>batch_inputs['token_type_ids']<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10911532650663086, 'fraction_numerical': 0.01074366291757596, 'mean_word_length': 4.706896551724138, 'pattern_counts': {'":': 0, '<': 67, '<?xml version=': 0, '>': 67, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '17', 'dir': 'jupyter-structured-clean-dedup', 'id': '635782', 'license': 'Apache-2.0', 'n_tokens_mistral': 3520, 'n_tokens_neox': 4214, 'n_words': 588, 'path': '_notebooks/2021-12-20-Do_natural_language1.ipynb', 'repo_name': 'KSY1526/myblog', 'size': '5968'}