<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jeong_jaeyoon.log</title>
        <link>https://velog.io/</link>
        <description>이직하고 싶은 직장인의 기록장</description>
        <lastBuildDate>Wed, 06 Oct 2021 09:58:45 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jeong_jaeyoon.log</title>
            <url>https://images.velog.io/images/jeong_jaeyoon/profile/7fbaa955-cb6f-4322-9ee3-ad3a4c130755/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jeong_jaeyoon.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jeong_jaeyoon" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[CS231n] Lecture 4 : Introduction to Neural Networks]]></title>
            <link>https://velog.io/@jeong_jaeyoon/CS231n-Lecture-4-Introduction-to-Neural-Networks</link>
            <guid>https://velog.io/@jeong_jaeyoon/CS231n-Lecture-4-Introduction-to-Neural-Networks</guid>
            <pubDate>Wed, 06 Oct 2021 09:58:45 GMT</pubDate>
            <description><![CDATA[<h1 id="introduction">Introduction</h1>
<p><img src="https://user-images.githubusercontent.com/68625698/136149951-8039cb02-85d2-4b21-aa1a-3d1eb3a02b0d.png" alt="image"></p>
<p>지난 시간에 저희는 loss function과 optimization에 대해서 배웠습니다. 그리고 최적의 weight를 찾기 위해서 우리는 편미분을 통해 gradient를 구해야 한다는 점도 배웠습니다. gradient를 구하는 방식은 Numerical gradient와 Analytic gradient로 크게 2가지를 설명했습니다. 각각의 특징를 확인하고 Numerical gradient의 경우, 직접 예시를 통해 확인했습니다. 그러나 Numerical gradient의 경우, 차원이 커지면 커질 수록 너무 비효율적이라는 단점을 가지고 있었습니다. 그래서 일반적으로는 analytic gradient를 사용하고, 확인용으로 numerical gradient를 사용한다고 했습니다. </p>
<p>이번에는 analytic gradient에 대해서 이야기하겠습니다.</p>
<h1 id="backpropagation">Backpropagation</h1>
<p>analytic gradient를 하기 위해서는 Backpropagation에 대해서 제대로 이해해야합니다. 예시를 통해 차근차근 알아보겠습니다. </p>
<p><img src="https://user-images.githubusercontent.com/68625698/136152084-7d56cb8a-c731-4863-92aa-13aaebe3c33a.png" alt="image"></p>
<p>다음과 같은 함수가 있다고 가정합시다. x,y,z는 각각 -2, 5, -4의 값을 가집니다. 이를 이해하기 쉽게 그래프로 나타내면 오른쪽과 같습니다. 함수에 따라 값을 구하면 우리는 최종적으로 -12라는 값을 가지게 됩니다.</p>
<p>이 때 우리가 알고 싶은 것은 $x,y,z$가 $f$에 미치는 영향력을 알고 싶은 것입니다. 즉, 각각의 편미분 값인 $\frac{\partial f}{\partial x}, \frac{\partial f}{\partial y}, \frac{\partial f}{\partial z}$을 구해야하는 것이죠. 이 값들을 찾기 위해서는 가장 끝부터 차근차근 계산을 해야합니다. </p>
<p>우선 가장 끝값인 $\frac{\partial f}{\partial f}$값부터 구해봅시다. 이 때는 자기 자신을 미분한 것이므로 1의 값을 가질 것입니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/136154781-93e3aeb0-fa49-4f94-a462-2f5d62326eb9.png" alt="image"></p>
<p>이제 $\frac{\partial f}{\partial z}$값을 구해봅시다. $f = qz$이므로 z로 편미분을 진행하면 위에서 구한 것과 같이 $q$가 될 것입니다. 즉, $\frac{\partial f}{\partial z}$는 현재 $q$값인 3이 될 것입니다. </p>
<p><img src="https://user-images.githubusercontent.com/68625698/136155312-6b823479-f076-4738-932a-10a2411afd71.png" alt="image"></p>
<p>$\frac{\partial f}{\partial q}$값 역시 위에서 구해뒀기 때문에 쉽게 구할 수 있습니다. $f = qz$를 $q$로 편미분한 값이기에 $z$가 나올 것이고 현재 $z$의 값은 -4이므로 $\frac{\partial f}{\partial q}$는 -4가 될 것입니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/136155974-a724d0ce-3287-456e-9b78-6a019c2f3b16.png" alt="image"></p>
<p>그렇다면 $\frac{\partial f}{\partial x}, \frac{\partial f}{\partial y}$는 어떻게 구할까요? 지금까지는 간단한 편미분을 통해서 구했습니다. 하지만 지금부터는 $f$에 직접적으로 연결되어 있지 않습니다. $x$는 $q$에 영향을 주고, $q$는 $f$에 영향을 주게 되죠. 그래서 저희는 Chain rule이라는 미분의 연쇄법칙을 적용합니다. </p>
<p>Chain rule을 적용하게 되면 위의 공식처럼 $\frac{\partial f}{\partial y} = \frac{\partial f}{\partial q}\frac{\partial q}{\partial y}$가 되면서 앞서 우리가 구해놨던 조건들을 사용할 수 있게 됩니다. 따라서 $\frac{\partial f}{\partial y}$는 (-4)*1이 되면서 -4라는 값을 가지게 됩니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/136160698-c7add866-6797-47ea-b6ab-996ba5e02335.png" alt="image">
$\frac{\partial f}{\partial x}$값도 같은 방식으로 구할 수 있으며 -4라는 값을 얻을 수 있게 됩니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/136161265-9cdcc99c-d6f0-467e-937e-59f3c5474ac6.png" alt="image">
이를 일반화해보자면 위의 그림과 같이 표현할 수 있습니다. 우선 각 노드들은 모두 output값을 가지고 있습니다. 그리고 이를 노드의 변수들로 미분한 값을 local gradient라고 합니다. 앞에서 넘어온 gradient(global gradient, upstream gradient 등으로 불림)에 local gradient를 곱해 gradient는 구하는 것입니다. 그리고 뒤에 노드들이 연결되어 있다면 계산한 gradient를 뒤로 넘기는 것입니다. 이 과정을 더 이상 뒤로 넘길 node가 없을 때까지 반복하는 것입니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/136165353-90efac9c-7ebf-4be2-8cd8-70b1e03b448d.png" alt="image">
앞선 예시보다 더 복잡한 예시를 보겠습니다. $f(w,x)$를 위와 같이 정의해봅시다. 그러면 연산에 대한 그래프는 다음과 같이 나타낼 수 있을 것입니다. 그리고 저희가 앞으로 사용할 local gradient를 미리 구하면 위와 같이 총 4개의 수식을 구할 수 있습니다. </p>
<p>앞서 계산했듯이 처음 gradient는 1이 될 것입니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/136170446-4ad9a393-b81c-44d4-bcf0-a55fbaa85243.png" alt="image"></p>
<p>다음 gradient를 구해봅시다. 저희가 사용할 local gradient는 $\frac{-1}{x^2}$이 되고, 이 때의 gradient는 1이 됩니다. 따라서 이 두 값을 곱해주게 되면 $1 * \frac{-1}{1.37^2} = -0.53$이 됩니다. </p>
<p><img src="https://user-images.githubusercontent.com/68625698/136173333-cfd50709-8c29-44ad-b505-78ca26701d4e.png" alt="image">
<img src="https://user-images.githubusercontent.com/68625698/136173391-3224ad9f-b0e1-45c9-ba2c-4c6a4ca63468.png" alt="image"></p>
<p>이런 식으로 앞의 gradient를 계속해서 뒤로 넘겨주게 됩니다. $e^x$의 경우, 편미분했을 때도 $e^x$이므로 local gradient가 $e^{-1}$이 되고 들어온 gradient가 -0.53이 되면서 최종적으로 -0.2가 됩니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/136180020-7aa9edb2-335a-4c17-b74b-cae15039946b.png" alt="image">
<img src="https://user-images.githubusercontent.com/68625698/136180096-788b50e4-c302-4e80-b3a1-d0f0dd27ad1b.png" alt="image">
<img src="https://images.velog.io/images/jeong_jaeyoon/post/3112e8ad-43d5-49f0-bfcb-ab0c8542e7fb/image.png" alt="">
이와 같은 과정을 통해 우리는 최종 gradient를 구할 수 있게 됩니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/136181240-8a884738-e9cc-4907-bce2-48ae0dd646f9.png" alt="image"></p>
<p>여기서 backpropagation의 한 가지 특징이 나타납니다. 특정 함수들은 앞에서 했던 것처럼 하나하나 계산할 필요가 없다는 것입니다. </p>
<p>앞서 우리가 했던 예시는 sigmoid 함수에 대해서 하나하나  backpropagation을 진행한 것입니다. 하지만 sigmoid 함수 자체를 미분하여 local gradient로도 사용할 수 있습니다. 실제로 $\frac{d\sigma(x)}{dx}$를 구하면 $(1-\sigma(x))\sigma(x)$를 구할 수 있습니다. 즉, sigmoid gate 부분의 backpropagation 부분을 sigmoid의 local gradient를 통해 한 번에 구할 수 있게 됩니다. 이 과정을 통해 구한 값은 역시 0.2로 같은 값이 나오는 것을 확인할 수 있습니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/136263100-16745af4-58a2-47d5-988a-d22278011621.png" alt="image"></p>
<p>또한 이러한 과정을 통해 우리는 자주 쓰이는 add, mul, max gate 3가지에 대해 또 다른 특징을 발견하게 됩니다. add gate는 local gradient가 1입니다. 그렇기에 upstream gradient를 그래도 전해주기 때문에 distributor라고 불립니다.</p>
<p>max gate는 큰 값에 gradient를 그대로 전하고, 작은 값에는 0을 보냅니다. 이 모습이 최적의 경로를 지정하는 router와 닮아 gradient router라고 불리는 것 같습니다. </p>
<p>mul gate는 앞서 예시에서 풀어본 것과 마찬가지로 서로의 값을 교환하게 됩니다. 즉, switch가 되는 것이죠. 그래서 이 gate는 gradient switcher라고 불립니다. </p>
<p><img src="https://user-images.githubusercontent.com/68625698/136266380-76c0c0ad-3d15-43d8-965b-0d7213bcc5b2.png" alt="image"></p>
<p>지금까지는 upstream gradient가 1개 뿐이었습니다. 그렇다면 upstream gradient가 2개면 어떻게 될까요? 단순히 각 node에서 온 gradient들을 더해주시면 됩니다. </p>
<p><img src="https://user-images.githubusercontent.com/68625698/136330783-f6445c69-2130-491d-8f2f-e3b4d58e92dd.png" alt="image">
하지만 일반적으로 저희는 스칼라 값이 아니라 벡터값을 사용할 것입니다. 그래서 지금부터는 조금 더 확장해서 $x,y,z$가 모두 벡터라고 가정합시다. 전반적인 흐름은 우리가 위에서 한 예시와 다를 바 없습니다. 주의하여야 할 부분은 local gradient들이 모두 jacobian matrix 형태가 된다는 것입니다. </p>
<p>그렇다면 Jacobian matrix는 무엇일까요? n개의 변수를 가지는 함수가 m개 있다고 가정합시다. 
즉, $F_1(x_1,...,x_n),....,F_1(x_1,...,x_n)$라는 함수들이 있는 것이죠. 이 함수들을 모든 변수들에 대해서 편미분을 진행하고 이를 행렬로 나타낸 것을 jacobian matrix라고 합니다. 이 말을 수식으로 나타내면 아래의 행렬이 나타날 것입니다.</p>
<p>$$ \left[
\begin{matrix}
    \frac{\partial F_1}{\partial x_1} &amp; ... &amp; \frac{\partial F_1}{\partial x_n} \
    : &amp;  &amp; : \
    \frac{\partial F_m}{\partial x_1} &amp; ...&amp; \frac{\partial F_m}{\partial x_n} \
\end{matrix}
\right] $$</p>
<p><img src="https://images.velog.io/images/jeong_jaeyoon/post/d1349080-8df6-4215-842f-c9792113f764/image.png" alt=""></p>
<p>이제 다시 한번 차근차근 해봅시다. 위의 그림과 같이 input과 output의 차원이 4096일 때, Jacobian matrix의 크기는 행렬의 연산에 따라서 4096 X 4096이 될 것입니다. 이 때 주의하셔야 할 점은 input을 하나만 넣었을 때라는 점입니다.</p>
<p><img src="https://images.velog.io/images/jeong_jaeyoon/post/f45b9a39-0ee3-4683-9a0e-5cb45c647ed8/image.png" alt="">
만약 minibatch의 사이즈를 100으로 두고 진행한다면 저희가 연산해야하는 Jacobian matrix의 크기는 409600 x 409600이 될 것입니다. 그렇지만 이 모두를 염두해서 jacobian matrix를 계산해야 하지는 않을 것 같습니다. 그 이유는 우리의 연산에서 막상 jacobian matrix를 구하게 되면 대각행렬과 유사한 모양이 나오기 때문이죠. 따라서 행렬의 요소값을 전부 다 구할 필요는 없게 됩니다.</p>
<p><img src="https://images.velog.io/images/jeong_jaeyoon/post/1c0dfc8f-f05b-474e-a5ca-e03a1ccbcfa3/image.png" alt=""></p>
<p>그렇다면 구체적인 예시를 통해 알아보겠습니다. 예시는 그림과 같고, $W, x$ 각각의 값은 위와 같이 정했습니다. 그리고 그래프를 따라 차근차근 계산을 해보면 최종적으로 우리는 $0.22^2 + 0.26^2 = 0.116$의 값을 가지게 됩니다. 그리고 backpropagation을 위해 가장 처음 gradient를 구하면 1이 나옵니다.</p>
<p><img src="https://images.velog.io/images/jeong_jaeyoon/post/bcbb3fb8-278f-4e4b-bc1f-52c6d60614db/image.png" alt=""></p>
<p>이 후 local gradient를 구해봅시다. 앞서 우리는 $f(q) = ||q||^2$이라고 정의했습니다. 이 때 $f$를 각$q_i$들로 편미분을 진행하면 $\frac{\partial f}{\partial q_i} = 2q_i$가 되기 때문에 위의 0.44와 0.52의 값을 얻을 수 있습니다.</p>
<p><img src="https://images.velog.io/images/jeong_jaeyoon/post/3db2910a-616f-4d79-9aee-8bd386a14904/image.png" alt=""></p>
<p>gradient를 다음 node로 넘겨 봅시다. 우선 local gradient의 값은 $1_{k = i}x_j$로 $k = i$일 때 $x_j$, 그렇지 않으면 0의 값을 가지게 됩니다. Chain rule에 의하여 최종 gradient를 구하게 되면 $2q_ix_j$의 값을 가지게 됩니다. 따라서 우리는 그림 왼쪽 위의  빨간 행렬을 얻을 수 있게 됩니다.</p>
<p>여기서 주의하셔야 할 점은 함부로 곱하는 것이 아닌 $x$ 행렬을 transpose 시켜야 한다는 점입니다. 왜냐하면 gradient 행렬의 크기는 원래 변수의 크기와 같아야 하기 때문입니다.</p>
<p><img src="https://images.velog.io/images/jeong_jaeyoon/post/644019de-6bee-47e5-9716-d1e09c2f1014/image.png" alt=""></p>
<p>마지막으로 $x$에 대한 gradient도 구합시다. 우선 local gradient를 구하면 $W_{k,i}$의 값이 나오게 됩니다. 앞서 했던 것처럼 Chain rule을 적용하면 최종적으로 우리는 위와 같은 gradient를 구할 수 있게 됩니다. 역시 여기서 주의하셔야 할 점은 $W$를 Transpose 시켜야 한다는 점입니다. 또한 연산의 순서도 앞의 $W$를 구할 때와는 다르므로 유의하여야 합니다. (연산의 순서가 다른 이유는 shape을 맞춰주기 위함으로 보입니다.)</p>
<h2 id="summary">Summary</h2>
<p>최종적으로 Backpropagation이라는 것은 Chain rule을 재귀적으로 적용해서 input과 parameter의 gradient들을 찾아나가는 과정입니다.</p>
<h1 id="neural-networks">Neural Networks</h1>
<p><img src="https://images.velog.io/images/jeong_jaeyoon/post/f6b3bbfe-d1b1-44ff-b6ef-45e6b0411ab7/image.png" alt=""></p>
<p>이전에 저희는 Linear score function과 같이 하나의 함수식만을 사용하여 이미지를 분류했습니다. 그러다보니 class마다 만들 수 있는 템플릿은 하나로 모든 이미지의 평균값 밖에 갖지 못했습니다. 대표적으로 자동차의 템플릿이 빨간색이다보니 다른 색의 자동차가 들어오면 자동차라고 제대로 분류를 못하는 것이죠. </p>
<p>하지만 이제부터는 layer를 여러개 쌓으면서 여러 개의 weight를 가질 수 있게 됐습니다. 그러다보니 템플릿은 더 이상 하나만을 사용하는 것이 아니게 됐습니다. 위의 예시를 보면 가운데 h라는 layer가 생겼고 이 때 노드가 100개가 되면서 총 100개의 템플릿을 만들 수 있게 됐습니다.</p>
<p><img src="https://images.velog.io/images/jeong_jaeyoon/post/3e21ce88-70e8-42a6-aad9-9a3287a85f2c/image.png" alt=""></p>
<p>3개의 layer는 이렇게 표현할 수 있습니다.</p>
<p><img src="https://images.velog.io/images/jeong_jaeyoon/post/67f9d309-a502-4adb-815f-aaaa450b5ace/image.png" alt="">
우리가 배울 Neural Network는 인간의 Neuron에서 착안해온 모델이다보니 상당부분 Neuron과 닮았습니다. Neuron은 synapse를 통해 자극이 들어오면 axon을 거친 뒤 그 다음 뉴런으로 신호를 전달합니다. </p>
<p>Neural Network 역시 이와 유사합니다. input이 들어오게 되면 가중치를 곱하고 이를 다 더해준 뒤, 활성함수를 거치게 됩니다. 그리고 그 값을 다음 노드에 전달하는 구조인 것이죠. 여기서 활성함수는 sigmoid와 같은 함수들입니다.</p>
<p>그러나 염두해야할 점은 실제 neuron과 neural network가 서로 같다고 이해하시면 안됩니다. 그 개념을 착안해왔다는 점을 알아두셔야 합니다.</p>
<p><img src="https://images.velog.io/images/jeong_jaeyoon/post/d3bb0c41-b84c-4080-9dff-476b0a2cb832/image.png" alt=""></p>
<p>지금까지는 활성화함수를 단순히 sigmoid만을 확인했었는데요. 활성화함수에는 sigmoid 말고도 relu, tanh 등 다양한 종류의 활성화함수가 있습니다.</p>
<p><img src="https://images.velog.io/images/jeong_jaeyoon/post/4bb69263-c10c-4c4d-b353-578702164a19/image.png" alt=""></p>
<p>마지막으로 2 layer neural network과 3 layer neural network는 위와 같은 구조를 가집니다. 그리고 위 모델의 마지막 layer와 그 앞의 hidden layer를 보면 모든 노드들이 다 연결된 것을 볼 수 있습니다. 우리는 이를 fully connected라고 합니다.</p>
<h1 id="reference">Reference</h1>
<p><a href="https://deepinsight.tistory.com/98">https://deepinsight.tistory.com/98</a>
<a href="https://lsjsj92.tistory.com/393?category=792966">https://lsjsj92.tistory.com/393?category=792966</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS231n] Lecture 3 : Loss Functions and Optimization]]></title>
            <link>https://velog.io/@jeong_jaeyoon/CS231n-Lecture-3-Loss-Functions-and-Optimization</link>
            <guid>https://velog.io/@jeong_jaeyoon/CS231n-Lecture-3-Loss-Functions-and-Optimization</guid>
            <pubDate>Wed, 29 Sep 2021 09:30:58 GMT</pubDate>
            <description><![CDATA[<h1 id="introduction">Introduction</h1>
<p><img src="https://user-images.githubusercontent.com/68625698/135212178-e6e9cf02-2fdb-435a-a60d-e588381b7c3f.PNG" alt="사진 1"></p>
<p>지난 2강에서는 Linear Classifier가 어떤 방식으로 작동하고 score를 뽑는지에 대해서 배웠습니다. 이 때 W, 가중치가 사용된다는 점도 확인했습니다. 그러나 중요한 점은 이 가중치가 이미지 분류를 제대로 해낼 수 있는지를 평가해야한다는 점입니다. </p>
<p>지난 강의 마지막 예시를 보면 자동차에 대해서는 제대로 분류했지만, 고양이나 개구리는 분류하지 못했다는 것을 알 수 있습니다. 이는 W의 성능이 좋지 못하다는 것을 의미하죠 그렇다면 우리는 이것을 어떻게 정량적으로 평가할 수 있을까요?</p>
<p>W의 성능이 괜찮은지 정량적으로 파악할 수 있는 방법이 바로 <strong>Loss Function</strong>입니다. Loss function을 통해 우리가 구한 W가 좋지 않다고 판단되면 좋은 W로 학습시켜야 할 것입니다. 이 과정을 Optimization이라고 합니다. 이번 3강에서는 이 2가지를 중점으로 강의가 진행됩니다.</p>
<h1 id="loss-function">Loss function</h1>
<p><img src="https://user-images.githubusercontent.com/68625698/135216437-32bc050b-6086-460b-8ac0-7e8bcfce0a26.PNG" alt="사진 2"></p>
<p>앞서 이야기 했듯이 Loss function이란 Classifier가 이미지를 잘 분류하는지에 대해서 정량적으로 평가하는 함수입니다. 우선 이미지 데이터인 x와 라벨 데이터인 y가 한 쌍인 데이터셋을 준비합니다. Classifier의 예측값과 라벨 데이터 y를 비교하여 모두 더한 뒤, 데이터의 개수로 나눈 값이 loss가 됩니다.</p>
<h2 id="multiclass-svm-loss">Multiclass SVM loss</h2>
<p>강의에서는 우선 Multiclass SVM loss에 대해서 설명합니다.
<img src="https://user-images.githubusercontent.com/68625698/135223644-7cc433bf-adcb-4fd0-a2e2-c1b625ef1251.PNG" alt="사진 3"></p>
<p>Multiclass SVM loss을 그래프로 그리면 위의 파란 그래프와 같은 형태를 지닙니다. 이 그래프가 문의 힌지와 비슷하고 해서 흔히 hinge loss라고도 불립니다. 구체적인 loss를 구하는 방법은 식과 같습니다. 여기서 $s_j$는 정답이 아닌 클래스의 score를 의미하고, $s_{y_i}$는 정답인 클래스의 score를 의미합니다. 그리고 상수는 safety margin으로 강의에서는 1로 설정했습니다. 여기서 safety margin을 더해서 분류의 최소값을 올리므로서 분류 성능을 끌어올리고  것입니다. </p>
<p>만약 정답인 클래스의 score가 정답이 아닌 클래스의 score + safety margin보다 크다면 loss는 0 값을 가집니다. 아니라면 $s_j - s_{y_i} + 1$의 loss값을 가지게 됩니다. 그리고 이 값들을 모두 합한 값이 최종 loss가 됩니다. </p>
<p><img src="https://user-images.githubusercontent.com/68625698/135229339-039045e7-d097-4449-890c-3d666cf02817.PNG" alt="사진 4"></p>
<p>위의 방식으로 각 class별 loss를 구하면 2.9, 0, 12.9라는 값을 가지게 됩니다. 마지막으로 모든 class별 loss의 평균을 구해주므로서 최종 loss인 $L$을 구할 수 있게 됩니다. 위의 예시에서는 5.27이라는 값을 가지게 되는 것이죠. </p>
<p><strong>Q1</strong>. 만약 자동차의 스코어를 약간 바꾼다면 loss에서는 무슨 일이 벌어질까?
<strong>A1</strong>. score를 약간 바꿔도 loss는 0으로 변하는 건 없습니다. 자동차의 score를 1.9보다 큰 값으로 빼지 않는이상 변하는 것은 없습니다. 이는 SVM의 특징으로 safety margin의 영향으로 볼 수 있을 것 같습니다. </p>
<p><strong>Q2.</strong> loss가 가질 수 있는 최소값과 최대값은 무엇일까요?
<strong>A2.</strong> 그래프를 보면 알 수 있듯이 최소값은 0, 최대값은 무한대가 될 것입니다.</p>
<p><strong>Q3.</strong> 처음 W가 너무 작아서 score가 0에 가까우면 loss는 어떻게 될까요?
<strong>A3.</strong> 모든 score가 0이라고 가정하고 고양이를 한번 계산을 해보겠습니다. $max(0, 0-0+1)+max(0, 0-0+1) = 2$가 되고 최종 loss는 $6/3 = 2$가 될 것입니다. 좀 더 보편적으로 적용해보면 class - 1의 값이 됩니다. 이는 처음 훈련을 시작할 때, 확인해볼 수 있는데 이 값이 예상과 다르게 나온다면 무엇인가 잘못됨을 파악할 수 있습니다.</p>
<p><strong>Q4.</strong> 만약 모든 클래스의 loss를 구해 다 더하면 어떻게 될까요?
<strong>A4.</strong> 각각의 loss는 1씩 증가할 것이고, 최종 loss 역시 1 증가할 것입니다. 사실 질문과 같은 방식으로 학습을 진행해도 크게 상관은 없습니다. 하지만 모든 값을 다 맞췄을 때를 가정하면 최종적으로 loss는 항상 1이 남게되는 현상이 발생한다는 것을 유의해야합니다. </p>
<p><strong>Q5.</strong> 단순 합 대신에 평균을 이용하면 어떨까요?
<strong>A5.</strong> 단순히 scale의 차이만 발생할 뿐, 훈련과정에서는 큰 차이가 발생하지는 않습니다. 중요한 것은 훈련을 통해 loss의 값을 줄여하는 것이지 scale를 줄이는 건 아니니까요.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/135241859-14643902-f2c0-4cea-922c-ba87669b7645.PNG" alt="사진 5"></p>
<p><strong>Q6.</strong> $L_i$를 제곱했을 때 어떤 일이 발생할까요?
<strong>A6.</strong> 만약 위와 같은 방식으로 $L_i$를 구하면 전혀 다른 결과를 낼 것입니다. 일단 새로운 식은 선형성이 깨져있다는 점이 중요합니다. 이 같은 loss를 우리는 squared hinge loss라고 합니다. 이 loss는 제곱으로 계산되기 때문에 굉장히 큰 값이 나올 수 있으며, 이는 곧 잘못 분류할 경우, penalty를 크게 준다는 것을 의미합니다. 약간의 오류에도 큰 패널티를 부여하는 것이죠.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/135371773-897864c7-2ddf-4582-b968-3a7ea746e681.PNG" alt="사진 6"></p>
<p>그렇다면 loss를 0으로 만드는 weight를 찾았다고 가정해봅시다. 과연 이 weight는 하나만 있는 것일까요? 간단하게 생각하면 weight에 상수배를 해도 loss는 변함이 없다는 것이죠.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/135372284-ba71aee4-9e50-4812-88b3-448aff4d11e7.PNG" alt="사진 7"></p>
<p>우리가 계속해서 확인했던 예제에서 자동차의 loss를 확인해봅시다. 단순히 weight를 2배 해준 것이므로 자동차 이미지를 넣었을 때 산출되는 결과의 score를 모두 2배로 올린 뒤, 계산을 해보면 여전히 결과는 0으로 동일합니다. 즉, loss를 0으로 만드는 최적의 weight는 여러 개 존재할 수 있다는 점이죠. </p>
<p><img src="https://user-images.githubusercontent.com/68625698/135384551-edb37247-5e26-4dfc-8312-1f1c0bcfcd1e.PNG" alt="사진 9"></p>
<p>이런 현상은 왜 일어나는 것일까요? 우리가 설정한 loss는 data loss로 training data와 모델의 예측값만을 가지고 loss를 구하기 때문입니다. 위의 그림을 보면 알 수 있듯이, 우리가 설정한 data loss가 0이라면 모델은 파란색 데이터를 모두 맞출 것입니다. 하지만 우리가 weight를 찾는 목적은 훈련 데이터를 완벽하게 맞추기 위한 것이 아닌, 새로운 데이터가 들어왔을 때 이를 정확하게 맞추기 위함입니다. 위의 모델에 새로운 초록색 데이터를 넣으면 하나도 못 맞추거나 맞춰도 정확도가 낮을 것입니다. 즉, overfitting이 발생하는 것이죠. </p>
<p><img src="https://user-images.githubusercontent.com/68625698/135385052-839a2981-c48b-4d99-a4d3-ceecd8ad5991.PNG" alt="사진 10"></p>
<p>이러한 문제를 막기 위해서, overfitting된 모델이 아닌 초록색 선의 모델을 찾기 위해서 우리는 regularization을 loss function에 추가해주는 것입니다. 즉, loss function에 패널티를 부여해서 최종 loss가 너무 낮아지는 것을 방지하기 위함이죠. 이 과정을 통해 우리는 이전보다는 모델에 일반성을 부여할 수 있게 됩니다. </p>
<h2 id="regularization">Regularization</h2>
<p><img src="https://user-images.githubusercontent.com/68625698/135388287-e28fe5f7-b339-4b1e-8c77-104d1e582b00.PNG" alt="사진 11"></p>
<p>위의 사진에서보면 알 수 있듯이 Regularization의 방법에는 여러 종류가 있습니다. 이번에는 대표적인 L1 regularization과 L2 regularization에 대해서 알아보도록 하겠습니다.</p>
<p>예를 들어 L1 regularization의 loss function은 $L = \frac{1}{N}\sum^{N}_{i=1}{L_i(f(x_i,W),y_i)}$ $+ \frac{\lambda}{n}\Sigma|W|$라고 가정해봅시다. 이 후 편미분을 하고 가중치를 업데이트 하게 되면 $W$ -&gt; $W&#39; = W - \frac{\eta\lambda}{n}sgn(W) - \eta\frac{\partial L}{\partial W}$이 됩니다. 결국 전체 weight는 가감방식으로 줄어들게 됩니다. </p>
<p>반면 L2 regularization의 loss function을 $L = \frac{1}{N}\sum^{N}_{i=1}{L_i(f(x_i,W),y_i)}$ $+ \frac{\lambda}{n}\Sigma W^2$ 으로 가정해봅시다. 이 후 weight의 업데이트를 위해 편미분을 하고 연산을 진행하면 $W$ -&gt; $W&#39; = W - \frac{\eta\lambda}{n}W - \eta\frac{\partial L}{\partial W}$ $= (1-\frac{2\eta \lambda}{n})w - \eta\frac{\partial L}{\partial W}$가 되면서 L1과 마찬가지로 줄어들기는 하나 L1과는 다르게 곱해지는 식으로 값이 변하게 됩니다. </p>
<p>즉, L1 regularization을 사용하게 되면 상수의 값들을 빼주기에 비중이 작은 가중치들은 0이 되어 필요한 변수들만 남게 되는 반면, L2 regularization은 상수를 곱해주면서 값을 줄여나가기 때문에 가중치의 값이 작아질지언정 모두 남게 되는 것이죠.</p>
<h2 id="softmax-classifier">Softmax Classifier</h2>
<p>이미지의 다중 분류문제에 있어서 Hinge loss보다 더 자주 쓰이는 loss는 Softmax Classifier에 사용되는 Cross Entropy Loss입니다. </p>
<p><img src="https://user-images.githubusercontent.com/68625698/135393315-720fe00b-1edb-4c35-8c12-5585289ca6a9.PNG" alt="사진 12"></p>
<p>고양이 사진을 예시로 들 때, softmax의 함수는 $\frac{e^{s_k}}{\Sigma_j{e^{s_j}}}$가 됩니다. 이 때 softmax 함수에는 자연 상수 $e$를 취하게 되는데요. 그 이유는 미분했을 때 계산이 용이하다는 장점과 score간의 차이를 더 극명하게 나타내기 위함입니다.</p>
<p>우리는 이 방식으로 확률값을 구할 수 있게되고, 정답 클래스에 $-log$를 위하면서 최종 loss값을 구할 수 있게됩니다. 이 때 로그를 취하는 이유는 곱셈에 대한 계산이 용이하기 때문입니다. </p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/135397793-f7a0741b-7605-4cec-bd6f-627ba00572aa.png" alt="사진 13">
<a href="https://kkukowiki.kr/w/%EB%A1%9C%EA%B7%B8%ED%95%A8%EC%88%98">https://kkukowiki.kr/w/%EB%A1%9C%EA%B7%B8%ED%95%A8%EC%88%98</a></p>
</blockquote>
<p>그리고 음수를 취해주는 이유는 그림을 보면 알 수 있습니다. 기존의 로그함수에 음수를 취해주므로서 확률에 로그 함수를 취한 값을 양수로 만들 수 있을 뿐만 아니라 완벽히 맞췄을 경우, 0의 loss를 갖을 수 있게 됩니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/135398612-24707a1c-1fec-49f1-a99b-95a6dc7dbded.PNG" alt="사진 14"></p>
<p>구체적인 예시로 이를 구해보면 최종적으로 loss는 0.89라는 값을 가지게 됩니다. </p>
<p><strong>Q1</strong>. $L_i$의 최대값과 최소값은 무엇일까요?
<strong>A1</strong>. 위의 로그 그래프를 보면 알 수 있듯이 최소값은 0, 최대값은 무한대가 될 것입니다.</p>
<p><strong>Q2.</strong> 초기 가중치가 너무 작아 score가 0에 가까울 때 loss는 어떻게 나올까요?
<strong>A2.</strong> 간단하게 위의 식에 넣어서 계산을 해보면 됩니다. class가 cat, car, frog로 3개일 때, 모든 class의 score가 0이라고 가정합시다. 이 때 확률값을 구하면 모두 $\frac{1}{3}$이 되면서 $L_i = -log(\frac{1}{3})$이 나오게 될 것입니다. 일반화 시키면 $\frac{1}{class의 수}$에 $-log$를 취한 값이 되겠죠.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/135400637-c3a89e83-bc72-46af-b950-ff2968804b72.PNG" alt="사진 15"></p>
<p>그렇다면 score의 값을 약간 바꿨을 때, softmax와 SVM의 loss는 어떻게 변할까요? 앞서 설명했듯이 SVM은 변화하는 값이 충분히 크지 않는다면 기존의 loss와 차이가 없을 것입니다. 반면 softmax는 각 class의 비율이 달라지는 것이기 때문에 약간의 변화에도 굉장히 크게 변할 것입니다. 강의에서는 SVM은 둔감하고, softmax는 민감하다고 표현합니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/135402776-51d6c811-79ef-498e-a376-2118cf200c8d.PNG" alt="사진 16">
최종적으로 우리는 이미지, 라벨 형식의 데이터셋을 구한 뒤, score function을 설정합니다. 이 후, loss function을 설정하여 우리가 찾은 W가 정량적으로 좋은지 나쁜지를 판단하는 것입니다. loss function의 경우, 어떤 모델, 어떤 작업을 하느냐에 따라 다 다르지만 최종적으로 사용하는 Full loss에서는 Regularization 역시 고려해주어야 합니다. 그렇다면 우리는 어떻게 좋은 weight를 구할 수 있을까요?</p>
<h1 id="optimization">Optimization</h1>
<p>최적의 weight를 찾는 방법이 바로 Optimization입니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/135404910-45c6b41d-84a3-4ea9-bfcc-f944a53b0af3.PNG" alt="사진 17"></p>
<p>흔히 Optimization은 두 눈을 가리고 산을 내려가는 것과 같다고 비유하곤 합니다. loss function의 최저점을 찾아 내려가는 것이라는 의미이죠. 이 때 몇 가지 optimization의 방법이 있습니다. </p>
<p><img src="https://user-images.githubusercontent.com/68625698/135407324-859006f3-167d-4abb-af86-1b2cc7290b70.PNG" alt="사진 18"></p>
<p>그 예시로 든 방법이 Random search입니다. 즉, 가중치를 무작위로 지정해서 결과값을 산출하는 것입니다. 물론 운이 정말 좋다면 최적의 파라미터를 찾을 수도 있지만 거의 불가능하고 절대 좋은 방법이 아닙니다. 절대 사용해서는 안되는 방법입니다.</p>
<p>이 방법으로 정확도를 산출해보면 15.5%를 얻을 수 있습니다. 당시 SOTA인 95%에 비하면 의미없는 성능인 것이죠.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/135409061-91ee6c4f-82c4-4d5d-8470-7124ac03b513.PNG" alt="사진 19"></p>
<p>따라서 우리는 경사를 따라 내려가는 경사하강법을 사용합니다. </p>
<p>이 경사하강법을 사용할 때 필요한 것이 바로 미분 공식입니다. 특히 이미지의 경우, 다차원 데이터이기 때문에 편미분을 사용하게 됩니다. 이렇게 구한 벡터를 우리는 gradient 벡터라고 하며 이는 경사가 가장 가파른 방향을 가르킬 것입니다. 따라서 우리는 이 방향의 반대 방향을 따라 내려가야 하는 것이죠.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/135416233-7b9d6002-0fdd-4e3f-af51-cffce31bb2a1.PNG" alt="사진 20">
그렇다면 위의 수식을 사용하여 한 번 직접 해보겠습니다. 우선 현재의 가중치의 loss는 그림과 같습니다. 이 때 첫 번째 값에 0.0001만큼 더한 뒤, loss를 구하면 1.25322가 나오게 되죠. 이 때 gradient벡터의 첫 번째 값을 구하면 -2.5라는 값을 얻을 수 있습니다. 이 과정을 모든 차원에서 진행하면 되죠.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/135416889-0efa81d5-30c6-4fea-8e3d-114bae09f9ab.PNG" alt="사진 21">
하지만 이 방식은 너무 오래 걸리고 효율적이지 못합니다. 결국 우리가 원하는 것은 loss function을 W로 미분한 값이기 때문이죠.</p>
<p>그래서 우리는 Chain rule이라는 미분공식을 사용하여 이 값을 한 번에 구할 것입니다. (추후 강의에서 진행 예정)</p>
<p><img src="https://user-images.githubusercontent.com/68625698/135418093-292d14f6-c003-4308-b4fc-65bf2a441add.PNG" alt="사진 22"></p>
<p>요약하자면 하나하나 계산하는 방식은 대략적이고 느리지만 계산이 쉽고, 미분 공식을 활용하는 Analytic gradient는 정확하고 빠르지만 에러가 발생할 수 있다는 단점이 있죠. 그래서 우리는 항상 Analytic gradient를 사용하되 numerical gradient로 그 값을 확인하는 것입니다.</p>
<h2 id="gradient-descent">Gradient Descent</h2>
<p><img src="https://user-images.githubusercontent.com/68625698/135421575-114bc5ca-470b-404f-bbc8-5efa371f3008.PNG" alt="사진 23"></p>
<p>경사하강법은 위와 같이 구하면 됩니다. loss function, 전체 data, 현재 weights로 weights의 gradient를 구해줍니다. weight_gradient는 미분을 통해 구할 수 있습니다. 그리고 step size와 weight_gradient를 곱한 뒤, 현재의 weight에서 빼주시면 됩니다.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/135422774-d73c75e4-ac0d-4495-94c0-2eae4292d41d.png" alt="사진 24">
<a href="https://daebaq27.tistory.com/35">https://daebaq27.tistory.com/35</a></p>
</blockquote>
<p>이 때 빼주는 이유는 위에서 언급했듯이 우리가 구한 gradient vector는 경사가 제일 가파른 곳(가장 심하게 변하는 곳)으로 방향을 가지기 때문입니다. 위의 그림을 보시면 좀 더 직관적인 이해가 가능합니다. 즉, 우리는 이와는 반대의 방향으로 가야 최적의 weight를 찾을 수 있기 때문에 빼주셔야 합니다.</p>
<p>하지만 Gradient Descent는 단점이 있는데요. 한 step을 나가기 위해서 모든 데이터를 다 훑어보고 계산하기 때문에 시간이 오래걸리고 컴퓨터의 용량이 커야한다는 점입니다.</p>
<h2 id="stochastic-gradient-descentsgd">Stochastic Gradient Descent(SGD)</h2>
<p><img src="https://user-images.githubusercontent.com/68625698/135428811-4f6266c8-bf29-47bd-a820-0959bfcc014b.PNG" alt="사진 25">
이를 개선하기 위해서 나온 방식이 바로 Stochastic Gradient Descent입니다. 즉, 한 번 step을 나갈 때 전체 데이터를 보는 것이 아니라 일부의 데이터만을 가지고 step을 나가는 것입니다. 확실히 Gradient Descent보다는 훨씬 연산속도도 빠르고 컴퓨터의 용량도 덜 사용합니다. 하지만 전체 데이터를 사용하는 것이 아니기에 최적값을 찾아가는데 약간 헤메는 모습을 보여줍니다. </p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/135430419-3ea8462f-21c0-4406-a780-954c90bdb7ce.png" alt="사진 26">
<a href="https://seamless.tistory.com/38">https://seamless.tistory.com/38</a></p>
</blockquote>
<p>위의 사진을 보면 두 방법이 확연하게 다르다는 점을 확인할 수 있습니다. </p>
<h1 id="etc">ETC</h1>
<p><img src="https://user-images.githubusercontent.com/68625698/135540757-d3f819b8-38cf-43e4-bd71-04869b4900ea.png" alt="image"></p>
<p>지난 시간 배운 선형분류기를 통해 이미지를 인식시킬 때는 그냥 이미지 자체를 input으로 집어 넣었습니다. 하지만 이는 그렇게 좋은 방법이 아니었습니다. 그래서 CNN이 나오기 전 사람들은 다양한 방법을 찾았습니다. 그 중 하나가 바로 위의 사진과 같은 방법입니다. </p>
<p>두 단계를 거쳐서 결과를 도출하는 방식인데요. 우선 이미지의 여러 특성을 뽑아내는 과정을 거친 뒤, 이를 하나의 벡터로 연결시켜줍니다. 그리고 이 벡터가 Linear Classifier의 input으로 넣는 것입니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/135542014-ada1ce0a-315f-4346-915e-559d67417051.png" alt="image"></p>
<p>그 첫 번째 예가 color histogram입니다. 이미지에서 색상 값을 뽑아 어떤 색이 가장 많이 나오는지 그 빈도를 측정하는 것입니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/135542495-a50878cf-ab2b-4d19-91be-125eaa02bd01.png" alt="image"></p>
<p>두 번째 방법이 HoG(Histogram of Oriented Gradients)입니다. 첫 번째가 이미지의 색상 값을 feature로 뽑았다면 이 방법은 이미지의 방향값, 테두리를 feature로 뽑은 뒤, 이를 히스토그램으로 표현하는 것입니다. 그래서 이미지를 8x8로 자르고 해당 부분에 어떤 테두리의 방향이 많은지를 히스토그램으로 나타낸 뒤 이를 추출하는 것입니다.</p>
<p><img src="https://user-images.githubusercontent.com/68625698/135544283-7cae4645-b1a9-4476-b08c-15a591338076.png" alt="image"></p>
<p>마지막으로 bad of words 방법입니다. 이 방법은 자연어처리에서 많이 사용되는 방법입니다. 우선 기존의 이미지들을 random하게 잘라냅니다. 그리고 이 부분들을 클러스터링을 하는 것입니다. 그러면 알고리즘을 통해 색깔, 방향 등의 특징들을 기반으로 클러스터가 형성될 것입니다. 즉, codebook을 만드는 것입니다. 그리고 분류하고 싶은 이미지를 넣으면 이 이미지를 잘라서 학습된 클러스터와 비교하여 어떤 특징을 가지고 있는지를 비교하는 것입니다. </p>
<p><img src="https://user-images.githubusercontent.com/68625698/135544744-ea0cc365-2de3-408d-8332-dcd78582bde0.png" alt="image"></p>
<p>몇 년전만 해도 이렇게 feature를 추출한 뒤 이미지를 인식하는 방법을 취했다면, 이제는 CNN이 발달하면서 특징을 뽑아주는 것이 아닌 모델이 알아서 이미지의 특징을 뽑을 수 있도록 발달했습니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS231n] Lecture 2 : Image Classification pipeline]]></title>
            <link>https://velog.io/@jeong_jaeyoon/CS231n-Lecture-2-Image-Classification-pipeline</link>
            <guid>https://velog.io/@jeong_jaeyoon/CS231n-Lecture-2-Image-Classification-pipeline</guid>
            <pubDate>Tue, 14 Sep 2021 08:22:51 GMT</pubDate>
            <description><![CDATA[<h1 id="image-classification">Image Classification?</h1>
<p>Image Classification란 시스템이 입력 이미지를 받으면 미리 저장되어 있던 카테고리에서 어떤 카테고리에 속할지 결정하는 것을 의미합니다. 우리에겐 굉장히 쉬운 일이지만 컴퓨터에게는 쉬운 일이 아닙니다. </p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133303276-4358e032-3559-42c9-aeca-154ff6483644.png" alt="image">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>위의 그림을 보면 알 수 있듯이, 컴퓨터에게 고양이 이미지는 단순히 숫자의 집합에 불과하기 때문입니다. 즉, &#39;고양이&#39;라는 개념이 가진 의미는 실제 컴퓨터가 고양이를 이해하는 픽셀 값과는 큰 차이가 있게 되는데 이러한 문제를 의미적 차이(Semantic Gap)이라고 합니다.  </p>
<p>이렇게 컴퓨터가 이미지를 픽셀 값으로 보는 것은 골치 아픈 문제들을 만듭니다. 조금 옆으로 이동해서 대상을 찍거나, 조명 차이, 자세 차이, 일부분만 나타나는 등의 약간의 변화에도 큰 격차가 생겨 대상을 인식하지 못 하기 때문입니다. 따라서 알고리즘은 이러한 변화에도 큰 영향을 받지 않고 (Robust) 객체를 인식할 수 있어야 합니다.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133357261-98a9d56e-6f94-408d-b415-94a572cce10d.PNG" alt="사진 10">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>처음 사람들은 이미지 분류 문제를 해결하기 위해서 위의 그림과 같은 방식으로 접근했습니다. 읽어들인 이미지에서 테두리를 추출하고, 꼭지점에 해당하는 곳들을 보면서 객체의 특징을 찾은 뒤 분류를 합니다. 그러나 이 방식은 작은 변화에도 큰 영향을 받고, 새로운 객체를 인식시키려면 새롭게 만들어야 한다는 단점이 있습니다. </p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133377186-961a4938-dd13-4105-9b73-686bfb5a2604.PNG" alt="사진 11">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>그래서 사람들은 Data-Driven Approach(데이터 중심 접근방식)을 고안해냅니다. 이전의 방식과는 달리, 수 많은 label이 달린 이미지 데이터셋을 바탕으로 고안된 방법입니다. 각 카테고리별로 수 많은 데이터셋을 수집한 뒤, Machine Learning Classifier를 학습시켜 객체를 인식하게 됩니다.  </p>
<p>따라서 이미지 분류 알고리즘에 대한 생각도 조금 바뀌게 됩니다. 이미지를 넣으면 label이 나오는 단순한 함수에서 images, label을 넣으면 model이 나오는 train함수와 model, test_images를 넣으면 test_labels가 나오는 predict 함수로 말이죠. </p>
<h1 id="nearest-neighbor">Nearest Neighbor</h1>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133411343-ca8d42b4-2d7a-4fee-ac9e-a74658241c92.png" alt="사진 12">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>우선 Nearest Neighbor를 먼저 살펴보겠습니다. Nearest Neighbor의 알고리즘은 단순합니다. train에서 모든 이미지와 label을 기억한 뒤, predict에서 기존의 이미지와 새로운 이미지를 비교하여 가장 유사한 이미지로 label을 예측합니다. Nearest Neighbor를 사용한 결과 오른쪽과 같은 결과를 얻을 수 있었습니다.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133412155-a588c35a-22ee-4f28-a6b4-7da8b8183c11.PNG" alt="사진 14">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>그렇다면 Nearest Neighbor는 두 이미지가 유사한 지 어떤 기준으로 판단할까요? 일반적으로 거리를 사용하며 위의 사례에서는 L1 distance (manhattan distance)를 사용했습니다. 위의 그림을 보면 알 수 있듯이 L1 distance는 각 이미지 픽셀끼리의 차이에 절대값을 취하여 모두 더한 값입니다. 즉, 현재 test image와 training image는 서로 456의 차이를 가지는 것이죠. Nearest Neighbor는 이 값이 가장 작은 값을 가장 유사한 이미지라고 판단하게 됩니다. </p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133554853-4d7b419e-395d-4a51-aea9-00fdf9416a7c.PNG" alt="사진 15">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>위의 코드가 L1 distance를 사용하여 Nearest Neighbor Classifier를 구현한 코드입니다. 유의해야 할 점은, Train 함수의 시간복잡도보다 Predict 함수의 시간복잡도가 더 짧다는 것입니다. 일반적으로 사람들은 학습에서는 시간이 오래걸려도 괜찮지만 예측에서는 시간이 짧게 걸리길 바라기 때문에, 이는 큰 단점으로 다가옵니다.</p>
<h1 id="k---nearest-neighbor">K - Nearest Neighbor</h1>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133569163-689ad0d4-2f97-4660-99ae-c200159d5ea5.PNG" alt="사진 16">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>왼쪽의 첫 번째 그림 Nearest Neighbor를 한 결과를 나타낸 것입니다. 그림을 보면 몇 가지 특징이 보입니다. 첫 번째로 녹색 지점 한 가운데에 노란 점이고, 두 번째로는 어느 부분에서 다른 영역을 침범하는 모습을 보인다는 점입니다. 즉, 이미지 분류에 있어서 일반화가 부족하다는 점입니다.  </p>
<p>그래서 사람들이 고안해낸 방법이 KNN 방법입니다. 가장 가까운 하나의 이웃을 찾는 것이 아닌 K개의 이웃을 찾아서 투표한 뒤, 가장 많은 레이블로 예측하는 알고리즘입니다. 오른쪽의 그림들이 K를 1보다 크게 지정했을 때의 결과입니다. K = 1일 때 나타나던 특징들이 모두 없어졌다는 점을 확인할 수 있습니다. </p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133573811-21f2c334-d405-4a66-9fa0-16b754a4ac15.PNG" alt="사진 17">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>KNN 알고리즘은 K뿐만 아니라 distance metric도 조절할 수 있습니다. 앞서 우리는 L1 distance만을 사용하여 분류기를 만들었습니다. 그러나 L1 distance가 아닌 L2 distance를 선택해도 됩니다. 실제로 L2 distance를 사용했을 때가 L1 distance를 사용했을 때보다 경계가 훨씬 자연스러운 것을 알 수 있습니다. 일반적으로 L1 distance는 좌표계의 영향을 많이 받으므로 특징 벡터의 요소들이 개별적 의미를 가질 때 사용하면 좋고, L2 distance의 경우 요소들의 실질적 의미를 잘 모를 때 사용하면 좋습니다. </p>
<h1 id="hyperparameters">Hyperparameters</h1>
<p>K나 distance와 같은 이러한 변수들을 우리는 하이퍼 파라미터라고 부릅니다. 이 변수들은 학습과정에서 자연스럽게 찾아지는 것이 아니기에 직접 정해야 합니다. 그렇다면 어떤 기준으로 이 값을 찾을 수 있을까요?</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133579013-1df78741-0cf7-4e33-bd32-ad7cdcace263.PNG" alt="사진 18">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>강의에서는 총 3가지 아이디어를 이야기합니다. 첫 번째는 전체 데이터에 대해서 최고 성능을 내는 값을 선택하는 것입니다. 이 방법은 훈련 데이터셋에 대해서는 좋은 성능을 낼 수 있으나 새로운 데이터에 대해서는 제대로 분류하지 못하는 문제가 발생합니다. 즉, 과적합으로 인해 새로운 데이터는 제대로 예측하지 못하게 됩니다.</p>
<p>두 번째는 훈련 데이터셋과 테스트 데이터셋을 나눠, 훈련 데이터셋만으로 최적의 파라미터를 구하는 방법입니다. 첫 번째보다는 나은 방식이나 여전히 &#39;새로운&#39; 데이터를 완전히 대비하진 못합니다. 최적이라고 생각했던 파라미터가 어쩌면 테스트셋에 대한 것만일 가능성도 있기 때문입니다.  </p>
<p>그래서 최종적으로는 데이터셋을 총 train, test, validation set으로 구성해야 합니다. train 데이터셋을 통해 모델을 학습시키고, 이를 validation 데이터셋으로 평가하며 최적의 파라미터를 추정합니다. 마지막으로 test 데이터셋을 통해 모델의 성능을 평가하는 것입니다.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133664694-3703e0a1-f906-4c43-ae6d-e78c5fe38001.png" alt="image">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>데이터셋이 작을 경우, 위와 같이 Cross Validation이라는 기법을 사용할 수 있습니다. 하지만 딥러닝의 경우, 연산량이 많기 때문에 사용되지 않는 경향이 있습니다.</p>
<p>우선 데이터셋을 train과 test로 분할해줍니다. 그리고 train을 원하는 만큼 나눠줍니다. 위의 그림처럼 번갈아가면서 validation을 정하고 초록색 fold로는 학습을, 노란색 fold로는 최적의 파라미터를 찾는 것입니다.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133666731-fc94b5a0-40ba-41cb-8051-840b49acfa7a.png" alt="image">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>위와 같은 방법을 통해 KNN의 하이퍼파라미터를 찾을 수 있습니다. 하지만 이미지 분류에 있어서 KNN은 사용되지 않습니다. 왜냐하면 test 시간이 오래걸린다는 점과 이미지간의 유사도를 측정하는 방식으로 사용되는 Distance Metrics가 유사도의 기준으로 적당하지 않는다는 점 때문이죠. 가장 왼쪽의 사진이 원본이고, 오른쪽의 사진들은 왼쪽의 사진들을 조금씩 변형한 것인데요. 이 오른쪽 사진들은 L2 distance로 유사도를 구하면 모두 같은 유사도를 가지는 결과를 보여줍니다.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133669730-b70e7df9-31e2-4b30-852a-d2bc452af5ab.png" alt="image">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>또한 KNN은 차원의 저주 문제와 관련이 있습니다. 이미지는 굉장히 다 차원의 데이터입니다. 이를 KNN 분류기를 통해 잘 분류하기 위해서는 굉장히 데이터가 촘촘하게 존재해야합니다. 그렇지 않으면 새로운 이미지가 들어왔을 때 제대로 분류해내지 못할 가능성이 굉장히 높습니다. 즉, 높은 차원에서 좋은 성능을 내기 위해서는 데이터가 무수히 많아야 하는데, 원하는 만큼의 데이터를 수집하기는 거의 불가능합니다. </p>
<h1 id="linear-classification">Linear Classification</h1>
<p>Linear Classification은 NN과 CNN 등의 딥러닝 알고리즘의 기반이 되는 알고리즘으로 가장 단순한 parametic model입니다. </p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133672491-c8cb0bbb-bf71-4b07-891c-e3ecc47d7d0c.png" alt="image">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>parametic model은 데이터가 특정 분포를 따른다고 가정하고, 학습과정에서 모델의 가중치가 구해지는 형태의 모델을 의미합니다. 그림을 보면 알 수 있듯이 Lieanr classifier는 크게 W, x, b로 구성됩니다. 여기서 x는 input을 의미하고 W는 가중치를, b는 bias를 의미합니다. </p>
<p>모델은 가중치와 input을 곱해준 뒤 bias를 더해주는 연산을 통해 총 10개의 숫자를 output으로 산출합니다. 이 10개의 숫자는 10개의 카테고리에 대한 스코어로 이 값이 높으면 해당 카테고리일 가능성이 크다는 것을 의미합니다. </p>
<p>파라미터를 사용하지 않는 KNN과는 다르게 Linear classifier에서는 파라미터인 W를 구하는 것이 가장 중요한 일이 됐습니다. train 과정에서 W를 찾으면서 기존에 KNN의 test time이 오래 걸리는 문제를 해결할 수 있게 됐습니다.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133678846-761b1293-eedc-4f6c-a1dd-02476a853006.png" alt="image">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>강의의 예시를 보겠습니다. 이미지는 2x2 사이즈이며 class는 총 3개입니다. input으로 받은 이미지를 4x1의 벡터로 펼쳐서 가중치 행렬 w와 내적을 해줍니다. 그리고 bias를 더해줌으로서 class에 대한 최종 스코어를 구하는 것입니다. 예시에서는 고양이 이미지를 넣었으나 개라고 분류하고 있는데요. 이는 아직 모델이 제대로 학습하지 못했음을 암시하고 있습니다. </p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133679586-37e108b1-ba97-4234-9dc1-6e3d92c91e35.png" alt="image">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>실제로 CIFAR-10의 데이터를 바탕으로 linear classifier의 W를 학습시킨 결과를 이미지로 나타내면 위의 그림과 같이 나타납니다. 굉장히 흐릿하긴 하나 약간은 각 class의 이미지들이 담겨있는 것을 확인할 수 있습니다. 동시에 정확하지 않다는 점들도 눈에 띕니다. </p>
<p>각 class당 하나의 대표 이미지만 학습 가능하다는 점이 단점이지만 이는 나중에 복잡한 모델로 들어가면서 해결하게 됩니다.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133680805-e44370f4-b5fa-451f-a6d1-a562ac052e64.png" alt="image">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>Linear classifier를 좀 더 확장된 관점으로 봅시다. 이미지를 그대로 받아드리는 것이 아닌 고차원에서의 하나의 점으로서 보는 것입니다. 그렇게 되면 위의 그림과 같이 linear classifier는 각 class를 구분시켜주는 선형 경계를 그어 나가는 역할을 하게 되는 것이죠.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133682164-ffa5fbef-4053-4df7-9223-f78c06bf3a38.png" alt="image">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>하지만 이 역시 만능은 아닙니다. 위의 그림처럼 parity problem이나 multimodal problem 등은 선형 경계만으로는 분류해내기 어렵다는 단점을 가지고 있습니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS231n] Lecture1 : Introduction]]></title>
            <link>https://velog.io/@jeong_jaeyoon/CS231n-Lecture1-Introduction</link>
            <guid>https://velog.io/@jeong_jaeyoon/CS231n-Lecture1-Introduction</guid>
            <pubDate>Mon, 13 Sep 2021 08:11:23 GMT</pubDate>
            <description><![CDATA[<h1 id="computer-vision">Computer Vision</h1>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133038782-7838af94-8317-41bd-ab2b-b3b582f1b418.PNG" alt="사진 1">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>최근 센서의 증가로 시각적 데이터들이 엄청나게 쏟아지고 있습니다. 이러한 시각적 데이터를 컴퓨터가 이해하고 분석할 수 있도록 알고리즘을 개발하는 연구를 컴퓨터 비전이라고 합니다. 컴퓨터 비전은 다양한 분야와 연결되어 있고, 여러 분야에서 활발히 연구가 이루어지고 있습니다. </p>
<h1 id="history-of-vision">History of Vision</h1>
<p>시각은 대부분의 생물에게 가장 중요한 감각기관 중 하나이며, 사람 역시 시각에 들어오는 정보를 처리하기 위해서 약 50% 이상의 뉴런들을 활용합니다. 일찍이 학자들은 시각의 중요성을 깨닫고 다양한 방면으로 연구를 진행했습니다. 그리고 이러한 연구들이 오늘날 Computer Vision 연구에 큰 영향을 미치게 됩니다. </p>
<h2 id="1950년대">1950년대</h2>
<p>Hubel과 Wiesel은 생물의 시각적 매커니즘에 대한 연구로, 시각 정보 처리가 인간과 유사한 고양이의 뇌에 전극을 꽂고 실험을 했습니다. 실험 결과, 고양이의 시각 피질은 테두리가 움직일 때 크게 흥분하는 것을 알 수 있었습니다. 최종적으로 이들은 &#39;시각은 테두리와 같은 단순한 구조부터 시작해서 점점 복잡한 요소들을 처리하며, 마지막엔 input을 실제로 인식할 수 있다.&#39;라고 결론을 내렸습니다.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133051582-5b0598cf-c7c6-4579-bbda-c5309ab84264.PNG" alt="사진 2">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<h2 id="1960년대">1960년대</h2>
<p>이 시기에 들어서면서 본격적으로 시각으로 보이는 입체적인 물체들을 단조롭게 표현하고 재구성하는 연구를 시작합니다.  </p>
<p>또한 MIT에서는 시각체계를 구성해서 컴퓨터가 이미지를 인식하게끔 만드는 Summer Vision Project를 진행하기도 했습니다.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133193315-65bbd00e-7e3b-449d-bfb2-18cf89f004f1.PNG" alt="사진 3">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<h2 id="1970년대">1970년대</h2>
<p>MIT의 과학자 David Marr는 &#39;VISION&#39;이라는 책을 저술하면서 컴퓨터 비전 연구를 어떻게 진행해야하는지 방향성을 제시했습니다.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133195843-eed81eae-6b56-4036-bb66-d20c512a2e28.PNG" alt="사진 4">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>그는 이미지가 3D 표현에 도달하기 까지는 여러 단계를 거쳐야 한다고 말합니다. 우선 이미지가 들어오게 되면 모서리, 가장자리, 꼭지점 등을 파악하는 Primal Sketch를 지나게 됩니다. 이 후, 표면 정보, 레이어, 깊이 정보 등을 파악하는 &#39;2 1/2_D Sketch&#39;에서 여러 정보들을 종합한 뒤에 최종적으로 3D 모델을 만들 수 있습니다. 이 방식은 굉장히 이상적인 사고 방식으로 지난 수 십년간 컴퓨터 비전 연구의 근간이 됐습니다. </p>
<h2 id="1980년대">1980년대</h2>
<p>학자들은 객체 인식 문제를 해결하기 위해서, 시각적 세계를 단순하게 재구성하거나 인식하는 방법 등 여러 시도를 했으나 현실적으로 많은 발전은 없었습니다. 이 때부터 학자들은 객체 인식을 하기 전에 객체 분할을 하는 것이 도움이 될 것이라고 생각하고 객체 분할에 대해서 연구를 시작했습니다. </p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133200088-d6ef08e8-f7c4-4cf0-8eeb-04c39c1a9f24.PNG" alt="사진 5">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<h2 id="1990년대---2000년대">1990년대 - 2000년대</h2>
<p>이 시기에는 머신러닝 기법들이 큰 성장을 이뤘습니다. SVM, Boosting, 초기 Neural Network 기법이 크게 발전했습니다. 그 중 Vision에서 가장 큰 기여을 한 연구는 AdaBoost를 사용한 실시간 얼굴인식이었습니다.   </p>
<p>이 시기 가장 영향력 있는 연구는 Feature를 기반으로 한 객체 인식 알고리즘이었습니다. 대표적인 연구가 David Lowe의 SIFT였습니다. 일반적으로 이미지는 카메라의 각도, 조명, 시점 등의 영향으로 객체의 변형이 일어날 수 있습니다. 하지만 이러한 변화에도 변하지 않는 Feature들이 있습니다. 이 Feature들을 찾아 객체들을 매칭하는 방법이 SIFT입니다. </p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133205786-3619014b-503c-40c4-ae47-a0c0798bba75.PNG" alt="사진 6">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<h2 id="2000년대">2000년대</h2>
<p>인터넷과 디지털 카페라 기술의 성장으로 Computer Vision을 연구하기 좋은 환경이 만들어지고 있었다. 또한 Feature의 중요성을 발견하면서 이전에 미뤄뒀던 객체 인식문제를 다시 언급했다. 객체 인식에 대한 문제를 해결해보고자 사람들은 좋은 데이터셋을 모으기 시작했다. 그런 의도로 만들어진 데이터셋이 바로 PASCAL Visual Object Challenge와 ImageNet이다.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133208885-dda1282b-a7fb-4829-b3ac-a33352daeffa.PNG" alt="사진 7">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>ImageNet은 기존의 머신러닝에서의 Overfitting 문제( 데이터 부족 및 시각 데이터의 복잡함 )에 대한 해결과 일반화 능력을 높이기 위해 만들어진 가장 큰 이미지 데이터셋입니다. 총 22K의 카테고리와 14M 개의 이미지이며 이 데이터 셋을 가지고 ILSVRC(ImageNet Large Scale Visual Recognition Challenge)를 개최합니다.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133211232-adaa21a1-571d-4f78-8ebd-b277809b1c25.PNG" alt="사진 8">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>대회 결과 에러율은 점점 줄어드는 것을 확인할 수 있습니다. 여기서 주목해야할 시점은 2012년도로 처음으로 CNN이 나온 해입니다. 그 당시 에러율은 전년도보다 10%나 줄어든 것을 볼 수 있습니다. 하지만 CNN은 갑자기 나온 알고리즘이 아닙니다. 이미 1998년도부터 제안된 알고리즘이었지만, 양질의 데이터 부족과 컴퓨터 연산 능력의 부족이라는 한계가 존재했던 것입니다.</p>
<blockquote>
<p><img src="https://user-images.githubusercontent.com/68625698/133212604-0ce74287-6abe-4fa2-8aa6-b0a34132ab62.PNG" alt="사진 9">
<em>[출처 : CS231n 강의자료]</em></p>
</blockquote>
<p>하지만 최근 GPU의 개발과 양질의 데이터셋이 만들어지면서 CNN은 Computer Vision의 여러 분야에서 그 성능을 인정 받게 됩니다.</p>
]]></description>
        </item>
    </channel>
</rss>