[๐ค ๊ฐ์ข 6.3] "๋น ๋ฅธ(fast)" ํ ํฌ๋์ด์ ์ ํน๋ณํ ๋ฅ๋ ฅ
์ด ์น์
์์๋ ๐คTransformers์์ ํ ํฌ๋์ด์ ์ ๊ธฐ๋ฅ์ ์์ธํ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ง๊ธ๊น์ง๋ ์
๋ ฅ์ ํ ํฐํํ๊ฑฐ๋ ํ ํฐ ์์ด๋๋ฅผ ๋ค์ ํ
์คํธ๋ก ๋์ฝ๋ฉํ๋๋ฐ๋ง ์ฌ์ฉํ์ง๋ง ํ ํฌ๋์ด์ , ํนํ ๐คTokenizers ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ง์ํ๋ ํ ํฌ๋์ด์ ๋ ํจ์ฌ ๋ ๋ง์ ์์
์ ์ํํ ์ ์์ต๋๋ค. ์ด๋ฌํ ์ถ๊ฐ ๊ธฐ๋ฅ์ ์ค๋ช
ํ๊ธฐ ์ํด 1์ฅ์์ ์ฒ์ ์ ํ token-classification
(NER) ๋ฐ question-answering
ํ์ดํ๋ผ์ธ์ ๊ฒฐ๊ณผ๋ฅผ ์ฌํํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ด
๋๋ค.
๋ค์ ๋ ผ์์์ ์ฐ๋ฆฌ๋ ์ข ์ข "๋๋ฆฐ(slow)" ํ ํฌ๋์ด์ ์ "๋น ๋ฅธ(fast)" ํ ํฌ๋์ด์ ๋ฅผ ๊ตฌ๋ถํด์ ์ค๋ช ํฉ๋๋ค. "๋๋ฆฐ(slow)" ํ ํฌ๋์ด์ ๋ ๐คTransformers ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ด๋ถ์์ Python์ผ๋ก ์์ฑ๋ ๊ฒ์ด๊ณ , ๋น ๋ฅธ ๋ฒ์ ์ Rust๋ก ์์ฑ๋์ด ๐คTokenizers์์ ์ ๊ณตํ๋ ๊ฒ์ ๋๋ค. ์ฝ๋ฌผ ๊ฒํ (drug review) ๋ฐ์ดํฐ์ ์ ํ ํฐํํ๋๋ฐ ๋น ๋ฅธ ํน์ ๋๋ฆฐ ํ ํฌ๋์ด์ ์ ์คํ ์๋๋ฅผ ๋ณด๊ณ ํ 5์ฅ์ ํ๋ฅผ ๊ธฐ์ตํ๋ค๋ฉด ์ฐ๋ฆฌ๊ฐ ์ด๋ฅผ ๋น ๋ฅด๊ณ ๋๋ฆฐ ๊ฒ์ผ๋ก ๋ถ๋ฅด๋ ์ด์ ๋ฅผ ์ ์ ์์ ๊ฒ์ ๋๋ค.
๋จ์ผ ๋ฌธ์ฅ์ ํ ํฐํํ ๋ ๋์ผํ ํ ํฌ๋์ด์ ์ ๋๋ฆฐ ๋ฒ์ ๊ณผ ๋น ๋ฅธ ๋ฒ์ ๊ฐ์ ์๋ ์ฐจ์ด๊ฐ ํญ์ ๋๋ ๊ฒ์ ์๋๋๋ค. ์ฌ์ค, ๋น ๋ฅธ ๋ฒ์ ์ ์ค์ ๋ก ๋ ๋๋ฆด ์ ์์ต๋๋ค! ๋ง์ ํ ์คํธ๋ฅผ ๋์์ ํ ํฐํํ ๋๋ง ์ฐจ์ด๋ฅผ ๋ช ํํ๊ฒ ์ ์ ์์ต๋๋ค.
๋ฐฐ์น ์ธ์ฝ๋ฉ (Batch encoding)
ํ ํฌ๋์ด์ ์ ์ถ๋ ฅ์ ๋จ์ํ Python ๋์
๋๋ฆฌ๊ฐ ์๋๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ป๋ ๊ฒ์ ์ค์ ๋ก ํน๋ณํ BatchEncoding
๊ฐ์ฒด์
๋๋ค. ์ด๊ฒ์ ๋์
๋๋ฆฌ์ ํ์ ํด๋์ค์ด์ง๋ง(์ด๊ฒ์ด ์ด์ ์ ์ฐ๋ฆฌ๊ฐ ๋ฌธ์ ์์ด ํด๋น ๊ฒฐ๊ณผ๋ฅผ ์์ธํํ ์ ์์๋ ์ด์ ์
๋๋ค), ๋น ๋ฅธ ํ ํฌ๋์ด์ ์์ ์ฃผ๋ก ์ฌ์ฉํ๋ ์ถ๊ฐ ๋ฉ์๋๊ฐ ์์ต๋๋ค.
๋ณ๋ ฌํ(parallelization) ๊ธฐ๋ฅ ์ธ์๋, ๋น ๋ฅธ ํ ํฌ๋์ด์ ์ ์ฃผ์ ๊ธฐ๋ฅ์ ์ต์ข ํ ํฐ์ด ์๋ณธ ํ ์คํธ์์ ์ด๋์ ์์นํ๋์ง ๋ฒ์(span)๋ฅผ ํญ์ ์ถ์ ํ๋ค๋ ๊ฒ์ ๋๋ค. ์ด๋ฅผ ์คํ์ ๋งคํ(offset mapping) ์ด๋ผ๊ณ ํฉ๋๋ค. ์ด๊ฒ์ ์ฐจ๋ก๋๋ก ๊ฐ ๋จ์ด๋ฅผ ์์ฑ๋ ํ ํฐ์ ๋งคํํ๊ฑฐ๋ ์๋ณธ ํ ์คํธ์ ๊ฐ ๋ฌธ์๋ฅผ ๋ด๋ถ ํ ํฐ์ ๋งคํํ๊ฑฐ๋ ๊ทธ ๋ฐ๋๋ก ๋งคํํ๋ ๊ฒ๊ณผ ๊ฐ์ ๊ธฐ๋ฅ๋ค์ ๋๋ค.
์๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
example = "My name is Sylvain and I work at Hugging Face in Brooklyn."
encoding = tokenizer(example)
print(type(encoding))
์์์ ์ธ๊ธํ๋ฏ์ด, ํ ํฌ๋์ด์ ์ ์ถ๋ ฅ์์ BatchEncoding
๊ฐ์ฒด๋ฅผ ์ป์ต๋๋ค. AutoTokenizer
ํด๋์ค๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋น ๋ฅธ ํ ํฌ๋์ด์ ๋ฅผ ์ ํํ๋ฏ๋ก ์ด BatchEncoding
๊ฐ์ฒด๊ฐ ์ ๊ณตํ๋ ์ถ๊ฐ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ํ ํฌ๋์ด์ ๊ฐ ๋น ๋ฅธ์ง ๋๋ฆฐ์ง ํ์ธํ๋ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ์ฐ์ , ํ ํฌ๋์ด์ ์ is_fast
์์ฑ์ ํ์ธํ ์ ์์ต๋๋ค:
tokenizer.is_fast
๋๋ encoding
์ is_fast
์์ฑ์ ํ์ธํ๋ ๋ฐฉ๋ฒ๋ ์์ต๋๋ค:
encoding.is_fast
๋น ๋ฅธ ํ ํฌ๋์ด์ ๋ฅผ ๊ฐ์ง๊ณ ์ฐ๋ฆฌ๊ฐ ๋ฌด์์ ํ ์ ์๋์ง ๋ด ์๋ค. ์ฒซ์งธ, ํ ํฐ ์์ด๋๋ฅผ ๋ค์ ํ ํฐ์ผ๋ก ๋ณํํ์ง ์๊ณ ๋ ํ ํฐ์ ์ก์ธ์คํ ์ ์์ต๋๋ค:
encoding.tokens()
์ด ๊ฒฝ์ฐ ์ธ๋ฑ์ค 5์ ํ ํฐ์ ##yl
์ด๋ฉฐ, ์ด๋ ์๋ ๋ฌธ์ฅ์์ "Sylvain"์ด๋ผ๋ ๋จ์ด์ ์ผ๋ถ์
๋๋ค. ๋ํ word_ids()
๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ํ ํฐ์ด ์ ๋๋ ํด๋น ๋จ์ด์ ์ธ๋ฑ์ค๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค:
encoding.word_ids()
ํ ํฌ๋์ด์ ์ ํน์ ํ ํฐ [CLS] ๋ฐ [SEP]๊ฐ None
์ผ๋ก ๋งคํ๋ ๋ค์, ๊ฐ๋ณ ํ ํฐ๋ค์ด ํด๋น ํ ํฐ์ด ์ ๋ํ ๋จ์ด์ ๋งคํ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ์ด ๋ฉ์๋๋ ๋ ๊ฐ์ ํ ํฐ์ด ๊ฐ์ ๋จ์ด์ ์๋์ง ์๋๋ฉด ํ ํฐ์ด ๋จ์ด์ ์์ ๋ถ๋ถ์ ์๋์ง ํ์ธํ๋๋ฐ ํนํ ์ ์ฉํฉ๋๋ค. ์ด๋ฅผ ์ํด ##
์ ๋์ฌ๋ฅผ ์ฌ์ฉํ ์ ์์ง๋ง ์ด๋ BERT์ ๊ฐ์ ์ ํ์ ํ ํฌ๋์ด์ ์์๋ง ์๋ํฉ๋๋ค. ์ด ๋ฐฉ๋ฒ์ ์๋๊ฐ ๋น ๋ฅธ ๋ชจ๋ ์ ํ์ ํ ํฌ๋์ด์ ์์ ์ ํจํฉ๋๋ค. ๋ค์ ์ฅ์์๋ ์ด ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ ๊ฐ์ฒด๋ช
์ธ์(NER) ๋ฐ ํ์ฌ(POS) ํ๊น
๊ณผ ๊ฐ์ ์์
์์ ๊ฐ ๋จ์ด์ ํด๋นํ๋ ๋ ์ด๋ธ์ ํ ํฐ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ณผ ๊ฒ์
๋๋ค. ๋ง์คํฌ ์ธ์ด ๋ชจ๋ธ๋ง(masked language modeling), ์ฆ ์ ์ฒด ๋จ์ด ๋ง์คํน(whole word masking)์ด๋ผ๊ณ ํ๋ ๊ธฐ๋ฒ์์, ๋์ผํ ๋จ์ด์์ ๋ถ๋ฆฌ๋ ๋ชจ๋ ํ ํฐ๋ค์ ๋ง์คํนํ๋ ๋ฐ ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
๋จ์ด๊ฐ ๋ฌด์์ธ์ง์ ๋ํ ๊ฐ๋ ์ ๋ณต์กํฉ๋๋ค. ์๋ฅผ ๋ค์ด, "I'll"("I will"์ ์ถ์ฝํ)์ ํ๋์ ๋จ์ด์ผ๊น์? ์๋๋ฉด ๋๊ฐ์ผ๊น์? ์ด๋ ์ค์ ๋ก ํ ํฌ๋์ด์ ์ ์ ์ฉ๋๋ ์ฌ์ ํ ํฐํ(pre-tokenization) ์์ ์ ๋ฐ๋ผ ๋ค๋ฆ ๋๋ค. ์ผ๋ถ ํ ํฌ๋์ด์ ๋ ๊ณต๋ฐฑ ๊ธฐ์ค์ผ๋ก ๋ถํ ํ๋ฏ๋ก ์ด๋ฅผ ํ ๋จ์ด๋ก ๊ฐ์ฃผํฉ๋๋ค. ๋ ๋ค๋ฅธ ํ ํฌ๋์ด์ ๋ค์ ๊ณต๋ฐฑ ์์ ๊ตฌ๋์ ์ ์ฌ์ฉํ๋ฏ๋ก ๋ ๋จ์ด๋ก ๊ฐ์ฃผํฉ๋๋ค.
๋ง์ฐฌ๊ฐ์ง๋ก, ํ ํฐ์ ๊ฐ์ ธ์จ ๋ฌธ์ฅ์ ํด๋น ํ ํฐ์ ๋งคํํ๋๋ฐ ์ฌ์ฉํ ์ ์๋ sentence_ids()
๋ฉ์๋๊ฐ ์์ต๋๋ค(์ด ๊ฒฝ์ฐ ํ ํฌ๋์ด์ ์์ ๋ฐํ๋ token_type_ids
๊ฐ ๋์ผํ ์ ๋ณด๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค).
๋ง์ง๋ง์ผ๋ก word_to_chars()
๋๋ token_to_chars()
๋ฐ char_to_word()
๋๋ char_to_token()
๋ฉ์๋๋ฅผ ํตํด ๋ชจ๋ ๋จ์ด ๋๋ ํ ํฐ์ ์๋ณธ ํ
์คํธ์ ๋ฌธ์์ ๋งคํํ ์ ์์ผ๋ฉฐ ๊ทธ ๋ฐ๋๋ก๋ ๋งคํํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, word_ids()
๋ฉ์๋๋ ##yl
์ด ์ธ๋ฑ์ค 3์ ์๋ ๋จ์ด์ ์ผ๋ถ๋ผ๊ณ ์๋ ค์คฌ์ง๋ง ์ ํํ ๋ฌธ์ฅ ๋ด์์ ์ด๋ค ๋จ์ด์ ํด๋นํ๋ ๊ฑธ๊น์? ๋ค์๊ณผ ๊ฐ์ด ์ ์ ์์ต๋๋ค:
start, end = encoding.word_to_chars(3)
example[start:end]
์ด์ ์ ์ธ๊ธํ๋ฏ์ด ์ด ๋ชจ๋ ๊ฒ์ ๋น ๋ฅธ ํ ํฌ๋์ด์ ๊ฐ ์คํ์
(offset) ๋ชฉ๋ก์์ ๊ฐ ํ ํฐ์ด ๊ฐ์ ธ์จ ํ
์คํธ ๋ฒ์(span)๋ฅผ ์ถ์ ํ๋ค๋ ์ฌ์ค์ ๊ธฐ๋ฐํ์ฌ ๊ตฌ๋๋ฉ๋๋ค. ํ์ฉ ๋ฐฉ๋ฒ์ ์ค๋ช
ํ๊ธฐ ์ํด ๋ค์์ผ๋ก token-classification
ํ์ดํ๋ผ์ธ์ ๊ฒฐ๊ณผ๋ฅผ ์๋์ผ๋ก ๋ณต์ ํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด๊ฒ ์ต๋๋ค.
token-classification
ํ์ดํ๋ผ์ธ์ ๋ด๋ถ ๋์
1์ฅ์์ ์ฐ๋ฆฌ๋ ๐คTransformers์ pipeline()
ํจ์๋ฅผ ์ฌ์ฉํ์ฌ, ํ
์คํธ์ ์ด๋ ๋ถ๋ถ์ด ์ฌ๋(person), ์์น(location) ๋๋ ์กฐ์ง(organization)๊ณผ ๊ฐ์ ์ํฐํฐ(entities)์ ํด๋นํ๋์ง ์๋ณํ๋ ์์
์ธ NER์ ์ฒ์์ผ๋ก ์ดํด๋ดค์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ 2์ฅ์์ ํ์ดํ๋ผ์ธ์ด ์์ ํ
์คํธ๋ฅผ ๋์์ผ๋ก ์์ธกํ๋๋ฐ ํ์ํ ์ธ ๋จ๊ณ ์ฆ, ํ ํฐํ(tokenization), ๋ชจ๋ธ์ ํตํ ์
๋ ฅ ์ ๋ฌ, ํ์ฒ๋ฆฌ(post-processing)๋ฅผ ์ด๋ป๊ฒ ๊ทธ๋ฃนํํ๋์ง๋ฅผ ๋ณด์์ต๋๋ค. token-classification
ํ์ดํ๋ผ์ธ์ ์ฒ์ ๋ ๋จ๊ณ๋ ๋ค๋ฅธ ํ์ดํ๋ผ์ธ๊ณผ ๋์ผํ์ง๋ง ํ์ฒ๋ฆฌ(post-processing)๋ ์กฐ๊ธ ๋ ๋ณต์กํฉ๋๋ค. ํ๋ฒ ์ดํด๋ด
์๋ค!
ํ์ดํ๋ผ์ธ์ผ๋ก ๊ธฐ๋ณธ ์คํ ๊ฒฐ๊ณผ ๋์ถํ๊ธฐ
๋จผ์ , ์์์
์ผ๋ก ๋น๊ตํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๋๋ก token-classification
ํ์ดํ๋ผ์ธ์ ๊ตฌํํด ๋ณด๊ฒ ์ต๋๋ค. ์ฌ์ฉ๋๋ ๋ชจ๋ธ์ dbmdz/bert-large-cased-finetuned-conll03-english์
๋๋ค. ์ด ๋ชจ๋ธ์ ๋ฌธ์ฅ์ ๋ํด NER๋ฅผ ์ํํฉ๋๋ค:
from transformers import pipeline
token_classifier = pipeline("token-classification")
token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.")
๋ชจ๋ธ์ "Sylvain"์์ ๋ถ๋ฆฌ๋ ๊ฐ ํ ํฐ๋ค์ ๋ชจ๋ ์ฌ๋(person)์ผ๋ก, "Hugging Face"์์ ๋ถ๋ฆฌ๋ ๊ฐ ํ ํฐ๋ค์ ๋ชจ๋ ์กฐ์ง(organization)์ผ๋ก, "Brooklyn" ํ ํฐ์ ์์น(location)๋ก ์ฌ๋ฐ๋ฅด๊ฒ ์๋ณํ์ต๋๋ค. ํ์ดํ๋ผ์ธ์ ๋์ผํ ์ํฐํฐ์ ํด๋นํ๋ ํ ํฐ์ ๊ทธ๋ฃนํํ๋๋ก ์์ฒญํ ์๋ ์์ต๋๋ค:
from transformers import pipeline
token_classifier = pipeline("token-classification", aggregation_strategy="simple")
token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.")
aggregation_strategy
๋ฅผ ์์ ๊ฐ์ด ์ง์ ํ๋ฉด ํ ํฐ๋ค์ด ํ๋๋ก ํฉ์ณ์ง ์ํฐํฐ์ ๋ํด ์๋กญ๊ฒ ๊ณ์ฐ๋ ์ค์ฝ์ด๋ฅผ ์ ์ํฉ๋๋ค. "simple
"์ ๊ฒฝ์ฐ ์ค์ฝ์ด๋ ํด๋น ๊ฐ์ฒด๋ช
๋ด์ ๊ฐ ํ ํฐ์ ๋ํ ์ค์ฝ์ด์ ํ๊ท ์
๋๋ค. ์๋ฅผ ๋ค์ด, "Sylvain"์ ์ค์ฝ์ด๋ ์ด์ ์์์ S, ##yl, ##va ๋ฐ ##in ํ ํฐ์ ๋ํด ๊ณ์ฐ๋ ์ค์ฝ์ด์ ํ๊ท ์
๋๋ค. ์ฌ์ฉ ๊ฐ๋ฅํ ๋ค๋ฅธ ์ง์ ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
-
"
first
", ์ฌ๊ธฐ์ ๊ฐ ๊ฐ์ฒด๋ช ์ ์ค์ฝ์ด๋ ํด๋น ๊ฐ์ฒด๋ช ์ ์ฒซ ๋ฒ์งธ ํ ํฐ์ ์ค์ฝ์ด์ ๋๋ค(๋ฐ๋ผ์ "Sylvain"์ ๊ฒฝ์ฐ ํ ํฐ S์ ์ ์์ธ 0.993828์ด ๋จ). -
"
max
", ์ฌ๊ธฐ์ ๊ฐ ์ํฐํฐ์ ์ค์ฝ์ด๋ ํด๋น ์ํฐํฐ๋ด์ ํ ํฐ๋ค ์ค์ ์ต๋๊ฐ ์ค์ฝ์ด์ ๋๋ค("Hugging Face"์ ๊ฒฝ์ฐ "Face"์ ์ ์๋ 0.98879766์ด ๋จ). -
"
average
", ์ฌ๊ธฐ์ ๊ฐ ํญ๋ชฉ์ ์ค์ฝ์ด๋ ํด๋น ํญ๋ชฉ์ ๊ตฌ์ฑํ๋ ๋จ์ด(ํ ํฐ์ด ์๋๋๋ค) ์ค์ฝ์ด์ ํ๊ท ์ ๋๋ค(๋ฐ๋ผ์ "Sylvain"์ ๊ฒฝ์ฐ "simple
" ์ง์ ์์ ์ฐจ์ด๊ฐ ์์ง๋ง "Hugging Face"์ ์ ์๋ 0.9819์ด๋ฉฐ "Hugging"์ 0.975์ด๊ณ "Face"๋ 0.98879์ ๋๋ค).
์ด์ pipeline()
ํจ์๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์ด๋ฌํ ๊ฒฐ๊ณผ๋ฅผ ์ป๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค!
์ ๋ ฅ(inputs)์์ ์์ธก(predictions)๊น์ง
๋จผ์ ์
๋ ฅ์ ํ ํฐํํ๊ณ ๋ชจ๋ธ์ ํตํด ์ ๋ฌํด์ผ ํฉ๋๋ค. ์ด๋ 2์ฅ์์ ์ค๋ช
ํ ๋ด์ฉ๊ณผ ๋์ผํ๊ฒ ์ํ๋ฉ๋๋ค. AutoXxx
ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ํ ํฌ๋์ด์ ์ ๋ชจ๋ธ์ ์ธ์คํด์คํํ ํ์ ์ด๋ฅผ ์์ ์์ ์ฌ์ฉํฉ๋๋ค:
from transformers import AutoTokenizer, AutoModelForTokenClassification
model_checkpoint = "dbmdz/bert-large-cased-finetuned-conll03-english"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
model = AutoModelForTokenClassification.from_pretrained(model_checkpoint)
example = "My name is Sylvain and I work at Hugging Face in Brooklyn."
inputs = tokenizer(example, return_tensors="pt")
outputs = model(**inputs)
์ฌ๊ธฐ์์ AutoModelForTokenClassification
์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ์
๋ ฅ ์ํ์ค์ ๊ฐ ํ ํฐ์ ๋ํด ํ๋์ logits
์ธํธ๋ฅผ ์ป์ต๋๋ค:
print(inputs["input_ids"].shape)
print(outputs.logits.shape)
19๊ฐ์ ํ ํฐ์ผ๋ก ๊ตฌ์ฑ๋ 1๊ฐ์ ์ํ์ค๊ฐ ์๋ ๋ฐฐ์น(batch)๊ฐ ์๊ณ ๋ชจ๋ธ์๋ 9๊ฐ์ ์๋ก ๋ค๋ฅธ ๋ ์ด๋ธ์ด ์กด์ฌํ๋ฏ๋ก ๋ชจ๋ธ์ ์ถ๋ ฅ์ 1 x 19 x 9์ ๋ชจ์์ ๊ฐ์ต๋๋ค. text-classification
ํ์ดํ๋ผ์ธ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก softmax
ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น logits
์ ํ๋ฅ ๋ก ๋ณํํ๊ณ argmax
๋ฅผ ์ฌ์ฉํ์ฌ ์์ธก ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค(softmax
๋ ์์๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ธฐ ๋๋ฌธ์ logits
์ ๋ํด์ argmax
๋ฅผ ์ทจํ ์ ์์ต๋๋ค):
import torch
probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1)[0].tolist()
predictions = outputs.logits.argmax(dim=-1)[0].tolist()
print(probabilities)
print(predictions)
model.config.id2label
์์ฑ์๋ ์์ธก ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ๋๋ฐ ์ฌ์ฉํ ์ ์๋ ๋ ์ด๋ธ์ ๋ํ ์ธ๋ฑ์ค ๋งคํ์ด ํฌํจ๋์ด ์์ต๋๋ค:
model.config.id2label
์์์ ๋ณด๋ฏ์ด ์ด 9๊ฐ์ ๋ ์ด๋ธ์ด ์์ต๋๋ค. O๋ ๊ฐ์ฒด๋ช ์ ํฌํจ๋์ง ์๋ ํ ํฐ์ ๋ํ ๋ ์ด๋ธ("outside"๋ฅผ ๋ํ๋)์ด๊ณ ๊ฐ ๊ฐ์ฒด๋ช ์ ํ, ์ฆ ๊ธฐํ(miscellaneous), ์ธ๋ช (person), ๊ธฐ๊ด๋ช (organization), ์ง๋ช (location) ๊ฐ๊ฐ์ ๋ํด ๋ ๊ฐ์ ๋ ์ด๋ธ์ด ์์ต๋๋ค. ๋ ์ด๋ธ B-XXX๋ ํ ํฐ์ด ๊ฐ์ฒด๋ช XXX์ ์์ ๋ถ๋ถ์ ์์์ ๋ํ๋ด๊ณ , ๋ ์ด๋ธ I-XXX๋ ํ ํฐ์ด ๊ฐ์ฒด๋ช XXX์ ๋ด๋ถ์ ์์์ ๋ํ๋ ๋๋ค. ์๋ฅผ ๋ค์ด, ์ด์ ์์์์ ์ฐ๋ฆฌ๋ ๋ชจ๋ธ์ด ํ ํฐ "S"๋ฅผ B-PER(์ธ๋ช ๊ฐ์ฒด๋ช ์ ์์)์ผ๋ก ๋ถ๋ฅํ๊ณ "##yl", "##va" ๋ฐ "##in" ํ ํฐ์ I-PER(์ธ๋ช ๊ฐ์ฒด๋ช ์ ๋ด๋ถ)๋ก ๋ถ๋ฅํ๊ธฐ๋ฅผ ๊ธฐ๋ํ์ ์๋ ์์ต๋๋ค.
๊ทธ๋ฐ๋ฐ ์ ๊ฒฐ๊ณผ์์ ๋ณด๋ ๋ฐ์ ๊ฐ์ด 4๊ฐ ํ ํฐ ๋ชจ๋์ I-PER์ด๋ผ๋ ๋ ์ด๋ธ์ ๋ถ์ฌํ๊ธฐ ๋๋ฌธ์ ์์ธก์ ์ค๋ฅ๊ฐ ์๋ค๊ณ ์๊ฐํ ์ ์์ง๋ง ๊ทธ๋ ์ง ์์ ์๋ ์์ต๋๋ค. ์ค์ ๋ก ์ด๋ฌํ B- ๋ฐ I- ๋ ์ด๋ธ ํ๊ธฐ ๋ฐฉ์์๋ IOB1 ๋ฐ IOB2์ ๋ ๊ฐ์ง ํ์์ด ์์ต๋๋ค. IOB2 ํ์(์๋ ๊ทธ๋ฆผ์์ ๋ถํ์ ํ๊ทธ)์ ์ฐ๋ฆฌ๊ฐ ๋์ ํ ํ์์ธ ๋ฐ๋ฉด, IOB1 ํ์(ํ๋์ ํ๊ทธ)์์ B-๋ก ์์ํ๋ ๋ ์ด๋ธ์ ๋์ผํ ์ ํ์ ์ธ์ ํ ๋ ์ํฐํฐ๋ฅผ ๊ตฌ๋ถํ๋ ๋ฐ๋ง ์ฌ์ฉ๋ฉ๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ๋ ๋ชจ๋ธ์ IOB1 ํ์์ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ์ ์์ ๋ฏธ์ธ ์กฐ์ ๋์์ผ๋ฏ๋ก "S" ํ ํฐ์ ๋ ์ด๋ธ I-PER์ ํ ๋นํฉ๋๋ค.
์ด ๋งต์ ์ฌ์ฉํ์ฌ token-classification
ํ์ดํ๋ผ์ธ์ ๊ฒฐ๊ณผ๋ฅผ (๊ฑฐ์ ์์ ํ) ์ฌํํ ์ค๋น๊ฐ ๋์์ต๋๋ค. O๋ก ๋ถ๋ฅ๋์ง ์์ ๊ฐ ํ ํฐ์ ์ ์์ ๋ ์ด๋ธ๋ง ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค:
results = []
tokens = inputs.tokens()
for idx, pred in enumerate(predictions):
label = model.config.id2label[pred]
if label != "O":
results.append(
{"entity": label, "score": probabilities[idx][pred], "word": tokens[idx]}
)
print(results)
์ด ๊ฒฐ๊ณผ๋ ์ด์ ๊ฒฐ๊ณผ์ ๋งค์ฐ ์ ์ฌํ์ง๋ง ํ๊ฐ์ง ์ฐจ์ด์ ์ด ์์ต๋๋ค. ํ์ดํ๋ผ์ธ์ ๋ํ ์๋ณธ ๋ฌธ์ฅ์์ ๊ฐ ์ํฐํฐ์ ์์๊ณผ ๋์ ๋ํ ์ ๋ณด๋ฅผ ์ ๊ณตํ์ต๋๋ค. ์ฌ๊ธฐ์์ ์คํ์
๋งคํ(offset mapping)์ด ์๋ํฉ๋๋ค. ์คํ์
(offset)์ ์ป์ผ๋ ค๋ฉด ์
๋ ฅ์ ํ ํฌ๋์ด์ ๋ฅผ ์ ์ฉํ ๋ return_offsets_mapping=True
๋ฅผ ์ค์ ํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค:
inputs_with_offsets = tokenizer(example, return_offsets_mapping=True)
inputs_with_offsets["offset_mapping"]
๊ฐ ํํ์ ๊ฐ ํ ํฐ์ ํด๋นํ๋ ํ ์คํธ ๋ฒ์์ด๋ฉฐ, ์ฌ๊ธฐ์ (0, 0)์ ํน์ ํ ํฐ์ฉ์ผ๋ก ์์ฝ๋์ด ์์ต๋๋ค. ์ด์ ์ ์ธ๋ฑ์ค 5์ ํ ํฐ์ด "##yl"์ด๊ณ ํด๋น ์คํ์ ์ด (12, 14)๋ก ์ง์ ๋์ด ์๋ ๊ฒ์ ๋ณด์์ต๋๋ค. ์ด ์คํ์ ์ผ๋ก ์ฌ๋ผ์ด์ฑ์ ํ๋ฉด:
example[12:14]
'##' ์์ด ์ ์ ํ ํ ์คํธ ๋ฒ์(text span)๋ฅผ ์ป์ต๋๋ค.
์ด๋ฅผ ์ฌ์ฉํ์ฌ ์ด์ ์ด์ ๊ฒฐ๊ณผ์ ์ฌํ(reproduction)์ ์๋ฃํ ์ ์์ต๋๋ค:
results = []
inputs_with_offsets = tokenizer(example, return_offsets_mapping=True)
tokens = inputs_with_offsets.tokens()
offsets = inputs_with_offsets["offset_mapping"]
for idx, pred in enumerate(predictions):
label = model.config.id2label[pred]
if label != 'O':
start, end = offsets[idx]
results.append(
{
"entity": label,
"score": probabilities[idx][pred],
"word": tokens[idx],
"start": start,
"end": end,
}
)
print(results)
์ด ๊ฒฐ๊ณผ๋ ์ฐ๋ฆฌ๊ฐ ํ์ดํ๋ผ์ธ ์คํ์ ํตํด ์ป์ ๊ฒฐ๊ณผ์ ๋์ผํฉ๋๋ค!
์ํฐํฐ ๊ทธ๋ฃนํ
์คํ์
์ ์ฌ์ฉํ์ฌ ๊ฐ ์ํฐํฐ์ ์์ ๋ฐ ๋ ํค๋ฅผ ๊ฒฐ์ ํ๋ ๊ฒ์ ํธ๋ฆฌํ์ง๋ง ํด๋น ์ ๋ณด๊ฐ ๊ผญ ํ์ํ ๊ฒ์ ์๋๋๋ค. ๊ทธ๋ฌ๋ ์ํฐํฐ ํ ํฐ์ ๊ทธ๋ฃนํํ๋ ค๋ ๊ฒฝ์ฐ ์คํ์
์ ์ฌ์ฉํ๋ฉด ์ง์ ๋ถํ ์ฝ๋๋ฅผ ๋ง์ด ์ ์ฝํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด Hu, ##gging ๋ฐ Face ํ ํฐ์ ํ๋๋ก ๊ทธ๋ฃนํํ๋ ค๋ ๊ฒฝ์ฐ, ์ฒ์ ๋ ํ ํฐ์ ## ์์ด ํฉ์ณ์ผ ํ๊ณ Face๋ ##๋ก ์์ํ์ง ์์ผ๋ฏ๋ก ์์ ๊ณต๋ฐฑ์ ์ถ๊ฐํ์ฌ ๊ฒฐํฉํด์ผ ํ๋ค๋ ํน์ ๊ท์น์ ๋ง๋ค์ด์ผ ํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ด๋ฌํ ๊ท์น๋ค์ ํน์ ์ ํ์ ํ ํฌ๋์ด์ ์์๋ง ์๋ํฉ๋๋ค. SentencePiece
๋๋ Byte-Pair-Encoding
ํ ํฌ๋์ด์ (์ด ์ฅ์ ๋ท๋ถ๋ถ์์ ์ค๋ช
)์์๋ ๋๋ค๋ฅธ ๊ท์น ์งํฉ์ ์์ฑํด์ผ ํฉ๋๋ค.
์คํ์ ์ ์ฌ์ฉํ๋ฉด ๋ชจ๋ ์ฌ์ฉ์ ์ ์ ์ฝ๋๊ฐ ์ฌ๋ผ์ง๋๋ค. ๋จ์ง ์ฒซ ๋ฒ์งธ ํ ํฐ์ผ๋ก ์์ํ๊ณ ๋ง์ง๋ง ํ ํฐ์ผ๋ก ๋๋๋ ์๋ณธ ํ ์คํธ์ ๋ฒ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ Hu, ##gging ๋ฐ Face ํ ํฐ์ ๊ฒฝ์ฐ, ์ด๋ฅผ ํฉ์น๊ธฐ ์ํด์ 33๋ฒ์งธ ๋ฌธ์(Hu์ ์์ ๋ถ๋ถ)์์ ์์ํ์ฌ 45๋ฒ์งธ ๋ฌธ์(Face์ ๋ ๋ถ๋ถ) ์๊น์ง ์ฌ๋ผ์ด์ฑ์ ํด์ฃผ๋ฉด ๋ฉ๋๋ค:
example[33:45]
ํน์ ์ํฐํฐ์ ํฌํจ๋ ํ ํฐ๋ค์ ๊ทธ๋ฃนํํ๋ ๋์ ์์ธก ๊ฒฐ๊ณผ๋ฅผ ํ์ฒ๋ฆฌํ๋ ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ํด B-XXX ๋๋ I-XXX๋ก ๋ ์ด๋ธ์ด ์ง์ ๋ ์ ์๋ ์ฒซ ๋ฒ์งธ ์ํฐํฐ๋ฅผ ์ ์ธํ๊ณ ์ฐ์์ ์ด๊ณ I-XXX๋ก ๋ ์ด๋ธ์ด ์ง์ ๋ ์ํฐํฐ๋ฅผ ํจ๊ป ๊ทธ๋ฃนํํฉ๋๋ค. ๋ฐ๋ผ์ O, ์๋ก์ด ์ ํ์ ์ํฐํฐ ๋๋ ๋์ผํ ์ ํ์ ์ํฐํฐ๊ฐ ์์๋๊ณ ์์์ ์๋ฆฌ๋ B-XXX๋ฅผ ๋ฐ์ผ๋ฉด ์ํฐํฐ ๊ทธ๋ฃนํ๋ฅผ ์ค์งํฉ๋๋ค:
import numpy as np
results = []
inputs_with_offsets = tokenizer(example, return_offsets_mapping=True)
tokens = inputs_with_offsets.tokens()
offsets = inputs_with_offsets["offset_mapping"]
idx = 0
while idx < len(predictions):
pred = predictions[idx]
label = model.config.id2label[pred]
if label != "O":
# Remove the B- or I-
label = label[2:]
start, _ = offsets[idx]
# Grab all the tokens labeled with I-label
all_scores = []
while (
idx < len(predictions)
and model.config.id2label[predictions[idx]] == f"I-{label}"
):
all_scores.append(probabilities[idx][pred])
_, end = offsets[idx]
idx += 1
# The score is the mean of all the scores of the tokens in that grouped entity
score = np.mean(all_scores).item()
word = example[start:end]
results.append(
{
"entity_group": label,
"score": score,
"word": word,
"start": start,
"end": end,
}
)
idx += 1
print(results)
์ด๋ ๊ฒ ํ์ดํ๋ผ์ธ ์คํ ๊ฒฐ๊ณผ์ ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ต๋๋ค!
์ด ์คํ์ ์ด ๋งค์ฐ ์ ์ฉํ๊ฒ ํ์ฉ๋๋ ๋ ๋ค๋ฅธ ์๋ ์ง์ ์๋ต(question answering)์ ๋๋ค. ๋ค์ ์น์ ์์ ํ์ดํ๋ผ์ธ์ ์์ธํ ๊ณต๋ถํ๋ฉด์ ๐คTransformers ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์๋ ํ ํฌ๋์ด์ ์ ๋ง์ง๋ง ๊ธฐ๋ฅ์ธ ์ ๋ ฅ์ ์ฃผ์ด์ง ๊ธธ์ด๋ก ์๋ฅผ ๋ ๋์น๋ ํ ํฐ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Author And Source
์ด ๋ฌธ์ ์ ๊ดํ์ฌ([๐ค ๊ฐ์ข 6.3] "๋น ๋ฅธ(fast)" ํ ํฌ๋์ด์ ์ ํน๋ณํ ๋ฅ๋ ฅ), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://velog.io/@spasis/๋น ๋ฅธ-ํ ํฌ๋์ด์ Fast-tokenizer์-ํน๋ณํ-๋ฅ๋ ฅ์ ์ ๊ท์: ์์์ ์ ๋ณด๊ฐ ์์์ URL์ ํฌํจ๋์ด ์์ผ๋ฉฐ ์ ์๊ถ์ ์์์ ์์ ์ ๋๋ค.
์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ ์ธ ๋ฐ๊ฒฌ์ ์ ๋ (Collection and Share based on the CC Protocol.)
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค