| <!--Copyright 2020 The HuggingFace Team. All rights reserved. |
|
|
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
|
|
| http://www.apache.org/licenses/LICENSE-2.0 |
|
|
| Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
| an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations under the License. |
| --> |
|
|
| # κ³ μ κΈΈμ΄ λͺ¨λΈμ ννλ μν°(Perplexity)[[perplexity-of-fixedlength-models]] |
|
|
| [[open-in-colab]] |
|
|
| ννλ μν°(Perplexity, PPL)λ κ°μ₯ μΌλ°μ μΈ μΈμ΄ λͺ¨λΈ νκ°μ§ν μ€ νλμ
λλ€. |
| μμΈν μμ보기 μ μ μ΄ νκ°μ§νλ κ³ μ μ μΈ μΈμ΄ λͺ¨λΈ(μκΈ°νκ· λλ μΈκ³Όμ μΈμ΄ λͺ¨λΈμ΄λΌκ³ λ ν¨)μλ§ μ μ©λλ©° BERTμ κ°μ λ§μ€νΉλ μΈμ΄ λͺ¨λΈμλ μ μ μ©νμ§ μμ΅λλ€ (BERTλ [summary of the models](../en/model_summary) λ¬Έμλ₯Ό μ°Έκ³ νμΈμ). |
|
|
| ννλ μν°λ μνμ€μ μμ λ‘κ·Έ μ°λ(negative log-likelihood, NLL) κ°μ νκ· μ μ§μ(exponentiate)λ₯Ό μ·¨ν κ°μΌλ‘ μ μλ©λλ€. |
| ν ν°νλ μνμ€ \\(X = (x_0, x_1, \dots, x_t)\\) κ° μμ λ, \\(X\\) μ ννλ μν°λ μλ μμκ³Ό κ°μ΄ ꡬν μ μμ΅λλ€. |
| |
| $$\text{PPL}(X) = \exp \left\{ {-\frac{1}{t}\sum_i^t \log p_\theta (x_i|x_{<i}) } \right\}$$ |
| |
| \\(\log p_\theta (x_i|x_{<i})\\) λ λͺ¨λΈμ iλ²μ§Έ μ΄μ κΉμ§ ν ν°μ΄ μ£Όμ΄μ‘μ λ iλ²μ§Έ ν ν°μ λ‘κ·Έ μ°λκ°μ
λλ€. |
| |
| μ§κ΄μ μΌλ‘ λ§λμΉμμ μ§μ λ ν ν° μ§ν©μ κ· μΌνκ² μμΈ‘νλ λͺ¨λΈμ λ₯λ ₯μ λν νκ°λ‘ μκ°ν μ μμ΅λλ€. |
| μ€μν μ μ ν ν°ν κ³Όμ μ΄ λͺ¨λΈμ ννλ μν°μ μ§μ μ μΈ μν₯μ λ―ΈμΉλ―λ‘ μλ‘ λ€λ₯Έ λͺ¨λΈμ λΉκ΅ν λ νμ μ΄λ₯Ό κ³ λ €ν΄μΌ ν©λλ€. |
| |
| μ΄λ λ°μ΄ν°μ λͺ¨λΈ μμΈ‘ κ°μ cross-entropy κ°μ μ§μλ₯Ό μ·¨ν κ²κ³Ό λμΌν©λλ€. |
| ννλ μν°μ λ¬ΈμλΉ λΉνΈ μ(BPC) λ° λ°μ΄ν° μμΆκ³Όμ κ΄κ³μ λν΄ λ μ§κ΄μ μΈ μ΄ν΄λ₯Ό μνμ λ€λ©΄ λ€μ κΈ |
| [fantastic blog post on The Gradient](https://thegradient.pub/understanding-evaluation-metrics-for-language-models/)μ νμΈνμΈμ. |
| |
| ## κ³ μ κΈΈμ΄ λͺ¨λΈμ ννλ μν°(PPL) κ³μ°νκΈ°[[calculating-ppl-with-fixedlength-models]] |
| |
| λͺ¨λΈμ 컨ν
μ€νΈ ν¬κΈ°κ° μ ν΄μ Έμμ§ μλ€λ©΄, |
| μλμ κ°μ΄ μνμ€λ₯Ό μλ νκ·μ μΌλ‘ λΆν΄νκ³ κ° λ¨κ³μμ μ ν νλ μ 체 μνμ€λ₯Ό μ‘°κ±΄λΆ νλ₯ μ λ£μ΄ λͺ¨λΈμ ννλ μν°λ₯Ό κ³μ°ν κ²μ
λλ€. |
| |
| <img width="600" alt="Full decomposition of a sequence with unlimited context length" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/ppl_full.gif"/> |
| |
| κ·Έλ¬λ λͺ¨λΈμ κ·Όμ¬μΉλ₯Ό ꡬν λλ μΌλ°μ μΌλ‘ λͺ¨λΈμ΄ μ²λ¦¬ν μ μλ ν ν° μμ μ νμ΄ μμ΅λλ€. |
| μλ₯Ό λ€μ΄, κ°μ₯ ν° λ²μ μ [GPT-2](model_doc/gpt2)λ ν ν°μ κΈΈμ΄κ° 1024λ‘ κ³ μ λμ΄ μμ΅λλ€. |
| λ°λΌμ \\(t\\) κ° 1024λ³΄λ€ ν° κ²½μ°μ \\(p_\theta(x_t|x_{<t})\\) μ κ³μ°ν μ μμ΅λλ€. |
| |
| λμ μνμ€λ μΌλ°μ μΌλ‘ λͺ¨λΈμ μ΅λ μ
λ ₯ ν¬κΈ°μ λμΌν κΈΈμ΄λ κ°μ§λ λΆλΆ μνμ€λ‘ μͺΌκ°λλ€. |
| λ§μ½ λͺ¨λΈμ μ΅λ μ
λ ₯ κΈΈμ΄κ° \\(k\\) λΌλ©΄, |
| ν ν° \\(x_t\\) μ μ°λ κ°μ κ³μ°ν λ μ΄μ ν ν°μ λͺ¨λ μ¬μ©νμ§ μκ³ , \\(k-1\\) ν ν°κΉμ§ μ¬μ©ν΄ λλ΅μ μΈ μ°λ κ°μ μΆμ ν©λλ€. |
| |
| λͺ¨λΈμ μνμ€μ λν ννλ μν°λ₯Ό κ³μ°ν λ, |
| μμνμ§λ§ μ°¨μ μ±
μ μνμ€λ₯Ό μ²ν¬λ‘ μͺΌκ°κ³ λΆν΄λ κ° λΆλΆμ λ‘κ·Έ μ°λ κ°μ λ
립μ μΌλ‘ ν©μ°νλ κ²μ
λλ€. |
| |
| <img width="600" alt="Suboptimal PPL not taking advantage of full available context" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/ppl_chunked.gif"/> |
|
|
| μ΄ λ°©λ²μ κ° λΆλΆμ ννλ μν°λ₯Ό ν λ²μ ν¬μλ ν¨μ€λ‘ κ³μ°ν μ μμ΄ λΉ λ₯΄μ§λ§ μΌλ°μ μΌλ‘ λ λμ(λ λμ) PPLμ μ°μΆν©λλ€. |
| μλνλ©΄ λλΆλΆμ μμΈ‘ λ¨κ³μμ λͺ¨λΈμ 컨ν
μ€νΈκ° μ κΈ° λλ¬Έμ
λλ€. |
|
|
| λμ , κ³ μ κΈΈμ΄ λͺ¨λΈμ PPLμ μ¬λΌμ΄λ© μλμ° μ λ΅μΌλ‘ νκ°ν΄μΌ ν©λλ€. |
| μ΄ μ λ΅μλ 컨ν
μ€νΈ μλμ°μ λ°λ³΅μ μΌλ‘ μ¬λΌμ΄λ©ν΄ λͺ¨λΈμ΄ κ° μμΈ‘μ μνν λ λ λ§μ 컨ν
μ€νΈλ₯Ό κ°λλ‘ νλ μμ
μ΄ ν¬ν¨λ©λλ€. |
|
|
| <img width="600" alt="Sliding window PPL taking advantage of all available context" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/ppl_sliding.gif"/> |
|
|
| μ΄λ μνμ€ νλ₯ μ μ€μ λΆν΄μ λ κ°κΉμ΄ κ·Όμ¬μΉμ΄λ©° μΌλ°μ μΌλ‘ λ μ 리ν μ μλ₯Ό μ°μΆν©λλ€. |
| λ¨μ μ λ§λμΉμ κ° ν ν°μ λν΄ λ³λμ ν¬μλ ν¨μ€κ° νμνλ€λ κ²μ
λλ€. |
| νμ€μ μΌλ‘ μ’μ μ μΆ©μμ ν λ²μ ν ν ν°μ© μ¬λΌμ΄λ©νλ κ²μ΄ μλλΌ λ ν° κ°κ²©μΌλ‘ 컨ν
μ€νΈλ₯Ό μ΄λνλ μ€νΈλΌμ΄λκ° μ μ©λ μ¬λΌμ΄λ© μλμ°μ μ¬μ©νλ κ²μ
λλ€. |
| μ΄λ κ² νλ©΄ κ³μ°μ ν¨μ¬ λ λΉ λ₯΄κ² μ§ννλ©΄μλ λͺ¨λΈμ κ° λ¨κ³μμ μμΈ‘μ μνν μ μλ κΈ΄ 컨ν
μ€νΈλ₯Ό μ 곡ν μ μμ΅λλ€. |
|
|
| ## μμ : π€ Transformersμμ GPT-2λ‘ ννλ μν°(perplexity) κ³μ°νκΈ°[[example-calculating-perplexity-with-gpt2-in-transformers]] |
|
|
| μ΄μ GPT-2λ‘ μμ κ³Όμ μ μμ°ν΄ λ³΄κ² μ΅λλ€. |
|
|
| ```python |
| from transformers import GPT2LMHeadModel, GPT2TokenizerFast |
| |
| device = "cuda" |
| model_id = "openai-community/gpt2-large" |
| model = GPT2LMHeadModel.from_pretrained(model_id).to(device) |
| tokenizer = GPT2TokenizerFast.from_pretrained(model_id) |
| ``` |
|
|
| WikiText-2 λ°μ΄ν° μΈνΈλ₯Ό κ°μ Έμ€κ³ λͺ κ°μ§ μ¬λΌμ΄λ© μλμ° μ λ΅μ μ¬μ©ν΄ ννλ μν°λ₯Ό κ³μ°ν΄λ³΄κ² μ΅λλ€. |
| μ΄ λ°μ΄ν° μΈνΈλ ν¬κΈ°κ° μκ³ ν¬μλ ν¨μ€ ν λ²λ§ μννκΈ° λλ¬Έμ μ 체 λ°μ΄ν° μΈνΈλ₯Ό λ©λͺ¨λ¦¬μ κ°μ Έμ€κ³ μΈμ½λ©ν μ μμ΅λλ€. |
|
|
| ```python |
| from datasets import load_dataset |
| |
| test = load_dataset("wikitext", "wikitext-2-raw-v1", split="test") |
| encodings = tokenizer("\n\n".join(test["text"]), return_tensors="pt") |
| ``` |
|
|
| π€ Transformersλ₯Ό μ¬μ©νλ©΄ λͺ¨λΈμ `labels`λ‘ `input_ids`λ₯Ό μ λ¬ν΄ κ° ν ν°μ λν νκ· μμ μ°λ κ°μ μμ€λ‘ λ°νν μ μμ΅λλ€. |
| νμ§λ§ μ¬λΌμ΄λ© μλμ° λ°©μμ μ¬μ©νλ©΄ κ° λ°λ³΅λ§λ€ λͺ¨λΈμ μ λ¬νλ ν ν°μ΄ κ²ΉμΉ©λλ€. |
| 컨ν
μ€νΈλ‘ μ²λ¦¬νλ ν ν°μ λν λ‘κ·Έ μ°λ κ°μ΄ μμ€μ ν¬ν¨λλ κ²μ μνμ§ μκΈ° λλ¬Έμ μ΄λ¬ν ν ν°μ `input_ids`λ₯Ό `-100`μΌλ‘ μ€μ νμ¬ λ¬΄μν μ μμ΅λλ€. |
|
|
| λ€μμ μ€νΈλΌμ΄λ(stride)λ₯Ό `512`λ‘ μ¬μ©ν μμμ
λλ€. |
| μ¦, λͺ¨λΈμ΄ ν ν ν°μ μ‘°κ±΄λΆ μ°λ κ°μ κ³μ°ν λ 컨ν
μ€νΈμ μ΅μν 512κ°μ ν ν°μ΄ ν¬ν¨λμ΄μλ€λ μλ―Έμ
λλ€ (ν΄λΉ ν ν° μμ 512κ°μ ν ν°μ΄ μλ κ²½μ°). |
|
|
| ```python |
| import torch |
| from tqdm import tqdm |
| |
| max_length = model.config.n_positions |
| stride = 512 |
| seq_len = encodings.input_ids.size(1) |
| |
| nlls = [] |
| prev_end_loc = 0 |
| for begin_loc in tqdm(range(0, seq_len, stride)): |
| end_loc = min(begin_loc + max_length, seq_len) |
| trg_len = end_loc - prev_end_loc # λ§μ§λ§ 루νμ μ€νΈλΌμ΄λ κ°κ³Ό λ€λ₯Ό μ μμ |
| input_ids = encodings.input_ids[:, begin_loc:end_loc].to(device) |
| target_ids = input_ids.clone() |
| target_ids[:, :-trg_len] = -100 |
| |
| with torch.no_grad(): |
| outputs = model(input_ids, labels=target_ids) |
| |
| # μμ€μ λͺ¨λ μ ν¨ν λ μ΄λΈμ λν νκ· κ°μ ꡬνλ κ΅μ°¨ μνΈλ‘νΌ(cross entropy)λ‘ κ³μ°λ©λλ€. |
| # λμ΄λΈ λ² μ΄μ§μ λͺ¨λΈμ λ΄λΆμ μΌλ‘ λ μ΄λΈμ μΌμͺ½μΌλ‘ 1κ°μ© λ°κΈ° λλ¬Έμ, (νμΌ - 1)κ° λ§νΌμ λ μ΄λΈμ λν΄ μμ€μ κ³μ°ν©λλ€. |
| neg_log_likelihood = outputs.loss |
| |
| nlls.append(neg_log_likelihood) |
| |
| prev_end_loc = end_loc |
| if end_loc == seq_len: |
| break |
| |
| ppl = torch.exp(torch.stack(nlls).mean()) |
| ``` |
|
|
| μ€νΈλΌμ΄λλ₯Ό μ΅λ μ
λ ₯ κΈΈμ΄μ λμΌνκ² μ€μ νλ©΄ μμμ μ€λͺ
ν μ°¨μ μ±
μΈ λΉμ¬λΌμ΄λ© μλμ° μ λ΅κ³Ό λμΌν©λλ€. |
| μΌλ°μ μΌλ‘ μ€νΈλΌμ΄λκ° μμμλ‘ λͺ¨λΈμ΄ κ° μμΈ‘μ ν λ λ λ§μ 컨ν
μ€νΈλ₯Ό λ³Ό μ μκ² λμ΄ ννλ μν° κ°μ΄ μ’μμ§λλ€. |
|
|
| μμ κ³μ°μ ν ν°μ΄ κ²ΉμΉμ§ μλλ‘ `stride = 1024`λ‘ μ€μ νλ©΄ PPLμ `19.44`λ‘ GPT-2 λ
Όλ¬Έμμ λ³΄κ³ λ `19.93`κ³Ό κ±°μ λμΌν©λλ€. |
| `stride = 512`λ‘ μ¬λΌμ΄λ© μλμ° μ λ΅μ μ¬μ©νλ©΄ PPLμ `16.45`λ‘ λ¨μ΄μ§λλ€. |
| μ΄λ λ μ’μ μ μμΌ λΏλ§ μλλΌ μνμ€ νλ₯ μ μ€μ μλ νκ· λΆν΄μ λ κ°κΉμ΄ λ°©μμΌλ‘ κ³μ°λ©λλ€. |