월간 데이콘 숫자 3D 이미지 분류 AI 경진대회

최종 순위 관련 문의(업데이트)

2022.09.30 13:14 1,851 조회

안녕하세요 private 6위 lastdefiance20입니다. 최종순위 공지에 작성된 DATA LEAKAGE, "Test 데이터에 PCA.fit_transform() 적용 후 모델 학습에 활용"에 대해서 이의를 제기합니다. 대회 관련 문의에도 작성하였으나, 사진을 첨부해서 토크 게시판에도 올립니다.


우선 제가 생각하는 data leakage의 정의부터 간단히 하고 들어가겠습니다. data leakage란 test 데이터의 분포를 train시 사용하거나, test 데이터를 잘못 활용할 때 발생하는 행위입니다.


가장 판단하기 쉽게 말하자면, test 데이터의 개수나 분포 등이 변화할 때마다 train을 진행할 때나 test를 진행할때 영향을 끼치게 되는 요소가 있다면, data leakage로 판단할 수 있습니다.


기존 대회에서 data leakage 가장 빈번했던 부분은 정형 데이터 대회에서 스케일러를 사용할 때 train셋에 fit_transform, test셋에 fit_transform을 하는 부분입니다. test셋에 fit_transform을 하는 행위가 data leakage인 경우는 다음과 같은 이유입니다. minmax encoder를 사용한다고 가정할 경우, train셋에는 age에 대한 분포가 0~100까지 있지만, test셋에는 age에 대한 분포가 50~70까지 있고, 이를 minmax하여 train과 test셋에 fit_transform하면 train셋에서의 100은 1로, test셋의 70은 1로 대응되게 됩니다. 따라서 만약 다른 test셋이 주어지고, 그 셋에는 age에 대한 분포가 40~80이라면, 80이 1로 대응되어서 완전히 다른 결과가 나오게 됩니다.


마찬가지로 정형 데이터 train셋에서 train셋의 mean값을 활용해 나눈 변수를 test셋에서 test셋의 mean값을 활용해 나눈 결과물을 사용하거나 학습에 활용한다면, test셋의 분포가 바뀔 때마다 다른 결과물이 나오게 됩니다. (예를 들어 나이 50이라는 데이터가 test셋 1에서는 평균값 20으로 나누어져 2.5로 계산되고, test셋 2에서는 평균값 25로 나누어져 2로 계산되며, 같은 데이터에 대해 다른 결과를 예측함, data leakage)


더 많은 예시들이 존재하나, 아마 이러한 탈락 경우들과 유사하다고 판단하고, fit_transform이라는 행위 자체가 데이터 leakage의 판단 근거로 삼아서 탈락처리를 했다고 생각됩니다.


하지만 현재 제가 진행한 방식에는 data leakage에 대한 이유가 전혀 존재하지 않는다고 생각합니다.


우선 첫 번째로, test 데이터의 input이 바뀌면 결과가 달라지는지 살펴보도록 하겠습니다. 현재 제가 진행하고 있는 방식은 각각의 이미지마다 새로운 PCA로 fit_transform을 진행해서 이미지마다 최적의 주성분을 찾아서 (쉽게 말하자면 가장 최적으로 2d로 만들기 위한 개별 이미지 공간 탐색 및 밀도 탐색) 개별 이미지마다 fit 및 transform을 진행하였으며, 이때 여기서 중요한 것은 "개별 이미지" 라는 것입니다. test 데이터 전체의 평균값이나, 이미지 몇 개의 정보들을 활용해서 어떠한 척도로 사용한 것이 아니라, test 개별 이미지에 대해서 개별적인 2d 이미지로 뽑아내는 과정에서 fit_transform을 사용했기 때문에 test 이미지가 하나여도 똑같은 결과가 나오게 됩니다.



<좌 = ~400까지 진행하면서 fit_transform, 우 = 400번만 fit_transform, 어짜피 df_pca로 항상 개별 데이터를 분석하고 투영시켜 결과가 같은 모습을 보임>

따라서 fit_transform행위는 개별 이미지에 적용하는 계산일 뿐입니다.


두번째로, 모델 학습에 test 데이터의 어떠한 정보도 들어가지 않았습니다. 제 코드를 보시게 되면 생성된 test 데이터는 규칙에 맞게 리더보드 제출을 위한 추론에만 사용했으며, 학습에 사용된 적이 없습니다. 어느 부분에서 test 데이터를 학습 시 사용했다고 판단하였는지 궁금합니다.


마지막으로, DACON에서 이야기하고 있는 data leakage의 정의와, 사례들을 확인했음에도, 사용한 PCA는 개별 이미지에 대해서 fit_transform으로 사용해 2d image로 투영해 만들었으며, 이러한 행위는 문젯거리가 될 것이 없다고 판단하였습니다. 쉽게 말하면 개별적으로 3d 이미지를 2d로 투영하는 부분이 전부이기 때문에 문제가 될 부분이 없다고 생각합니다.


따라서 탈락 사유에 해당하는 data leakage에 대한 부분이 제 코드에 존재하지 않음을 확인하였고, 이에 따른 추가 확인 및 답변을 요청드립니다.


<PCA 내부 코드 fit_transform 분석>

fit_transform시 X는 input data, 여기서는개별  image에 해당함.

fit_transform에서 transform 이전 fit 호출 -> self _fit_full에서 svd 모델 객체를 새로 생성해서 분석함 (따라서 Decomposition 라이브러리들은 multiple fit을 하더라도 이전 fit 정보를 저장하지 않고, 새로운 객체를 생성해서 fit하기 때문에 for문 내부에 넣더라도 동일함

따라서 사이킷런 트리 등의 모델과는 다르게, multiple time fit을 하더라도 기존 학습결과 활용 X


<PCA는 sklearn.decomposition에 속해있으며, 다른 model과는 다르게 이전 fit에 대한 정보를 저장하지 않는다는 근거 2>

<좌 : pca 생성 이후 400까지 fit_transform한 이후 0번째 transform, pca가 내부에 위치 / 우: pca를 외부에서 생성하며 400까지 fit_transform한 이후 0번째 transform, 이미지는 동일>

<좌 : pca 생성 이후 400번째만 fit_transform한 이후 0번째 transform / 우: pca 생성 이후 pca 생성 이후 0번째만 fit_transform한 이후 0번째 transform>

로그인이 필요합니다
0 / 1000
DACON.GM
2022.09.30 13:16

안녕하세요 lastdefiance20님,
PCA.fit_transform() 함수에 test 데이터셋을 적용한다면 Data Leakage입니다.
3D인 test dataset를 PCA를 통해 Inference를 위한 2d 이미지로 변환하려면 PCA.transform()을 사용해야합니다.
PCA가 test dataset에 대하여 fit이 되었고 이를 통해 생성된 2d 이미지로 추론을 하였기에 Data Leakage입니다.
test dataset에는 train dataset에만 fit된 PCA를 적용해야합니다.
감사합니다.

lastdefiance20
2022.09.30 13:39

안녕하세요 GM님. 우선 답변 감사드립니다.

하지만 "PCA가 test dataset에 대하여 fit이 되었고 이를 통해 생성된 2d 이미지로 추론을 하였기에 Data Leakage입니다."라는 것에 대해서 저는 동의할 수 없습니다.

PCA를 fit 하는 과정은 단순히 이미지에 대해서 pca 알고리즘을 통해 가장 효율적으로 투영할 수 있는 2d 차원을 찾아서 투영하는 것에 불과합니다. 이전에 정형 데이터에서 fit_transform해서 생기는 관련 data leakage 문제와 완전히 다른 문제라는 것입니다.

"pca를 개별 image에 fit하고, 2d 차원으로 transform"하는 과정이 문제가 된다면, CNN에서 개별 image에 fit하고, pooling을 통해서 더욱 작은 image로 return하는 과정이 문제가 된다는 말과 같다고 생각됩니다. 이미지에서 노이즈를 제거하는 NLmeans와 같은 알고리즘도 우선 개별 이미지를 fit하는 과정을 통해서 내부 정보를 통해 알고리즘으로 계산하고, transform, 즉 결과를 뱉어내게 됩니다. albumentations같은 데이터 증강 알고리즘에서 사용하는 blur 등도 같습니다. 그러면 이러한 알고리즘을 사용해 test image를 preprocessing할때나 증강해 TTA를 진행하는 것이 문제가 되어왔나요? 전혀 아닙니다.

따라서 제가 한 행위는 image processing의 한 부분에 불과하며, test dataset에 PCA를 fit하는 행위는 개별 이미지에 pca 알고리즘을 사용해서 가장 변수의 분포가 많은 2d 차원에 대한 투영을 하기 위한 일환임을 다시 한번 말씀드립니다.

이러한 제 이유에도 불구하고 "PCA가 test dataset에 대하여 fit이 되었고 이를 통해 생성된 2d 이미지로 추론을 하였기에 Data Leakage"에 해당 된다면, 해당 근거를 자세히 설명해주시면 제가 이해에 도움이 될 것 같습니다.

감사합니다.

DACON.GM
2022.09.30 15:06

 lastdefiance20님의 코드는 PCA에 Test dataset의 전체에 대해 fit을 시키고 동시에 transform하였기때문에 단순 Blur와 같은 예시와는 다른 상황입니다.
PCA에 Test 모두를 fit시키고 Test에 대하여 PCA를 통해 변환된 결과를 얻는 것은 명백한 Data Leakage입니다. (Test dataset의 정보 활용)
따라서 PCA는 Train으로만 fit을 시켜야하며, Test데이터를 PCA를 통해 변환시키기 위해서는 fit_transform()이 아닌 train데이터로 fit된 PCA를 통해 transform()을 함수를 활용해야합니다.
감사합니다.

lastdefiance20
2022.09.30 15:14

친절한 답변 정말로 감사합니다.

GM님 말씀대로 만약 전체를 fit한 결과를 사용하거나, 이미지를 fit한 결과를 저장하여 재사용한다면 data leakage가 발생하는 것이 맞습니다. GM님의 답변을 보고 다시 한번 제가 놓친게 없는지 살펴보았으나, 제 코드를 보면 전체에 대해 fit시키고 transform한 것이 아닌, 개별 이미지마다 새롭게 fit하는 모습을 보이고 있기 때문에 blur과 같은 예시와 같다고 생각하게 되었습니다.

코드를 들여다보면 df_pca부분에 fit_transform한 결과를 저장하게 됩니다. 따라서 fit이 진행된 pca 객체는 저장되지 않고 소멸되며, pca 변수는 항상 초기의 학습되지 않은 객체로 유지되고 있기 때문에 이후에 연속적으로 pca.fit_transform을 진행하더라도 똑같이 초기의 학습되지 않은 pca에 개별 이미지를 넣어서 투영을 진행하게 됩니다. 

같은 3d 이미지여도 90도 회전을 하게된다면 세로로 자르는 것이 아닌, 가로로 잘라야 가장 넓은 면을 투영할 수 있는 것처럼 개별적인 이미지마다 새로운 pca를 생성하고, fit하고, transform하는 것을 통해서 최적의 면을 pca 알고리즘에 의해 찾아내고, 자르는 preprocessing이 필요하기 때문에 다른 이미지들의 fit 정보를 사용할 수 없을 뿐더러, 저장되거나 사용하지도 않고 있습니다. 이러한 의미에서, 기존에 사용하던 pca의 방법과는 다르게 투영의 의미인 preprocessing으로 blur과 같은 사용을 했다고 말씀드리는 것입니다.

따라서 pca 변수에는 항상 초기 상태의 학습되지 않은 객체가 유지되기 때문에 제 코드로 생성한 모든 이미지들은 새로운 pca 객체가 개별 이미지 input을 받아 최적의 슬라이싱 output을 하고 소멸하게 되는 과정을 유지하고 있으며, 따라서 blur와 같은 맥락으로 3d 이미지에서 가장 표현력이 큰 면을 찾아 투영하는 알고리즘을 개별 이미지마다 적용했다고 생각하는것이 맞을 것 같습니다.

lastdefiance20
2022.09.30 15:14

또한, 코드 내부에서 train_data 준비 과정이나, test_data 준비 과정 내부에 이미지가 저장된 변수 이름이 "test data"라고 적혀있지만, 이는 전체 train 데이터나, test 데이터에서 인덱싱을 통해서 뽑아온 1개의 개별적인 이미지라서 "tmp_img"라고 봐도 무방합니다. (코드를 대충 짜서 변수 이름이 이상합니다.)

test_data의 shape을 확인해보면, 3 shape을 가진 개별 흑백 이미지에 불과하다는 것을 확인할 수 있습니다. 변수 이름 때문에 헷갈릴 수 있으나, 데이터셋 전체에 대해서 fit_transform을 적용하지 않았습니다.

DACON.GM
2022.09.30 15:20

삭제된 댓글입니다

DACON.GM
2022.09.30 15:21

안녕하세요 lastdefiance20님,
말씀해주신 내용과 같이 Test dataset의 한개의 입력에 대해서만 독립적으로 PCA가 fit_transform이 이루어지기 위해서라면, PCA 선언이 for문 내부에서 이루어져야합니다.
감사합니다.

lastdefiance20
2022.09.30 16:30

안녕하세요 GM님,
PCA 선언이 for문 내부에 이루어지나, 바깥에서 이루어지나 사이킷런의 Decomposition에 해당하는 PCA 모델은 fit을 진행할 시 새로운 객체를 생성하고, 이전 정보를 활용하지 않기 때문에 같은 결과가 나오게 됩니다. 따라서 한개의 입력에 대해서만 독립적으로 PCA가 활용됩니다.

제가 이 정보를 봤었던 글을 찾지 못하여, 깃허브에 올라온 사이킷런 내부 코드 분석과 실험을 글에 첨부했습니다.

감사합니다.

DACON.GM
2022.09.30 17:34

안녕하세요 lastdefiance20님,
말씀해주신 내용을 바탕으로 내부적으로 sklearn의 PCA 동작방식에 대해 내부 테스트한 결과,
PCA 선언 후 Test Dataset에 대하여 Sample 한개 마다 fit_transform()를 호출하는 경우의 결과값과 Test Dataset에 대하여 Sample 한개 마다 PCA를 선언 후 fit_transform()을 호출하는 경우의 결과값이 동일하게 나옴을 확인하였습니다.
따라서 lastdefiance20님의 방식과 Mingihong님의 방식은 PCA로 Test Dataset의 모든 정보를 활용하는 것이 아닌, 현재 입력으로 들어온 Test Dataset의 Sample 한개에 대한 전처리로 판단하여, Data Leakage 대한 결정을 정정하기로 결정하였습니다.
소중한 의견 주셔서 감사하며 최종 결과 발표 후 Data Leakage 결정에 대해 우려를 끼쳐드린 점 죄송합니다.
감사합니다.

lastdefiance20
2022.09.30 17:29

안녕하세요 GM님,
실제로도 fit_transform 관련 leakage가 많이 발생함에 따라서 충분히 우려가 가능한 상황이었다고 생각합니다.
계속되는 질문에도 친절하게 답변해 주셔서 정말로 감사합니다!

이대권
2022.10.02 19:27

축하드립니다.!

lastdefiance20
2022.10.02 21:02

감사합니다 •ᴗ•

Ski
2022.10.02 20:17

축하드립니다!

lastdefiance20
2022.10.02 21:02

감사합니다 XD

도플라밍고
2022.10.04 02:58

축하드려요!

나는슬플때파이썬을해
2022.10.16 16:36

우왕 멋있어요