내 데이터셋의 99%는 어디로 갔는가
나는 수백만 개의 학습 예제로 이루어진 데이터셋을 만들겠다고 나섰다. 파이프라인이 끝났을 때, 그것이 내게 건넨 건 그 수치의 고작 몇 퍼센트였다 — 너무 작아서 오타처럼 보일 정도의 분량이었다. 아무것도 망가지지 않았다. 어떤 에러도 발생하지 않았다. 데이터 생성에 실패한 게 아니었다. 그것은 조용히 자기 자신의 거의 전부를 내다 버리고는, 성공했다고 보고했다.
맞다고 하기엔 너무 작았던 숫자
이런 종류의 버그가 가진 이상한 점은, 스스로를 드러내지 않는다는 것이다. 크래시가 난 파이프라인은 시끄럽다. 너무 적게 생산하면서도 조용한 파이프라인은 그냥 끝나서 파일 하나를 건네주고, 당신이 알아챌 때까지 기다린다. 내가 예상했던 예제 수가 대략 얼마였는지를 우연히 기억하지 못했더라면, 살아남은 것들로 학습을 시키고는 나머지가 사라졌다는 사실을 영영 몰랐을지도 모른다.
유일한 증상은 거의 두 자릿수만큼 어긋난 개수였다. 그리고 개수가 틀린 것은 세상에서 가장 그냥 지나치기 쉬운 증상 중 하나다. 예상보다 작은 숫자도 여전히 진짜 숫자처럼 보이기 때문이다. 그것은 에러처럼 느껴지지 않는다. 결과처럼 느껴진다.
”왜 이렇게 적지?”는 진짜 버그의 한 부류다
우리는 망가지는 것을 디버깅하도록 훈련받았다. 그저 부재하는 것 — 존재해야 하는데 없는 데이터, 만들어졌어야 하는데 결코 만들어지지 않은 예제 — 을 디버깅하는 데에는 훨씬 서툴다. 가지 않은 길에는 스택 트레이스가 없다. 파이프라인은 내가 시킨 그대로 정확히 했다. 다만 내가 시킨 그 일이 처리 과정에서 입력의 대부분을 버려 버렸을 뿐이다.
데이터는 어디로 갔는가
원인은 거의 민망할 만큼 평범했다. 과정 어딘가에서, 나는 타임라인을 큰 보폭으로 건너뛰며 지나가고 있었다 — 한 순간을 보고, 긴 간격을 건너뛰어 다음으로, 다시 건너뛰고. 내가 건너뛴 모든 위치는 한 번도 검토되지 않고 한 번도 만들어지지 않은 잠재적 예제였다. 나는 그 보폭을 초기에, 이제는 기억나지 않는 어떤 이유로 설정해 두었고, 그것이 거기 있다는 사실을 잊어버렸다.
그래서 데이터셋은 손상된 것도, 필터링된 것도, 정제되어 줄어든 것도 아니었다. 그것은 그저 한 번도 온전히 들여다본 적이 없었던 것이다. 가용한 데이터의 압도적 다수는 루프의 보폭에서 한 걸음 바깥에 손도 닿지 않은 채 앉아 있었고, 그 사이 파이프라인은 그것을 지나쳐 행진하며 다 끝났다고 보고했다.
조용한 손실이 위험한 부류다
이 부분이 내가 계속 곱씹게 되는 지점이다. 시끄러운 실패는 선물이다. 그것은 당신을 멈춰 세우고, 자기 자신을 가리키며, 주의를 요구한다. 조용한 손실은 그런 것을 전혀 주지 않는다. 그럴듯해 보이는 출력을 내놓고, 불평 없이 돌아가며, 하류의 모든 것이 그 위에 세워지는 토대를 조용히 바꿔 버린다. 당신은 모델을 학습시키고, 평가하고, 거기서 결론을 끌어낼 수 있다 — 그 모든 것을, 당신이 가졌다고 생각한 것의 은밀하게 작디작고 대표성 없는 한 조각에 불과한 데이터셋 위에서.
위험한 것은 단지 숫자가 틀렸다는 점이 아니다. 숫자가 틀렸는데 시스템은 그것을 만족스러워한다는 점이다 — 모든 게 초록불이고, 모든 게 돌아가고, 모든 게 바로 첫 단계에서 당신을 배신한 토대 위에 세워져 있다.
해결책: 전부 검토한 뒤, 무엇을 남길지 고른다
수리는 건너뛰기를 멈추는 것이었다. 타임라인을 가로질러 성큼성큼 걸으며 우연히 발을 디딘 지점만 검사하는 대신, 나는 그 과정이 각 위치를 차례로 살피도록 했다 — 그리고 무엇을 남길지에 대한 결정을, 샘플링 단계의 우연한 부산물이 아니라 명시적이고 의도적인 필터로 만들었다. 내가 버린 데이터는, 이제 소리 내어 말할 수 있는 이유를 가지고 의도적으로 버렸다. 내가 남긴 데이터는, 실제로 들여다보았기 때문에 남겼다.
데이터셋은 본래 있어야 할 크기에 가깝게 돌아왔다. 그것을 이뤄낸 영리한 무언가는 없었다. 나는 그저 의도치 않게 데이터를 버리는 일을 멈췄을 뿐이다.
데이터 작업에서 가장 값싼 점검
교훈은 교훈이라고 느껴지기엔 거의 너무 단순하다. 당신이 예상한 크기와 실제로 얻은 크기를 비교하라. 그것은 내가 형편없이 적게 써먹어 온 값싼 정합성 점검이고, 이걸 했더라면 몇 초 만에 이 문제를 잡아냈을 것이다. 내가 가졌다고 생각한 데이터의 양과 실제로 존재하는 데이터의 양 사이의 큰 간극은 버그로 취급될 자격이 있다 — 심지어, 특히, 그것을 알려줄 만한 어떤 크래시도 나지 않았을 때 말이다.
이제 어떤 데이터셋을 받든 내가 가장 먼저 하는 일은 그 내용을 들여다보는 것이 아니다. 그 개수를 들여다보고, 그 숫자가 애초에 그럴듯하기는 한지 묻는 것이다. 내가 겪은 최악의 데이터 문제 중 다수는 데이터를 손상시키지 않았다. 그것들은 그저 내가 믿었던 것보다 조용히 더 적게 생산하고는, 내가 그 차이 위에 무언가를 쌓도록 내버려 두었다.
당신의 데이터 대부분을 목소리 한번 높이지 않고 잃어버리는 파이프라인은 크래시가 난 것이 아니다 — 그것은 작성된 그대로 정확히 돌아가면서도, 여전히 잘못된 일을 하고 있다. 버그는 결코 기계의 결함이 아니었다. 그것은 내가 가정한 것과 내가 굳이 확인한 것 사이의 간극에 있었다.
— 시그널 없음, 수익 없음, 투자 자문 아님.