�� : [aikorea.org - cs231n](http://aikorea.org/cs231n/) <br> 강의 링크 : [youtube - 2017 Spring (English)](https://www.youtube.com/playlist?list=PL3FW7Lu3i5JvHM8ljYj-zLfQRF3EO8sYv)
{:.notice--warning}

<br>
<br>
<br>

## Optimization

<img src='https://user-images.githubusercontent.com/78655692/164610220-db94ac17-560c-45b2-8719-ea18f43ebf81.png' width=500>

- 우리는 어떻게 해야 실제 loss를 줄일 수 있는 w를 찾을 수 있을까?
- 그림과 같이 골짜기의 밑바닥을 찾아야 한다.
  - 여기서 loss는 위치의 **높이**에 해당한다.
  - 높이는 w의 값에 따라 변한다.

<br>
<br>

### 1. Random Search (Bad idea)

- 단순한 방법으로 무작위 탐색(random search)이 있다.
- 임의로 샘플링한 $W$들을 모아놓고 loss를 계산해 어떤 $W$가 좋은지 찾는 것이다.
- 하지만, 굉장히 좋지 않은 방법이므로 추천하지 않는다.

<br>
<br>

### 2. Follow the slope

- 두 발로 땅의 경사를 느끼고, 어느 방향으로 내려가야 할지 판단한다.
- 그 방향으로 한발자국 내딛고, 다시 두발로 느끼는 방향을 찾는다.
- 구체적으로, 임의의 $W$에서 시작하고, 또 다른 임의의 방향 $\delta W$으로 살짝 움직여본다.
- 만약 움직여간 자리($W+\delta W$)에서의 손실값(loss)가 더 낮으면, 거기로 움직이고 다시 탐색을 시작한다.
- 이런 반복으로, 골짜기를 내려간다.

<br>

- **경사(slope)**: 1차원 공간에서 어떤 함수에 대한 **미분값(derivative)**
  - $\frac{df(x)}{dx}=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$
  - 따라서 경사는 방향(direction) 정보를 가지고 있다. 
- x를 입력으로 받으면 출력은 곡선의 높이로 생각할 수 있다.
- 곡선의 일부를 구하면 기울기를 계산할 수 있다.
- **적어도 반지름이 0으로 수렴하는 아주 좁은 근방에서는 가장 가파르게 감소하는 최선의 방향을 구할 수 있고, 이 방향을 따라 가중치 벡터를 움직인다.**
  - 발 밑 지형을 잘 더듬어보고 가장 가파르다는 느낌을 주는 방향으로 내려간다.
- x가 벡터일 경우, 이 때 미분을 **편미분(partial derivatives)**이라 한다.
- **그레이디언트(gradient)** : 각 차원으로의 편미분들을 모아놓은 벡터 (집합)
  - 그레이디언트의 각 요소는 "임의의 방향으로 갈때 함수 f의 경사가 어떤지"의 정보를 알려준다.
- 그레이디언트의 방향은 함수에서 '가장 많이 오름/내림'하는 함수 이다.
- 임의의 방향의 그레이디언트는 그것의 방향의 내적이다.
- 아래 그림처럼, gradient의 각 요소는 한 방향으로 아주 조금씩 이동했을 때, loss값이 어떻게 변하는지를 알려주는 것이다.

<img src='https://user-images.githubusercontent.com/78655692/164625554-f7076983-557c-4c39-82ab-acc627f2034d.png' width=650>

- 하지만, 위의 방법은 시간이 엄청 오래 걸린다.
- 즉, **Numerical gradient**를 사용하지 않고, **Analytic gradient**를 사용한다.
  - **Numerical gradient** : 근사치(approximate), 느림(slow), 쉬운 방법(easy to write)
  - **Analytic gradient** : 정확(fast), 빠름(exact), 실수하기 쉬운(error-prone)
- 그레이디언트를 나타내는 식을 찾고, 그걸 이용해여 한번에 그레이디언트 dW를 계산한다.
- 하지만, 구현하는 데 실수하기 쉽기 때문에, 실제 응용할 때 해석적으로 구한 다음에 수치적으로 구한 것과 비교해보고, 틀린 경우 고치는 작업을 한다.
  - 이것을 **gradient check**라 한다.

<img src='https://user-images.githubuser