Sckit-Learn 사용하지 않고 로지스틱 회귀 함수 구현하기

Ryan Kim
9 min readAug 8, 2021

--

2021 구글 머신러닝 부트캠프 : Coursera 강의 1차 미션 후기, 코드 정리

1. 구글 머신러닝 부트캠프 시작

2019년부터 구글에서 매년 진행한 머신러닝 부트캠프에 이번 년도 합격을 하게 되어 수업을 이수받게 되었다.

https://developers-kr.googleblog.com/2021/07/mlbootcamp21.html

처음 수료 조건을 봤을 땐, 별로 어렵지 않을 것 같은데? 싶었는데 생각보다 해야할 것도 많고, 수료 이후에 취업 연계까지 함께 되는 교육 과정이기 때문에 미리 준비해야할 것도 많다.

아직 부트캠프 초반이라 대단한 걸 배웠다고 얘기하기는 좀 그렇지만, 학교에서 데이터 과학을 배울 때, 수학적인 개념은 둘째치고 파이썬 모듈로 활용하는 것을 많이 배웠던 로지스틱 회귀 함수를 사이킷런을 사용하지 않고 구현하는 방법을 배우게 되어 정리해보고자 한다.

2. 인공지능 분야에서 Numpy의 지위

우선, 데이터 과학 / 머신러닝 / 딥러닝에 빠지지 않고 항상 등장하는 모듈 중에 numpy라는 것이 있다.

처음에는 모듈이 겹치는 것도 많고, 굳이 이런 것까지 왜 numpy 모듈에 일일이 구현해놨지 싶은 것들이 있어서 ‘기능이 잡다한’ 모듈 정도로 생각했다.

예를 들면, 수학적으로 지수함수를 구현할 때, 파이썬에는 math.exp() 함수가 있어서 결과를 얻어낼 수 있는데, 동일한 결과를 가져오는 np.exp()라는 모듈이 있을 뿐더러 곱셈 연산자 ‘*’가 있는데 이것조차 np.multiply()라는 것이 있어서 이상하다고 생각했다.

그런데 수강 중인 강의인 “Deep Learning Specialization”의 경우, 이 업계에 잘 알려져 있는 스탠포드 앤드류 응 교수님이 강의를 진행하는데 numpy를 왜 사용해야하는지 아주 명확한 논리로 파이썬 연산자들과 구분을 했다.

https://abit.ly/pqzdlq

위의 코드는 두개의 행렬 곱셈 수행을 위해 np.dot을 사용하는데, 동일한 결과를 얻기 위해 for 반복문을 사용해서 구성하는 것도 가능하다.

그러나 두 연산을 각각 수행했을 때, 연산 속도에서 엄청난 차이가 발생하게 된다.

속도에 있어서 거의 800배 차이난다.

즉, numpy는 데이터 셋의 고속 연산을 위해 C언어로 제작되었으며, 결과적으로 파이썬으로 구성한 코드로 작업을 해도 연산 속도에서 큰 차이가 있다는 것이다.

이러한 연산이 첫번째 미션 수행 학습인 로지스틱 회귀에 굉장히 많이 활용된다.

또 하나 numpy의 중요한 특징은 Broadcasting 연산이라는 것인데, 본래 대부분의 프로그래밍 언어가 그렇지만, 연산하는 값들의 자료형을 통일시켜줘야한다.

예를 들어 배열끼리 합친다면, 합치는 한 쪽의 자료형이 문자열이나 실수 값이 될 수는 없다.

그런데, numpy는 이를 융통성있게 적용하며, a = np.array([1,2,3,4]) / b = 100이라고 할 때 a + b 연산을 진행하면 결과 값이 [101, 102, 103, 104] 로 나오게 된다.

사용자의 계산에 있어 불필요한 시간 낭비를 줄여주는 것도 큰 매력인 것 같다.

3. 로지스틱 회귀 이론적인 설명

이미 인터넷에 많이 나와 있어서 이 글을 읽기 전에 잘 알고 있는 사람들도 있겠지만, 로지스틱 회귀는 범주형 데이터(Categorical Data, 값이 연속적으로 연결되는 것이 아니라 특정 단위로 끊기는 형태)를 대상으로 하며 입력 데이터가 주어졌을 때 해당 데이터의 결과가 특정 분류로 나뉘기 때문에 일종의 Classification 기법으로 활용된다.

주로 학교 수업에선 스팸과 스팸이 아닌 값을 구분할 때, 코세라 수업에선 고양이와 고양이가 아닌 이미지를 분류하는 문제, 그리고 날씨에 있어선 추위와 더위를 분류하는 형태로 로지스틱 회귀 함수를 사용할 수 있다.

몇 도인지가 아니라 추운지 더운지를 구분하고자 할 때

얼핏 보고 느끼기에는 선형 회귀랑 느낌이 비슷한데, 조심해야할 것이 선형 회귀의 경우 y = wTx + b 의 값의 형태를 띄고 있어서 특정 기준으로 값을 분류하기 어렵지만, 로지스틱 회귀의 경우 위 값에 활성함수(또는 시그모이드 함수)를 사용하기 때문에 값이 [0,1]로 제한된다.

아래 방정식을 앤드류 응 교수님이 몇 번씩 설명해 나간다.

(그리고 저 수학적인 설명을 코드로 구현한다)

이걸로 거의 모든 값을 유도해낸다.

그리고 위의 수식에 따른 손실 값도 항상 존재하기 때문에 이에 따른 손실 값도 수학적으로 이미 구현이 되어 있다.

참고로 손실함수와 비용 함수는 큰 의미 구분 없이 사용되기는 하지만, 이것도 강의에서는 철저하게 구분해서 설명하는데 비용함수는 하나의 훈련 샘플에 대한 에러를 계산하는 과정에서 발생한 값이고, 손실 함수는 이렇게 발생한 손실 값들의 전체 평균 값을 구한 것 라고 한다.

이 2개를 기준으로 시그모이드 함수 구현 -> 매개변수 초기화 -> 손실함수 구현 -> 모델 학습 형태로 진행이 된다.

4. 로지스틱 함수 코드로 만들고 학습시키기

먼저 시그모이드 함수를 코드로 작성하면 아래와 같이 된다.

시그 모이드 함수의 수학적 모형을 코드화 시켰다.

여기서 np.exp(-z) 대신 math.exp(-z)를 사용해도 되지만, 앤드류 응 교수님은 numpy의 사용를 권장하고, 딥러닝 연산에 있어 불필요한 for 반복문을 제외하는 것을 강의 중간중간에 꾸준히 언급한다.

시그 모이드 함수를 구성했다면 시그 모이드 함수를 적용하게 될 y = wTx + b 함수에서 가중치를 의미하는 w와 b 값을 초기화 시킨다.

w는 입력값으로 주어질 x에 따라 적용이 되기 때문에 배열 값으로 0이 초기화되며 b는 상수항이라 실수 값으로 초기화를 시켰다.

매개변수 초기화 후, 시그모이드 값을 구한 것을 토대로 손실함수 구현하기

여기서 Y는 입력에 따른 결과 값이며 (로지스틱함수 자체가 지도학습이라 입력 — 결과 값은 주어져 있다고 전제한다), 예측 값이 우리가 구현한 시그모이드 값이다.

그래서 실제 값 (Y) - 예측 값(A)을 손실 함수 방정식에 따라 대입하고, 각 각의 연산 결과에 따라 가중치와 상수항의 기울기를 구해준다. (경사 하강법, 미분에 대한 지식이 필요하다.)

5. 그런데 결과가?

이렇게 만든 함수에 따라 손실치를 계산하면 생각보다 손실치가 어느 정도 나오는 것을 볼 수 있다.

그 이유는 지금 함수는 최적화가 진행되어 있지 않아 (즉, 학습이 된 상태가 아니다) 관련 작업을 추가적으로 해줘야하기 때문이다.

최적화가 필요해보인다.

코드를 gist를 사용해서 넣지 않는 이유는 일단 과제로 작성한 코드가 너무 많다.

결정적으로 주피터에 쓰다보니 함수 단위로 쪼개져 있어서 매번 gist로 만드는 게 힘이 너무 들어서 캡처해 추가하는 것을 양해하길 바란다.

글 하단에 깃헙 링크를 넣어놓을테니, 코드를 더 보고 싶은 사람은 하단 깃헙으로 들어가 내용을 보면 된다.

여기서 최적화를 진행하기 위해 매개변수 2개의 값을 디폴트 값을 지정해 놓은 게 있고, num_iterations 에 따라 반복하면서 비용이 줄어드는 것을 보여주는 함수를 구현해 놓은 것이 있다.

예측 값을 보다 정교하게 만들기 위한 최적화 함수 구현이 되었다면, 이제 값을 예측할 차례다.

문제에서는 1,0 을 구분하는 기준 값을 0.5로 뒀고 0.5보다 크면 예측 값을 1로, 그리고 0.5보다 작으면 0으로 구분하게 만들었다.

여기가 제일 신기했는데, 사이킷런을 쓰면 머신러닝 라이브러리를 사용하면 model 메소드 호출이 가능하다.

그 코드의 내부를 간단하게나마 구현한 값인데, 마치 사이킷런 모듈을 뜯어보는 것 같아서 이번 강의에서 좋은 인상을 받은 것 같다.

이 모델 함수는 앞서 설명한 시그모이드, 손실함수, 최적화, 예측 값을 모두 불러와서 데이터 예측을하는 하나의 패턴 (고양이인지 아닌지 구분하는)을 생성하는 값이다.

그리고 그 패턴을 우리가 훈련을 위해 만들어놓은 데이터와 훈련된 모델을 검증하는 데이터에 각각 사용해 정확도를 측정하게 되고, 그 결과가 아래 손실 함수 값의 감소를 통해 확인할 수 있다.

검증을 위한 데이터 셋에서는 훈련용 데이터와 오차가 크다.

이제 1주차 미션을 끝내기는 했지만, 솔직히 데이터 과학 수업을 학교에서 듣고 부트캠프 참여를 했기에 망정이지, 이걸 개발을 했던 사람이라도 생판 처음 듣는 사람이라면 좀 어려울 것 같다.

코드 구현이 문제는 아니고, 수학적인 부분을 잘 이해해야 코드로 풀어낼 수 있는데, 벌써 학습용 슬랙창을 보니 영어라서 이해가 잘 안된다는 사람들도 보인다.

천리길도 한 걸음부터 시작된다. 프로젝트 매니징 꾸준히 해나가자.

그래도 기분은 좋다.

수학적 원리 설명하고 바로 모듈 사용 방법으로 넘어가서 과제하는 게 아니라 라이브러리 원리를 직접 구현해보면서 코드를 짜니까 이해가 더 쏙쏙 잘되는 것 같다.

내 목표는 GCP Professional Data Engineer Certificate를 취득하는 건데 난이도가 좀 있어서 8월 말까지 코세라 강의를 마무리하고 10월 중순까지 이 자격증 취득을 하는데 시간을 몰입해야겠다.

Ryan

Github : https://abit.ly/wyxu0jd

한글강의 참고자료 : https://www.youtube.com/channel/UCueLU1pCvFlM8Y8sth7a6RQ/videos

코세라 강의 : https://www.coursera.org/specializations/deep-learning

--

--

Ryan Kim
Ryan Kim

No responses yet