|
<!--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 = "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`λ‘ λ¨μ΄μ§λλ€. |
|
μ΄λ λ μ’μ μ μμΌ λΏλ§ μλλΌ μνμ€ νλ₯ μ μ€μ μλ νκ· λΆν΄μ λ κ°κΉμ΄ λ°©μμΌλ‘ κ³μ°λ©λλ€. |