5 분 소요

image



Neural Networks Basics

Python and Vectorization

Vectorizing Logistic Regression

지금까지 벡터화를 통해 코드 속도를 크게 높일 수 있는 방법에 대해 설명했습니다. 이번에는 로지스틱 회귀 구현을 벡터화하여 전체 훈련 세트를 처리할 수 있는 방법에 대해 이야기할 것입니다.

즉 명시적 for 루프를 사용하지 않고도 전체 훈련 세트와 관련하여 단일 등급의 기울기 하강을 구현할 수 있습니다. 나중에 신경망에 대해 이야기 할 때 단 하나의 명시적 for 루프도 사용하지 않습니다. 그럼 시작해보겠습니다.

image

먼저 로지스틱 회귀의 네 가지 전파 단계를 살펴보겠습니다. $m$ 훈련 예제가 있는 경우 첫 번째 예제를 예측하려면 $z$를 계산해야 합니다. 위의 익숙한 공식을 써서 말이죠. 그리고 활성함수를 계산한 다음 첫 번째 예제에서 $\hat{y}$를 계산합니다.

두 번째 훈련 예제에 대해 예측을 수행하고 그것을 계산해야 합니다. 그런 다음 세 번째 예제에서 예측을 하려면 이를 계산하는 식으로 진행해야 합니다. 그리고 $m$ 훈련 예제가 있는 경우 이 작업을 $m$번 수행해야 할 수도 있습니다.

따라서 4개의 전파 단계를 수행하기 위해 즉 $m$ 훈련 예제에서 이러한 예측을 계산하기 위해 명시적 for 루프가 필요 없이 그렇게 하는 방법이 있습니다. 어떻게 할 수 있는지 봅시다.

먼저, 행렬 대문다 $X$를 쌓아 올려 훈련 입력으로 정의했다는 것을 보면 이것은 행렬 즉 $n_x \times m$ 행렬입니다. 그래서 이것을 파이썬 넘파이 모양으로 쓰고 있으며 (n_x, m) 이것은 $X$가 $n_x \times m$ 차원 행렬임을 의미합니다.

첫 번째로 가장 먼저 하고 싶은 것은 $z^{(1)}, z^{(2)}, z^{(3)}$ 등 실제로 한 줄의 코드로 모두 한 단계로 계산하는 방법을 보여주는 것입니다. 따라서 실제로 행 벡터인 $1 \times m$ 행렬을 구성하는 동시에 $z^{(1)}, z^{(2)}$ 등을 $z^{(m)}$까지 모두 한 번에 계산할 것입니다.

이것은 $w^TX + b$로 표현될 수 있다는 것이 밝혀졌습니다. b는 $1 \times m$의 $m$차원 행 벡터입니다. $w$가 $x^{(1)}, x^{(2)}$ 등을 전치하면 $w$ 전치는 행벡터가 될 수 있습니다.

따라서 이 $w$ 전치는 행 벡터를 나타내며 각 항은 위의 식처럼 나타나며 각 요소에 $b$를 추가하게 됩니다. 그러면 또 다른 $1 \times m$ 벡터가 생성됩니다.

그리고 위의 정의를 참조하면 각 요소는 $z$의 정의를 나타냅니다.

그러면 일단 $X$를 얻었을 때와 마찬가지로 훈련 예제를 가져와서 서로 옆에 수평으로 쌓았습니다. 여기 대문자 $Z$를 정의할텐데요. 소문자 $z$들을 가지고 수평으로 쌓아올리는 것입니다. 그리고 다른 훈련 예제에 해당하는 소문자 $x$를 쌓는 경우 수평으로 쌓으면 이 변수 대문자 $X$를 얻을 수 있고 여기 소문자 $z$ 변수를 같은 방식으로 수평으로 쌓으면 대문자 $Z$로 표현한 변수를 갖게 됩니다.

그리고 이를 구현하기 위해 넘파이 명령은 Z = np.dot(w.T,x) + b와 같다는 것이 밝혀졌습니다. 이제 파이썬에는 미묘한 부분이 있는데 여기에 $b$는 실수이거나 $1 \times 1$ 행렬을 알고 있다고 말하고 싶다면 그냥 일반 실수일 뿐입니다.

하지만, 이 벡터를 이 실수에 추가할 때 파이썬은 자동으로 이 실수 $b$를 가져와 이 $1 \times m$ 형 벡터로 확장합니다. 이 작업이 조금 이해하기 힘든 경우 이를 파이썬에서 “broadcasting”이라고 합니다. 아직은 걱정안하셔도 됩니다. 다음에 더 이야기 하겠습니다.

그러나 단 한 줄의 코드로 이 코드 줄을 사용하여 대문자 $Z$를 계산할 수 있으면 대문자 $Z$는 모든 소문자 $z$를 포함하는 $1 \times m$ 행렬이 될 것이라는 겁니다. 소문자 $z^{(1)}$부터 $z^{(m)}$까지 말이죠 그래서 그것은 $Z$였습니다.

그럼 A는 어떨까요? 다음에 우리가 하고 싶은 것은 $a^{(1)}, a^{(2)}$ 등을 동시에 계산하는 방법을 찾는 것이며 소문자 $x$를 쌓으면 대문자 $X$가 되고 소문자 $z$를 수평으로 쌓으면 대문자 $Z$가 되고 소문자 $a$를 쌓는 경우 새로운 변수가 생성될 것이며 대문자 $A$로 정의할 것입니다.

그리고 프로그램 할당에서 벡터값 시그모이드 함수를 구현하는 방법을 확인하여 시그모이드 함수가 대문자 $Z$를 변수로 입력하고 효율적으로 대문자 $A$를 출력합니다.

요약하자면 이번에 본 것은 소문자 $z$와 소문자 $a$를 계산하기 위해서 $m$ 훈련 예제를 반복해야 하는 대신 한 줄의 코드를 구현하여 이 모든 $z$를 동시에 계산할 수 있다는 것입니다.

그런 다음 이 한 줄의 코드와 $\sigma$를 적절히 구현하여 모든 $a$를 동시에 계산합니다. 따라서 이것이 모든 $m$ 훈련 예제에 대한 네 가지 전파의 벡터화 구현을 동시에 구현하는 방법입니다.

요약하자면, 방금 본 것은 벡터화를 사용하여 모든 활성함수 모든 $a$를 동시에 매우 효율적으로 계산하는 방법입니다. 다음으로, 벡터화를 사용하여 역방향 전파를 효율적으로 계산하고 기울기를 계산할 수 있다는 것이 밝혀졌습니다. 다음에 어떻게 하는지 살펴보겠습니다.

Vectorizing Logistic Regression

이전에 벡터화를 사용하여 예측값을 계산하는 방법을 살펴보았습니다. 소문자 $a$는 전체 훈련 세트를 동시에 나타냅니다. 이번에는 벡터화를 사용하여 모든 $m$ 훈련 샘플에 대한 기울기 계산을 수행하는 방법에 대해 설명합니다.

다시 말하지만, 모든 것이 동시에 그리고 모든 것들을 종합해서 로지스틱 회귀의 매우 효율적인 구현을 어떻게 도출할 수 있는지 보여줄 것입니다.

image

따라서 기울기 계산의 경우 첫 번째 예제에서 $dz^{(1)}$을 계산한 것입니다. 이것은 $dz^{(1)} = a^{(1)} - y^{(1)}, dz^{(2)} = a^{(2)} - y^{(2)}, \dots$ 와 같습니다. 모든 $m$ 훈련 예제도 마찬가지입니다.

이제 새로운 변수를 정의하겠습니다. $dz = [dz^{(1)},dz^{(2)}, \dots ,dz^{(m)}]$이 됩니다. 다시 말하지만, $dz$ 변수가 수평으로 쌓였습니다. 따라서 이것은 $1 \times m$ 행렬 또는 $m$ 차원 행 벡터가 됩니다.

이제 이전에 대문자 $A$를 계산하는 방법을 알아냈습니다. $a^{(1)}$에서 $a^{(m)}$까지 그리고 대문자 $Y$를 $y^{(1)}$에서 $y^{(m)}$으로 정의했습니다. 이것 또한, 수평으로 쌓인 것이죠.

이러한 정의를 기반으로 $dz = A -Y = [a^{(1)} \cdot y^{(1)}, a^{(2)} \cdot y^{(2)}, \dots]$로 표현될 수 있습니다. 그렇게 해서 한 줄의 코드로 이 모든 것을 동시에 계산할 수 있습니다.

이제, 이전 구현에서 이미 for 루프를 제거했지만 훈련 예제에 대한 두 번째 for 루프는 여전히 있었습니다.

우리가 할 수 있는 일은 이렇습니다. $db$의 벡터화된 구현을 위해 기본적으로 이 모든 $dz$를 합한 다음 $m$으로 나눕니다. $db = \cfrac{1}{m} \displaystyle\sum_{i=1}^{m} dz^{(i)}$으로 나타납니다. 파이썬에서는 1/m * np.sum(dz) 입니다.

$dw$는 어떻습니까? $dw = \cfrac{1}{m} \times dz^T$인 것으로 드러났습니다. 행렬 벡터 곱셉으로 계산을 한 것인데요. 이 또한 코드 한 줄로 $dw$를 계산할 수 있습니다. 도함수 계산의 벡터화된 구현은 db = 1/m * np.sum(dz)dw = 1/m * dz^T를 통해서 for 루프가 없어도 원하는 계산을 할 수 있습니다.

image

로지스틱 회귀를 실제로 구현하는 방법에 대해 살펴보겠습니다. 이것이 원본인데요. 매우 비효율적인 비벡터화 구현입니다. 이전에 가장 먼저 $dw$ 계산 부분을 삭제했습니다. 따라서 이 값을 $dw_1, dw_2$ 등으로 반복하는 대신에 이것을 $dw += x^{(1)} \dot dz^{(i)}$로 대체했습니다.

그러나 이제 이 for 루프뿐만 아니라 상단의 for 루프도 제거할 수 있음을 알 수 있습니다.

$Z = w^TX + b$이고 코드는 Z = np.dot(x.T,x) + b로 작성합니다.

$A = \sigma{z}$이고, $dz = A - Y$ 입니다.

마지막으로 $dw = \cfrac{1}{m} \times dz^T$, db = 1/m * np.sum(dz)입니다.

for 루프를 사용하지 않고 모든 $m$ 훈련 예제에서 실제로 예측을 계산하고 도함수를 계산하여 순방향 전파와 역방향 전파를 완료했습니다.

그래서 기울기 하강 업데이트는 위에서 방금 계산한 $w := w - \alpha dw$, $b := b - \alpha db$로 업데이트 됩니다.

이렇게 하여, 로지스틱 회귀에 대한 기울기 하강의 단일 반복을 구현했습니다. 지금까지 말씀드린 바와 같이 할 수 있을때마다 for 루프를 명시적으로 사용하지만 여러 번 반복 구현하지 않도록 해야 합니다.

기울기 하강을 원하는 경우 반복 횟수에 대한 for 루프가 여전히 필요합니다. 따라서 수천 번의 기울기 하강을 반복하고 싶다면 반복 횟수에 대한 for 루프가 가장 바깥쪽에 있으며 for 루프를 제거할 방법이 없다고 생각합니다.

이제 로지스틱 회귀를 위한 기울기 하강을 벡터화하고 효율적으로 구현할 수 있게 되었습니다. 다음에는 앞서 언급한 broadcasting이라 불리는 기술에 대한 간략한 설명인데요. broadcasting은 파이썬과 넘파이가 코드의 특정 부분을 훨씬 더 효율적으로 만들기 위해 사용할 수 있는 기술인 것으로 밝혀졌습니다. 그럼 다음에 broadcasting에 대한 내용을 살펴보겠습니다.

댓글남기기