비전·음성·추천

DOMAIN / 10번째 글

텍스트 분류: 언어에 레이블을 붙이는 기술

레이블 구조 세 가지부터 TF-IDF 기준선, BERT 파인튜닝의 손잡이, 불균형과 신뢰도 게이팅, 계층 분류, 한국어 전처리, 오답 50건을 읽는 순서까지 텍스트 분류를 실무 기준으로 정리한다.

PALDYN Team29 MIN READ

지난 글에서 텍스트에 담긴 감정을 읽는 감성 분석을 다뤘다. 감성 분석도 사실 더 큰 갈래인 텍스트 분류의 한 종류다. 텍스트 분류는 주어진 텍스트에 하나 혹은 여러 개의 레이블을 자동으로 붙이는 일이고, 스팸 필터, 뉴스 카테고리화, 챗봇의 의도 파악, 고객 문의 자동 라우팅이 전부 여기에 얹혀 있다.

분류는 가장 오래된 태스크라 「어떻게 만드는가」는 이미 널리 알려져 있다. 그런데 실제로 서비스에 올려 보면 막히는 자리는 모델이 아니라 다른 데 있다. 레이블 구조를 잘못 잡아 손실 함수가 어긋나 있거나, 정확도 92%를 찍어 놓고 정작 중요한 소수 클래스는 하나도 못 맞히거나, 모델이 0.99의 확신으로 틀린 답을 내놓는다. 이 글은 그 막히는 자리들을 순서대로 짚는다.

레이블 구조

무엇을 먼저 정해야 하냐면 모델이 아니라 레이블의 모양이다. 이것이 손실 함수와 출력층, 그리고 판정 절차까지 전부 끌고 간다.

레이블 구조가 출력층과 손실을 정한다

이진과 다중 클래스

이진 분류는 두 클래스 중 하나를 고른다. 스팸/정상, 긍정/부정이 대표적이다. 다중 클래스 분류는 세 개 이상 중 하나를 고른다. 뉴스 카테고리(스포츠·정치·경제·문화)가 전형적인 예다.

둘 다 출력층은 소프트맥스이고 손실은 교차 엔트로피(CE)다. 여기서 중요한 성질 하나가 나온다 — 소프트맥스의 출력은 클래스 전체를 합하면 반드시 1이다. 한 클래스의 확률이 올라가면 다른 클래스의 확률은 자동으로 내려간다는 뜻이고, 이것은 「정답이 정확히 하나」라는 가정을 출력층이 구조로 강제한다는 뜻이기도 하다.

다중 레이블

다중 레이블 분류는 한 텍스트에 여러 레이블을 동시에 붙인다. 기사에 「경제」와 「글로벌」을 함께 붙이는 경우다. 여기서는 소프트맥스를 쓰면 안 된다. 「경제」가 확실하다고 해서 「글로벌」의 확률이 내려가야 할 이유가 없는데, 합이 1이라는 성질이 그것을 강제해 버리기 때문이다.

그래서 다중 레이블은 출력층을 시그모이드로 두고 손실을 BCE로 바꾼다. 시그모이드는 클래스마다 독립적으로 0~1 값을 내므로 합이 1이 아니어도 되고, 레이블 셋이 동시에 0.9를 받는 것도 가능해진다. 레이블 구조를 정하는 순간 손실 함수가 따라온다는 말이 이 뜻이다 — 다중 레이블 문제에 소프트맥스를 붙여 놓고 성능이 안 오른다고 모델을 바꾸는 것이 실무에서 가장 흔한 헛수고다.

클래스별 임계값

다중 클래스에서는 「가장 큰 값」을 고르면 끝이라 임계값이 따로 없다. 다중 레이블에서는 클래스마다 「몇 점을 넘으면 붙일 것인가」를 정해야 하고, 그 값이 전부 0.5일 이유가 없다.

전체 문서의 40%에 붙는 흔한 레이블과 0.5%에 붙는 희귀 레이블을 생각해 보자. 희귀 레이블의 시그모이드 출력은 학습 중에 거의 항상 0 쪽으로 눌려 있으므로, 0.5를 넘는 일 자체가 드물다. 임계값을 0.5로 고정하면 그 레이블은 사실상 영영 안 붙는다. 검증 세트에서 클래스마다 F1이 최대가 되는 임계값을 따로 찾아 두는 것이 정석이고, 이 한 가지만으로 macro-F1이 몇 %p 움직이는 일이 흔하다. 임계값 탐색은 학습이 끝난 뒤에 하는 후처리라 모델을 다시 돌릴 필요가 없다는 점도 크다 — 예측 점수를 한 번 저장해 두면 0.05 간격으로 훑는 데 몇 초면 된다.

TF-IDF 기준선

BERT부터 시작하지 않는 이유가 있다. 기준선이 없으면 파인튜닝한 모델의 F1 0.88이 좋은 값인지 나쁜 값인지 알 수가 없다.

세 고전 모델

TF-IDF는 문서에 자주 나오면서 다른 문서에는 잘 안 나오는 단어에 높은 점수를 주는 가중치 방식이다. 그렇게 만든 희소 벡터를 고전 분류기에 넣는다.

  • 나이브 베이즈: 학습이 가장 빠르고 데이터가 수백 건일 때도 무너지지 않는다. 단어 사이의 독립을 가정하므로 짧은 텍스트, 어휘가 뚜렷이 갈리는 문제(스팸)에 강하다.
  • SVM: 고차원 희소 벡터에서 가장 안정적이다. 클래스 경계가 좁고 데이터가 수천~수만 건일 때 기본값으로 쓸 만하다.
  • 로지스틱 회귀: 확률을 직접 내놓으므로 임계값을 만지거나 신뢰도로 쓰기에 좋다. 계수를 그대로 읽어 「어느 단어가 이 판정을 밀었는가」를 볼 수 있다는 점도 실무에서 크다.

세 개의 손잡이

TF-IDF 쪽에서 실제로 점수를 움직이는 설정은 사실 셋뿐이다.

ngram_range=(1,2)는 두 단어 묶음을 함께 센다. 「좋지 않다」처럼 부정이 뒤에 붙는 표현이 있는 문제에서는 이것 하나로 F1이 눈에 띄게 오르고, 대신 특징 수가 몇 배로 부푼다. sublinear_tf=True는 빈도에 로그를 씌워 「같은 단어 30번」이 「3번」의 열 배 신호가 되지 않게 누른다. 리뷰·상담 로그처럼 같은 말이 반복되는 데이터에서 효과가 크다. max_features는 상위 몇 개 특징만 남길지를 정하고, 이 값을 줄이면 학습은 빨라지되 희귀 클래스를 가르는 단어부터 먼저 잘려 나간다.

기준선을 먼저 세우는 순서

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline

pipeline = Pipeline([
    ("tfidf", TfidfVectorizer(
        analyzer="word",
        tokenizer=mecab_tokenize,  # KoNLPy Mecab
        ngram_range=(1, 2),
        max_features=50_000,
        sublinear_tf=True,
    )),
    ("clf", LogisticRegression(
        C=5.0,
        max_iter=1000,
        class_weight="balanced",
    )),
])

pipeline.fit(train_texts, train_labels)
preds = pipeline.predict(test_texts)

이 파이프라인은 수만 건 규모에서 몇 초 만에 학습이 끝난다. 그 점이 핵심이다 — 데이터를 받은 날 오전에 기준선을 세워 두면, 이후의 모든 작업은 「그 숫자보다 얼마나 나은가」로 이야기할 수 있게 된다. 사전학습 모델을 파인튜닝해서 얻은 이득이 2%p뿐이라면 그 모델을 서비스에 올려 GPU를 물릴 이유가 없고, 반대로 15%p라면 그 비용은 쉽게 정당화된다. 기준선 없이 시작하면 이 판단 자체가 불가능하다.

BERT 파인튜닝

텍스트 분류 파이프라인

파이프라인은 입력 → 토크나이저 → 인코더 → 분류기 헤드 → 레이블 순서다. 사전학습 언어 모델은 문맥을 담은 밀집 표현을 내놓고, 그 위에 선형 층 하나를 얹어 클래스 수만큼의 점수를 뽑는다. 얹는 층은 정말로 얇지만, 그 아래 인코더 전체의 가중치도 함께 갱신된다는 것이 파인튜닝의 뜻이다.

두 가지 풀링

문장 하나를 벡터 하나로 줄이는 방법이 둘이다. [CLS] 풀링은 시퀀스 맨 앞에 붙는 특수 토큰의 마지막 은닉 상태를 그대로 쓴다. 평균 풀링은 모든 토큰의 은닉 상태를 패딩을 뺀 채 평균 낸다.

분류 파인튜닝에서는 [CLS] 쪽이 기본값이다. 사전학습 단계에서 그 자리가 이미 문장 전체를 요약하도록 훈련돼 있고, 파인튜닝을 하면 그 자리가 이번 태스크에 맞게 다시 조정되기 때문이다. 반대로 인코더를 얼려 두고 특징만 뽑아 쓸 때는 평균 풀링이 낫다 — 학습이 안 일어나므로 [CLS]가 이번 태스크를 향해 조정될 기회가 없고, 그 자리는 사전학습 목표에 맞춰진 상태로 남는다. 「파인튜닝이면 [CLS], 동결이면 평균」이 실무 기준선이다.

학습률과 에폭

학습률 2e-55e-5, 에폭 24가 관례가 된 데에는 이유가 있다. 파인튜닝은 이미 잘 학습된 가중치를 조금 미는 일이라 처음부터 학습하는 것보다 훨씬 작은 걸음이 필요하다. 이 대역을 벗어나면 증상이 각각 다르게 나온다.

벗어난 방향 증상
학습률이 너무 큼(1e-4 이상) 첫 에폭에서 손실이 안 내려가거나 발산한다. 사전학습된 표현이 한 번에 무너진 것이다
학습률이 너무 작음(1e-6 이하) 손실이 아주 천천히 내려가고 에폭을 늘려도 기준선을 못 넘는다
에폭이 너무 많음(5 이상) 학습 손실은 계속 내려가는데 검증 F1이 2에폭째부터 꺾인다. 과적합이다

warmup_ratio=0.1 정도를 함께 두면 초반 몇 스텝 동안 학습률이 0에서 목표값까지 올라가면서 첫 번째 증상이 크게 줄어든다.

입력 길이

max_length를 512로 두고 시작하는 습관은 비싸다. 어텐션의 계산량은 길이의 제곱에 비례하므로 512는 128의 열여섯 배다.

정하는 절차는 간단하다. 학습 데이터를 토크나이저에 통과시켜 토큰 길이의 분포를 구하고, 95 백분위 지점에서 자른다. 그 지점을 넘는 5%는 뒤가 잘리지만, 대부분의 분류 문제에서 판정 근거는 앞쪽에 몰려 있어 손실이 작다. 뉴스 제목 분류라면 32로 충분하고, 리뷰는 128, 긴 문의 메일은 256쯤에서 95 지점이 잡힌다. 모르고 512를 쓰면 없는 패딩을 계산하느라 학습 시간을 네 배쯤 버린다.

HuggingFace 텍스트 분류 구현

from transformers import (
    AutoTokenizer,
    AutoModelForSequenceClassification,
    TrainingArguments,
    Trainer,
)
from datasets import load_dataset
import numpy as np
from sklearn.metrics import f1_score

MODEL_NAME = "klue/roberta-base"

tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model = AutoModelForSequenceClassification.from_pretrained(
    MODEL_NAME, num_labels=7
)

dataset = load_dataset("klue", "ynat")  # 뉴스 7개 카테고리
dataset = dataset.map(
    lambda b: tokenizer(b["title"], truncation=True, max_length=64),
    batched=True,
)

def compute_metrics(eval_pred):
    logits, labels = eval_pred
    preds = np.argmax(logits, axis=-1)
    return {"f1": f1_score(labels, preds, average="macro")}

args = TrainingArguments(
    output_dir="./results",
    num_train_epochs=3,
    per_device_train_batch_size=32,
    learning_rate=3e-5,
    warmup_ratio=0.1,
    eval_strategy="epoch",
    save_strategy="epoch",
    load_best_model_at_end=True,
    metric_for_best_model="f1",
)

Trainer(
    model=model,
    args=args,
    train_dataset=dataset["train"],
    eval_dataset=dataset["validation"],
    compute_metrics=compute_metrics,
).train()

불균형과 신뢰도

세 가지 대응

클래스별 샘플 수가 100:1로 벌어지면 모델은 다수 클래스만 찍어도 정확도 99%를 얻는다. 손대는 자리가 셋이고 서로 다르다.

class_weight는 손실 쪽을 만진다. 희귀 클래스의 오답에 더 큰 벌점을 매겨 기울기를 키운다. 데이터를 건드리지 않으므로 가장 싸고 먼저 시도할 값이다. 오버샘플링은 데이터 쪽을 만진다. 희귀 클래스를 복제하거나 증강해 배치 안의 비율 자체를 바꾼다. 중복이 늘어 과적합 위험이 함께 온다. Focal Loss는 손실의 모양을 만진다 — 이미 잘 맞히는 쉬운 샘플의 기여를 지수적으로 눌러 어려운 샘플로 기울기를 몰아준다. 불균형이 극단적이고 쉬운 샘플이 배치를 가득 채우는 경우에 쓴다.

순서는 싼 것부터다. class_weight를 켜고 macro-F1을 다시 재 보고, 그것으로 안 되면 희귀 클래스만 증강하고, 그래도 안 되면 손실 자체를 바꾼다. 셋을 한꺼번에 걸면 어느 것이 효과를 냈는지 알 수 없게 되고, 다음에 데이터가 바뀌었을 때 무엇을 다시 조정해야 하는지도 알 수 없다.

macro-F1

지표를 정확도로 두는 한 위의 어떤 대응도 효과가 안 보인다. 정확도는 샘플 수로 가중되므로 다수 클래스의 성능이 곧 전체 숫자가 되기 때문이다.

macro-F1은 클래스마다 F1을 따로 구해 단순 평균한다. 클래스 일곱 중 여섯이 잘 맞고 하나가 0이면 macro-F1은 0.86에서 멈추고, 그 하나가 어디인지가 지표에 즉시 드러난다. 소수 클래스가 중요한 문제라면 판단 지표를 여기로 옮기는 것이 먼저다.

과신과 게이팅

소프트맥스 최댓값을 그대로 신뢰도로 쓰는 일이 흔한데, 이 값은 확률이라기보다 「모델이 얼마나 확신하는 것처럼 보이는가」에 가깝다. 사전학습 모델은 전반적으로 과신하는 성질이 있어, 학습 분포 밖의 입력에도 0.95를 내놓는다.

그래도 이 값은 쓸모가 있다 — 절대값을 믿지 않고 상대적 순위로 쓰면 된다. 최댓값이 낮은 건을 모아 보면 실제로 오답률이 높다. 그래서 「0.7 미만은 분류 불가로 빼고 사람에게 넘긴다」는 게이팅이 통한다. 이때 0.7은 신념이 아니라 검증 세트에서 정하는 값이다. 임계값을 올릴수록 자동 처리 비율은 내려가고 자동 처리된 것의 정확도는 올라가므로, 그 둘을 표로 그려 놓고 운영이 감당할 수 있는 지점을 고른다.

계층 분류

두 단이 이기는 지점

클래스가 50개를 넘어가면 단일 분류기의 macro-F1이 눈에 띄게 주저앉는다. 출력층이 50방향으로 갈라지는데 클래스당 데이터는 그만큼 얇아지고, 서로 닮은 클래스들이 같은 결정 경계 근처에 몰리기 때문이다.

대분류 → 소분류 2단 구성은 이 문제를 두 개의 쉬운 문제로 나눈다. 대분류기는 클래스가 대여섯뿐이라 데이터가 넉넉하고, 소분류기는 이미 좁혀진 영역 안에서만 갈라 주면 된다. 대신 대분류에서 틀리면 소분류가 아무리 정확해도 복구가 안 되는 구조라, 대분류기 쪽에 정확도를 몰아주는 것이 맞다. 대분류기에만 더 큰 모델을 쓰거나, 대분류 단계에서만 상위 두 후보를 남겨 소분류기 둘을 모두 돌린 뒤 점수를 곱해 고르는 구성이 흔하다. 후자는 계산이 두 배가 되지만 첫 단의 실수가 최종 답을 결정해 버리는 성질을 누그러뜨린다.

혼동 행렬 읽기

계층으로 나눌지 말지, 어디서 나눌지는 감이 아니라 혼동 행렬이 알려 준다. 두 클래스가 서로를 먹는 짝, 즉 A를 B로 틀린 수와 B를 A로 틀린 수가 둘 다 큰 자리를 찾는다.

그런 짝이 나오면 모델을 의심하기 전에 레이블 체계 자체를 의심한다. 사람이 봐도 경계가 안 갈리는 두 클래스를 만들어 놓은 경우가 대부분이고, 그때 할 일은 모델을 키우는 것이 아니라 두 클래스를 합치거나 판정 기준을 문서로 다시 못 박고 재라벨링하는 것이다. 라벨러 둘에게 같은 100건을 주고 일치도를 재 보면 답이 빨리 나온다.

새 클래스가 생길 때

운영 중인 분류기에는 반드시 새 클래스가 추가된다. 단일 분류기라면 출력층 크기가 바뀌므로 전체를 다시 학습해야 하고, 기존 클래스의 성능이 함께 흔들린다. 계층 구조라면 새 클래스가 속할 대분류 아래의 소분류기 하나만 다시 학습하면 되고, 나머지 가지는 손대지 않은 채로 남는다. 클래스가 계속 늘어날 것이 예상되는 문제에서 계층 구성을 고르는 이유는 정확도만이 아니라 이 유지 비용 쪽이 더 크다.

한국어 전처리

형태소와 서브워드

한국어에서는 같은 뜻이 「좋다」·「좋아서」·「좋았던」·「좋습니다」로 갈라진다. 이것이 두 접근에 각각 다른 일을 요구한다.

TF-IDF에서는 이 넷이 전부 다른 특징이 되므로 신호가 넷으로 쪼개진다. 그래서 형태소 분석기로 어간을 뽑아 통일해야 한다 — Mecab이나 Kiwi로 「좋」을 뽑으면 넷이 한 특징으로 모인다. 반대로 BERT 계열에서는 형태소 분석을 먼저 돌리면 안 된다. 사전학습이 서브워드 토큰 위에서 이루어졌으므로 그 모델의 토크나이저가 기대하는 입력은 원문 그대로이고, 형태소로 잘라 넣으면 학습할 때 본 적 없는 분절이 들어간다. 한국어 모델을 쓰면서 KoNLPy를 앞에 붙여 두는 실수가 여기서 나온다.

구어체 정규화

소셜 미디어와 상담 로그에는 오탈자, 신조어, 이모지, 「ㅋㅋㅋㅋㅋㅋ」 같은 반복 문자가 섞인다. 전부 지우는 것이 정답은 아니다.

반복 문자는 길이만 줄인다. 「ㅋㅋㅋㅋㅋㅋㅋ」를 「ㅋㅋ」로 줄이면 어휘 폭발은 막으면서 그 표시가 있었다는 사실은 남는다. 이모지는 감성·의도 분류에서 강한 신호이므로 지우지 말고 토큰으로 남기거나 이름으로 치환한다. 오탈자는 건드리지 않는 쪽이 대체로 낫다 — 자동 교정이 고유명사와 신조어를 망가뜨리는 비용이 오탈자가 주는 손해보다 큰 경우가 많고, 서브워드 토크나이저는 원래 미등록어에 강하다.

모델 고르기

상황 고를 것
레이블 수백~수천 건, 빠른 기준선 TF-IDF + 로지스틱 회귀
고성능, 도메인 범용 KLUE-RoBERTa-base 파인튜닝
마지막 몇 %p가 필요함 KLUE-RoBERTa-large
추론 속도가 중요함 DistilKoBERT 또는 양자화한 base
레이블 10개 미만, 예제 부족 LLM few-shot

도메인이 금융·의료·법률처럼 어휘가 크게 다르면 그 도메인 데이터로 지속 사전학습(CPT)까지 가는 선택지가 있지만, 그 전에 도메인 데이터 수천 건으로 파인튜닝만 해 보는 편이 비용 대비 이득이 크다. 한국어 토크나이저가 같은 글을 얼마나 다른 개수의 토큰으로 자르는지는 한국어 토큰세에 실측이 있다.

오답 분석

50건을 직접 읽는다

지표가 멈추면 다음에 할 일은 하이퍼파라미터 탐색이 아니라 오답을 읽는 것이다. 검증 세트에서 틀린 건을 신뢰도 순으로 정렬해 50건을 뽑아 직접 읽는다. 한 시간이면 끝나고, 거기서 나오는 것이 둘 중 하나다.

라벨 오류는 모델이 맞고 정답이 틀린 경우다. 이 비율이 10%를 넘으면 모델을 손보는 것은 의미가 없다 — 지표의 상한이 이미 그만큼 깎여 있고, 학습 데이터에도 같은 비율로 섞여 있을 것이기 때문이다. 할 일은 라벨 정제다. 모델 오류는 정답이 맞는데 모델이 틀린 경우이고, 이쪽은 다시 패턴별로 묶인다. 특정 표현에서만 틀리는지, 길이가 긴 건에서만 틀리는지, 한 클래스 쌍에서만 틀리는지에 따라 대응이 각각 다르다.

증강은 적은 클래스에만

역번역(한→영→한)과 동의어 치환은 데이터를 늘리는 값싼 방법이지만, 전체에 거는 순간 이득이 사라진다. 다수 클래스까지 함께 늘어나 비율이 그대로 남고, 증강이 만드는 잡음만 전 구간에 깔리기 때문이다.

희귀 클래스에만 걸면 불균형을 줄이면서 그 클래스의 표현 다양성을 늘리는 두 가지 효과를 동시에 얻는다. 다만 늘린 뒤에 반드시 몇 건을 눈으로 확인한다. 역번역은 고유명사와 도메인 용어를 조용히 갈아 끼우고, 동의어 치환은 감성 분류에서 극성을 뒤집기도 한다.

재학습 시점

서비스에 나간 분류기는 시간이 가면 반드시 나빠진다. 새로운 말이 들어오고, 문의 유형의 분포가 바뀌고, 없던 제품이 생긴다. 정답 라벨은 실시간으로 안 들어오므로 정확도로는 이 순간을 못 잡는다.

대신 라벨 없이 볼 수 있는 신호가 셋 있다. 신뢰도 게이팅에 걸려 사람에게 넘어가는 건의 비율이 올라가는 것, 예측된 클래스 분포가 과거와 달라지는 것, 그리고 미등록어(UNK)나 서브워드로 잘게 쪼개지는 입력의 비율이 오르는 것이다. 이 셋 중 하나라도 평소 대역을 벗어나면 그때 최근 데이터에서 표본을 떠 라벨을 붙이고 실제 정확도를 잰다. 달력으로 정한 주기가 아니라 이 신호가 재학습 시점을 정하게 하는 편이 비용도 적고 반응도 빠르다.

분류는 대개 더 큰 파이프라인의 첫 단계다. 다음 글에서는 그 뒤에 자주 붙는 작업, 곧 긴 문서를 한 문단으로 줄이는 요약을 다룬다. 분류가 텍스트를 한 칸에 넣는 일이라면 요약은 텍스트를 다시 텍스트로 만드는 일이라, 정답을 고르는 문제에서 정답을 짓는 문제로 성격이 한 번 바뀐다.


읽어주셔서 감사합니다. 😊

LATEST

비전·음성·추천의 최신 글

비전·음성·추천2026.09.07

오프라인 강화학습 — 쌓인 로그만으로 정책을 배우기

실제 서비스에서 탐색은 곧 사용자에게 나쁜 행동을 해 보는 일입니다. 이미 쌓인 로그만으로 정책을 배우려 할 때 왜 Q값이 혼자 부풀어 오르는지, 그 부풀음을 누르는 세 갈래 대응, 행동 복제라는 기준선의 무게, 그리고 배포 전에 성능을 재는 일이 왜 가장 어려운지를 정리합니다.

18 MIN
비전·음성·추천2026.09.07

다국어 전이 — 라벨 없는 언어에서 모델이 동작하는 이유

영어 라벨만으로 학습한 분류기가 한국어 문장을 그대로 처리하는 일이 실제로 일어납니다. 여러 언어가 한 표현 공간에 겹쳐 놓이는 원리, 그 겹침이 무너지는 조건, 번역해서 학습할지 번역해서 추론할지 고르는 기준, 그리고 언어별로 나눠 재야 하는 이유를 정리합니다.

16 MIN
비전·음성·추천2026.09.07

정보 추출 — 글 한 덩이를 표 한 줄로 바꾸는 일

계약서와 이메일을 데이터베이스에 넣으려면 글에서 값을 뽑아 칸에 채워야 합니다. 개체명·관계·사건의 세 층위, 값을 정규화하는 일이 왜 절반인지, 근거 위치를 함께 남겨야 하는 이유, 규칙·전용 모델·언어 모델의 갈림길, 그리고 필드별로 재는 평가법을 정리합니다.

17 MIN