Dogs vs. Cats (1)
나는 올해 4학년이다. 2학년 때까지는 인공지능 분야에 애매한 태도를 취하다가('이거 한 번 해볼까?' 정도), 작년부터 본격적으로 인공지능 쪽으로 대학원을 가기로 마음을 먹고 머신러닝/딥러닝에 대해 본격적으로 공부하기 시작했다. 하지만 지난 1년을 돌이켜보면, 책에만 전적으로 의존한 나머지 내 실력은 전혀 늘지 않았던 것 같다. 책에 나와있는 코드를 따라치기만 했을 뿐, 내 힘으로 모델을 설계해보려는 노력을 하지 않았다.
지금 와서 생각해보면, 나의 가장 큰 단점은 시작을 무서워한다는 것이다. 아무리 책을 보면서 개념을 공부해도 결국 프로젝트를 할 때는 내가 공부하지 않은걸 끌어와서 써야 되는 경우가 훨씬 많았다. 그래서 시작하기도 전에 AI 프로젝트를 하는 것에 흥미를 잃어버리고, 아예 프로젝트를 시작하는 것 자체에 거부감이 생기게 된 것 같다. 강제로 프로젝트를 해야되는 상황이라면 그냥 챗GPT가 던져주는 코드를 복사/붙여넣기 하는데 급급했었다. 결국 나는 인공지능에 관심이 있다고 주장만 하고, 실제로는 아무것도 하지 않은 것과 마찬가지인 상태로 3학년이 끝나버렸다.
결국 이렇게 어영부영 4학년이 되었다. 남들은 이 시점에 학부 연구생도 해보고, 공모전에서 입상도 해보고, 심지어는 논문까지 써보인 사람도 있다더라. 이 사람들에 비하면 나는 정말 이론만 깔짝 한 2학년 수준이라고 할 수 있다. 너무 늦었다는 생각이 들지만 그렇다고 높은 곳만 계속 쳐다보게 되면 4학년마저도 아무것도 못 한 채로 끝나게 될 것이다. 남은 1년이라도 쉬운것부터 차근차근 혼자서 구현하는 연습을 해보려고 한다. 물론 혼자서 구현하면 어디에도 쓰지 못하는 쓰레기같은 모델이 나올 가능성이 높겠지만 그런 모델이라도 만들어본 것과 아무것도 안 만들어 본 것은 차이가 분명히 클 것 같다.
만약 26년 전기에 대학원에 입학하지 못한다면 후기라도 노릴 생각이다. 아니, 시간이 더 필요하다면 27년 전기까지 노려보기로 하자. 기간이 얼마나 걸리든 일단 시작을 한다는게 중요하다.
https://www.kaggle.com/competitions/dogs-vs-cats
Dogs vs. Cats
Create an algorithm to distinguish dogs from cats
www.kaggle.com
내가 처음으로 도전해본 경진대회는 Dogs vs. Cats라는 경진대회이다. 강아지 사진이나 고양이 사진이 주어지는데, 주어진 사진이 강아지인지 고양이인지 판별하는 정말 간단한 문제라서 내가 처음으로 도전해보기에 적합한 문제라고 생각했다. 주어진 사진이 고양이면 0으로, 강아지면 1로 분류하면 된다.
먼저 Input에 주어진 파일들은 다음과 같다.
- sampleSubmission.csv (제출 파일)
- test1.zip (테스트 데이터셋)
- train.zip (훈련 데이터셋)
주어진 파일들은 다음과 같은 방법으로도 확인할 수 있다.
os 모듈의 listdir() 메서드는 해당 폴더에 들어있는 모든 파일의 이름을 리스트로 반환하는데, 이를 출력하면 폴더 내에 어떤 파일들이 들어있는지 알 수 있다. 내용물이 궁금한 폴더의 경로를 인자로 전달하면 된다.
먼저, '../input' 폴더 안에는 'dogs-vs-cats'라는 폴더가 들어있었고, 'dogs-vs-cats' 폴더 안에는 위에서 언급한 3개의 파일이 들어있었다.
그런데 데이터셋은 압축된 상태로는 사용할 수 없다. 압축을 풀어야 그 안의 내용물을 사용하든지 말든지 할 수 있을 것이다. 그래서 먼저 압축을 풀어보기로 했다.
압축을 푸는 방법은 다음과 같다.
- 먼저 zipfile 모듈에서 ZipFile 클래스를 import 한다.
- ZipFile의 인자에 압축파일의 경로를 전달하면 해당 압축파일에 대한 ZipFile 객체가 생성된다. 이 객체를 with 문을 이용해 zipper에 할당한다.
- zipper에 대해 extractall() 메서드를 호출하여 압축을 푼다.
파이썬을 하면서 with 문의 존재를 알고 있었지만 정확히 언제 사용하는지는 잘 몰랐어서 이번 기회에 알아봤다.
'with A as B' 라는 구문은 B라는 변수에 A라는 자원을 할당하고, 이후에 B라는 변수를 통해 A라는 자원을 사용할 수 있게 하는 구문이다. 자원을 더 이상 사용할 필요가 없다면 메모리 누수를 방지하기 위해 자원을 반납해야 하는데, with 문은 with 문을 빠져나오기만 하면 자원이 알아서 반납된다. 즉, 내가 close() 같은 내장 함수를 굳이 호출하지 않아도 자원이 알아서 반납되기 때문에 파일과 관련된 작업을 할 때 매우 유용한 구문이라고 할 수 있다.
어쨌든 이렇게 압축을 풀어봤고, 다음으로 데이터를 이리저리 살펴보는 시간을 가져보기로 했다.
os.listdir()은 해당 폴더 내에 있는 모든 파일의 이름을 리스트로 반환한다고 했으니, 이에 대한 len()은 곧 폴더 내 파일 개수를 의미하게 된다. 출력 결과를 보면 train 폴더에는 25,000개의 데이터가, test1 폴더에는 12,500개의 데이터가 들어있음을 알 수 있다.
train 폴더와 test1 폴더에 각각 어떤 파일이 있는지 5개씩만 출력해봤다. 두 폴더 모두 강아지 또는 고양이 사진만이 들어있다. 차이가 있다면 train 폴더의 사진들은 파일명에 정답(cat 또는 dog)이 명시되어 있고, test1 폴더의 사진들은 파일명에 정답이 명시되어 있지 않다는 것이다.
이제 폴더 내에 어떤 데이터들이 있는지 대강 알게 되었으니, 본격적으로 모델을 설계해보기로 했다. 그 전에 먼저 데이터프레임을 만들기로 하자.
import pandas as pd
filenames = []
labels = []
for filename in os.listdir("train/"):
filenames.append(filename)
if filename.split('.')[0] == "cat":
labels.append(0)
else:
labels.append(1)
df = pd.DataFrame({
'filename': filenames,
'label': labels
})
df
데이터프레임(df)의 열은 'filename'(파일명)과 'label'(정답값)으로 구성하였다. 파일명이 'cat.'으로 시작하면 정답값이 0이고, 파일명이 'dog.'으로 시작하면 정답값이 1이므로 이에 맞는 알고리즘에 따라 데이터프레임을 만들어 봤다. 데이터프레임의 출력 결과는 다음과 같다.
ndarray 객체에 대해 value_counts() 메서드를 호출하면 각각의 값이 몇 개씩 존재하는지 알 수 있다. 0과 1이 12,500개씩으로 같으므로, 고양이와 강아지 사진이 12,500개씩으로 개수가 같음을 알 수 있다.
import matplotlib.pyplot as plt
import random as r
import cv2
plt.figure(figsize=(15, 15))
row = 3
col = 3
for i in range(row * col):
img_idx = r.randint(0, len(df))
filename = df["filename"][img_idx]
img = cv2.imread("train/" + filename)
plt.subplot(row, col, i+1)
plt.imshow(img)
plt.title(filename)
이번에는 사진을 출력창에 실제로 띄워볼 것이다.
- 먼저 plt.figure() 함수에 figsize 인자를 (가로 길이, 세로 길이) 형태로 전달하여 사진의 크기를 결정한다. 직접 출력해보고 적당한 크기로 선택하면 된다.
- 출력할 이미지를 임의로 고르기 위해 img_idx를 0부터 24,999(len(df)-1)까지의 정수 중에서 랜덤하게 선택되도록 한다.
- 인덱스가 img_idx인 사진의 파일명을 filename 변수에 저장한다.
- cv2.imread() 함수의 인자에 출력하고자 하는 이미지 파일의 경로를 전달하면 해당 이미지를 읽어온다. 읽어온 이미지를 img에 저장한다.
- plt.subplot(row, col, i+1)은 row×col 크기의 서브플롯 그리드를 만들어서, 사진을 i+1번째 칸에 넣겠다는 의미이다. i+1번째에 넣을 사진은 plt.show() 함수로 정하면 된다. 여기서는 아까 img에 저장된 사진을 i+1번째 칸에 넣게 된다. 참고로 3×3 크기의 서브플롯 그리드는 다음과 같다.
1 2 3 4 5 6 7 8 9 - 마지막으로 plt.title() 함수를 통해 각 사진에 제목을 붙여준다. 제목은 해당 사진의 파일명으로 붙여줬으며, 이를 통해 고양이 사진의 파일명이 'cat.'으로 시작하는지 또는 강아지 사진의 파일명이 'dog.'으로 시작하는지 확인할 수 있다.
사진 출력 결과는 다음과 같다.
다음 포스팅에서는 이제 본격적으로 모델을 설계해볼 것이다.
Dogs vs. Cats (2) : (업로드 예정)