W&B Tables를 사용하여 표 형식(tabular) 데이터를 시각화하고 기록할 수 있습니다. W&B Table은 각 열이 하나의 데이터 타입만 가지는 2차원 그리드입니다. 각 행은 W&B 실행에 로그된 하나 이상의 데이터 포인트를 나타냅니다. W&B Tables는 기본 및 숫자형 데이터 타입뿐만 아니라 중첩 리스트, 딕셔너리, 리치 미디어 타입도 지원합니다.
W&B Table은 W&B의 특수한 데이터 타입으로, 아티팩트 객체로 로그됩니다.
W&B Python SDK를 사용하여 테이블 객체를 생성하고 로그합니다. 테이블 객체를 생성할 때 테이블의 열과 데이터, 그리고 모드를 지정합니다. 모드에 따라 ML 실험 동안 테이블이 어떻게 로그되고 업데이트될지가 결정됩니다.
INCREMENTAL 모드는 W&B Server v0.70.0 이상에서 지원됩니다.
wandb.init()으로 새 실행을 초기화합니다.
wandb.Table 클래스로 Table 객체를 생성합니다. columns와 data 매개변수에 각각 테이블의 열과 데이터를 지정합니다. 선택적 매개변수인 log_mode는 기본값 IMMUTABLE을 포함해 MUTABLE, INCREMENTAL 중 하나로 설정할 것을 권장합니다. 자세한 내용은 다음 섹션의 Table Logging Modes를 참고하세요.
run.log()를 사용하여 테이블을 W&B에 로그합니다.
다음 예시는 두 개의 열 a와 b, 그리고 두 개의 데이터 행 ["a1", "b1"] 및 ["a2", "b2"]를 가진 테이블을 생성하고 로그하는 방법을 보여줍니다:
import wandb
# 새 실행 시작
with wandb.init(project="table-demo") as run:
# 두 개의 열과 두 개의 행으로 구성된 테이블 객체 생성
my_table = wandb.Table(
columns=["a", "b"],
data=[["a1", "b1"], ["a2", "b2"]],
log_mode="IMMUTABLE"
)
# W&B에 테이블 로깅
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에 한 번 로깅되면 수정할 수 없습니다. | - 추가 분석을 위해 실행이 끝날 때 생성된 테이블형 데이터를 저장할 때 | - 실행 종료 시점에 로깅할 경우 오버헤드 최소화 - 모든 행이 UI에 렌더링됨 |
MUTABLE | 테이블을 W&B에 로깅한 이후, 기존 테이블을 새로운 테이블로 덮어쓸 수 있습니다. | - 기존 테이블에 열이나 행을 추가할 때 - 결과를 새로운 정보로 보강할 때 | - 테이블 변경 사항 캡처 - 모든 행이 UI에 렌더링됨 |
INCREMENTAL | 머신러닝 실험 전체에 걸쳐 새로운 행 배치를 테이블에 계속 추가합니다. | - 테이블에 행을 배치 단위로 추가할 때 - 장시간 실행되는 학습 작업 - 대규모 데이터셋을 배치 단위로 처리할 때 - 진행 중인 결과를 모니터링할 때 | - 학습 중 UI에서 업데이트를 확인 가능 - 증가분을 단계별로 확인 가능 |
다음 섹션에서는 각 모드에 대한 예제 코드 스니펫과, 각 모드를 언제 사용하는 것이 적절한지에 대한 고려 사항을 설명합니다.
MUTABLE 모드는 기존 테이블을 새로운 테이블로 교체하는 방식으로 업데이트합니다. MUTABLE 모드는 반복 루프 없이(비반복적, non-iterative) 기존 테이블에 새로운 열과 행을 추가하려는 경우에 유용합니다. UI에서는 초기 로깅 이후에 추가된 열과 행을 포함해, 모든 행과 열이 있는 테이블이 렌더링됩니다.
MUTABLE 모드에서는 테이블을 로그할 때마다 테이블 객체가 교체됩니다. 테이블을 새 테이블로 덮어쓰는 작업은 연산 비용이 많이 들며, 테이블이 큰 경우 속도가 느려질 수 있습니다.
다음 예시는 MUTABLE 모드에서 테이블을 생성하고 로깅한 뒤, 새 열을 추가하는 방법을 보여줍니다. 테이블 객체는 총 세 번 로깅됩니다. 처음에는 초기 데이터, 두 번째는 신뢰도 점수(confidence scores), 세 번째는 최종 예측값으로 로깅됩니다.
다음 예시에서는 데이터를 로드하기 위해 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)
# 1단계: 초기 데이터 기록
run.log({"eval_table": table}) # 초기 테이블 기록
# 2단계: 신뢰도 점수 추가 (예: 최대 소프트맥스)
confidences = np.max(raw_preds, axis=1)
table.add_column("confidence", confidences)
run.log({"eval_table": table}) # 신뢰도 정보 추가
# 3단계: 후처리된 예측값 추가
# (예: 임계값 적용 또는 평활화된 출력)
post_preds = (confidences > 0.7).astype(int)
table.add_column("final_prediction", post_preds)
run.log({"eval_table": table}) # 새 열을 추가한 최종 업데이트
훈련 루프에서처럼 새로운 행 배치(열은 없음)만 순차적으로 추가하려는 경우에는, 대신 INCREMENTAL 모드를 사용하는 것이 좋습니다.
INCREMENTAL 모드에서는 머신러닝 실험 동안 테이블에 행 배치를 나누어 기록합니다. 이는 실행 시간이 긴 작업을 모니터링하거나, 실행 중에 업데이트용으로 기록하기에는 비효율적인 대용량 테이블을 다룰 때 적합합니다. UI에서 테이블은 새 행이 기록될 때마다 업데이트되므로, 전체 실행이 끝날 때까지 기다리지 않고도 최신 데이터를 확인할 수 있습니다. 또한 각 증분을 단계별로 살펴보며 서로 다른 시점의 테이블 상태를 확인할 수 있습니다.
W&B App의 실행 워크스페이스에는 증분 100개 제한이 있습니다. 100개를 초과하여 기록하면, 실행 워크스페이스에는 가장 최근 100개만 표시됩니다.
다음 예시는 INCREMENTAL 모드에서 테이블을 생성하고, 이를 기록한 뒤 새로운 행을 추가합니다. 테이블은 학습 스텝(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이 테이블의 모든 행을 렌더링하지 못할 수 있습니다. 실행이 진행되는 동안 테이블 데이터를 업데이트해서 확인하고, 동시에 분석을 위해 모든 데이터를 사용할 수 있어야 한다면 두 개의 테이블 사용을 고려하십시오. 하나는 INCREMENTAL 로그 모드, 다른 하나는 IMMUTABLE 로그 모드를 사용합니다.
다음 예제는 이러한 목표를 달성하기 위해 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:
# 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}) # 원시 예측값 기록
# 2단계: 신뢰도 점수 추가 (예: 최대 소프트맥스)
confidences = np.max(raw_preds, axis=1)
table.add_column("confidence", confidences)
run.log({"eval_table": table}) # 신뢰도 정보 추가
# 3단계: 후처리된 예측값 추가
# (예: 임계값 적용 또는 평활화된 출력)
post_preds = (confidences > 0.7).astype(int)
table.add_column("final_prediction", post_preds)
run.log({"eval_table": table})
실행을 재개할 때에도 INCREMENTAL 테이블에 계속 로그를 기록할 수 있습니다:
# 실행을 시작하거나 재개합니다
resumed_run = wandb.init(project="resume-incremental", id="your-run-id", resume="must")
# 증분 테이블을 생성합니다. 이전에 로깅된 테이블의 데이터로 채울 필요가 없습니다.
# 증분 데이터는 계속해서 Table 아티팩트에 추가됩니다.
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")를 사용해 증분 테이블에 사용되는 키에 대한 요약(summary)을 끄면, 증분 데이터는 새 테이블에 기록됩니다.
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)
# 모델 추론 실행
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)