W&B Tables를 사용해 테이블 형식 데이터를 시각화하고 로깅하세요. W&B 테이블은 각 열이 단일 데이터 유형을 갖는 2차원 데이터 그리드입니다. 각 행은 W&B run에 로깅된 하나 이상의 데이터 포인트를 나타냅니다. W&B Tables는 기본형 및 숫자형은 물론, 중첩된 목록, 딕셔너리, 리치 미디어 유형도 지원합니다.
W&B 테이블은 W&B의 특수한 데이터 유형으로, artifact 객체로 로깅됩니다.
W&B Python SDK를 사용해 테이블 객체를 생성하고 로깅합니다. 테이블 객체를 만들 때는 열과 데이터, 그리고 모드를 지정합니다. 모드는 ML 실험 중 table이 어떻게 로깅되고 업데이트되는지를 결정합니다.
INCREMENTAL 모드는 W&B Server v0.70.0 이상에서 지원됩니다.
wandb.init()으로 새 run을 초기화합니다.
wandb.Table 클래스로 테이블 객체를 생성합니다. columns와 data 파라미터에 각각 테이블의 열과 데이터를 지정합니다. 선택 log_mode 파라미터는 IMMUTABLE(기본값), MUTABLE, INCREMENTAL의 세 가지 모드 중 하나로 설정하는 것이 좋습니다. 자세한 내용은 다음 섹션의 테이블 Logging Modes를 참조하세요.
run.log()로 테이블을 W&B에 로깅합니다.
다음 예제는 a와 b 두 개의 열과 ["a1", "b1"], ["a2", "b2"] 두 개의 데이터 행이 있는 테이블을 생성하고 로깅하는 방법을 보여줍니다:
import wandb
# 새 run 시작
with wandb.init(project="table-demo") as run:
# 두 개의 열과 두 개의 행 데이터로 table 객체 생성
my_table = wandb.Table(
columns=["a", "b"],
data=[["a1", "b1"], ["a2", "b2"]],
log_mode="IMMUTABLE"
)
# W&B에 table 로그
run.log({"Table Name": my_table})
wandb.Table log_mode 파라미터는 ML 실험 중 테이블이 어떻게 로깅되고 업데이트되는지를 결정합니다. log_mode 파라미터는 IMMUTABLE, MUTABLE, INCREMENTAL의 세 가지 인자 중 하나를 받습니다. 각 모드는 테이블이 로깅되는 방식, 수정 가능한 방식, 그리고 W&B App에서 렌더링되는 방식에 서로 다른 영향을 미칩니다.
다음은 세 가지 로깅 모드와 각 모드의 주요 차이점, 그리고 각 모드의 일반적인 사용 사례를 설명합니다:
| Mode | Definition | Use Cases | Benefits |
|---|
IMMUTABLE | 테이블이 W&B에 로깅되고 나면 수정할 수 없습니다. | - 추가 분석을 위해 run 종료 시 생성된 테이블형 데이터를 저장 | - run 종료 시 로깅하면 오버헤드가 최소화됨 - 모든 행이 UI에 렌더링됨 |
MUTABLE | 테이블을 W&B에 로깅한 후 기존 테이블을 새 테이블로 덮어쓸 수 있습니다. | - 기존 테이블에 열이나 행 추가 - 새 정보로 결과 보강 | - 테이블 변경 사항 캡처 - 모든 행이 UI에 렌더링됨 |
INCREMENTAL | 머신 러닝 실험 전반에 걸쳐 테이블에 새 행 배치를 추가합니다. | - 테이블에 행을 배치 단위로 추가 - 장시간 실행되는 트레이닝 작업 - 대규모 데이터셋을 배치로 처리 - 진행 중인 결과 모니터링 | - 트레이닝 중 UI에서 업데이트 확인 - 증가분을 step 단위로 확인 가능 |
다음 섹션에서는 각 모드의 예제 코드 스니펫과 함께, 각 모드를 언제 사용해야 하는지에 대한 고려 사항을 보여줍니다.
MUTABLE 모드는 기존 테이블을 새 테이블로 교체해 업데이트합니다. MUTABLE 모드는 반복하지 않는 프로세스에서 기존 테이블에 새 열과 행을 추가하려는 경우에 유용합니다. UI에서는 초기 로깅 후 추가된 새 행과 열을 포함해 모든 행과 열이 표시됩니다.
MUTABLE 모드에서는 테이블을 로깅할 때마다 테이블 객체가 교체됩니다. 새 테이블로 덮어쓰는 작업은 계산 비용이 크므로, 큰 테이블에서는 느릴 수 있습니다.
다음 예제에서는 MUTABLE 모드로 테이블을 만들고, 이를 로깅한 뒤 새 열을 추가하는 방법을 보여줍니다. 테이블 객체는 세 번 로깅됩니다. 한 번은 초기 데이터로, 한 번은 신뢰도 점수로, 마지막 한 번은 최종 예측으로 로깅됩니다.
다음 예제에서는 데이터를 로드하기 위해 플레이스홀더 함수 load_eval_data()를 사용하고, 예측을 수행하기 위해 플레이스홀더 함수 model.predict()를 사용합니다. 이 함수들은 사용자의 데이터 로드 함수와 예측 함수로 바꿔야 합니다.
import wandb
import numpy as np
with wandb.init(project="mutable-table-demo") as run:
# MUTABLE 로깅 모드로 테이블 객체 생성
table = wandb.Table(columns=["input", "label", "prediction"],
log_mode="MUTABLE")
# 데이터 로드 및 예측 수행
inputs, labels = load_eval_data() # 플레이스홀더 함수
raw_preds = model.predict(inputs) # 플레이스홀더 함수
for inp, label, pred in zip(inputs, labels, raw_preds):
table.add_data(inp, label, pred)
# Step 1: 초기 데이터 로깅
run.log({"eval_table": table}) # 초기 테이블 로깅
# Step 2: 신뢰도 점수 추가 (예: max softmax)
confidences = np.max(raw_preds, axis=1)
table.add_column("confidence", confidences)
run.log({"eval_table": table}) # 신뢰도 정보 추가
# Step 3: 후처리된 예측값 추가
# (예: 임계값 적용 또는 평활화된 출력)
post_preds = (confidences > 0.7).astype(int)
table.add_column("final_prediction", post_preds)
run.log({"eval_table": table}) # 새 열을 추가한 최종 업데이트
새로운 행 배치만(열은 추가하지 않고) 트레이닝 루프에서처럼 점진적으로 추가하려는 경우에는 대신 INCREMENTAL 모드를 사용하는 것이 좋습니다.
incremental 모드에서는 머신 러닝 실험 중에 행 배치를 테이블에 로깅합니다. 이 방식은 오래 실행되는 작업을 모니터링하거나, 업데이트를 위해 run 도중 로깅하기에는 비효율적인 큰 테이블을 다룰 때 특히 적합합니다. UI에서는 행가 로깅될 때마다 새로운 행로 테이블이 업데이트되므로, 전체 run이 끝날 때까지 기다리지 않고도 최신 데이터를 확인할 수 있습니다. 또한 increment를 단계별로 넘겨 보면서 서로 다른 시점의 테이블을 확인할 수 있습니다.
W&B App의 run Workspace는 increment를 최대 100개까지 지원합니다. 100개를 초과해 increment를 로깅하면 run Workspace에는 가장 최근 100개만 표시됩니다.
다음 예제에서는 INCREMENTAL 모드로 테이블을 생성하고, 이를 로깅한 다음 새 행를 추가합니다. 테이블은 각 트레이닝 step(step)마다 한 번씩 로깅된다는 점에 유의하세요.
다음 예제에서는 데이터를 로드하기 위한 플레이스홀더 함수 get_training_batch(), 모델을 트레이닝하기 위한 플레이스홀더 함수 train_model_on_batch(), 그리고 예측을 수행하기 위한 플레이스홀더 함수 predict_on_batch()를 사용합니다. 이 함수들은 직접 구현한 데이터 로딩, 트레이닝, 예측 함수로 교체해야 합니다.
import wandb
with wandb.init(project="incremental-table-demo") as run:
# INCREMENTAL 로깅 모드로 테이블 생성
table = wandb.Table(columns=["step", "input", "label", "prediction"],
log_mode="INCREMENTAL")
# 트레이닝 루프
for step in range(get_num_batches()): # 플레이스홀더 함수
# 배치 데이터 로드
inputs, labels = get_training_batch(step) # 플레이스홀더 함수
# 트레이닝 및 예측
train_model_on_batch(inputs, labels) # 플레이스홀더 함수
predictions = predict_on_batch(inputs) # 플레이스홀더 함수
# 테이블에 배치 데이터 추가
for input_item, label, prediction in zip(inputs, labels, predictions):
table.add_data(step, input_item, label, prediction)
# 테이블을 증분 방식으로 로깅
run.log({"training_table": table}, step=step)
증분 로깅은 일반적으로 매번 새 테이블을 로깅하는 것보다(log_mode=MUTABLE) 계산 효율이 더 높습니다. 하지만 많은 수의 증분을 로깅하면 W&B App에서 테이블의 모든 행을 렌더링하지 못할 수 있습니다. 목표가 run이 진행되는 동안 테이블 데이터를 업데이트하고 확인하면서, 분석에 사용할 모든 데이터를 확보하는 것이라면 테이블 두 개를 사용하는 것을 고려하세요. 하나는 INCREMENTAL log 모드를 사용하고, 다른 하나는 IMMUTABLE log 모드를 사용합니다.
다음 예제는 이를 위해 INCREMENTAL 및 IMMUTABLE 로깅 모드를 함께 사용하는 방법을 보여줍니다.
import wandb
with wandb.init(project="combined-logging-example") as run:
# 트레이닝 중 효율적인 업데이트를 위한 증분 테이블 생성
incr_table = wandb.Table(columns=["step", "input", "prediction", "label"],
log_mode="INCREMENTAL")
# 트레이닝 루프
for step in range(get_num_batches()):
# 배치 처리
inputs, labels = get_training_batch(step)
predictions = model.predict(inputs)
# 증분 테이블에 데이터 추가
for inp, pred, label in zip(inputs, predictions, labels):
incr_table.add_data(step, inp, pred, label)
# 증분 업데이트 로깅 (최종 테이블과 구분하기 위해 -incr 접미사 사용)
run.log({"table-incr": incr_table}, step=step)
# 트레이닝 종료 시 모든 데이터를 포함한 완전한 불변 테이블 생성
# 전체 데이터셋 보존을 위해 기본 IMMUTABLE 모드 사용
final_table = wandb.Table(columns=incr_table.columns, data=incr_table.data, log_mode="IMMUTABLE")
run.log({"table": final_table})
이 예제에서는 트레이닝 중에 incr_table을 증분 방식으로 로깅합니다(log_mode="INCREMENTAL"). 이렇게 하면 새 데이터가 처리될 때마다 테이블의 업데이트를 로깅하고 확인할 수 있습니다. 트레이닝이 끝나면 증분 테이블의 모든 데이터를 포함하는 불변 테이블(final_table)이 생성됩니다. 불변 테이블은 이후 분석을 위해 전체 데이터셋을 보존할 수 있도록 로깅되며, W&B App에서 모든 행을 확인할 수 있게 해줍니다.
import wandb
import numpy as np
with wandb.init(project="mutable-logging") as run:
# Step 1: 초기 예측 로깅
table = wandb.Table(columns=["input", "label", "prediction"], log_mode="MUTABLE")
inputs, labels = load_eval_data()
raw_preds = model.predict(inputs)
for inp, label, pred in zip(inputs, labels, raw_preds):
table.add_data(inp, label, pred)
run.log({"eval_table": table}) # 원시 예측 로깅
# Step 2: 신뢰도 점수 추가 (예: max softmax)
confidences = np.max(raw_preds, axis=1)
table.add_column("confidence", confidences)
run.log({"eval_table": table}) # 신뢰도 정보 추가
# Step 3: 후처리된 예측 추가
# (예: 임계값 적용 또는 평활화된 출력)
post_preds = (confidences > 0.7).astype(int)
table.add_column("final_prediction", post_preds)
run.log({"eval_table": table})
INCREMENTAL 테이블로 run 재개하기
run을 재개할 때 INCREMENTAL 테이블에 계속 로그를 기록할 수 있습니다:
# run 시작 또는 재개
resumed_run = wandb.init(project="resume-incremental", id="your-run-id", resume="must")
# incremental table 생성; 이전에 로깅된 table의 데이터로 채울 필요 없음
# 증분 데이터는 계속해서 Table artifact에 추가됩니다.
table = wandb.Table(columns=["step", "metric"], log_mode="INCREMENTAL")
# 로깅 계속
for step in range(resume_step, final_step):
metric = compute_metric(step)
table.add_data(step, metric)
resumed_run.log({"metrics": table}, step=step)
resumed_run.finish()
wandb.Run.define_metric("<table_key>", summary="none") 또는 wandb.Run.define_metric("*", summary="none")를 사용해 incremental 테이블에 사용되는 키의 summary를 끄면, 증분은 새 테이블에 로깅됩니다.
INCREMENTAL 배치 트레이닝을 사용해 트레이닝하기
with wandb.init(project="batch-training-incremental") as run:
# 증분 테이블 생성
table = wandb.Table(columns=["step", "input", "label", "prediction"], log_mode="INCREMENTAL")
# 시뮬레이션 트레이닝 루프
for step in range(get_num_batches()):
# 배치 데이터 로드
inputs, labels = get_training_batch(step)
# 이 배치로 모델 트레이닝
train_model_on_batch(inputs, labels)
# 모델 Inference 실행
predictions = predict_on_batch(inputs)
# 테이블에 데이터 추가
for input_item, label, prediction in zip(inputs, labels, predictions):
table.add_data(step, input_item, label, prediction)
# 테이블의 현재 상태를 증분 방식으로 로깅
run.log({"training_table": table}, step=step)