<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="3.9.2">Jekyll</generator><link href="https://tinnunculus.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://tinnunculus.github.io/" rel="alternate" type="text/html" hreflang="en" /><updated>2022-08-18T10:44:28+00:00</updated><id>https://tinnunculus.github.io/feed.xml</id><title type="html">SaRang</title><subtitle>사랑이 집사
</subtitle><author><name>&lt;Lee&gt; &lt;Jongyeon&gt;</name><email>&lt;lee0301jy@naver.com&gt;</email></author><entry><title type="html">Topology- Set Theory, Functions</title><link href="https://tinnunculus.github.io/math/2022-07-31-topology_2/" rel="alternate" type="text/html" title="Topology- Set Theory, Functions" /><published>2022-07-31T00:00:00+00:00</published><updated>2022-07-31T00:00:00+00:00</updated><id>https://tinnunculus.github.io/math/topology_2</id><content type="html" xml:base="https://tinnunculus.github.io/math/2022-07-31-topology_2/">&lt;p&gt;&lt;strong&gt;참고&lt;/strong&gt;&lt;br /&gt;
[1] Topology 2e, James Munkres&lt;/p&gt;
&lt;hr /&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot; id=&quot;markdown-toc-introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#rule-of-assignment&quot; id=&quot;markdown-toc-rule-of-assignment&quot;&gt;Rule of assignment&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#define-function&quot; id=&quot;markdown-toc-define-function&quot;&gt;Define function&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#restriction&quot; id=&quot;markdown-toc-restriction&quot;&gt;restriction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#injective-surjective-bijective&quot; id=&quot;markdown-toc-injective-surjective-bijective&quot;&gt;injective, surjective, bijective&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#lemma-by-inverse-function&quot; id=&quot;markdown-toc-lemma-by-inverse-function&quot;&gt;Lemma by inverse function&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#image-preimage-of-set-under-f&quot; id=&quot;markdown-toc-image-preimage-of-set-under-f&quot;&gt;image, preimage of set under \(f\)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Function에 대한 정의를 Set의 개념에 통해서 접근해본다.&lt;/li&gt;
  &lt;li&gt;Function의 여러 구성요소와 operation에 대해서 알아본다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;rule-of-assignment&quot;&gt;Rule of assignment&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;두 집합(\(C, D\))의 &lt;strong&gt;Cartesian product&lt;/strong&gt;의 &lt;strong&gt;subset&lt;/strong&gt;이다.&lt;/li&gt;
  &lt;li&gt;ordered pair에 있는 집합 \(C\) 에 있는 elemenet는 &lt;strong&gt;단 한개&lt;/strong&gt;만 존재해야만 하는 &lt;strong&gt;Property&lt;/strong&gt;가 있다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;many to one&lt;/strong&gt;이라고 생각하면 쉽다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
\text{a subset r of C } \times \text{ D is a rule of assignment if} \\[1em]
[(c, d) \in r \text{ and } (c, e) \in r ] \Rightarrow [d = e] 
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;rule of assignment r 이 주어져있을때, &lt;strong&gt;domain of r&lt;/strong&gt; 은 rule의 ordered pair에 존재하는 집합 &lt;strong&gt;\(C\) 의 subset&lt;/strong&gt;이다. 반대로 &lt;strong&gt;\(D\) 의 subset&lt;/strong&gt;은 &lt;strong&gt;image set&lt;/strong&gt; of r 이라고 부른다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
\text{domain r } = \{ c | \text{ there exists } d \in D \text{ such that } (c, d) \in r \} \\[1em]
\text{image r } = \{ d | \text{ there exists } c \in C \text{ such that } (c, d) \in r \} \\[1em]
\end{aligned}\]

&lt;h2 id=&quot;define-function&quot;&gt;Define function&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;function \(f\)&lt;/strong&gt; 는 rule of assignment r 을 의미한다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;domain of the function&lt;/strong&gt; \(f\) 는 domain A of the rule 을 의미한다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;image of the function&lt;/strong&gt; \(f\) 는 image set of the rule 을 의미한다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;range of the function&lt;/strong&gt; \(f\) 는 전체 set B를 의미한다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;function \(f\)&lt;/strong&gt; 가 domain A와 range B를 가지고 있을때, 다음과 같디 표현한다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
\text{&quot;} f \text{ is function from A to B&quot;} \\[1em]
f : A \rightarrow B
\end{aligned}\]

&lt;h2 id=&quot;restriction&quot;&gt;restriction&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;function \(f : A \rightarrow B\) 가 있고 \(A_0\)가 \(A\)의 subset일때, &lt;strong&gt;restriction of \(f\) to \(A_0\)&lt;/strong&gt; 는 다음을 의미한다.&lt;/li&gt;
&lt;/ul&gt;

\[\{(a, f(a)) | a \in A_0\}\]

&lt;h2 id=&quot;injective-surjective-bijective&quot;&gt;injective, surjective, bijective&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;function \(f : A \rightarrow B\) 가 있고, A의 element가 assign하는 &lt;strong&gt;B의 element가 하나만 존재할 때&lt;/strong&gt;, 함수 \(f\)를 &lt;strong&gt;injective function&lt;/strong&gt;이라고 부른다.&lt;/li&gt;
&lt;/ul&gt;

\[[f(a) = f(b)] \Rightarrow [a = b]\]

&lt;ul&gt;
  &lt;li&gt;image of \(f\)와 &lt;strong&gt;range of \(f\)가 **동일&lt;/strong&gt;할 때, 함수 \(f\)를 &lt;strong&gt;surjective function&lt;/strong&gt;이라고 부른다.&lt;/li&gt;
&lt;/ul&gt;

\[[b \in B] \Rightarrow [b = f(a) \text{ for at least one } a \in A]\]

&lt;ul&gt;
  &lt;li&gt;injective 조건과 surjective 조건을 모두 만족시키는 함수를 &lt;strong&gt;bijective function&lt;/strong&gt;이라고 부른다.&lt;/li&gt;
  &lt;li&gt;만일 function \(f\)가 &lt;strong&gt;bijective이라면&lt;/strong&gt; \(f : B \rightarrow A\) 인 함수가 존재하며, 이를 &lt;strong&gt;inverse of \(f\)&lt;/strong&gt; 라고 부르고 \(f^{-1}\) 로 표시한다.&lt;/li&gt;
  &lt;li&gt;\(f^{-1}(b) \Rightarrow f(a) = b\) 를 의미한다. \(f\) 의 &lt;strong&gt;surjective 조건&lt;/strong&gt;은 \(f^{-1}(b)\) 가 &lt;strong&gt;존재&lt;/strong&gt;하게 보장해주며, &lt;strong&gt;injective&lt;/strong&gt;는  \(f^{-1}(b)\) 가 &lt;strong&gt;하나의 값&lt;/strong&gt;을 나타내게 보장해준다.&lt;/li&gt;
  &lt;li&gt;inverse of \(f\) 또한 bijective function 이다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;lemma-by-inverse-function&quot;&gt;Lemma by inverse function&lt;/h2&gt;

\[\begin{aligned}
&amp;amp;f : A \rightarrow B, g : B \rightarrow A, h : B \rightarrow A \\[1em]
&amp;amp;\text{if } g(f(a)) = a \text{ for every } a \text{ in } A \text{ and } f(h(b)) = b \text{ for every } b \text{ in } B, \\[1em]
&amp;amp;\text{then } f \text{ is bijective function and } g = h = f^{-1} 
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;\(g(f(a)) = a\) 는 함수 \(f\)가 injective function인 것을 보장해주고, \(f(h(b)) = b\) 는 surjective function인 것을 보장해준다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;image-preimage-of-set-under-f&quot;&gt;image, preimage of set under \(f\)&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;함수 \(f : A \rightarrow B\), \(A_0\) 는 \(A\)의 subset이라고 할때, \(f(A_0)\) 를 다음과 같이 정의하고 &lt;strong&gt;image of \(A_0\) under \(f\)&lt;/strong&gt; 라고 부른다.&lt;/li&gt;
&lt;/ul&gt;

\[f(A_0) = \{ b | b = f(a) \text{ for at least one } a \in A_0 \}\]

&lt;ul&gt;
  &lt;li&gt;\(B_0\) 를 \(B\) 의 subset이라고 할때, \(f^{-1}(B_0)\) 를 다음과 같이 정의하고 &lt;strong&gt;preimage of \(B_0\) under \(f\)&lt;/strong&gt; 라고 부른다.&lt;/li&gt;
&lt;/ul&gt;

\[f^{-1}(B_0) = \{ a | f(a) \in B_0 \}\]

&lt;ul&gt;
  &lt;li&gt;반드시 \(f^{-1}\) 가 inverse of \(f\)를 의미하는 것은 아니다. \(f\) 가 &lt;strong&gt;bijective가 아닐때도 preimage를 정의할 수 있으며&lt;/strong&gt;, &lt;strong&gt;preimage는 공집합일 수도 있다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;\(f^{-1}\) 은 inclusions, unions, intersections, differences of sets 에 대해서 preserves 하지만, \(f\) 는 오로지 inclusions와 unions에 대해서만 preserve 하다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
B_0 \subset B_1 &amp;amp;\Rightarrow f^{-1}(B_0) \subset f^{-1}(B_1) \\[1em]
f^{-1}(B_0 \cup B_1) &amp;amp;= f^{-1}(B_0) \cup f^{-1}(B_1) \\[1em]
f^{-1}(B_0 \cap B_1) &amp;amp;= f^{-1}(B_0) \cap f^{-1}(B_1) \\[1em]
f^{-1}(B_0 - B_1) &amp;amp;= f^{-1}(B_0) - f^{-1}(B_1) \\[1em]
B_0 \subset B_1 &amp;amp;\Rightarrow f(B_0) \subset f(B_1) \\[1em]
f(B_0 \cup B_1) &amp;amp;= f(B_0) \cup f(B_1) \\[1em]
f(B_0 \cap B_1) &amp;amp;\subset f(B_0) \cap f(B_1) \quad \text{ equality holds when f is injective.} \\[1em]
f(B_0 - B_1) &amp;amp;\supset f(B_0) - f(B_1) \quad \text{ equality holds when f is injective.}\\[1em]
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;if \(f : A \rightarrow B\) and \(A_0 \subset A \text{ and } B_0 \subset B\) 이라고 할때, 다음을 만족한다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
&amp;amp;A_0 \subset f^{-1}(f(A_0)) \quad \text{ equality holds when f is injective } \\[1em]
&amp;amp;f(f^{-1}(B_0)) \subset B_0 \quad \text{ equality holds when f is surjective } \\[1em]
\end{aligned}\]</content><author><name>&lt;Lee&gt; &lt;Jongyeon&gt;</name><email>&lt;lee0301jy@naver.com&gt;</email></author><category term="math" /><summary type="html">참고 [1] Topology 2e, James Munkres</summary></entry><entry><title type="html">Topology- Set Theory, Fundamental Concepts</title><link href="https://tinnunculus.github.io/math/2022-07-27-topology_1/" rel="alternate" type="text/html" title="Topology- Set Theory, Fundamental Concepts" /><published>2022-07-27T00:00:00+00:00</published><updated>2022-07-27T00:00:00+00:00</updated><id>https://tinnunculus.github.io/math/topology_1</id><content type="html" xml:base="https://tinnunculus.github.io/math/2022-07-27-topology_1/">&lt;p&gt;&lt;strong&gt;참고&lt;/strong&gt;&lt;br /&gt;
[1] Topology 2e, James Munkres&lt;/p&gt;
&lt;hr /&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot; id=&quot;markdown-toc-introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#property&quot; id=&quot;markdown-toc-property&quot;&gt;property&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#union-intersection-and-empty-set&quot; id=&quot;markdown-toc-union-intersection-and-empty-set&quot;&gt;Union, Intersection and Empty Set&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#vacuous-truth&quot; id=&quot;markdown-toc-vacuous-truth&quot;&gt;Vacuous Truth&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#negation&quot; id=&quot;markdown-toc-negation&quot;&gt;Negation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#distributive-law&quot; id=&quot;markdown-toc-distributive-law&quot;&gt;Distributive law&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#collections-of-sets&quot; id=&quot;markdown-toc-collections-of-sets&quot;&gt;Collections of Sets&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#arbitrary-unions-and-intersections&quot; id=&quot;markdown-toc-arbitrary-unions-and-intersections&quot;&gt;Arbitrary Unions and Intersections&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cartesian-product&quot; id=&quot;markdown-toc-cartesian-product&quot;&gt;Cartesian Product&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Set Theory에서 Set에 대한 기본 개념과 간단한 operation에 대해서 알아본다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;property&quot;&gt;property&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;property &lt;strong&gt;\(P(x)\)는 참과 거짓을 다루는 함수이다.&lt;/strong&gt; 파라미터를 가질 수 있다.&lt;/li&gt;
  &lt;li&gt;Set을 이루는 element들을 &lt;strong&gt;제한&lt;/strong&gt;하는데 사용한다.&lt;/li&gt;
&lt;/ul&gt;

\[B = \{x|x\text{ is integer greater than 5}\}\]

&lt;ul&gt;
  &lt;li&gt;위의 Equation은 말로 풀어 쓰면 “B is &lt;strong&gt;the set&lt;/strong&gt; of &lt;strong&gt;all \(x\)&lt;/strong&gt; &lt;strong&gt;such that&lt;/strong&gt; \(x\) is integer greater than 5”을 의미한다.&lt;/li&gt;
  &lt;li&gt;\(\{\}\)은 &lt;strong&gt;Set의 정의&lt;/strong&gt;, \(x\)|은 &lt;strong&gt;모든 x를 의미&lt;/strong&gt;, \(x \text{ is integer greater than 5}\)는 &lt;strong&gt;property&lt;/strong&gt;를 의미한다.&lt;/li&gt;
  &lt;li&gt;위의 Equation에서 Property \(P(x, 5) = x &amp;gt; 5 \text{ and x is integer}\) 을 의미한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;union-intersection-and-empty-set&quot;&gt;Union, Intersection and Empty Set&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;union&lt;/strong&gt; of \(A\) and \(B\) :&lt;/li&gt;
&lt;/ul&gt;

\[A \cup B = \{x|x\in A \text{ or } x\in B \}\]

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;intersection&lt;/strong&gt; of \(A\) and \(B\) :&lt;/li&gt;
&lt;/ul&gt;

\[A \cap B = \{x|x\in A \text{ and } x\in B \}\]

&lt;ul&gt;
  &lt;li&gt;만약에 \(x\in A \text{ and } x\in B\) 을 만족하는 x가 하나도 존재하지 않을 시에는 \(A \cap B = \varnothing\) 이라고 한다. 그리고 이런 경우 \(A\) 와 \(B\)는 &lt;strong&gt;disjoint&lt;/strong&gt;하다고 한다.&lt;/li&gt;
  &lt;li&gt;empty set은 element를 하나도 가지지 않는 set을 의미한다.&lt;/li&gt;
  &lt;li&gt;empty set의 개념은 어려울 수 있다. element를 가지지 않는게 Set이라고 부를 수 있는가. 이것은 수체계에서 0을 수로 인정하는 것과 같다. 0을 처음 수로 인정하는게 어려웠나보다. Convention 하게 empty set을 도입할 경우, 여러 이론과 증명이 정확히 떨어지는 경우가 많기에 직관상 이상하지만 수학적으로 사용하는 개념이라 볼 수 있다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
A \cup \varnothing = A \quad \text{ and } \quad A \cap \varnothing = \varnothing \quad \quad \text{for every set A}
\end{aligned}\]

&lt;h2 id=&quot;vacuous-truth&quot;&gt;Vacuous Truth&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;\(\varnothing \subset A\) 이것은 참일까, 거짓일까&lt;/li&gt;
  &lt;li&gt;그전에 “if P, then Q”의 Statement를 보자. 만약에 P를 만족시키는 &lt;strong&gt;event가 하나도 존재하지 않다면 어떻게 될까.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Set Theory에서는 &lt;strong&gt;가정이 잘못되면 그 Statement는 참으로 본다.&lt;/strong&gt; 이것을 &lt;strong&gt;Vacuous Truth&lt;/strong&gt;라고 부른다.&lt;/li&gt;
  &lt;li&gt;아래의 Statement는 참이다. if 문을 만족시키는 x가 없기 때문이다.&lt;/li&gt;
&lt;/ul&gt;

\[\text{if } x^2 &amp;lt; 0, \text{then } x = 23\]

&lt;ul&gt;
  &lt;li&gt;다시 \(\varnothing \subset A\)를 보자. 이것을 문자로 풀어보면 \(\text{if } x \in \varnothing \text{, then } x \in A\) 이다. if 문을 만족시키는 x가 없기 때문에 vacuous truth에 의해 이 명제는 참이다. 심지어 \(\varnothing \subset \varnothing\) 또한 참이다. 하지만 \(\varnothing \in \varnothing\)은 참이 아니다.&lt;/li&gt;
  &lt;li&gt;vacuous truth는 직관적인 이해보다는 수학적 논리에의해 정의된 convention에 가깝다. 예를들면 vacuous truth는 &lt;strong&gt;contrapositive&lt;/strong&gt;가 성립한다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
\text{if } x^2 &amp;lt; 0&amp;amp;, \text{then } x = 23 \\[1em]
\text{if } x \neq 23 &amp;amp;, x^2 &amp;gt;= 0
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;다음은 vacuous truth의 조건들이다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{cases}
\forall x: P(x) \Rightarrow Q(x), \text{where it is the case that} \forall x: \neg P(x) \\[1em]
\forall x \in A : Q(x), \text{where the set A is empty}
\end{cases}\]

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;좀 더 직관적인 이해를 해보자.&lt;/strong&gt; \(\text{if P,then Q}\) 를 Set의 개념으로 생각해보면, P를 만족시키는 event의 set을 \(P\)라고 하고, Q를 만족시키는 event의 set을 \(Q\)라고 하자. 앞의 statement를 set operation으로 바꾸면 \(P \subseteq Q\) 으로 표현될 수 있다. 만약에 \(P\)가 empty set이라면 Q에 포함된다는 의미니까 앞의 statement는 참이 된다. contrapositive를 보면 \(\neg P\) 는 모든 element를 담은 set이기 때문에 모든 set Q에 대해서도 명제는 참이된다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;negation&quot;&gt;Negation&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;negation of statement&lt;/strong&gt; \(P\)는 &lt;strong&gt;not&lt;/strong&gt; \(P\)를 의미한다.&lt;/li&gt;
  &lt;li&gt;대부분의 경우에서 not \(P\)를 구하는 것은 쉬울 것이다. 하지만 “&lt;strong&gt;for every&lt;/strong&gt;”, “&lt;strong&gt;for at least one&lt;/strong&gt;” 같은 &lt;strong&gt;logical quantifiers&lt;/strong&gt;에서는 혼동이 올 수 있다.&lt;/li&gt;
&lt;/ul&gt;

\[\text{For every } x \in A, \text{statement P holds}\]

&lt;ul&gt;
  &lt;li&gt;위의 statement의 negation은 다음과 같다. “&lt;strong&gt;for every&lt;/strong&gt;“의 negation은 “&lt;strong&gt;for at least one&lt;/strong&gt;“인 것에 주의하자.&lt;/li&gt;
&lt;/ul&gt;

\[\text{For at least one } x \in A, \text{statement P does not hold}\]

&lt;ul&gt;
  &lt;li&gt;반대로 “&lt;strong&gt;for at least one&lt;/strong&gt;“의 negation은 “&lt;strong&gt;for every&lt;/strong&gt;” 이다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;distributive-law&quot;&gt;Distributive law&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Set의 \(\cup, \cap\) 은 distribute law를 만족한다.&lt;/li&gt;
  &lt;li&gt;\(\cup, \cap\) 모두 만족시킬 수 있다는 것에 주의하자.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
A \cup (B \cap C) = (A \cup B) \cap (A \cup C) \\[1em]
A \cap (B \cup C) = (A \cap B) \cup (A \cap C)
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;다음의 equation을 DeMorgan’s laws 라고 부른다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
A - (B \cup C) = (A - B)\cap(A - C) \\[1em]
A - (B \cap C) = (A - B)\cup(A - C)
\end{aligned}\]

&lt;h2 id=&quot;collections-of-sets&quot;&gt;Collections of Sets&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Set은 Set을 element로 가질 수 있다.&lt;/li&gt;
  &lt;li&gt;Set의 &lt;strong&gt;모든 element가 Set으로&lt;/strong&gt; 이루어졌으면 그 Set을 &lt;strong&gt;Collection&lt;/strong&gt; of Set 이라 부른다.&lt;/li&gt;
  &lt;li&gt;대표적으로 &lt;strong&gt;the power set of \(A\)&lt;/strong&gt;이 있다.&lt;/li&gt;
  &lt;li&gt;power set of \(A\)는 \(A\)의 모든 Subset을 element로 가지고 있는 Set을 의미한다. \(\mathcal{P}(A)\)로 표시한다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
A &amp;amp;= \{a, b, c\} \\[1em]
a &amp;amp;\in A, \\[1em]
\{a\} &amp;amp;\subset A, \\[1em]
\{a\} &amp;amp;\in \mathcal{P}(A)
\end{aligned}\]

&lt;h2 id=&quot;arbitrary-unions-and-intersections&quot;&gt;Arbitrary Unions and Intersections&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;union과 intersection을 꼭 두개의 Set에 대해서만 할 필요는 없다. &lt;strong&gt;여러개&lt;/strong&gt;를 같이 할 수도 있다.&lt;/li&gt;
  &lt;li&gt;Collection \(\mathcal{A}\) 이 있을때, the union of the elements of \(\mathcal{A}\) 은 다음과 같이 정의한다.&lt;/li&gt;
&lt;/ul&gt;

\[\bigcup_{A \in \mathcal{A}} A = \{x|x \in A \text{ for at least one } A \in \mathcal{A}\}\]

&lt;ul&gt;
  &lt;li&gt;그리고 the intersection of the elements of \(\mathcal{A}\) 은 다음과 같이 정의한다.&lt;/li&gt;
&lt;/ul&gt;

\[\bigcap_{A \in \mathcal{A}} A = \{x|x \in A \text{ for every } A \in \mathcal{A}\}\]

&lt;ul&gt;
  &lt;li&gt;만약에 \(\mathcal{A}\) 가 &lt;strong&gt;empty set이라면 어떻게 될까.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Union의 경우 생각해보자. Property 부분만 따로 떼어내보면, x가 존재하기 위해서는 &lt;strong&gt;적어도 하나 이상의 \(A\)가 있어야 한다.&lt;/strong&gt; 하지만 \(A\)는 empty이기 때문에 적어도 하나의 \(A\)는 존재하지 않기에 Property를 만족시키는 \(x\)는 없다.&lt;/li&gt;
  &lt;li&gt;Intersection의 경우를 생각해보자. 위의 Property를 문장으로 표현하면 \(\forall A \in \mathcal{A}, x \in A\) 이다. vacuous truth 두번째 조건을 보면 Intersection의 Property와 동일한 구조이다. 그렇기에 어떠한 \(x\) 인지 상관없이 위의 statement는 참이 된다.&lt;/li&gt;
  &lt;li&gt;하지만 많은 수학자가 위의 논리를 인정하지 않기에 Intersection of collection은 collection이 empty set일 때 정의하지 않는다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;cartesian-product&quot;&gt;Cartesian Product&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Cartesian product Set \(A \times B\) 는 다음과 같이 정의된다.&lt;/li&gt;
&lt;/ul&gt;

\[A \times B = \{(a, b)\text{ }|\text{ } a \in A \text{ and } b \in B\}\]

&lt;ul&gt;
  &lt;li&gt;\((a, b)\) 는 &lt;strong&gt;ordered pair&lt;/strong&gt;라고 부른다.&lt;/li&gt;
  &lt;li&gt;대부분의 ordered pair는 단순히 \(a\) 와 \(b\) 를 element로 가지는 Set으로 여겨지지만, &lt;strong&gt;ordered pair의 정의에 따라 다를 수 있다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Cartesian product로 생성된 Set들 간에 Cartesian product를 수행할 수도 있다.&lt;/li&gt;
&lt;/ul&gt;

\[(A \times B) \times (C \times D) = \{(a, b, c, d)\text{ }|\text{ } a \in A, b \in B, c \in C, d \in D \}\]</content><author><name>&lt;Lee&gt; &lt;Jongyeon&gt;</name><email>&lt;lee0301jy@naver.com&gt;</email></author><category term="math" /><summary type="html">참고 [1] Topology 2e, James Munkres</summary></entry><entry><title type="html">Normalized Cut</title><link href="https://tinnunculus.github.io/paper/2022-07-08-ncut/" rel="alternate" type="text/html" title="Normalized Cut" /><published>2022-07-08T00:00:00+00:00</published><updated>2022-07-08T00:00:00+00:00</updated><id>https://tinnunculus.github.io/paper/ncut</id><content type="html" xml:base="https://tinnunculus.github.io/paper/2022-07-08-ncut/">&lt;p&gt;&lt;strong&gt;참고&lt;/strong&gt;&lt;br /&gt;
[1] &lt;a href=&quot;https://people.eecs.berkeley.edu/~malik/papers/SM-ncut.pdf&quot;&gt;https://people.eecs.berkeley.edu/~malik/papers/SM-ncut.pdf&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;코드&lt;/strong&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/tinnunculus/Ncut/blob/master/Ncut.ipynb&quot;&gt;https://github.com/tinnunculus/Ncut/blob/master/Ncut.ipynb&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot; id=&quot;markdown-toc-introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#conventional-cutting-algorithm&quot; id=&quot;markdown-toc-conventional-cutting-algorithm&quot;&gt;Conventional Cutting algorithm&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#normalized-cut&quot; id=&quot;markdown-toc-normalized-cut&quot;&gt;Normalized Cut&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#computing-the-optimal-partition&quot; id=&quot;markdown-toc-computing-the-optimal-partition&quot;&gt;Computing the Optimal Partition&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#grouping-algorithm&quot; id=&quot;markdown-toc-grouping-algorithm&quot;&gt;Grouping Algorithm&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#example-brightness-images&quot; id=&quot;markdown-toc-example-brightness-images&quot;&gt;Example: Brightness Images&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#review&quot; id=&quot;markdown-toc-review&quot;&gt;Review&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;이 논문은 2000년도에 출간된 논문으로 Spectral Graph Theory를 기반으로 새로운 Graph Partitioning 기법을 제시한다.&lt;/li&gt;
  &lt;li&gt;기존에 있던 Graph Cutting 알고리즘에 문제를 해결하는 새로운 Graph Cutting 기법인 Normalized Cut 알고리즘을 만들었다.&lt;/li&gt;
  &lt;li&gt;새로운 Normalized Cut 알고리즘의 NP 문제를 generalized eigenvalue problem으로 접근해 효율적으로 해결하였다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conventional-cutting-algorithm&quot;&gt;Conventional Cutting algorithm&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;그래프 \(G = (\mathbf{V}, \mathbf{E})\) 를 두개의 disjoint sets \(\mathbf{A}, \mathbf{B}, \mathbf{A} \cup \mathbf{B} = \mathbf{V}, \mathbf{A} \cap \mathbf{B} = \emptyset\) 으로 나누는 문제를 Graph Cut이라고 한다.&lt;/li&gt;
  &lt;li&gt;그래프는 노드의 집합 \(\mathbf{V}\) 와 두 노드간의 similarity를 나타내는 집합 \(\mathbf{E}\) 로 구성되어있다.&lt;/li&gt;
  &lt;li&gt;두개의 sets \(\mathbf{A}, \mathbf{B}\) 의 association의 척도를 나타내는 함수를 \(asso(\mathbf{A}, \mathbf{B})\) 라고 한다.&lt;/li&gt;
&lt;/ul&gt;

\[assoc(\mathbf{A}, \mathbf{B}) = \displaystyle\sum_{u \in \mathbf{A}, v \in \mathbf{B}} w(u, v)\]

&lt;ul&gt;
  &lt;li&gt;Optimal Graph Partitioning은 \(assoc(\mathbf{A}, \mathbf{B})\) 의 값을 최소화 시키는 \(\mathbf{A}, \mathbf{B}\) 을 찾는 것이다. 즉 가장 dissociation한 두개의 disjoint set \(\mathbf{A}, \mathbf{B}\) 을 구하는 문제이다.&lt;/li&gt;
  &lt;li&gt;전체 set \(\mathbf{V}\) 을 두개의 sets \(\mathbf{A}, \mathbf{B}\)으로 나누어 지는 경우의 수는 exponential의 빅오를 가지기 때문에 매우 많은 계산량이 필요하지만, \(minimum asso\) 문제는 당시에도 well-studied problem 이었기 때문에 이 문제를 풀기 위한 효율적인 알고리즘이 존재했다.&lt;/li&gt;
  &lt;li&gt;하지만 위의 식을 최소화 시키는 방향으로 Group을 Cutting하다 보면 Graph에서 혼자 고립된(similarity가 작은) 노드를 cutting하는 것을 선호한다. 즉, association 함수가 Normalized가 되지 않은 Summation으로 이뤄지기 때문에 Summation의 항의 수가 작은 방향으로 Cutting될 확률이 높기에 small set of node로 cutting되는 경향이 있다. 아래의 그림에서 노드 간의 거리가 가까우면 weight가 높은 그래프가 있다고 했을 때, 중앙의 선으로 partition하는게 이상적으로 보이지만, 실제로는 n1과 n2노드가 분리되는 방향으로 cutting이 진행된다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;550&quot; src=&quot;/assets/img/paper/ncut/1.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;위의 문제는 단순히 Summation으로 assocation을 측정했기 때문이다. 그러면 Summation이 아닌 edge의 수로 나눠주는 normalized를 처리하면 문제가 해결될까..? 그렇지 않다. edge의 수로 normalized를 해도 똑같이 고립된(simmilarity가 작은) 노드를 컷팅하는 경향이 생길 것이다. 평균의 weight가 가장 작은 edge를 고르는 것이기 때문이다. 아래의 그림에서도 마찬가지로 중앙의 선이 아닌 가장 멀리 떨어진 하나의 노드를 나누는 식으로 cutting이 될 것이다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;550&quot; src=&quot;/assets/img/paper/ncut/2.jpeg&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;normalized-cut&quot;&gt;Normalized Cut&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;본 논문에서는 새로운 Normalized Association 함수를 제시한다.&lt;/li&gt;
  &lt;li&gt;단순의 두개의 sets \(\mathbf{A}, \mathbf{B}\) 에 존재하는 similarity의 Summation이 아닌 연결된 전체 노드간의 비율로 계산을 한다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
Nassoc(\mathbf{A}, \mathbf{B}) = \frac{assoc(\mathbf{A}, \mathbf{B})}{assoc(\mathbf{A}, \mathbf{V})} + \frac{assoc(\mathbf{A}, \mathbf{B})}{assoc(\mathbf{B}, \mathbf{V})}
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;새로운 Assocation 함수를 이용하면 기존 알고리즘에서 문제가 되었던 고립된 노드를 걷어내는 식으로 Cutting이 되는 경향을 해결할 수 있다.&lt;/li&gt;
  &lt;li&gt;한쪽 set의 노드 수가 다른 set보다 극히 작응면 \(Nassoc\) 함수의 한쪽 항은 0, 다른 항은 1에 가까워지기 때문이다.&lt;/li&gt;
  &lt;li&gt;또한&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
Nassoc(\mathbf{A}, \mathbf{B}) &amp;amp;= \frac{assoc(\mathbf{A}, \mathbf{B})}{assoc(\mathbf{A}, \mathbf{V})} + \frac{assoc(\mathbf{A}, \mathbf{B})}{assoc(\mathbf{B}, \mathbf{V})} \\[1em]
&amp;amp;= \frac{assoc(\mathbf{A}, \mathbf{V}) - assoc(\mathbf{A}, \mathbf{A})}{assoc(\mathbf{A}, \mathbf{V})} + \frac{assoc(\mathbf{B}, \mathbf{V}) - assoc(\mathbf{B}, \mathbf{B})}{assoc(\mathbf{B}, \mathbf{V})} \\[1em]
&amp;amp;= 2 - (\frac{assoc(\mathbf{A}, \mathbf{A})}{assoc(\mathbf{A}, \mathbf{V})} + \frac{assoc(\mathbf{B}, \mathbf{B})}{assoc(\mathbf{B}, \mathbf{V})})
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;Nassoc의 식을 최소화하는 것은 위의 식의 마지막 항에 \((\frac{assoc(\mathbf{A}, \mathbf{A})}{assoc(\mathbf{A}, \mathbf{V})} + \frac{assoc(\mathbf{B}, \mathbf{B})}{assoc(\mathbf{B}, \mathbf{V})})\) 항을 최대화하는 것과 같다. 즉, 기존의 cutting 되는 edge만 고려했던 association 함수와 달리 Normalized association 함수는 자기 자신 그룹의 association이 증가되는 방향으로 cutting되기 때문에 기존 알고리즘의 문제였던 small set으로 분리되는 경향은 사라진다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
\text{number of total nodes} &amp;amp;= N \\[1em]
|\mathbf{A}| &amp;amp;= x \\[1em]
\end{aligned}\]

\[\begin{aligned}
\frac{assoc(\mathbf{A}, \mathbf{A})}{assoc(\mathbf{A}, \mathbf{V})} &amp;amp;= \frac{\displaystyle\sum_{i=1}^{x}i}{x(N-1)} \\[1em]
&amp;amp;= \frac{x(x + 1)}{2x(N - 1)} \\[1em]
&amp;amp;= \frac{x + 1}{2(N - 1)} \\[1em]
\end{aligned}\]

\[\begin{aligned}
\therefore \frac{assoc(\mathbf{A}, \mathbf{A})}{assoc(\mathbf{A}, \mathbf{V})} + \frac{assoc(\mathbf{B}, \mathbf{B})}{assoc(\mathbf{B}, \mathbf{V})} &amp;amp;= \frac{x + 1}{2(N - 1)} + \frac{N -x + 1}{2(N - 1)} \\[1em]
&amp;amp;= \frac{N + 1}{2(N - 1)}
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;위의 식은 \(Nassoc\) 를 계산하기 위해 사용하는 그래프의 edge 수를 계산한 것이다.&lt;/li&gt;
  &lt;li&gt;마지막 식을 보면 식의 항에 \(x\) 가 없는 것을 볼 수 있는데, 이것은 기존 \(assoc\) 함수에서 문제가 되었던 edge의 수가 작아질수록 assocation 값이 작아지는 경향의 문제를 해결했음을 알 수 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;computing-the-optimal-partition&quot;&gt;Computing the Optimal Partition&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Graph partitioning 문제는 \(Nassoc\) 함수를 최소화시키는 set \(\mathbf{A}, \mathbf{B}\)를 찾는 것으로 해결한다.&lt;/li&gt;
  &lt;li&gt;그러나 \(Nassoc\) 의 최소값을 구하는 문제는 정확하게 NP 문제이다.&lt;/li&gt;
  &lt;li&gt;하지만 그래프가 real-valued domain이라고 한정한다면 이 문제는 approximate solution으로 해결될 수 있다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
&amp;amp;\mathbf{x} : N = ||\mathbf{V}|| \text{의 dimension을 가진 vector, 1 if node i is in A and -1, otherwise} \\[1em]
&amp;amp;\mathbf{d}(i) = \sum_{j}w(i, j) \\[1em]
&amp;amp;\mathbf{D} : \text{N x N diagonal matrix with d on its diagonal} \\[1em]
&amp;amp;\mathbf{W} : \text{N x N symmetrical matrix with } W(i, j) = w_{ij} \\[1em]
&amp;amp;k = \frac{\sum_{x_i&amp;gt;0} \mathbf{d}_i}{\sum_i \mathbf{d}_i} = \frac{assoc(\mathbf{A},\mathbf{V})}{assoc(\mathbf{V},\mathbf{V})}
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;위의 notation을 활용하여 기존의 set \(\mathbf{A}, \mathbf{B}\)를 찾는 partitioning 문제를 벡터 x를 찾는 문제로 대체할 수 있다.&lt;/li&gt;
  &lt;li&gt;\(Nassoc\) 함수를 위의 수식들로 대체할 수 있다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
4Nassoc(\mathbf{A}, \mathbf{B}) &amp;amp;= 4(\frac{assoc(\mathbf{A}, \mathbf{B})}{assoc(\mathbf{A}, \mathbf{V})} + \frac{assoc(\mathbf{B}, \mathbf{A})}{assoc(\mathbf{B}, \mathbf{V})}) \\[1em]
&amp;amp;= 4(\frac{\sum_{(x_i&amp;gt;0, x_j&amp;lt;0)} -w_{ij}\mathbf{x}_i\mathbf{x}_j}{\sum_{\mathbf{x}_i&amp;gt;0}\mathbf{d}_i} + \frac{\sum_{(x_i&amp;lt;0, x_j&amp;gt;0)} -w_{ij}\mathbf{x}_i\mathbf{x}_j}{\sum_{\mathbf{x}_i&amp;lt;0}\mathbf{d}_i}) \\[1em]
&amp;amp;= \frac{(\mathbf{1} + \mathbf{x})^T(\mathbf{D} - \mathbf{W})(\mathbf{1} + \mathbf{x})}{k\mathbf{1}^T\mathbf{d}\mathbf{1}} + \frac{(\mathbf{1} - \mathbf{x})^T(\mathbf{D} - \mathbf{W})(\mathbf{1} - \mathbf{x})}{(1 - k)\mathbf{1}^T\mathbf{d}\mathbf{1}} \\[1em]
&amp;amp;= \frac{\mathbf{x}^T(\mathbf{D} - \mathbf{W})\mathbf{x} + \mathbf{1}^T(\mathbf{D} - \mathbf{W})\mathbf{1}}{k(1-k)\mathbf{1}^T\mathbf{D}\mathbf{1}} + \frac{2(1-2k)\mathbf{1}^T(\mathbf{D} - \mathbf{W})\mathbf{x}}{k(1-k)\mathbf{1}^T\mathbf{D}\mathbf{1}}
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;\(Nassoc\)는 위의 식처럼 \(\mathbf{x}\) 의 이차식으로 표현될 수 있다. 무엇인가가 이차식으로 표현되었으면 최대한 완전 제곱식으로 표현하고 싶은게 인지상정.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
\alpha(x) &amp;amp;= \mathbf{x}^T(\mathbf{D} - \mathbf{W})\mathbf{x}, \\[1em]
\beta(x) &amp;amp;= \mathbf{1}^T(\mathbf{D} - \mathbf{W})\mathbf{x}, \\[1em]
\gamma(x) &amp;amp;= \mathbf{x}^T(\mathbf{D} - \mathbf{W})\mathbf{1}, \\[1em]
M &amp;amp;= \mathbf{1}^T\mathbf{D}\mathbf{1}
\end{aligned}\]

\[\begin{aligned}
&amp;amp;= \frac{(\alpha(\mathbf{x}) + \gamma) + 2(1 - 2k)\beta(\mathbf{x})}{k(1-k)M} \\[1em]
&amp;amp;= \frac{(\alpha(\mathbf{x}) + \gamma) + 2(1 - 2k)\beta(\mathbf{x})}{k(1-k)M} - \frac{2(\alpha(\mathbf{x}) + \gamma)}{M} + \frac{2\alpha(\mathbf{x})}{M} + \frac{2\gamma}{M} \\[1em]
&amp;amp;= \frac{(\alpha(\mathbf{x}) + \gamma) + 2(1 - 2k)\beta(\mathbf{x})}{k(1-k)M} - \frac{2(\alpha(\mathbf{x}) + \gamma)}{M} + \frac{2\alpha(\mathbf{x})}{M} \\[1em]
&amp;amp;= \frac{(1 - 2k + 2k^2)(\alpha(\mathbf{x}) + \gamma) + 2(1 - 2k) \beta(\mathbf{x}) }{k(1 - k)M} + \frac{2\alpha(\mathbf{x})}{M} \\[1em]
&amp;amp;= \frac{\frac{(1-2k+2k^2)}{(1-2k)^2}(\alpha(\mathbf{x}) + \gamma) + \frac{2(1-2k)}{(1-k)^2}\beta(\mathbf{x})}{\frac{k}{1-k}M} + \frac{2\beta(\mathbf{x})}{M}
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;\(b = \frac{k}{1-k}\) 라고 할 때,&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
&amp;amp;= \frac{(1 + b^2)(\alpha(\mathbf{x}) + \gamma) + 2(1 - b^2)\beta(\mathbf{x})}{} + \frac{2b\alpha(\mathbf{x})}{bM} \\[1em]
&amp;amp;= \frac{(1 + b^2)(\alpha(\mathbf{x}) + \gamma)}{bM} + \frac{2(1 - b^2)\beta(\mathbf{x})}{bM} + \frac{2b\alpha(\mathbf{x})}{bM} - \frac{2b\gamma}{bM} \\[1em]
&amp;amp;= \frac{(1 + b^2)(\mathbf{x}^T(\mathbf{D} - \mathbf{W})\mathbf{x} + \mathbf{1}^T(\mathbf{D} - \mathbf{W})\mathbf{1})}{b\mathbf{1}^T\mathbf{D}\mathbf{1}} 
+ \frac{2(1 - b^2)\mathbf{1}^T(\mathbf{D} - \mathbf{W})\mathbf{x}}{b\mathbf{1}^T\mathbf{D}\mathbf{1}}
+ \frac{2b\mathbf{x}^T(\mathbf{D} - \mathbf{W})\mathbf{x}}{b\mathbf{1}^T\mathbf{D}\mathbf{1}}
- \frac{2b\mathbf{1}^T(\mathbf{D} - \mathbf{W})\mathbf{1}}{b\mathbf{1}^T\mathbf{D}\mathbf{1}} \\[1em]
&amp;amp;= \frac{(\mathbf{1} + \mathbf{x})^T(\mathbf{D} - \mathbf{W})(\mathbf{1} + \mathbf{x})}{b\mathbf{1}^T\mathbf{D}\mathbf{1}}
+ \frac{b^2(\mathbf{1} - \mathbf{x})^T(\mathbf{D} - \mathbf{W})(\mathbf{1} - \mathbf{x})}{b\mathbf{1}^T\mathbf{D}\mathbf{1}}
- \frac{2b(\mathbf{1} - \mathbf{x})^T(\mathbf{D} - \mathbf{W})(\mathbf{1} + \mathbf{x})}{b\mathbf{1}^T\mathbf{D}\mathbf{1}} \\[1em]
&amp;amp;= \frac{[(\mathbf{1} + \mathbf{x}) - b(\mathbf{1} - \mathbf{x})]^2(\mathbf{D} - \mathbf{W})[(\mathbf{1} + \mathbf{x}) - b(\mathbf{1} - \mathbf{x})]}{b\mathbf{1}^T\mathbf{D}\mathbf{1}} \\[3em]
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;새로운 \(\mathbf{x}\)에 대한 변수 \(\mathbf{y} = (\mathbf{1} + \mathbf{x}) - b(\mathbf{1} - \mathbf{x})\) 라고 할 때,&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
\mathbf{y}^T\mathbf{D}\mathbf{y} &amp;amp;= 4\displaystyle\sum_{x_i&amp;gt;0}\mathbf{d}_i + 4b^2\displaystyle\sum_{x_i&amp;lt;0}\mathbf{d}_i \\[1em]
&amp;amp;= 4b\displaystyle\sum_{x_i&amp;lt;0}\mathbf{d}_i + 4b^2\displaystyle\sum_{x_i&amp;lt;0}\mathbf{d}_i \\[1em]
&amp;amp;= 4b(\displaystyle\sum_{x_i&amp;lt;0}\mathbf{d}_i + b\displaystyle\sum_{x_i&amp;lt;0}\mathbf{d}_i) \\[1em]
&amp;amp;= 4b\mathbf{1}^T\mathbf{D}\mathbf{1}
\end{aligned}\]

\[\begin{aligned}
\therefore min_\mathbf{x}Nassoc(\mathbf{x}) &amp;amp;= min_\mathbf{y}\frac{\mathbf{y}^T(\mathbf{D}-\mathbf{W})\mathbf{y}}{\mathbf{y}^T\mathbf{D}\mathbf{y}}
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;최종적인 간단해지고 정교해진 식은 \(\mathbf{y}\) 는 real-values 를 가지고, \(\mathbf{D} - \mathbf{W}\) 는 real-value와 symmetric하기 때문에 positive semidefinite이다.&lt;/li&gt;
  &lt;li&gt;위의 식을 Rayleigh quotient 식이라고 불른다.&lt;/li&gt;
  &lt;li&gt;위의 식은 \(\mathbf{y}^T\mathbf{D}\mathbf{y} = 1\) 의 제한조건 상에서 \(\mathbf{y}^T(\mathbf{D} - \mathbf{W})\mathbf{y}\) 을 최소화하는 문제와 같다.&lt;/li&gt;
  &lt;li&gt;라그랑지안 상수법을 이용해서 위의 문제를 쉽게 풀 수 있다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
&amp;amp;\text{minimized} \quad \mathbf{y}^T(\mathbf{D} - \mathbf{W})\mathbf{y} \\[1em]
&amp;amp;\text{subject to} \quad \mathbf{y}^T\mathbf{D}\mathbf{y} = 1
\end{aligned}\]

\[\begin{aligned}
0 &amp;amp;= \frac{\partial}{\partial\mathbf{y}}\mathbf{y}^T(\mathbf{D} - \mathbf{W})\mathbf{y} - \lambda\frac{\partial}{\partial\mathbf{y}}\mathbf{y}^T\mathbf{D}\mathbf{y} \\[1em]
&amp;amp;= 2(\mathbf{D} - \mathbf{W})\mathbf{y} + 2\lambda\mathbf{D}\mathbf{y} \\[3em]
\end{aligned}\]

\[\begin{aligned}
(\mathbf{D} - \mathbf{W})\mathbf{y} = \lambda\mathbf{D}\mathbf{y}
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;최종적으로 위의 solution 식을 generalized eigensystem이라 불리며, 이 문제를 풀어 \(\lambda\) 를 구하면 된다.&lt;/li&gt;
  &lt;li&gt;문제를 풀기 위해 새로운 변수 \(\mathbf{z} = \mathbf{D}^\frac{1}{2}\mathbf{y}\) 를 만들고 위의 식을 치환한다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
\mathbf{D}^{-\frac{1}{2}}(\mathbf{D} - \mathbf{W})\mathbf{D}^{-\frac{1}{2}}\mathbf{z} = \lambda\mathbf{z}
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;\(\mathbf{D}^{-\frac{1}{2}}(\mathbf{D} - \mathbf{W})\mathbf{D}^{-\frac{1}{2}}\)는 symmetric positive semidefinite 이다. 그렇기 때문에 \(\lambda\) 는 0 이상의 실수 값을 가진다.&lt;/li&gt;
  &lt;li&gt;실제로 \(\lambda = 0\) 일 때가 가장 smallest eigenvalue이며 그에 대응하는 eigenvector는 smallest eigenvector이다. 그러나 \(\lambda = 0\)이 된다면 \(k = 1\) 의 값을 가지므로 전제조건에 맞지 않다.&lt;/li&gt;
  &lt;li&gt;그래서 이 논문에서는 second smallest eigen value를 object function의 최소값으로 여기며, 그에 해당하는 second smallest eigen vector를 방정식의 해로 보고 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;grouping-algorithm&quot;&gt;Grouping Algorithm&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;Given an image or image sequence, set up a weighted graph \(\mathbf{G} = (\mathbf{V}, \mathbf{E})\) and set the weight on the edge connecting two nodes to be a measure of the similarity between the two nodes.&lt;/li&gt;
  &lt;li&gt;Solve \(\mathbf{D}^{-\frac{1}{2}}(\mathbf{D} - \mathbf{W})\mathbf{D}^{-\frac{1}{2}}\mathbf{x} = \lambda\mathbf{x}\) for eigenvectors with the smallest eigenvalues.&lt;/li&gt;
  &lt;li&gt;Use the eigenvector with the second smallest eigenvalue to bipartition the graph.&lt;/li&gt;
  &lt;li&gt;Decide if the current partition should be subdivided and recursively repartition the segmented parts if necessary.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;example-brightness-images&quot;&gt;Example: Brightness Images&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;Construct a weighted graph \(\mathbf{G} = (\mathbf{V}, \mathbf{E})\) by taking each pixel as a node and connecting each pair of pixels by an edge. \(F(i), X(i)\) are the pixel value and spatial location of node i, respectively.&lt;/li&gt;
&lt;/ol&gt;

\[\begin{aligned}
w_{ij} = e^{\frac{-||\mathbf{F}_{(i)} - \mathbf{F}_{(j)}||_2^2}{\sigma_I^2}} *
\begin{cases}
    e^{\frac{-||\mathbf{X}_{(i)} - \mathbf{X}_{(j)}||_2^2}{\sigma_X^2}}       &amp;amp; \quad \text{if } ||\mathbf{X}_{(i)} - \mathbf{X}_{(j)}||_2 &amp;lt; r \\[1em]
    0  &amp;amp; \quad \text{otherwise}
\end{cases}
\end{aligned}\]

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Solve the generalized eigensystem for the eigenvectors with the smallest eigenvalues of the system.
\(\mathbf{D}^{-\frac{1}{2}}(\mathbf{D} - \mathbf{W})\mathbf{D}^{-\frac{1}{2}}\mathbf{x} = \lambda\mathbf{x}\)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Once the eigenvectors are computed, we can partition the graph into two pieces using second smallest eigenvector. but, nonideally our eigenvectors have continuout values and just we need to choose a splitting point to partition it into two parts. normally we can take 0 as splitting point.&lt;/li&gt;
  &lt;li&gt;After the graph is broken into two pieces. we can recursively run our algorithm on the two partitioned parts. Or, we coule take adventage of the other small eigenvectors to partition more than two pieces. but the greater eigenvalue, the lower stability on the partition boundary. as we see in the eigenvector with the seventh to ninth smallest eigenvalues on the bottom picture, the eigenvectors take on the shape of a continuous function rather than discrete that we seek. so we simply choose to ignore all those eigenvetors which have smoothly varying eigenvector values by measuring the degree of smoothness in the eigenvector values and thresholding.&lt;/li&gt;
&lt;/ol&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;/assets/img/paper/ncut/3.png&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;review&quot;&gt;Review&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;이 논문은 분명 기존의 Graph Cut 함수의 문제점과 좋은 Normalized Cut 알고리즘을 제시하고, 계산방법을 제시하였다.&lt;/li&gt;
  &lt;li&gt;특히 제시한 Normalized Cut으로부터 Rayleigh quotient 형식을 이끌어 냈다는 점에서 훌륭한 논문이라고 할 수 있다.&lt;/li&gt;
  &lt;li&gt;하지만 minimized 시키는 방법에 대해서는 의문이 있다. Rayleigh quotient의 solution을 구하는 식 \(\mathbf{D}^{-\frac{1}{2}}(\mathbf{D} - \mathbf{W})\mathbf{D}^{-\frac{1}{2}}\mathbf{x} = \lambda\mathbf{x}\) 은 minimized를 구하는 식이 아닌 critical point를 구하는 식이다. 즉, object function의 값의 법위는 eigenvalue의 값의 범위와 같다. 그렇기에 smallest eigenvalue가 아닌 second smallest eigenvalue는 이 함수의 최소값이라고 단정할 수 없다고 생각한다. 즉 제한 조건이 있는 상태에서 풀어낸 solution의 신뢰성에 의심을 한다. 다만 응용에서 벡터는 이미지 픽셀 전체를 나타내기에 상당히 큰 차원의 벡터를 추정한다. 그렇기에 second smallest eigenvalue은 최솟값일지는 모르겠지만 충분히 작은 값을 나타낸다고 할 수 있고, second가 아닌 그 뒤에 있는 third~ninth까지도 충분히 작은 값을 나타낸다고 볼 수 있다. 또한 모든 eigenvector가 orthogonal 하기 때문에 각각의 eigenvector는 겹치지 않는 고유의 특징을 표현한다고 기대할 수 있겠다.&lt;/li&gt;
&lt;/ul&gt;</content><author><name>&lt;Lee&gt; &lt;Jongyeon&gt;</name><email>&lt;lee0301jy@naver.com&gt;</email></author><category term="paper" /><summary type="html">참고 [1] https://people.eecs.berkeley.edu/~malik/papers/SM-ncut.pdf</summary></entry><entry><title type="html">DINO</title><link href="https://tinnunculus.github.io/paper/2022-07-05-dino/" rel="alternate" type="text/html" title="DINO" /><published>2022-07-05T00:00:00+00:00</published><updated>2022-07-05T00:00:00+00:00</updated><id>https://tinnunculus.github.io/paper/dino</id><content type="html" xml:base="https://tinnunculus.github.io/paper/2022-07-05-dino/">&lt;p&gt;&lt;strong&gt;참고&lt;/strong&gt;&lt;br /&gt;
[1] &lt;a href=&quot;https://arxiv.org/pdf/2104.14294.pdf&quot;&gt;https://arxiv.org/pdf/2104.14294.pdf&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot; id=&quot;markdown-toc-introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#ssl-with-knowledge-distillation&quot; id=&quot;markdown-toc-ssl-with-knowledge-distillation&quot;&gt;SSL with Knowledge Distillation&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#training-student-model&quot; id=&quot;markdown-toc-training-student-model&quot;&gt;Training student model&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#teacher-network&quot; id=&quot;markdown-toc-teacher-network&quot;&gt;Teacher network&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#avoiding-collapse&quot; id=&quot;markdown-toc-avoiding-collapse&quot;&gt;Avoiding collapse&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#algorithm&quot; id=&quot;markdown-toc-algorithm&quot;&gt;Algorithm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;최근 Vision Transformer는 Vision Task에서 Convolution을 대체할 만큼 좋은 성능을 보여주고 있다.&lt;/li&gt;
  &lt;li&gt;이 논문에서는 Vision Task에서 Transformer의 성공이 Transformer의 pretrain 과정에서의 supervison을 통해 설명될 수 있을까 의문을 던졌고, 이것은 NLP 분야에서의 Transformer의 성공 중 하나인 self-supervised pretrain의 사용으로부터 동기를 얻었다.&lt;/li&gt;
  &lt;li&gt;NLP 분야에서의 self-supervised pretrain은 language modeling 혹은 문장 중에 비어있는 word를 생성하는 방식으로 학습이 진행되고 이것은 문장의 label을 예측하는 학습보다 풍부한 문장의 인지 능력을 가지게 된다.&lt;/li&gt;
  &lt;li&gt;이미지 분야에서도 마찬가지로 Vit처럼 supervised 학습은 이미지에 포함된 풍분한 visual information을 가지지 못하기에 이 논문에서는 self-supervised 학습을 통해 풍부한 visual information을 가지는 것을 목표로 한다.&lt;/li&gt;
  &lt;li&gt;이 논문에서는 ViT 모델을 이용해서 self-supervised pretraining의 효과를 연구한다.&lt;/li&gt;
  &lt;li&gt;연구의 결과 self-supervised ViT는 supervised ViT와는 달리 명백히 scene layout(object boundaries)을 예측할 수 있다. 이것은 학습 완료된 ViT 모델의 last block에서 볼 수 있다.&lt;/li&gt;
  &lt;li&gt;이런 segmentation 적인 특징이 나타나는 것은 여러 self-supervised method들의 사용을 통한 결과라고 예측할 수 있다.&lt;/li&gt;
  &lt;li&gt;그러나 k-NN을 통한 좋은 classification 결과를 보여주는 것은 momentum encoder과 multi-crop augmentation 기술 덕분이라고 할 수 있다.&lt;/li&gt;
  &lt;li&gt;이 논문에서는 student model과 teacher model을 통해 self-supervised 학습을 진행하는 knowledge distillation with no labels 기법을 사용하고, momentum encoder를 통해 학습을 진행한다.&lt;/li&gt;
  &lt;li&gt;기존의 다른 논문과는 다르게 오직 teacher 모델의 centering과 sharpening을 통해 학습이 collapse되는 것을 막는다.&lt;/li&gt;
  &lt;li&gt;self-supervised의 knowledge distillation 학습은 label이 없이 student와 teacher의 output으로만 학습이 진행되기 때문에 학습 도중에 모든 데이터에 대해서 어느 특정한 값으로 쏠려버리는 현상 같은게 일어날 수 있다. 그러한 현상을 collapse라고 한다. 예를 들면 모든 이미지에 대해서 결과 값이 0.5, 0.5, …, 0.5 혹은 1, 0, …, 0 을 출력하는 경우이다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;ssl-with-knowledge-distillation&quot;&gt;SSL with Knowledge Distillation&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;이 논문에서 제안하는 모델 DINO는 distillation knowledge 기법을 기반으로 student, teacher model을 학습한다.&lt;/li&gt;
  &lt;li&gt;student model과 teacher model은 동일한 아키텍쳐를 사용한다.&lt;/li&gt;
  &lt;li&gt;student model의 학습은 모델의 마지막단의 [CLS] 토큰을 통해 이루어지며, student와 teacher model의 결과물에는 softmax를 취하기 전에 특정 값으로 나눠준다. 이것은 output distribution의 sharpness를 컨트롤할 수 있다. 값이 작아질 수록 분포는 더욱 뾰족해질 것이다.&lt;/li&gt;
  &lt;li&gt;뭔가 student의 output에는 sharpness를 하지 않고 teacher의 output에만 sharpness를 하는게 더 맞지 않나… 라고 생각이 든다. 둘다 shaprness를 하면 어차피 다시 값이 평행하도록 학습이 될 것 같은 느낌인데, 물론 학습 극 초반에 평행하도록 되는 현상은 막을 수 있을 것 같지만…&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;550&quot; src=&quot;/assets/img/paper/dino/1.png&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;training-student-model&quot;&gt;Training student model&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;student model과 teacher model이 동일한 이미지를 입력으로 받지 않는다. 만일 동일한 이미지를 입력으로 받는다면 값의 차이가 크지 않아 collapse가 일어날 확률이 쉬워지고, classification에서의 성능이 떨어질 것이다.&lt;/li&gt;
  &lt;li&gt;이미지는 crop되어서 student model과 teacher model에 입력으로 들어가는데, 상대적으로 이미지가 큰 global views \(x_1^g, x_2^g\)와 이미지가 작은 local views group으로 나눠지며, teacher model에는 큰 이미지만이 들어간다. 즉, ‘local-to-global’ 관련성을 찾도록 유도하고, 이것은 classification 문제에 적합하다.&lt;/li&gt;
  &lt;li&gt;global view로는 224x224 크기의 image를 사용하고, 기존 이미지의 절반 이상을 덮을 수 있어야 한다. local view로는 96x96 크기의 image를 사용하고 기존 이미지의 절반 이하의 영역을 가리켜야 한다.&lt;/li&gt;
  &lt;li&gt;학습은 stochastic gradient descent를 통해 이뤄진다. momentum을 사용하지 않는 것에 주의하자.&lt;/li&gt;
  &lt;li&gt;momentum을 사용하지 않는 이유는 sharpening을 강화하기 위함이라고 생각한다. momentum을 가질경우 기존의 결과의 영향으로 centering되는 collapse가 일어날 수 있겠다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;550&quot; src=&quot;/assets/img/paper/dino/2.png&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;teacher-network&quot;&gt;Teacher network&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;다른 knowledge distillation와는 다르게 이 논문에서는 label이 없고 student와 teacher가 동일한 network 구조를 사용하기 때문에 실직적인 teacher는 존재하지 않는다.&lt;/li&gt;
  &lt;li&gt;하나의 에폭을 학습하는데 teacher network를 freezing시키는 것이 더 좋은 결과를 보여주었고, 단순히 student weight를 teacher weight로 복사하는 것은 모델이 수렴하는데에 실패하였다.&lt;/li&gt;
  &lt;li&gt;student weight를 단순히 복사하는 것이 아닌 exponential moving average을 사용하여 momentum을 가져가는 것이 더 학습의 안정화를 이끌어낼 수 있었다.&lt;/li&gt;
  &lt;li&gt;\(\theta_t = \lambda\theta_t + (1 - \lambda)\theta_s\) 의 object function으로 teacher weight가 갱신되며, \(\lambda\)는 cosine schedule로 0.996부터 1까지 증가한다. 굉장히 작은 크기의 student weight가 영향을 미친다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;600&quot; src=&quot;/assets/img/paper/dino/3.png&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;avoiding-collapse&quot;&gt;Avoiding collapse&lt;/h3&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;600&quot; src=&quot;/assets/img/paper/dino/4.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;이 논문에서는 self-supervised 학습의 collapse를 피하기 위해 Sharpening, Centering 두가지 기법을 사용한다.&lt;/li&gt;
  &lt;li&gt;Sharpening은 앞서 보았던 모델의 output에 softmax를 취하기 전 작은 값으로 나눠 분포를 더욱 다이나믹하게 하는 것이다.&lt;/li&gt;
  &lt;li&gt;centering은 teacher 모델의 output에 softmax를 취하기 전 기존 output의 momentum을 더해 특정 차원에 dominate해지는 것을 막는다.&lt;/li&gt;
  &lt;li&gt;위 두 기법은 trade-off로 작용되어 학습의 collapse를 막도록 한다.&lt;/li&gt;
  &lt;li&gt;위 그림에서 KL-divergence는 \(H(P_t, P_s) = h(P_t) + D_{KL}(P_t\|P_s)\) 로 계산한다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
g_t(x) = g_t(x) + c \\[1em]
c = mc + (1-m)\frac{1}{B}\sum_{i=1}^{B} g_{\theta_t}(x_i)
\end{aligned}\]

&lt;h2 id=&quot;algorithm&quot;&gt;Algorithm&lt;/h2&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;600&quot; src=&quot;/assets/img/paper/dino/5.png&quot; /&gt;&lt;/p&gt;</content><author><name>&lt;Lee&gt; &lt;Jongyeon&gt;</name><email>&lt;lee0301jy@naver.com&gt;</email></author><category term="paper" /><summary type="html">참고 [1] https://arxiv.org/pdf/2104.14294.pdf</summary></entry><entry><title type="html">Node- Socket</title><link href="https://tinnunculus.github.io/javascript/2022-07-01-node-scoket/" rel="alternate" type="text/html" title="Node- Socket" /><published>2022-07-01T00:00:00+00:00</published><updated>2022-07-01T00:00:00+00:00</updated><id>https://tinnunculus.github.io/javascript/node-scoket</id><content type="html" xml:base="https://tinnunculus.github.io/javascript/2022-07-01-node-scoket/">&lt;p&gt;&lt;strong&gt;참고&lt;/strong&gt;&lt;br /&gt;
[1] &lt;a href=&quot;https://socket.io/docs/v4&quot;&gt;https://socket.io/docs/v4&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot; id=&quot;markdown-toc-introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#socketio&quot; id=&quot;markdown-toc-socketio&quot;&gt;socket.io&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#io-객체&quot; id=&quot;markdown-toc-io-객체&quot;&gt;io 객체&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#socket-객체&quot; id=&quot;markdown-toc-socket-객체&quot;&gt;socket 객체&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;네트워크 상에서 정보를 주고 받는 방법(protocol)중 &lt;strong&gt;HTTP는&lt;/strong&gt; client에서 server로만 요청을 보낼 수 있는 &lt;strong&gt;단방향 통신이다.&lt;/strong&gt; 하지만 실시간 채팅처럼 server에서 client에게 데이터를 전송해야하는 문제도 있다. 기존에는 HTTP protocol은 유지한 채로 Poling 기법을 취했다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Poling 기법은&lt;/strong&gt; HTTP protocol 상에서 &lt;strong&gt;client가 주기적으로 server에게 어떠한 변화가 있는지 체크하는 요청&lt;/strong&gt;을 보내는 것이다. 주기적으로 확인 요청을 보내야하기 때문에 네트워크 상의 자원을 많이 차지하고 server에서 통신하는 client가 많아지면 server는 수 많은 확인 요청으로 인해 병목현상이 심화될 것이다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Socket protocol&lt;/strong&gt;은 HTTP protocol과 달리 &lt;strong&gt;양방향&lt;/strong&gt;으로 통신할 수 있는 protocol이다.&lt;/li&gt;
  &lt;li&gt;Socket protocol은 server와 client간에 &lt;strong&gt;connection&lt;/strong&gt;을 통해 양방향 통신을 가능하게 한다.&lt;/li&gt;
  &lt;li&gt;Socket protocol상에서 server와 client간에 connection에 따라 TCP, UDP 등으로 나뉜다.&lt;/li&gt;
  &lt;li&gt;connection은 항상 &lt;strong&gt;client에서 server로 연결 요청&lt;/strong&gt;을 보낸다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;550&quot; src=&quot;/assets/img/javascript/socket/1.png&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;socketio&quot;&gt;socket.io&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;socket.io는 node에서 socket을 편리하게 사용할 수 있게 하는 패키지이다.&lt;/li&gt;
  &lt;li&gt;nodejs에서 socket은 &lt;strong&gt;이벤트&lt;/strong&gt;를 통해 데이터를 주고 받는다.&lt;/li&gt;
  &lt;li&gt;socket.io 패키지를 이용하면 &lt;strong&gt;HTTP server와 연동하여 사용할 수 있다.&lt;/strong&gt; 즉, HTTP server를 통해 socket server를 구축할 수 있다. 그렇기에 socket 연결 요청도 HTTP server로 요청해야 한다.&lt;/li&gt;
  &lt;li&gt;아래의 코드에서 http_server 객체는 app.listen()의 output으로 http server에 대한 정보들이 저장되어 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SocketIO&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;socket.io&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SocketIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;http_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/socket.io&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// socket server를 http server에 connection. 동일한 port 번호 사용&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{});&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// connection이 완료되면 callback 함수가 실행된다. &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;io-객체&quot;&gt;io 객체&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;server의 socket에는 계층 구조가 있는데, 첫번째로 나눠지는 것을 &lt;strong&gt;namespace&lt;/strong&gt;라고 부른다.&lt;/li&gt;
  &lt;li&gt;client는 해당 socket server의 &lt;strong&gt;namespace로 connection 요청&lt;/strong&gt;을 보내야 한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;socket1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/socket1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;socket2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/socket2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;socket1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{});&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 클라이언트는 /socket1 으로 connection 요청을 보내야만 한다.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;socket2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{});&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 클라이언트는 /socket2 으로 connection 요청을 보내야만 한다.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;io.emit 메소드를 통해 현재 server에 있는 &lt;strong&gt;모든 socket에서 데이터를 전송할 수 있다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;550&quot; src=&quot;/assets/img/javascript/socket/3.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;client와 server간의 connection은 요청과 응답의 http protocol 상에서 이뤄지기 때문에 &lt;strong&gt;socket server에서도 middle-ware를 넣을 수 있고, connection 당시에만 실행된다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isValid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;invalid&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;io.socketsJoin 메소드를 통해 현재 socket server 내부에 있는 socket의 &lt;strong&gt;room 위치를 변경할 수 있다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 현재 socket server 내부에 있는 모든 socket들을 &quot;room1&quot;으로 옮긴다.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socketsJoin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// &quot;room1&quot;에 위치한 모든 socket을 'room2'와 'room3'로 옮긴다.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socketsJoin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room3&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// &quot;admin&quot; namespace를 사용하고 &quot;room1&quot;에 위치한 모든 socket을 &quot;room2&quot;로 옮긴다.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/admin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socketsJoin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 특정 socket id의 socket을 'room1'으로 옮긴다.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;theSocketId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socketsJoin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;io.socketsLeave 메소드를 통해 socket이 &lt;strong&gt;room을 떠나게 할 수 있다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// make all Socket instances leave the &quot;room1&quot; room&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socketsLeave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// make all Socket instances in the &quot;room1&quot; room leave the &quot;room2&quot; and &quot;room3&quot; rooms&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socketsLeave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room3&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// make all Socket instances in the &quot;room1&quot; room of the &quot;admin&quot; namespace leave the &quot;room2&quot; room&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/admin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socketsLeave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// this also works with a single socket ID&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;theSocketId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socketsLeave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;io.disconnectSockets 메소드를 통해 &lt;strong&gt;socket의 연결을 끊을 수 있다.&lt;/strong&gt; 특정 room만 연결을 끊는 socketsLeave와는 차이가 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// make all Socket instances disconnect&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;disconnectSockets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// make all Socket instances in the &quot;room1&quot; room disconnect (and discard the low-level connection)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;disconnectSockets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// make all Socket instances in the &quot;room1&quot; room of the &quot;admin&quot; namespace disconnect&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/admin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;disconnectSockets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// this also works with a single socket ID&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/admin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;theSocketId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;disconnectSockets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;io.fetchSockets 메소드를 통해 특정 &lt;strong&gt;socket들을 검색할 수 있다.&lt;/strong&gt; 리스트형태로 출력이 되니 for문을 이용하여 사용하자.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// return all Socket instances of the main namespace&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sockets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fetchSockets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// return all Socket instances in the &quot;room1&quot; room of the main namespace&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sockets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fetchSockets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// return all Socket instances in the &quot;room1&quot; room of the &quot;admin&quot; namespace&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sockets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/admin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;room1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fetchSockets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// this also works with a single socket ID&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sockets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;theSocketId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fetchSockets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sockets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;handshake&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rooms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;leave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;disconnect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;socket-객체&quot;&gt;socket 객체&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;socket 객체는 connection이 성공적으로 이루어지면 그 &lt;strong&gt;콜백 함수의 parameter로 들어간다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;socket protocol은 이벤트기반으로 데이터를 주고 받기에 socket 객체의 emit 메소드를 이용하여 이벤트를 발생시키고, on 메소드를 이용하여 이벤트를 받는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;650&quot; src=&quot;/assets/img/javascript/socket/2.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;모든 socket은 &lt;strong&gt;room&lt;/strong&gt;을 가지고 있다. room이란 namespace의 &lt;strong&gt;하위 구조&lt;/strong&gt;라고 볼 수 있으며, 하나의 socket이 &lt;strong&gt;여러 room에 속할 수 있고&lt;/strong&gt;, 하나의 room에 &lt;strong&gt;여러 socket이 들어있을 수 있다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;이벤트의 emit과 on은 room을 기준으로 하기에 해당 room에 속한 모든 socket에서 이벤트를 동일시 한다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;현재 자기 자신이 속하고 있는 room 외에도 다른 room에 속한 socket을 통해 데이터를 전송할 수 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rooms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Set { &amp;lt;socket.id&amp;gt; }&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;roomId1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;roomId2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rooms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Set { &amp;lt;socket.id&amp;gt;, roomId1, roomId2 }&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// roomId1과 roomId2에 있는 모든 socket에게 데이터를 전송한다.&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;roomId1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// roomId1에 있는 모든 socket에게 데이터를 전송한다.&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;roomId3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// roomId3에 있는 모든 socket에게 데이터를 전송한다.&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;disconnect&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;leave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;roomId1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;leave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;roomId2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;모든 socket은 &lt;strong&gt;고유의 id&lt;/strong&gt;를 가지고 있으며, server와 client에 동일한 id를 가진다. &lt;strong&gt;socket이 생성되면 default로 자기 id의 room에 들어간다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// ojIckSD2jqNzOqIrAGzL&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// client-side&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// ojIckSD2jqNzOqIrAGzL&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;anotherSocketId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;private message&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// anotherSocketId에 해당하는 socket에게만 메시지를 보낸다.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;server와 client가 connection 과정에서의 정보들도 담겨 있다. (hand-shake)&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* the headers of the initial request */&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* the query params of the initial request */&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* the authentication payload */&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* the date of creation (as string) */&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;issued&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* the date of creation (unix timestamp) */&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* the request URL string */&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* the ip of the client */&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;xdomain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* whether the connection is cross-domain */&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;secure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* whether the connection is secure */&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;socket.data 객체에 정보를 저장하면 io에서 fetchSocket을 통해 socket을 가져왔을 때, 데이터를 전달할 수 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// server A&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;alice&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// server B&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sockets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fetchSockets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sockets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &quot;alice&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name>&lt;Lee&gt; &lt;Jongyeon&gt;</name><email>&lt;lee0301jy@naver.com&gt;</email></author><category term="javascript" /><summary type="html">참고 [1] https://socket.io/docs/v4</summary></entry><entry><title type="html">Node- OAuth 2.0</title><link href="https://tinnunculus.github.io/javascript/2022-06-06-node-oauth2/" rel="alternate" type="text/html" title="Node- OAuth 2.0" /><published>2022-06-06T00:00:00+00:00</published><updated>2022-06-06T00:00:00+00:00</updated><id>https://tinnunculus.github.io/javascript/node-oauth2</id><content type="html" xml:base="https://tinnunculus.github.io/javascript/2022-06-06-node-oauth2/">&lt;p&gt;&lt;strong&gt;참고&lt;/strong&gt;&lt;br /&gt;
[1] &lt;a href=&quot;https://developers.google.com/identity/protocols/oauth2&quot;&gt;https://developers.google.com/identity/protocols/oauth2&lt;/a&gt;&lt;br /&gt;
[2] &lt;a href=&quot;https://blog.naver.com/mds_datasecurity/222182943542&quot;&gt;https://blog.naver.com/mds_datasecurity/222182943542&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot; id=&quot;markdown-toc-introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#oauth-20-protocol&quot; id=&quot;markdown-toc-oauth-20-protocol&quot;&gt;OAuth 2.0 protocol&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#authorization-code-grant&quot; id=&quot;markdown-toc-authorization-code-grant&quot;&gt;Authorization Code Grant&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#authorization-code-grant-절차&quot; id=&quot;markdown-toc-authorization-code-grant-절차&quot;&gt;Authorization Code Grant 절차&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#oauth-20을-이용한-gmail-api-관련-token-얻기&quot; id=&quot;markdown-toc-oauth-20을-이용한-gmail-api-관련-token-얻기&quot;&gt;OAuth 2.0을 이용한 GMail Api 관련 Token 얻기&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#access-token과-node-mailer-패키지를-이용하여-이메일-전송하기&quot; id=&quot;markdown-toc-access-token과-node-mailer-패키지를-이용하여-이메일-전송하기&quot;&gt;Access token과 Node mailer 패키지를 이용하여 이메일 전송하기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Oauth&lt;/strong&gt;는 &lt;strong&gt;Client(웹 어플리케이션)&lt;/strong&gt;가 &lt;strong&gt;Resource Server(구글)로 부터 Resource owner(웹 어플리케이션의 유저들)의 Resource&lt;/strong&gt;들을 사용하기위해 &lt;strong&gt;Authorization Server(구글)에게 Authentication(인증)과 Authorization(권한)을 받는 프로토콜이다.&lt;/strong&gt; 즉 내가 만든 서버가 유저의 구글 로그인, 네이버 로그인, 네이버 메일 등을 사용하기 위해 구글, 네이버에게 내 서버와 유저를 인증하는 절차이다.&lt;/li&gt;
  &lt;li&gt;이메일 인증을 위해 서버에서 Gmail을 이용하여 이메일을 유저들에게 보냈는데, 기존에는 Gmail의 아이디와 비밀번호만 서버에 저장하고 있고 서버에서 구글 이메일 서버에 접속해 아이디와 비밀번호를 통해 로그인하여 메일을 발송하였는데 최근에 구글에서 그 방법을 막기 시작하였다.&lt;/li&gt;
  &lt;li&gt;서버에서 유저의 아이디와 비밀번호를 저장하여 구글에 유저를 대행하여 로그인하는 것이 서버에서 유저행세를 하며 구글에서 유저정보를 빼앗는 것은 보안상 좋지 않다고 볼 수 있다. &lt;strong&gt;구글에서는 클라이언트 서버가 신뢰할만한 인증을 받는 것이 아니기 때문.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Clent 서버는 인증을 받으면 유저의 리소스를 사용할 수 있는 권리를 받는데 &lt;strong&gt;Access token&lt;/strong&gt;, &lt;strong&gt;Refresh token&lt;/strong&gt;을 통해 Resource Server로부터 유저의 Resource를 받아올 수 있다.&lt;/li&gt;
  &lt;li&gt;핵심은 Authorization Server는 유저와 Client &lt;strong&gt;모두를 인증&lt;/strong&gt;하고 Client 서버에게 권한을 부여하는 것이다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;oauth-20-protocol&quot;&gt;OAuth 2.0 protocol&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;OAuth 2.0을 다루는데 있어서 등장하는 요소들로는 Resource 소유자인 &lt;strong&gt;Resouce Owner&lt;/strong&gt;(편의상 Client의 유저라고 부르겠다), 유저의 Resource를 사용할려는 &lt;strong&gt;Client&lt;/strong&gt;, 유저의 Resource를 소유하고 있는 &lt;strong&gt;Resource server&lt;/strong&gt;, 유저와 Client부터 인증과 권한을 부여하는 &lt;strong&gt;Authorization Server&lt;/strong&gt;가 존재한다.&lt;/li&gt;
  &lt;li&gt;OAuth를 통해서 Client에게 Resource Server에서 유저의 Resource를 사용하도록 권한을 부여하는 여러 방법(4가지)가 존재하는데 그 중에서 가장 보편적으로 사용하는 &lt;strong&gt;Authorization Code Grant&lt;/strong&gt; 방식을 알아보도록 하겠다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;authorization-code-grant&quot;&gt;Authorization Code Grant&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Authorization Server에서 &lt;strong&gt;유저를 검증(Authentication)&lt;/strong&gt;하고 어떤 Resource를 사용할 지 &lt;strong&gt;Scope&lt;/strong&gt;을 정의한 후에 그 정보를 &lt;strong&gt;Authorization Code&lt;/strong&gt;로 만들어 Client에게 전달하고 Client는 자신을 Authorization Server에게 &lt;strong&gt;받은 Code와 함께 Client을 인증하면&lt;/strong&gt; 유저의 Resource를 사용할 수 있도록 하는 OAuth 프로토콜 중에 가장 보편적으로 사용하는 Authorization 방식이다.&lt;/li&gt;
  &lt;li&gt;Authorization Code는 &lt;strong&gt;인증된 유저 정보&lt;/strong&gt;, &lt;strong&gt;Scope 정보&lt;/strong&gt;, &lt;strong&gt;아직 인증되지 않은 Client 정보&lt;/strong&gt;가 있다. 그렇기 때문에 Client는 이 Code와 함께 Authorization Server에게 &lt;strong&gt;자신을 인증해야 한다.&lt;/strong&gt; 유저 검증을 &lt;strong&gt;Client가 하는 것이 아닌 Authorization Server가 하고&lt;/strong&gt; Client에서는 &lt;strong&gt;유저 정보를 가지고 있을 필요가 없기&lt;/strong&gt; 때문에 보안상 뛰어나다. 또한 유저 인증만 하였다고 &lt;strong&gt;Resource를 바로 쓸 수 있는 것이 아닌 Client도 검증 단계를 거쳐야만 Resource를 사용할 수 있다.&lt;/strong&gt; 유저 정보만 검증하고 &lt;strong&gt;Client는 검증하지 않을 경우&lt;/strong&gt; Client Id는 오픈된 정보이기 떄문에 &lt;strong&gt;다른 누군가가 Client 행세를 하여 Code를 얻을 수 있기 때문이다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Access token&lt;/strong&gt;과 &lt;strong&gt;Refresh token&lt;/strong&gt;을 사용하는 방식이다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;authorization-code-grant-절차&quot;&gt;Authorization Code Grant 절차&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;우선 Client를 Authorization Server에 등록하여 &lt;strong&gt;Client Id&lt;/strong&gt;와 &lt;strong&gt;Cleint Secret&lt;/strong&gt;을 받아야한다. 이것은 나중에 Authorization Server에서 Client를 인증할 때 사용한다.&lt;/li&gt;
  &lt;li&gt;Cleint에서 어떤 특정한 일에서 유저의 Resource를 사용한다고 하면 그 특정한 일을 유저가 요청할 때, Client에서는 &lt;strong&gt;Client Id&lt;/strong&gt;와 &lt;strong&gt;Resource Scope 정보&lt;/strong&gt;, &lt;strong&gt;인증이 완료되면 인증 코드를 보낼 redirected Url 주소&lt;/strong&gt;를 담아 Authorization Server에게 요청한다.&lt;/li&gt;
  &lt;li&gt;Authorization Server는 자체적으로 로그인 같은 방법으로 &lt;strong&gt;유저를 검증하고&lt;/strong&gt; 해당 Scope에 대해서 사용 동의를 얻은 후에 &lt;strong&gt;유저 정보와 Scope 정보가 담긴 Authorization Code를 만들어 Client에게 전달한다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;응답을 받은 Client는 &lt;strong&gt;Authorization Code&lt;/strong&gt;와 &lt;strong&gt;Client Id&lt;/strong&gt;, &lt;strong&gt;Client Secret&lt;/strong&gt; 정보를 다시 Authorization Server에게 전달한다.&lt;/li&gt;
  &lt;li&gt;Authorization Server는 받은 Client Id와 Client Secret을 통해 Client를 인증하고 해당 유저에 리소스에 접근할 수 있는 &lt;strong&gt;Access token&lt;/strong&gt;과 &lt;strong&gt;Refresh token&lt;/strong&gt;을 Client에게 발급한다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Access token에는 유저 정보와 Scope 정보, Client 정보가 담겨있다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Access token을 &lt;strong&gt;재발급&lt;/strong&gt; 받기 위해서는 &lt;strong&gt;Client Id, Client Secret, Refresh token&lt;/strong&gt; 3개가 필요하다.&lt;/li&gt;
  &lt;li&gt;Access token과 Refresh token을 이용하기 때문에 다음에 중복해서 인증할 필요가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;/assets/img/javascript/oauth/1.png&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;oauth-20을-이용한-gmail-api-관련-token-얻기&quot;&gt;OAuth 2.0을 이용한 GMail Api 관련 Token 얻기&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Gmail을 구글에서 제공하는 서비스이기 때문에 구글에 Client를 등록해야 한다.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://console.cloud.google.com/home/dashboard&quot;&gt;구글 클라우드 플랫폼&lt;/a&gt;에 Api 및 서비스에서 Client를 등록하여 Client Id와 Secret을 받는다.&lt;/li&gt;
  &lt;li&gt;Gmail api 서비스에서 유저는 이메일을 보내는 발신자이다. 일반적인 OAuth 2.0을 사용하는 로그인 서비스에서는 Authorization code를 Client로 응답하여 매번 유저마다 다른 Authorization Code를 받아 인증해야하는 것과는 달리, 로그인 서비스에서는 유저의 이메일을 등록하여 등록된 이메일을 사용해서 전송하면 되기 때문에 웹 브라우저를 통해 사용할 이메일을 한번만 인증하면 된다. 구글에서 제공하는 &lt;a href=&quot;https://developers.google.com/oauthplayground&quot;&gt;oauthplayground&lt;/a&gt;를 사용한다.&lt;/li&gt;
  &lt;li&gt;oauthplayground는 브라우저에서 oauth관련 일을 처리할 수 있는 Authorization Server라 생각하면 쉽다.&lt;/li&gt;
  &lt;li&gt;oauthplayground에서 Client Id와 gmail scope을 등록하고, 구글 로그인을 통해 유저 인증을 하면 Authorization Code를 얻는다.&lt;/li&gt;
  &lt;li&gt;받은 Authorization Code와 Clien Id, Client Secret을 입력하면 Access token과 Refresh token을 얻을 수 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;access-token과-node-mailer-패키지를-이용하여-이메일-전송하기&quot;&gt;Access token과 Node mailer 패키지를 이용하여 이메일 전송하기&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://tinnunculus.github.io/javascript/2022-03-30-node-nodemail/&quot;&gt;Node mailer을 이용하여 이메일 보내기&lt;/a&gt;에서 설명한 것처럼 mailer 패키지를 이용하여 메일을 전송하기 위해서는 Transporter 객체를 이용한다.&lt;/li&gt;
  &lt;li&gt;access token은 등록하지 않아도 된다. &lt;strong&gt;nodemailer가 자체적으로 refresh token, Client Id, Client Secret을 이용해서 access token을 발급하기 때문이다.&lt;/strong&gt;
    &lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transporter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;nodemailer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createTransport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;smtp.gmail.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;465&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;secure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;OAuth2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;user@example.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;clientId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;000000000000-xxx0.apps.googleusercontent.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;clientSecret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;XxxxxXXxX0xxxxxxxx0XXxX0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;refreshToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1/XXxXxsss-xxxXXXXXxXxx0XXXxxXXx0x00xxx&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;</content><author><name>&lt;Lee&gt; &lt;Jongyeon&gt;</name><email>&lt;lee0301jy@naver.com&gt;</email></author><category term="javascript" /><summary type="html">참고 [1] https://developers.google.com/identity/protocols/oauth2 [2] https://blog.naver.com/mds_datasecurity/222182943542</summary></entry><entry><title type="html">about requires_grad</title><link href="https://tinnunculus.github.io/pytorch/2022-06-03-about_requires_grad/" rel="alternate" type="text/html" title="about requires_grad" /><published>2022-06-03T00:00:00+00:00</published><updated>2022-06-03T00:00:00+00:00</updated><id>https://tinnunculus.github.io/pytorch/about_requires_grad</id><content type="html" xml:base="https://tinnunculus.github.io/pytorch/2022-06-03-about_requires_grad/">&lt;p&gt;&lt;strong&gt;참고&lt;/strong&gt;&lt;br /&gt;
[1] &lt;a href=&quot;https://pytorch.org/docs/stable/notes/autograd.html&quot;&gt;https://pytorch.org/docs/stable/notes/autograd.html&lt;/a&gt;&lt;br /&gt;
[2] &lt;a href=&quot;https://medium.com/@mrityu.jha/understanding-the-grad-of-autograd-fc8d266fd6cf&quot;&gt;https://medium.com/@mrityu.jha/understanding-the-grad-of-autograd-fc8d266fd6cf&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot; id=&quot;markdown-toc-introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#autograd의-처리-과정&quot; id=&quot;markdown-toc-autograd의-처리-과정&quot;&gt;Autograd의 처리 과정&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#saved-tensor&quot; id=&quot;markdown-toc-saved-tensor&quot;&gt;Saved Tensor&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#requires_grad-flag&quot; id=&quot;markdown-toc-requires_grad-flag&quot;&gt;Requires_grad flag&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#gradient-context&quot; id=&quot;markdown-toc-gradient-context&quot;&gt;Gradient context&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#in-place-operation&quot; id=&quot;markdown-toc-in-place-operation&quot;&gt;in-place operation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#tip&quot; id=&quot;markdown-toc-tip&quot;&gt;tip&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;코딩을 하면서 Tensor 객체가 가지고 있는 requires_grad flag에 대해서 항상 헷갈리는 점이 있었는데, 이번 기회에 정리를 해보자 한다.&lt;/li&gt;
  &lt;li&gt;pytorch의 autograd는 &lt;strong&gt;forward pass&lt;/strong&gt; 시에 &lt;strong&gt;directed gradient graph&lt;/strong&gt;를 생성하여, &lt;strong&gt;backward() 메소드를 통해 gradient를 계산한다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;autograd는 forward pass 중에 backward에서 gradient 계산을 위해 텐서들을 gradient function에 저장한다.&lt;/li&gt;
  &lt;li&gt;Requires_grad flag가 &lt;strong&gt;True인 leaf tensor를 수정하면 오류가 난다.&lt;/strong&gt; leaf tensor와 intermediate tensor의 차이점에 대해서 알아본다.&lt;/li&gt;
  &lt;li&gt;Requires_grad flag가 &lt;strong&gt;True인 텐서에 대해서면 gradient를 계산한다.&lt;/strong&gt; &lt;strong&gt;전령 gradient function이 존재하더라도&lt;/strong&gt; requires_grad가 True인 텐서만 골라서 gradient를 계산한다. 마찬가지로 forward할 시에 gradient에 필요한 saved tensor만 저장한다.&lt;/li&gt;
  &lt;li&gt;gradient를 계산하는 context로는 grad mode, no grad mode, inference mode가 존재한다. inference mode는 그레디언트를 전혀 계산하지 않는다.&lt;/li&gt;
  &lt;li&gt;saved tensor는 값이 바뀌면 안된다. 그렇기에 &lt;strong&gt;in place operation의 사용에 있어서는 주의해야한다.&lt;/strong&gt; 파이토치에서는 &lt;strong&gt;leaf node에 대해서 in place operation을 사용하는 것에 오류를 보낸다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;intermediate tensor에서는 in place operation을 사용한다고 오류를 내보내지 않는다. 자체적으로 clone하여 saved tensor를 저장한다. 이 말은 saved tensor를 저장하지 못한다는 이유로 leaf node에 in-place operation을 못하게 하는 것이 아닌, &lt;strong&gt;leaf tensor는 gradient function을 가져서는 안되는 특징을 가지고 있고, clone하여 leaf tensor는 유지하고 새로운 intermediate tensor를 만들어 해결한다면 그건 사실상 out place operation을 의미한다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;autograd의-처리-과정&quot;&gt;Autograd의 처리 과정&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;autograd&lt;/strong&gt;는 &lt;strong&gt;reverse automatic diffrentiation system&lt;/strong&gt;을 의미한다. 말 그대로 forward 연산을 &lt;strong&gt;역행&lt;/strong&gt;하여 자동으로 미분을 계산하는 시스템이다.&lt;/li&gt;
  &lt;li&gt;forward pass를 계산할 때, autograd는 gradient를 계산하는 &lt;strong&gt;Function을 노드로해서 grap&lt;/strong&gt;h를 만든다. &lt;strong&gt;graph&lt;/strong&gt;에는 노드 &lt;strong&gt;Function&lt;/strong&gt;과 엣지 &lt;strong&gt;Tensor&lt;/strong&gt;와 방향 &lt;strong&gt;input, output&lt;/strong&gt;이 기록되어 있다.&lt;/li&gt;
  &lt;li&gt;이렇게 만들어진 graph는 backward()메소드를 실행 시 forward pass의 역행으로 해서 계산되어 진다. 즉 forward pass에서 입력으로 들어간 &lt;strong&gt;leaf node는 backward pass에서 ouput&lt;/strong&gt;이 되고, forward pass에서 출력으로 나온 &lt;strong&gt;output tensor(root)는 backward pass에서 input tensor&lt;/strong&gt;가 된다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;saved-tensor&quot;&gt;Saved Tensor&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Gradient를 계산하기 위해서는 forward시에 입력으로 들어갔던 텐서들이 필요할 때가 있다. autograd는 그런 텐서들을 해당 &lt;strong&gt;operation에 gradient function과 함께 ctx라는 변수명으로 저장한다.&lt;/strong&gt; 물론 텐서를 복사 저장이 아닌 &lt;strong&gt;참조 저장이다.&lt;/strong&gt; 그렇기에 한번 저장된 텐서는 별도로 &lt;strong&gt;수정해서는 안된다.&lt;/strong&gt; 오류 발생&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ctx.save_for_backward()&lt;/strong&gt; 함수를 통해서 텐서를 저장할 수 있으며, &lt;strong&gt;ctx.saved_tensors&lt;/strong&gt;를 통해 불러올 수 있다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;intermediate tensor&lt;/strong&gt;에 저장된 gradient function으로 &lt;strong&gt;어떤 텐서들이 저장되어 있는지 확인할 수 있다.&lt;/strong&gt;
    &lt;div class=&quot;language-py highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requires_grad&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# dx/dy를 구하기 위해서는 x의 값이 필요하다.
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grad_fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_saved_self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# True... 참조형으로 저장되는 모습
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;requires_grad-flag&quot;&gt;Requires_grad flag&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;requires_grad는 모든 텐서가 가지고 있는 flag이며, 기본값은 False이다. nn.parameters()로 감싸진 tensor는 기본값이 True이다.&lt;/li&gt;
  &lt;li&gt;forward pass 중에 어떤 operation의 &lt;strong&gt;input중에 requires_grad가 하나라도 True이면&lt;/strong&gt; output Tensor는 모두 &lt;strong&gt;gradient function을 가지며 intermediate tensor가 된다.&lt;/strong&gt; gradient function이 저장되지만 &lt;strong&gt;gradient function과 함께 저장되는 텐서들은 모두 저장되는 것은 아니다.&lt;/strong&gt; &lt;strong&gt;requires_grad가 True인 input tensor의 gradient를 계산하기 위한 텐서들만 저장된다.&lt;/strong&gt; forward pass f(a, b) = a * b이고 requires_grad가 a는 True, b는 False일 때, 함수 f의 grad_fn은 requires_grad가 True인 tensor a의 gradient 계산에 필요한 &lt;strong&gt;b만을 저장한다.&lt;/strong&gt; 반면에 모든 input tensor가 requires_grad가 False라면 output tensor는 모두 gradient function을 가지지 않으며 &lt;strong&gt;leaf tensor&lt;/strong&gt;가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;/assets/img/pytorch/requires/1.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;backward pass 중에는 오로지 &lt;strong&gt;requires_grad가 True인 leaf tensor&lt;/strong&gt;(gradient function을 가지지 않는 tensor)&lt;strong&gt;만이 gradient값이 축적된다.&lt;/strong&gt; intermediate tensor들도 gradient 값을 축적시키고 싶다면 .retain_graph 를 True로 설정해서 grad 값을 축적시키도록 할 수 있다. 하지만 거의 쓰지 않을듯..?&lt;/li&gt;
  &lt;li&gt;autograd는 &lt;strong&gt;intermediate tensor는 항상 requires_grad가 True라고 가정하고 한다.&lt;/strong&gt; 만약 intermediate tensor가 requires_grad를 False로 선정한다면 파이토치상에서 오류를 일으킨다.&lt;/li&gt;
  &lt;li&gt;intermediate tensor를 gradient 계산이 필요 없어진다면, 즉 backward 그래프를 해당 tensor에서 끊고 싶다면 해당 &lt;strong&gt;tensor.detach()를 통해 graph를 끊을 수 있다.&lt;/strong&gt; 물론 .detach() 메소드는 in-place method가 아닌 &lt;strong&gt;graph가 끊어진 새로운 tensor를 복사하는 함수이다.&lt;/strong&gt; &lt;strong&gt;그렇기에 실제로는 graph가 남아있다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;700&quot; src=&quot;/assets/img/pytorch/requires/2.jpeg&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;어떤 특정 모델을 학습시키지 않고 싶다면&lt;/strong&gt; 그 모델의 parameter들을 모두 requires_grad = False로 만들면 된다. &lt;strong&gt;nn.module.requires_grad_(False) 함수를 사용하자.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;550&quot; src=&quot;/assets/img/pytorch/requires/3.jpeg&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;gradient-context&quot;&gt;Gradient context&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;텐서들의 requires_grad와는 별개로 gradient graph를 다루는 context blcok들이 존재한다.&lt;/li&gt;
  &lt;li&gt;첫번째로 &lt;strong&gt;grad mode&lt;/strong&gt;는 가장 기본적인 mode로써 requires_grad = True인 텐서들에 대한 gradient graph를 계산하는 것으로 default context이다.&lt;/li&gt;
  &lt;li&gt;두번쨰는 &lt;strong&gt;no_grad mode&lt;/strong&gt;로써 context box 내부에 있는 텐서 연산들은 모두 &lt;strong&gt;gradient graph를 만들지 않으며&lt;/strong&gt; 그 뜻은 gradient function, &lt;strong&gt;새로운 intermediate tensor를 만들지 않고 leaf tensor만을 만드는 context이다.&lt;/strong&gt; 텐서들을 모두 requires_grad=False로 가정하고 계산한 뒤에 &lt;strong&gt;동일한&lt;/strong&gt; 텐서에 대해서 requires_grad를 True로 바꾼다. 즉 &lt;strong&gt;값만 바꾼다고 생각하면 된다.&lt;/strong&gt; 주의할 점은 동일한 텐서라는 점이다. &lt;strong&gt;이름만 같은 다른 텐서는 requires_grad를 True로 바꾸지 않는다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;/assets/img/pytorch/requires/4.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;마지막으로는 &lt;strong&gt;inference mode&lt;/strong&gt;가 있다. 이것은 no_grad mode는 해당 context에서만 gradient flow를 생성하지 않고 context에서 출력한 output은 새로 grad mode에서 gradient graph를 만들 수 있다. 하지만 &lt;strong&gt;inference mode에서는&lt;/strong&gt; 이것조차 불가하여 해당 &lt;strong&gt;context에서 계산을 한 Tensor는 grad mode로 옮기더라도 더이상 gradient graph를 만들 수 없다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;700&quot; src=&quot;/assets/img/pytorch/requires/5.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;별개로 module의 &lt;strong&gt;evalution mode&lt;/strong&gt;는 requires_grad와는 별개의 기술이다. model.eval()으로 한다고 해서 &lt;strong&gt;requires_grad를 False로 계산하지 않는다.&lt;/strong&gt; nn.Batchnorm과 nn.dropout 같은 Train과 Evalution에 다르게 적용되어야 하는 operation을 위함이다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;in-place-operation&quot;&gt;in-place operation&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;in-place operation이란&lt;/strong&gt; 연산할 시에 새로운 객체를 만드는 것이 아닌 연산과 동시에 값을 대입하는 operation을 말한다. 예륻 들면 x += 5 같은 더하기 연산이 있다.&lt;/li&gt;
  &lt;li&gt;autograd 시스템에서도 in-place operation은 허락되어진다. 하지만 많은 경우에서 &lt;strong&gt;안정성이 좋지 않으며&lt;/strong&gt; out place operation을 사용하는 것을 추천한다.&lt;/li&gt;
  &lt;li&gt;requires_grad = True인 leaf tensor의 경우 in-place operation을 사용하는 것에 주의해야한다. Pytorch에서는 &lt;strong&gt;requires_grad가 True인 텐서가 어떤 연산을 수행할 경우 자동으로 gradient graph를 만들며&lt;/strong&gt; 연산의 결과로 grad_fn과 함께 intermediate tensor를 출력한다. 하지만 &lt;strong&gt;leaf tensor의 경우 grad_fn이 없는 텐서&lt;/strong&gt;를 의미하고 파이토치는 &lt;strong&gt;in-place operation을 통해 leaf tensor를 intermediate tensor로 변경하는 것을 허용하지 않는다.&lt;/strong&gt; 그러나 &lt;strong&gt;no grad mode 상에서는 requires_grad를 False로 만들고 계산을 하고, grad_fn을 만들지 않기 때문에 in-place operation이 허용된다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;700&quot; src=&quot;/assets/img/pytorch/requires/6.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;no grad mode와 함께 in-place operation을 사용하는 경우로 모델의 Parameter를 초기화할 경우가 있다.&lt;/strong&gt; 이 경우에서는 in-place operation만을 사용해야 실수를 안하기 쉽다. 예를 들면 모델을 생성하고 optimizer에 모델의 파라미터를 등록한 후, 모델의 파라미터를 out place operation을 통해 초기화한다면 &lt;strong&gt;optimizer가 가지고 있는 모델의 파라미터와 실제 모델이 가지고 있는 파라미터가 다른 텐서라서 학습이 진행되지 않는다.&lt;/strong&gt; 그렇기에 파라미터 초기화에는 in-place operation이 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;/assets/img/pytorch/requires/7.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;intermediate tensor의 in-place operation은 파이토치에서 오류를 내보내지 않는다.&lt;/strong&gt; 그렇다고 파이토치에서 in-place operation을 사용하는 것을 권하지는 않는다. 그럼 어떻게 intermediate tensor에서는 in-place operation이 가능한걸까??&lt;/li&gt;
  &lt;li&gt;기본적으로 requires_grad가 True인 tensor는 operation실행 시 gradient graph을 그리게 되고 gradient function와 함께 saved tensor를 저장한다. 하지만 &lt;strong&gt;in-place operation은 자기 자신의 tensor의 값을 바꿔버린다.&lt;/strong&gt; 그러면 &lt;strong&gt;saved tensor와 operation 결과의 tensor는 동일한 객체지만 값이 달라져야하는 현상이 생긴다.&lt;/strong&gt; pytorch에서는 이 문제를 자체적으로 해결해 주는데 &lt;strong&gt;input tensor를 clone하여 saved tensor로 저장하고 input tensor는 그대로 operation을 계산하여 출력된다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;/assets/img/pytorch/requires/8.png&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;tip&quot;&gt;tip&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;모델의 파라미터는 tensor 객체가 아닌 nn.Parameters() 객체를 가리켜야한다. nn.Parameters()는 tensor를 wrap한 것으로 tensor와 동일한데 후에 model.parameters()를 통해 해당 모델의 nn.Parameters()객체를 제너레이터형태로 끌어모을 수 있다.&lt;/li&gt;
  &lt;li&gt;optimizer는 초기화할 때, 모델의 파라미터를 넣기 때문에 모델의 파라미터의 값과 grad를 알 수 있다. 물론 업데이트를 해야하기 때문에 값 복사가 아닌 참조이다.&lt;/li&gt;
  &lt;li&gt;optim.zero_grad는 optimizer가 가지고 있는 모델의 파라미터의 grad를 모두 0으로 초기화한다. 그렇기 때문에 반드시 그레디언트를 계산하기 전(backward 앞)이나 모델의 파라미터를 업데이트한 후(optim.step) 불러와야 한다. backward와 optim.step 사이에 넣는다면 grad 값은 0으로 초기화 되기 때문에 모델의 파라미터가 업데이트 되지 않는다.&lt;/li&gt;
&lt;/ul&gt;</content><author><name>&lt;Lee&gt; &lt;Jongyeon&gt;</name><email>&lt;lee0301jy@naver.com&gt;</email></author><category term="pytorch" /><summary type="html">참고 [1] https://pytorch.org/docs/stable/notes/autograd.html [2] https://medium.com/@mrityu.jha/understanding-the-grad-of-autograd-fc8d266fd6cf</summary></entry><entry><title type="html">Cross Entropy</title><link href="https://tinnunculus.github.io/pytorch/2022-05-31-cross_entropy/" rel="alternate" type="text/html" title="Cross Entropy" /><published>2022-05-31T00:00:00+00:00</published><updated>2022-05-31T00:00:00+00:00</updated><id>https://tinnunculus.github.io/pytorch/cross_entropy</id><content type="html" xml:base="https://tinnunculus.github.io/pytorch/2022-05-31-cross_entropy/">&lt;p&gt;&lt;strong&gt;참고&lt;/strong&gt;&lt;br /&gt;
[1] &lt;a href=&quot;https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html&quot;&gt;https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html&lt;/a&gt;&lt;br /&gt;
[2] &lt;a href=&quot;https://pytorch.org/docs/stable/generated/torch.nn.BCELoss.html&quot;&gt;https://pytorch.org/docs/stable/generated/torch.nn.BCELoss.html&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot; id=&quot;markdown-toc-introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cross-entropy&quot; id=&quot;markdown-toc-cross-entropy&quot;&gt;Cross entropy&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#binary-cross-entropy&quot; id=&quot;markdown-toc-binary-cross-entropy&quot;&gt;Binary Cross Entropy&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cross-entropy-1&quot; id=&quot;markdown-toc-cross-entropy-1&quot;&gt;cross entropy&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#unnormalized-input-tensor를-입력으로-받는-이유&quot; id=&quot;markdown-toc-unnormalized-input-tensor를-입력으로-받는-이유&quot;&gt;Unnormalized input tensor를 입력으로 받는 이유&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;논문 코드를 구현하던 중 official 코드의 결과 값과 직접 구현한 코드의 결과 값의 차이가 많아 원인을 찾는 중에 발견한 그동안에 모르고 있었던 pytorch의 cross entropy 메소드에 대한 &lt;strong&gt;치명적인 실수&lt;/strong&gt;에 대한 짧은 글이다.&lt;/li&gt;
  &lt;li&gt;cross entropy는 &lt;strong&gt;KL divergence&lt;/strong&gt;의 식에서 유래한 objective fucntion이다. 그렇기 때문에 함수의 입력으로 들어가는 텐서들은 &lt;strong&gt;확률 값&lt;/strong&gt;을 나타내며 값이 0부터 1까지 &lt;strong&gt;normalize&lt;/strong&gt; 되어 있어야 한다.&lt;/li&gt;
  &lt;li&gt;하지만 pytorch의 cross entropy method는 &lt;strong&gt;unnormalized 데이터를 입력으로 받아&lt;/strong&gt; 내부에서 &lt;strong&gt;softmax&lt;/strong&gt;를 통해 normalize를 시킨다.&lt;/li&gt;
  &lt;li&gt;pytorch의 binary cross entropy method는 &lt;strong&gt;normalized 데이터를 입력으로 받는다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;pytorch의 binary cross entropy with logits method는 &lt;strong&gt;unnormlized 데이터를 입력으로 받아&lt;/strong&gt; 내부에서 sigmoid를 통해 normlized를 시킨다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;cross-entropy&quot;&gt;Cross entropy&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Cross entropy는 &lt;strong&gt;KL divergence&lt;/strong&gt;에서 유래한 식이다.&lt;/li&gt;
  &lt;li&gt;\(p(x)\)를 정답 labels라고 한다면 KL divergence 식에서 고정된 상수의 식을 제외한 항을 Cross Entropy라고 부르며, &lt;strong&gt;KL divergence를 최소화하는 것은 Cross Entropy를 최소화하는 것과 같다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;일반적으로 Classification 문제를 다룰 때, &lt;strong&gt;objective function으로 cross entropy&lt;/strong&gt;를 많이 사용한다.&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
  D_{KL}(p||q) = E_{x \sim p}[log(p(x))] - E_{x \sim p}[log(q(x))] \\[1em]
  CrossEntropy : H(p, q) = - E_{x \sim p}[log(q(x))] \\[1em]
                          = - \sum p(x)log(q(x))
\end{aligned}\]

&lt;h2 id=&quot;binary-cross-entropy&quot;&gt;Binary Cross Entropy&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;경우의 수가 True, Falce 두개인&lt;/strong&gt; Binary Classification 문제를 풀 땐, objective function으로 &lt;strong&gt;Binary cross entropy&lt;/strong&gt; 함수를 이용한다.&lt;/li&gt;
  &lt;li&gt;머신러닝 문제에서 입력되는 데이터를 \(x\)라 칭하고 모델의 결과 값을 y라고 칭한다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ground truth는 \(p(y \| x)\)이며&lt;/strong&gt;, 확률 변수 y가 가질 수 있는 데이터가 0과 1이기 때문에 &lt;strong&gt;\(p(y \| x)\) 는 Bernoulli distribution 이다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;우리의 모델&lt;/strong&gt; 또한 likelihood function이 &lt;strong&gt;Bernoulli distribution \(q(y\|x)\)을 따른다고 가정하며&lt;/strong&gt;, &lt;strong&gt;binary cross entropy 함수를 이용하여 bernoulli distribution의 parameter p = \(q(y=1\|x)\)를 구하는 학습을 진행한다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;대개의 경우 classification 문제이기 때문에 &lt;strong&gt;ground truth \(p(y\|x)\)는 \(p(y=1\|x) = 1 \text{ or } 0\) 의 값&lt;/strong&gt;을 나타낸다.&lt;/li&gt;
  &lt;li&gt;\(P(y=1\|x) = 1\)일 경우&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
  CrossEntropy : H(p, q) = - E_{y|x \sim p}[log(q(y|x))] \\[1em]
                          = - \sum p(y|x)log(q(y|x)) \\[1em]
                          = -log(q(y=1|x)) \\[1em]
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;\(P(y=1\|x) = 0\)일 경우&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
  CrossEntropy : H(p, q) = - E_{y|x \sim p}[log(q(y|x))] \\[1em]
                          = - \sum p(y|x)log(q(y|x)) \\[1em]
                          = -(1-log(q(y=1|x))) \\[1em]
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;Pytorch에서 &lt;strong&gt;binary cross entropy와 관련된 메소드는 두개&lt;/strong&gt;가 있다.&lt;/li&gt;
  &lt;li&gt;torch.nn.functional.binary_cross_entropy() 함수는 input tensor와 target tensor가 &lt;strong&gt;동일한 shape&lt;/strong&gt;을 가지고 있어야 하며, input tensor는 &lt;strong&gt;nomalized tensor&lt;/strong&gt;여야만 한다.&lt;/li&gt;
  &lt;li&gt;torch.nn.functional.binary_cross_entropy_with_logits() 함수도 마찬가지로 input tensor와 target tensor가 &lt;strong&gt;동일한 shape&lt;/strong&gt;을 가지고 있어야 하며, input tensor는 &lt;strong&gt;unnolized tensor&lt;/strong&gt;이고 내부에서 자체적으로 sigmoid 함수를 걸친다. 그렇기 때문에 따로 &lt;strong&gt;모델의 결과 값에 sigmoid를 넣지 않도록 해야만 한다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;input tensor 와 target tensor가 동일한 shape을 가지고 있어야 하는 이유는 &lt;strong&gt;tensor의 값 하나하나가 독립적인 하나의 확률 변수, 확률 분포라고 생각하기 때문이다.&lt;/strong&gt; 이것은 binary cross entropy 뿐만 아니라 cross entropy 함수도 동일하게 적용된다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;cross-entropy-1&quot;&gt;cross entropy&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;주로 경우의 수가 &lt;strong&gt;두개가 아닌 Classification 문제를 풀 때 사용하는 objective function이다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;경우의 수가 두개가 아니기 때문에 ground truth는 Bernoulli distribution의 multinomial variable 버전?인 &lt;strong&gt;Dirichlet distribution 이다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;ground truth는 \(p(y\|x)\)이며, 확률 변수 &lt;strong&gt;y = 0 ~ N 의 정수 값&lt;/strong&gt;을 가질 수 있다. ground truth는 one hot encoding하지 않도록 한다.&lt;/li&gt;
  &lt;li&gt;우리의 모델 또한 likelyhood function으로 Dirichlet distribution \(q(y\|x)\)을 따르고, parameter가 &lt;strong&gt;1개인 Bernoulli distribution과는 달리 여러개(N개)의 parameter&lt;/strong&gt;를 가지기 때문에 &lt;strong&gt;결과 값도 N개가 되어야 한다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;binary variables 때와 마찬가지로 대개의 경우 classification 문제이기 때문에 ground truth는 &lt;strong&gt;하나의 값에만 확률 값이 1&lt;/strong&gt;이고 나머지는 0인 분포를 띈다.&lt;/li&gt;
  &lt;li&gt;\(P(y=n\|x) = 1\) 일 경우&lt;/li&gt;
&lt;/ul&gt;

\[\begin{aligned}
  CrossEntropy : H(p, q) = - E_{y|x \sim p}[log(q(y|x))] \\[1em]
                          = - \sum p(y|x)log(q(y|x)) \\[1em]
                          = -log(q(y=n|x))) \\[1em]
\end{aligned}\]

&lt;ul&gt;
  &lt;li&gt;torch.nn.functional.cross_entropy() 함수는 input tensor와 target tensor가 &lt;strong&gt;다른 shape을 띄고 있다.&lt;/strong&gt; input tensor는 &lt;strong&gt;Dirichlet distribution의 파라미터 수(C)에 대해서의 값&lt;/strong&gt;을 가지고 있어야 하므로 &lt;strong&gt;(C) 혹은 (N, C) 혹은 (N, C, d_1, d_2, … , d_n)의 shape&lt;/strong&gt;을 가지고 &lt;strong&gt;target tensor는 classification 문제이기 때문에 어떤 값이 1인지 만 나타내면 되어서 (,) 혹은 (N) 혹은 (N, d_1, d_2, …, d_n)의 shape&lt;/strong&gt;을 가지고 있어야 한다. 혹은 &lt;strong&gt;classification 문제가 아닌 일반적인 문제일 경우 target tensor는 input tensor와 동일한 shape을 가지고 있으면 된다.&lt;/strong&gt; 두 경우 모두 C를 제외하면 동일한 shape을 가지고 있어야 하며 &lt;strong&gt;C 채널이 항상 가장 마지막에 있는 것이 아닌 두번째에 존재하는 것을 인지&lt;/strong&gt;해야 한다. 또한 &lt;strong&gt;unnormalized input tensor&lt;/strong&gt;를 입력으로 받고 내부에서 &lt;strong&gt;자체적으로 softmax 함수를 취한다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;bernoulli distribution의 경우에서는 입력 데이터 모두가 독립적인 확률 분포로 쓰였지만 &lt;strong&gt;dirichlet distribution의 경우에서는 입력 텐서의 C채널이 모두 하나의 확률 분포&lt;/strong&gt;를 나타내기 위해 쓰여진다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;unnormalized-input-tensor를-입력으로-받는-이유&quot;&gt;Unnormalized input tensor를 입력으로 받는 이유&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;논리적으로는 사용자가 직접 sigmoid나 softmax 함수를 통해 normalize를 한 후에 cross entropy에 입력으로 넣는게 맞는 것 같지만, 최근 파이토치 함수에서는 Unnormalized input tensor을 입력으로 받고 자체적으로 normalize를 한다.&lt;/li&gt;
  &lt;li&gt;정확하게 그렇게 취한 이유는 잘 모르겠지만 사용자가 실수하는 것을 줄이기 위해 하는 건지… normalize 과정과 cross entropy 계산 과정을 합침으로써 더 학습에 안정적으로 수식을 수정하는 방법이 있어서 그런건지는 잘 모르겠다…&lt;/li&gt;
  &lt;li&gt;그냥 인지하고 있자.&lt;/li&gt;
&lt;/ul&gt;</content><author><name>&lt;Lee&gt; &lt;Jongyeon&gt;</name><email>&lt;lee0301jy@naver.com&gt;</email></author><category term="pytorch" /><summary type="html">참고 [1] https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html [2] https://pytorch.org/docs/stable/generated/torch.nn.BCELoss.html</summary></entry><entry><title type="html">Mask2Former</title><link href="https://tinnunculus.github.io/paper/2022-05-26-mask2former/" rel="alternate" type="text/html" title="Mask2Former" /><published>2022-05-26T00:00:00+00:00</published><updated>2022-05-26T00:00:00+00:00</updated><id>https://tinnunculus.github.io/paper/mask2former</id><content type="html" xml:base="https://tinnunculus.github.io/paper/2022-05-26-mask2former/">&lt;p&gt;&lt;strong&gt;참고&lt;/strong&gt;&lt;br /&gt;
[1] &lt;a href=&quot;https://arxiv.org/abs/2112.01527&quot;&gt;https://arxiv.org/abs/2112.01527&lt;/a&gt;&lt;br /&gt;
[2] &lt;a href=&quot;https://github.com/facebookresearch/Mask2Former&quot;&gt;https://github.com/facebookresearch/Mask2Former&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;코드&lt;/strong&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/tinnunculus/Mask2Former/blob/master/mask2former.ipynb&quot;&gt;https://github.com/tinnunculus/Mask2Former/blob/master/mask2former.ipynb&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot; id=&quot;markdown-toc-introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#contribution&quot; id=&quot;markdown-toc-contribution&quot;&gt;Contribution&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#mask-classification-preliminaries&quot; id=&quot;markdown-toc-mask-classification-preliminaries&quot;&gt;Mask classification preliminaries&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#masked-attention&quot; id=&quot;markdown-toc-masked-attention&quot;&gt;masked attention&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#multi-scale-features&quot; id=&quot;markdown-toc-multi-scale-features&quot;&gt;Multi-scale features&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#optimization-improvements&quot; id=&quot;markdown-toc-optimization-improvements&quot;&gt;Optimization improvements&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#improving-training-efficiency&quot; id=&quot;markdown-toc-improving-training-efficiency&quot;&gt;Improving training efficiency&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;MaskFormer의 후속 논문이다. MaskFormer와 거의 유사한 모델 구조를 가진다.&lt;/li&gt;
  &lt;li&gt;이 논문 또한 MaskFormer와 마찬가지로 여러 Segmentation task를 하나의 통합된(universal) 모델 구조로 처리할 수 있는 것을 다룬다.&lt;/li&gt;
  &lt;li&gt;MaskFormer는 기존의 universal 모델들보다 좋은 성능을 보여주었지만, 여전히 &lt;strong&gt;task speicific한 모델들에 비해 단점이 존재했다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;MaskFormer는 Performance 측면에서 task specific한 모델에 비해 약간 좋거나 나쁜 수준이었지만, &lt;strong&gt;시간 복잡도와 메모리 복잡도 측면에서 매우 비효율적&lt;/strong&gt;인 모습을 보여주었다.&lt;/li&gt;
  &lt;li&gt;특히 MaskFormer는 이미지 한장(800, 600)을 학습하기 위해서는 &lt;strong&gt;32기가의 GPU 메모리&lt;/strong&gt;를 필요로 한다.&lt;/li&gt;
  &lt;li&gt;또한 MaskFormer는 task specific한 모델에 비해 학습의 시간과 수렴에 어려움이 있다.&lt;/li&gt;
  &lt;li&gt;이러한 퍼포먼스와 학습 및 수렴, 메모리 효율의 문제를 해결하기 위해 Mask2Former 모델을 제안한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;contribution&quot;&gt;Contribution&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Mask2Former는 모델의 성능을 개선하기 위해 Transformer decoder에 사용되는 &lt;strong&gt;masked attention&lt;/strong&gt;을 제안하였다. masked attention은 query와 key의 attention score를 계산할 때, 모든 영역에 대하여 계산하는 것이 아닌 &lt;strong&gt;이전 layer에서 추출한 mask의 영역에서만 attention을 계산하도록 한다.&lt;/strong&gt; 구현 상 효율성(시간, 메모리)를 개선하지는 않지만, &lt;strong&gt;더 빠른 수렴과 퍼포먼스의 증가를 보여주었다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;pixel-decoder의 하나의 feature map을 사용하는 것이 아닌 &lt;strong&gt;여러(3개) layer를 사용하여 Transformer decoder의 key, value로 사용하였다.&lt;/strong&gt; MaskFormer에서는 마지막 layer의 low resolution feature map만을 사용하였다.&lt;/li&gt;
  &lt;li&gt;Transformer layer의 &lt;strong&gt;self attention layer와 cross attention layer의 순서를 바꿨다.&lt;/strong&gt; 이것은 모델의 학습을 개선하는 효과를 내었다.&lt;/li&gt;
  &lt;li&gt;Transformer 모델에 &lt;strong&gt;dropout을 없앴다.&lt;/strong&gt; dropout은 모델의 성능에 영향을 주지 않고, 오히려 학습의 수렴에 방해하였다.&lt;/li&gt;
  &lt;li&gt;학습 시, mask loss를 계산하는 과정에서 &lt;strong&gt;모든 Pixel에 대해서 계산하는 것이 아닌 임의로 추출된 Pixel group에 대해서만 계산&lt;/strong&gt;하는 방법으로 성능은 유지하면서 메모리 효율성을 높였다.&lt;/li&gt;
  &lt;li&gt;MaskFormer와는 달리 Pixel decoder로 FPN이 아닌 &lt;strong&gt;Deformable Transformer를 사용하였다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;mask-classification-preliminaries&quot;&gt;Mask classification preliminaries&lt;/h2&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;700&quot; src=&quot;/assets/img/paper/mask2former/1.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Mask2Former는 전체적으로 MaskFormer와 동일한 구조를 가지고 있다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;N&lt;/strong&gt;개의 &lt;strong&gt;bianary mask&lt;/strong&gt;와 &lt;strong&gt;class labels&lt;/strong&gt;를 추출하는 것을 목표로 한다.&lt;/li&gt;
  &lt;li&gt;Backbone 모델을 이용해서 이미지로부터 &lt;strong&gt;multi-scale feature map&lt;/strong&gt;들을 추출한다.&lt;/li&gt;
  &lt;li&gt;Pixel decoder를 통해 multi scale feature map으로부터 &lt;strong&gt;multi-scale feature map&lt;/strong&gt;을 추출한다. per-pixel embedding은 나중에 mask embedded vector와 함께 mask segmentation을 만드는데 사용된다.&lt;/li&gt;
  &lt;li&gt;Transformer decoder는 고정된 N개의 object queries와 Pixel decoder로부터 multi-scale feature map을 입력으로 받아 N개의 &lt;strong&gt;embedded vector를&lt;/strong&gt; 추출한다. 이것은 선현 변환과 함께 N개의 class labels 결과를 내고, per-pixel embeded matrics와 함께 mask segmentation 결과를 낸다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;masked-attention&quot;&gt;masked attention&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;기존의 일반적인 &lt;strong&gt;cross attention을 대체하는&lt;/strong&gt; 새로운 attention 알고리즘이다.&lt;/li&gt;
  &lt;li&gt;cross attention과는 달리 &lt;strong&gt;모든 영역에 대해서 attention score 값을 계산하지 않는다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;이 전&lt;/strong&gt;의 Transformer decoder layer로 부터 뽑은 결과로 부터 &lt;strong&gt;mask를 추출해서 mask가 있는 영역(foreground)만을 attention 계산을 한다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;연산량은 동일하다.&lt;/strong&gt; 하지만 이것은 &lt;strong&gt;퍼포먼스를 증가시킨다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;다음 Layer이기 때문에 &lt;strong&gt;이미 이 전의 Layer의 결과물이 반영된 것&lt;/strong&gt;이다. 그럼에도 불구하고 mask를 씌우는 것은 일종의 dropout 같은 효과인데 랜덤하게 out 시키는 것이 아닌 흥미 없는 부분을 out 시켜서 &lt;strong&gt;더 강하게 attention 하는 것&lt;/strong&gt;이라고 볼 수 있다.&lt;/li&gt;
  &lt;li&gt;너무 영역을 제한해서 &lt;strong&gt;중요한 영역도 버릴 수 있지 않나&lt;/strong&gt;라고 생각이 들 수도 있지만 뒷 단에 나오는 &lt;strong&gt;self attention을 통해서 그 점을 보완&lt;/strong&gt;해준다.&lt;/li&gt;
  &lt;li&gt;중간 Layer마다 mask를 뽑고 사용하기 때문에 &lt;strong&gt;axial training&lt;/strong&gt;을 같이 해주면 도움이 될 듯하다.&lt;/li&gt;
  &lt;li&gt;masked attention layer의 구체적인 연산은 아래와 같다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;450&quot; src=&quot;/assets/img/paper/mask2former/2.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;450&quot; src=&quot;/assets/img/paper/mask2former/3.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;\(X_l \in R^{N \times C}\) 은 \(l\)번째 layer의 결과물을 나타내고 \(X_0\)는 Transformer decoder에 입력으로 들어가는 queries vector들이다.&lt;/li&gt;
  &lt;li&gt;\(K_l, V_l \in R^{H_lW_l \times C}\) 는 Pixel decoder로부터 Transformer decoder에 \(l\) 번째 layer로 들어가는 image feature를 나타낸다.&lt;/li&gt;
  &lt;li&gt;\(M_{l-1}\) 은 Trasnformer decoder의 이전 layer로부터 뽑은 결과로부터 mask를 추출(&lt;strong&gt;per-pixel embeddings&lt;/strong&gt;와 함께)한 것이다. per-pixel embeddings의 이미지 사이즈이기 때문에 resize를 거쳐준다.&lt;/li&gt;
  &lt;li&gt;\(M_0\) 는 Transformer decoder의 입력으로 들어가는 query vector로 부터 추출한다. &lt;strong&gt;의미가 없어 보일 수 있지만&lt;/strong&gt; query vector는 학습 가능한 벡터이기에 &lt;strong&gt;학습이 진행되면 진행될 수록 의미있는&lt;/strong&gt; mask가 추출될 것이다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;multi-scale-features&quot;&gt;Multi-scale features&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;이전의 MaskFormer와는 다르게 Mask2Former에서는 Pixel decoder의 최종 출력 feature map만이 아닌 중간중간의 layer로 부터 나온 feature map을 활용한다. MaskFormer는 low resolution feature map만을 사용하였다.&lt;/li&gt;
  &lt;li&gt;pixel-decoder로 부터 1/32, 1/16, 1/8 크기의 feature map을 추출한다. &lt;strong&gt;1/4는 추출하지 않는데 1/8 feature map을 단순히 upsampling 하여서 per-pixel embeddings&lt;/strong&gt;를 만든다. 즉 1/4 feature map은 transformer decoder에 들어가지 않고 mask를 뽑는데에만 사용된다.&lt;/li&gt;
  &lt;li&gt;거기에 고정된 sinusoidal positional embedding을 더한다. \(e_{pos} \in R^{H_lW_l \times C}\)&lt;/li&gt;
  &lt;li&gt;거기에 scale-level embedding도 곱한다. \(e_{lvl} \in R^{1 \times C}\)&lt;/li&gt;
  &lt;li&gt;이 세개의 레이어를 Transformer decoder에 L번 반복해서 넣으며, 그 결과로 Transformer decoder의 layer 수는 총 3L개가 존재하게 된다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;optimization-improvements&quot;&gt;Optimization improvements&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;기존의 일반적이 Transformer와는 달리 &lt;strong&gt;self attention 과 masked attention의 위치를 바꾸었다.&lt;/strong&gt; 이것은 논리적으로 더 옳다고 볼 수 있다. 처음 queries vector들은 아무런 의미가 없는 정보이기 때문.&lt;/li&gt;
  &lt;li&gt;모든 layer에서 &lt;strong&gt;Dropout을 없앴다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;improving-training-efficiency&quot;&gt;Improving training efficiency&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;전체적인 학습 방법은 기존의 MaskFormer와 동일하다.&lt;/li&gt;
  &lt;li&gt;hungarian maching과 objective function에 쓰인 &lt;strong&gt;mask loss를 개선했다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;기존의 mask loss는 &lt;strong&gt;모든 픽셀에 대해서 distance를 계산하였지만&lt;/strong&gt; 여기서는 &lt;strong&gt;임의의 픽셀을 추출해서&lt;/strong&gt; 그 픽셀에 대해서만 distance를 계산하였다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;maching&lt;/strong&gt;을 위한 mask loss를 계산할 시에는 &lt;strong&gt;uniform&lt;/strong&gt; 하게 &lt;strong&gt;모두 동일한 위치&lt;/strong&gt;의 pixel을 sampling 했으며, &lt;strong&gt;학습&lt;/strong&gt;을 위한 mask loss 계산을 위해서는 uniform 하지 않고 foreground에 더 중점적으로 sampling을 했으며 mask마다 다른 pixel group을 sampling 하였다.&lt;/li&gt;
  &lt;li&gt;sampling시에 사용한 함수로는 &lt;strong&gt;grid_sample&lt;/strong&gt; 함수를 사용하였다. 중복의 픽셀을 선택할 수도 있지만 이 논문에서는 이미지 크기의 비율을 줄이는 것이 아닌 &lt;strong&gt;고정된 픽셀 수&lt;/strong&gt;를 샘플리 하였기에 샘플링 수 보다 이미지 크기가 작을 수도 있다. 그렇기에 매 &lt;strong&gt;샘플링 마다 독립시행&lt;/strong&gt;으로 샘플링을 진행하였다.&lt;/li&gt;
  &lt;li&gt;1/3 수준으로 메모리가 절약했지만 퍼포먼스에는 영향을 미치지 않았다.&lt;/li&gt;
&lt;/ul&gt;</content><author><name>&lt;Lee&gt; &lt;Jongyeon&gt;</name><email>&lt;lee0301jy@naver.com&gt;</email></author><category term="paper" /><summary type="html">참고 [1] https://arxiv.org/abs/2112.01527 [2] https://github.com/facebookresearch/Mask2Former</summary></entry><entry><title type="html">MaskFormer</title><link href="https://tinnunculus.github.io/paper/2022-05-12-maskformer/" rel="alternate" type="text/html" title="MaskFormer" /><published>2022-05-12T00:00:00+00:00</published><updated>2022-05-12T00:00:00+00:00</updated><id>https://tinnunculus.github.io/paper/maskformer</id><content type="html" xml:base="https://tinnunculus.github.io/paper/2022-05-12-maskformer/">&lt;p&gt;&lt;strong&gt;참고&lt;/strong&gt;&lt;br /&gt;
[1] &lt;a href=&quot;https://arxiv.org/abs/2107.06278&quot;&gt;https://arxiv.org/abs/2107.06278&lt;/a&gt;&lt;br /&gt;
[2] &lt;a href=&quot;https://github.com/facebookresearch/MaskFormer&quot;&gt;https://github.com/facebookresearch/MaskFormer&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;코드&lt;/strong&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/tinnunculus/MaskFormer/blob/master/maskformer.ipynb&quot;&gt;https://github.com/tinnunculus/MaskFormer/blob/master/maskformer.ipynb&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot; id=&quot;markdown-toc-introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#mask-classification-formulation&quot; id=&quot;markdown-toc-mask-classification-formulation&quot;&gt;Mask classification formulation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#mask-classification-inference&quot; id=&quot;markdown-toc-mask-classification-inference&quot;&gt;Mask classification inference&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#general-inference&quot; id=&quot;markdown-toc-general-inference&quot;&gt;General inference&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#semantic-inference&quot; id=&quot;markdown-toc-semantic-inference&quot;&gt;Semantic inference&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;ul&gt;
    &lt;li&gt;MaskFormer는 Object dectection 모델인 &lt;strong&gt;DETR을 segmentation task에 맞게&lt;/strong&gt; 수정한 모델이라고 볼 수 있다.&lt;/li&gt;
    &lt;li&gt;그렇기 때문에 핵심 개념인 모델의 구조와 학습 방법으로는 DETR 모델과 거진 &lt;strong&gt;유사&lt;/strong&gt;하다.&lt;/li&gt;
    &lt;li&gt;기존에는 semantic, instance, panoptic 등의 여러가지 segmentation 문제마다 다르게 접근하여 문제를 풀었지만, 이 논문에서는 &lt;strong&gt;하나의 학습된&lt;/strong&gt; MaskFormer 모델로 inference 방법만 task 마다 다르게 하여 앞에 언급한 segmentation 문제를 모두 풀 수 있다.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;mask-classification-formulation&quot;&gt;Mask classification formulation&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;700&quot; src=&quot;/assets/img/paper/maskformer/1.png&quot; /&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;DETR 모델에서는 object detection 모델이기에 트랜스포머의 Query 토큰들이 가리키는 것은 object box 정보였다면 MaskFormer에서는 &lt;strong&gt;segmentation 정보의 embedding vector&lt;/strong&gt;를 가리킨다.&lt;/li&gt;
    &lt;li&gt;이 embedding vector는 후에 per-pixel embedding tensor와 곱셈 연산을 통해 &lt;strong&gt;mask segmentation&lt;/strong&gt; 정보를 가리키고 linear mapping을 통해 mask의 &lt;strong&gt;class 정보&lt;/strong&gt;를 기리키게 된다.&lt;/li&gt;
    &lt;li&gt;나머지 개념은 DETR과 동일하다. class는 no object를 포함하고 있고, bipartite maching을 통해 prediction 정보와 ground truth 정보를 1대1 mapping 하고 학습을 진행한다.&lt;/li&gt;
    &lt;li&gt;hungarian matching의 score 함수로 \(-p_i(c^{gt}_j) + L_{mask}(m_i, m^{gt}_j)\) 를 사용하여 bipartite matching 을 진행한다.&lt;/li&gt;
    &lt;li&gt;또한 학습 objective function으로는 아래의 식을 사용하였다.&lt;/li&gt;
    &lt;li&gt;참고로 위의 그림에서 H, W는 원본 이미지의 H, W가 아니다. 0.25배 축소된 크기의 H, W이다.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;600&quot; src=&quot;/assets/img/paper/maskformer/2.png&quot; /&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;mask loss는 DETR과 동일하게 &lt;strong&gt;focal loss&lt;/strong&gt;와 &lt;strong&gt;dice loss&lt;/strong&gt;의 linear combination으로 계산한다.&lt;/li&gt;
    &lt;li&gt;정답 mask는 binary이기에 예측한 mask는 sigmoid를 한번 걸친다. 그렇기에 l1,l2 distance 보다는 cross entropy 계열의 cost가 적합하고, 여기서는 더 구체적으로 focal loss를 사용하였다.&lt;/li&gt;
    &lt;li&gt;또한 iou 계열의 cost인 dice loss도 함께 사용하였다.&lt;/li&gt;
    &lt;li&gt;다른 Transformer 모델들과 같이 필요에 따라 auxiliary loss(transformer decoder의 layer마다 결과를 출력하여 loss를 매김)를 같이 학습할 수도 있다.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;mask-classification-inference&quot;&gt;Mask classification inference&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;ul&gt;
    &lt;li&gt;MaskFormer 모델 그 자체로는 단순히 N개의 binary segmentation(sigmoid by pixel) 정보와 class(softmax) 정보만을 가지고 있다.&lt;/li&gt;
    &lt;li&gt;여러 Task에 적합하게 MaskFormer를 inference해야만 한다.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;general-inference&quot;&gt;General inference&lt;/h3&gt;
  &lt;blockquote&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;픽셀마다 가장 확률 값이 높은 class를 고르는 것&lt;/strong&gt;으로 가장 기본적으로 접근할 수 있는 방법이다.&lt;/li&gt;
      &lt;li&gt;semantic segmentation을 위해서는 픽셀마다 class 하나 만을 뽑으면 된다.&lt;/li&gt;
      &lt;li&gt;instance-level segmentation을 위해서는 같은 클래스의 다른 &lt;strong&gt;mask index를 통해 instance&lt;/strong&gt;들을 구분한다.&lt;/li&gt;
      &lt;li&gt;panoptic segmentation을 위해서는 false positive 비율을 줄이기 위해 뭔 짓을 했는데 아직 잘 모르겟다!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!&lt;/li&gt;
      &lt;li&gt;각각의 \(mask_i\)에서 가장 확률 값이 높은 class \(c_i\) 를 뽑는다. ( \(c_i = argmax_{c\in\{1,...,K,\varnothing\}}{p_i(c)}\) )&lt;/li&gt;
      &lt;li&gt;이미지의 모든 픽셀 [h, w] 각각에 대해서 가장 predicted probability 값이 높은 class를 고른다. ( \(argmax_{i:c_i\neq\varnothing}p_i(c_i) \cdot m_i[h, w]\) )&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/blockquote&gt;

  &lt;h3 id=&quot;semantic-inference&quot;&gt;Semantic inference&lt;/h3&gt;
  &lt;blockquote&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;semantic segmentation&lt;/strong&gt;을 위한 inference 기법이다.&lt;/li&gt;
      &lt;li&gt;general inference에서 처럼 mask마다 하나의 class를 고정하는 것이 아닌 &lt;strong&gt;marginalization&lt;/strong&gt;을 통해 통합적인 값을 구하고 class를 선별한다.&lt;/li&gt;
      &lt;li&gt;\(argmax_{c\in\{1,...,K\}}\sum_{i=1}^{N}p_i(c) \cdot m_i[h, w]\) 으로 no object는 취급하지 않는다.&lt;/li&gt;
      &lt;li&gt;semantic inference에 대해서는 좋은 결과를 내었지만 낮은 performance 보여주었다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/blockquote&gt;
&lt;/blockquote&gt;</content><author><name>&lt;Lee&gt; &lt;Jongyeon&gt;</name><email>&lt;lee0301jy@naver.com&gt;</email></author><category term="paper" /><summary type="html">참고 [1] https://arxiv.org/abs/2107.06278 [2] https://github.com/facebookresearch/MaskFormer</summary></entry></feed>