6️⃣Evaluate

Huggingface Evaluate

Huggingface Evaluate는 다양한 평가 도구에 대한 액세스를 제공합니다. 여기에는 모델이나 데이터 세트를 평가하는 도구뿐만 아니라 텍스트, 컴퓨터 비전, 오디오 등과 같은 다양한 양식을 다룹니다. 이러한 도구는 세 가지 카테고리로 나뉩니다.

  • Metric: 모델의 성능을 평가하는 데 사용되며 일반적으로 모델의 예측과 일부 기준값 레이블을 포함합니다.

  • Comparison: 비교는 두 모델을 비교하는 데 사용됩니다. 예를 들어 두 모델의 예측을 기준값 레이블과 비교하고 일치도를 계산하여 비교를 수행할 수 있습니다.

  • Measurement:: 데이터 세트는 학습된 모델만큼이나 중요합니다. 측정을 통해 데이터 세트의 속성을 조사할 수 있습니다.

%pip install evaluate

Evaluate Load

import evaluate

accuracy = evaluate.load("accuracy")
accuracy.compute(references=[0,1,0,1], predictions=[1,0,0,1])
Downloading builder script:   0%|          | 0.00/4.20k [00:00<?, ?B/s]

{'accuracy': 0.5}

Combination

단일 지표뿐만 아니라 모델의 다양한 측면을 포착하는 다양한 지표를 평가하고자 하는 경우가 많습니다. 예를 들어 분류의 경우 일반적으로 모델 성능을 더 잘 파악하기 위해 정확도 외에도 F1 Score, Recall, Precision를 계산하는 것이 좋습니다. 물론 여러 메트릭을 로드하고 순차적으로 호출할 수 있습니다. 그러나 더 편리한 방법은 결합() 함수를 사용하여 함께 묶는 것입니다:

metrics = evaluate.combine(["accuracy", "f1", "precision", "recall"])
Downloading builder script:   0%|          | 0.00/6.77k [00:00<?, ?B/s]



Downloading builder script:   0%|          | 0.00/7.55k [00:00<?, ?B/s]



Downloading builder script:   0%|          | 0.00/7.36k [00:00<?, ?B/s]

predictionsreferencecompute() 메서드에 전달하고 결과를 반환합니다. 배치별로 메트릭을 계산하고 진행 상황을 추적하는 기능이 있습니다.

Community module

평가하기에서 구현된 모듈 외에도 메트릭 구현의 리포지토리 ID를 지정하여 모든 커뮤니티 모듈을 로드할 수도 있습니다:

import evaluate

accuracy = evaluate.load("accuracy")
word_length = evaluate.load(
    "word_length", 
    module_type="measurement"
)
Downloading builder script:   0%|          | 0.00/2.87k [00:00<?, ?B/s]


[nltk_data] Downloading package punkt to /home/kubwa/nltk_data...
[nltk_data]   Package punkt is already up-to-date!
element_count = evaluate.load("lvwerra/element_count", module_type="measurement")

List evaluation module

list_evaluation_modules()를 사용하면 허브에서 어떤 모듈을 사용할 수 있는지 확인할 수 있습니다. 원하는 경우 특정 모듈을 필터링하고 커뮤니티 지표를 건너뛸 수도 있습니다.

evaluate.list_evaluation_modules(
  module_type="comparison",
  include_community=False,
  with_details=True)

Evaluator

Transformer pipeline과 함께 사용지 evaluator() 메서드로 각 Task 별로 Metric을 불러와서 evaluate 할 수 있습니다. 지원하는 Metrics는 아래와 같습니다:

  • "text-classification": TextClassificationEvaluator

  • "token-classification": TokenClassificationEvaluator

  • "question-answering": QuestionAnsweringEvaluator

  • "image-classification": ImageClassificationEvaluator

  • "text-generation": TextGenerationEvaluator

  • "text2text-generation": Text2TextGenerationEvaluator

  • "summarization": SummarizationEvaluator

  • "translation": TranslationEvaluator

  • "automatic-speech-recognition": AutomaticSpeechRecognitionEvaluator

from transformers import pipeline
from datasets import load_dataset
from evaluate import evaluator
import evaluate

pipe = pipeline(
    "text-classification", 
    model="lvwerra/distilbert-imdb", device=0
)
data = load_dataset("imdb", split="test").shuffle().select(range(1000))
metric = evaluate.load("accuracy")

task_evaluator = evaluator("text-classification")

results = task_evaluator.compute(
    model_or_pipeline=pipe, 
    data=data, metric=metric,
    label_mapping={"NEGATIVE": 0, "POSITIVE": 1})

print(results)
config.json:   0%|          | 0.00/735 [00:00<?, ?B/s]



pytorch_model.bin:   0%|          | 0.00/268M [00:00<?, ?B/s]



tokenizer_config.json:   0%|          | 0.00/333 [00:00<?, ?B/s]



vocab.txt:   0%|          | 0.00/232k [00:00<?, ?B/s]



tokenizer.json:   0%|          | 0.00/466k [00:00<?, ?B/s]



special_tokens_map.json:   0%|          | 0.00/112 [00:00<?, ?B/s]



Downloading readme:   0%|          | 0.00/7.81k [00:00<?, ?B/s]


Downloading data: 100%|██████████| 21.0M/21.0M [00:00<00:00, 23.8MB/s]
Downloading data: 100%|██████████| 20.5M/20.5M [00:00<00:00, 30.7MB/s]
Downloading data: 100%|██████████| 42.0M/42.0M [00:00<00:00, 47.2MB/s]



Generating train split:   0%|          | 0/25000 [00:00<?, ? examples/s]



Generating test split:   0%|          | 0/25000 [00:00<?, ? examples/s]



Generating unsupervised split:   0%|          | 0/50000 [00:00<?, ? examples/s]


{'accuracy': 0.928, 'total_time_in_seconds': 7.195105906575918, 'samples_per_second': 138.98336077111205, 'latency_in_seconds': 0.007195105906575918}

Save Result

평가 결과를 저장하고 공유하는 것은 중요한 단계입니다. 지표 결과를 쉽게 저장할 수 있도록 evaluate.save() 함수를 제공합니다. 특정 파일 이름이나 디렉터리를 전달할 수 있습니다. 후자의 경우 결과는 자동으로 생성된 파일 이름으로 파일에 저장됩니다. 이 함수는 디렉터리나 파일 이름 외에도 키-값 쌍을 입력으로 받아 JSON 파일에 저장합니다.

!mkdir results

result = accuracy.compute(
    references=[0,1,0,1], 
    predictions=[1,0,0,1]
)

hyperparams = {"model": "bert-base-uncased"}
evaluate.save("./results", **result, **hyperparams)
fatal: not a git repository (or any of the parent directories): .git





PosixPath('results/result-2024_05_23-19_22_08.json')

results 디렉토리를 생성하고 "result-2024_05_23-19_22_08.json" json 포맷으로 저장했습니다.

Push to HF Hub

결과를 해당 Repository에 보고할 수 있습니다.

evaluate.push_to_hub() 함수를 사용하면 평가 결과를 모델의 리포지토리에 쉽게 보고할 수 있습니다:

evaluate.push_to_hub(
  model_id="huggingface/gpt2-wikitext2",  # model repository on hub
  metric_value=0.5,                       # metric value
  metric_type="bleu",                     # metric name, e.g. accuracy.name
  metric_name="BLEU",                     # pretty name which is displayed
  dataset_type="wikitext",                # dataset name on the hub
  dataset_name="WikiText",                # pretty name
  dataset_split="test",                   # dataset split used
  task_type="text-generation",            # task id, see https://github.com/huggingface/datasets/blob/master/src/datasets/utils/resources/tasks.json
  task_name="Text Generation"             # pretty name for task
)

Visualization

여러 모델을 비교할 때 단순히 점수만 보고는 성능의 차이를 파악하기 어려운 경우가 있습니다. 또한 최고의 모델이 하나만 있는 것이 아니라 지연 시간과 정확도 사이에 상충 관계가 있는 경우가 많으며, 더 큰 모델은 성능이 더 좋을 수 있지만 또한 더 느릴 수도 있습니다. 사용 사례에 가장 적합한 모델을 더 쉽게 선택할 수 있도록 플롯과 같은 다양한 시각화 접근 방식을 점진적으로 추가하고 있습니다.

import evaluate
from evaluate.visualization import radar_plot

data = [
   {"accuracy": 0.99, "precision": 0.8, "f1": 0.95, "latency_in_seconds": 33.6},
   {"accuracy": 0.98, "precision": 0.87, "f1": 0.91, "latency_in_seconds": 11.2},
   {"accuracy": 0.98, "precision": 0.78, "f1": 0.88, "latency_in_seconds": 87.6}, 
   {"accuracy": 0.88, "precision": 0.78, "f1": 0.81, "latency_in_seconds": 101.6}
   ]

model_names = ["Model 1", "Model 2", "Model 3", "Model 4"]
plot = radar_plot(data=data, model_names=model_names)
plot.show()

Custom Pipeline

Evaluator는 즉시 트랜스포머 파이프라인과 함께 작동하도록 설계되었습니다. 하지만 많은 경우 트랜스포머 에코시스템에 속하지 않는 모델이나 파이프라인이 있을 수 있습니다. 그래도 평가기를 사용하여 이러한 모델이나 파이프라인에 대한 지표를 쉽게 계산할 수 있습니다. 이 가이드에서는 Scikit-Learn 파이프라인과 Spacy 파이프라인에 대해 이 작업을 수행하는 방법을 보여드립니다. Scikit-Learn 사례부터 시작하겠습니다.

scikit-learn

IMDB 데이터셋으로 불러와서 scikit-learn pipeline으로 Text Classification을 수행해보겠습니다.

from datasets import load_dataset

ds = load_dataset("imdb")
from sklearn.pipeline import Pipeline
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer

text_clf = Pipeline([
        ('vect', CountVectorizer()),
        ('tfidf', TfidfTransformer()),
        ('clf', MultinomialNB()),
])

text_clf.fit(ds["train"]["text"], ds["train"]["label"])
Pipeline(steps=[('vect', CountVectorizer()), ('tfidf', TfidfTransformer()),
            (&#x27;clf&#x27;, MultinomialNB())])</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class="sk-container" hidden><div class="sk-item sk-dashed-wrapped"><div class="sk-label-container"><div class="sk-label fitted sk-toggleable"><input class="sk-toggleable__control sk-hidden--visually" id="sk-estimator-id-5" type="checkbox" ><label for="sk-estimator-id-5" class="sk-toggleable__label fitted sk-toggleable__label-arrow fitted">&nbsp;&nbsp;Pipeline<a class="sk-estimator-doc-link fitted" rel="noreferrer" target="_blank" href="https://scikit-learn.org/1.4/modules/generated/sklearn.pipeline.Pipeline.html">?<span>Documentation for Pipeline</span></a><span class="sk-estimator-doc-link fitted">i<span>Fitted</span></span></label><div class="sk-toggleable__content fitted"><pre>Pipeline(steps=[(&#x27;vect&#x27;, CountVectorizer()), (&#x27;tfidf&#x27;, TfidfTransformer()),            (&#x27;clf&#x27;, MultinomialNB())])</pre></div> </div></div><div class="sk-serial"><div class="sk-item"><div class="sk-estimator fitted sk-toggleable"><input class="sk-toggleable__control sk-hidden--visually" id="sk-estimator-id-6" type="checkbox" ><label for="sk-estimator-id-6" class="sk-toggleable__label fitted sk-toggleable__label-arrow fitted">&nbsp;CountVectorizer<a class="sk-estimator-doc-link fitted" rel="noreferrer" target="_blank" href="https://scikit-learn.org/1.4/modules/generated/sklearn.feature_extraction.text.CountVectorizer.html">?<span>Documentation for CountVectorizer</span></a></label><div class="sk-toggleable__content fitted"><pre>CountVectorizer()</pre></div> </div></div><div class="sk-item"><div class="sk-estimator fitted sk-toggleable"><input class="sk-toggleable__control sk-hidden--visually" id="sk-estimator-id-7" type="checkbox" ><label for="sk-estimator-id-7" class="sk-toggleable__label fitted sk-toggleable__label-arrow fitted">&nbsp;TfidfTransformer<a class="sk-estimator-doc-link fitted" rel="noreferrer" target="_blank" href="https://scikit-learn.org/1.4/modules/generated/sklearn.feature_extraction.text.TfidfTransformer.html">?<span>Documentation for TfidfTransformer</span></a></label><div class="sk-toggleable__content fitted"><pre>TfidfTransformer()</pre></div> </div></div><div class="sk-item"><div class="sk-estimator fitted sk-toggleable"><input class="sk-toggleable__control sk-hidden--visually" id="sk-estimator-id-8" type="checkbox" ><label for="sk-estimator-id-8" class="sk-toggleable__label fitted sk-toggleable__label-arrow fitted">&nbsp;MultinomialNB<a class="sk-estimator-doc-link fitted" rel="noreferrer" target="_blank" href="https://scikit-learn.org/1.4/modules/generated/sklearn.naive_bayes.MultinomialNB.html">?<span>Documentation for MultinomialNB</span></a></label><div class="sk-toggleable__content fitted"><pre>MultinomialNB()</pre></div> </div></div></div></div></div></div>
Transformer 텍스트 분류 파이프라인의 규칙에 따라 파이프라인은 호출 가능하고 사전 목록을 반환해야 합니다. 또한 작업 속성을 사용하여 파이프라인이 평가기와 호환되는지 확인합니다. 이를 위해 작은 래퍼 클래스를 작성할 수 있습니다:
Custom Transformer pipeline
class ScikitEvalPipeline:    def __init__(self, pipeline):        self.pipeline = pipeline        self.task = "text-classification"    def __call__(self, input_texts, **kwargs):        return [{"label": p} for p in self.pipeline.predict(input_texts)]pipe = ScikitEvalPipeline(text_clf)
from evaluate import evaluatortask_evaluator = evaluator("text-classification")task_evaluator.compute(pipe, ds["test"], "accuracy")

Last updated