<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Jayde's Blog</title>
    <link>https://jayde.tistory.com/</link>
    <description>jayde 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Sun, 12 Apr 2026 03:10:47 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Jaedey</managingEditor>
    <item>
      <title>[PEP series] PEP-008 Style Guide (2)</title>
      <link>https://jayde.tistory.com/6</link>
      <description>&lt;div class='markdown-body'&gt;
&lt;h1&gt;Comments&lt;/h1&gt;
&lt;h2&gt;Common Tips&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;주석에 쓰이는 언어를 모르는 사람이 없다고 확신할 때만 영어가 아닌 다른 언어를 쓸 것&lt;/li&gt;
&lt;li&gt;첫 문장은 무조건 대문자로 쓸 것 (아니면 identifier로 헷갈릴 수 있다.)&lt;/li&gt;
&lt;li&gt;identifier의 대문자 소문자는 꼭 구별해서 잘 쓸 것&lt;/li&gt;
&lt;li&gt;마지막 문장을 제외하면 각 문장마다 공백을 써서 가독성을 높일 것&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Block Comment&lt;/h2&gt;
&lt;p&gt;블록 코멘트는 &lt;code&gt;#&lt;/code&gt;와 이후 따라오는 single space로 쓰여진다.&lt;/p&gt;
&lt;p&gt;또, 해당 코멘트로 설명하려는 코드와 동일한 indent level을 가져야 한다.&lt;/p&gt;
&lt;h2&gt;Inline Comment&lt;/h2&gt;
&lt;p&gt;블록 코멘트와 같이 &lt;code&gt;#&lt;/code&gt; 와 이후 따라오는 single space로 쓴다.&lt;/p&gt;
&lt;p&gt;inline comment는 해당 코드와 동일한 라인에 적는데, 코드와 적어도 2개 이상의 공백으로 분리한다.&lt;/p&gt;
&lt;p&gt;PEP에서는 inline comment를 적게 쓰는 것을 권장한다.&lt;/p&gt;
&lt;p&gt;왜냐하면 single line에 대한 설명이기 때문에, 너무 당연한 내용에 대해 서술한다면,  오히려 가독성만 떨어지기 때문이다. 다만, 특정 경우에는 유용하다. ( clean code에서 나왔듯, 코드에 대한 직접적인 설명보다는 코드의 의도나 다른 부가적인 설명같은 경우를 말하는 것 같다.)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Useless Case
x = x + 1                 # Increment x

# Useful Case: Trying to expalin its intention
x = x + 1                 # Compensate for border&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Documentation String&lt;/h2&gt;
&lt;p&gt;Docstring에 대해서는 PEP257에서 메인으로 다룬다.&lt;/p&gt;
&lt;p&gt;Docstring은 모든 public module, function, class, method에 대해 작성되어야 한다.&lt;/p&gt;
&lt;p&gt;non-public인 경우에는 docstring이 필수는 아니지만, 해당 내용에 대한 주석이 필요하다. 이 주석은 &lt;code&gt;def&lt;/code&gt; 라인 이후에 나와야 한다.&lt;/p&gt;
&lt;h1&gt;Naming Conventions&lt;/h1&gt;
&lt;h2&gt;Overriding Principle&lt;/h2&gt;
&lt;p&gt;user에게 공개되는 public part는 내부 구현보다는 usage에 맞는 컨벤션으로 이름이 작성되어야 한다.&lt;/p&gt;
&lt;h2&gt;Descriptive: Naming Styles&lt;/h2&gt;
&lt;p&gt;Python에서 쓰이는 Naming Style 자체에 대한 내용이다.&lt;/p&gt;
&lt;p&gt;크게&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UPPERCASE&lt;/li&gt;
&lt;li&gt;lowercase&lt;/li&gt;
&lt;li&gt;lower_snake_case&lt;/li&gt;
&lt;li&gt;lowerCamelCase&lt;/li&gt;
&lt;li&gt;UpperCamelCase&lt;/li&gt;
&lt;li&gt;UPPER_CASE_WITH_UNDERSCORE&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;가 쓰인다. (이 때, 줄임말에 대해서는 모두 uppercase를 쓴다. e.g. &lt;code&gt;HTTPServerError&lt;/code&gt; - (O) &lt;code&gt;HttpServerError&lt;/code&gt;  - (X) )&lt;/p&gt;
&lt;p&gt;또한, underscore 역시 의미있게 쓰이는데,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;_single_leading_underscore&lt;/code&gt;: internal use only. &lt;code&gt;from M import *&lt;/code&gt;를 통해 import 되지 않는다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;single_trailing_underscore&lt;/code&gt;: keyword와 겹치는 것을 막기 위해 쓰는 경우&lt;br&gt;e.g. &lt;code&gt;def invert(class_=&amp;#39;ClassName&amp;#39;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__double_leading_underscore&lt;/code&gt;: C++의 private과 동일한 역할을 한다.&lt;br&gt;&lt;code&gt;foo.__bar&lt;/code&gt;등을 통해 접근할 수는 없고, &lt;code&gt;foo._foo__bar&lt;/code&gt;를 통해 접근할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__double_leading_trailing_underscore&lt;/code&gt;: magic object/attribute를 위한 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Prescriptive: Naming Styles&lt;/h2&gt;
&lt;p&gt;그대로 쓰다 보니 내용에 비해 글이 너무 복잡하게 나왔다.&lt;/p&gt;
&lt;p&gt;Naming Style 마지막에 정리해놓을테니, 아래 내용은 그냥 읽어보고 중요한 것만 나중에 외우도록 하자.&lt;/p&gt;
&lt;h3&gt;Basics&lt;/h3&gt;
&lt;p&gt;lower L, upper O, upper i를 단독으로 쓰지 말 것, (or 폰트를 맞추거나) ASCII compatible한 문자로 이름을 지을 것&lt;/p&gt;
&lt;h3&gt;Pacakges, and Modules&lt;/h3&gt;
&lt;p&gt;lowercase로 작성하자. 만약 가독성을 높일 수 있다면, underscore를 사용해도 좋다.&lt;/p&gt;
&lt;p&gt;python package에서 같이 사용되는 C/C++ package의 경우 single leading underscore를 사용하자.&lt;/p&gt;
&lt;h3&gt;Class Names&lt;/h3&gt;
&lt;p&gt;UpperCamelCase로 쓰되, 우선적으로 callable로 쓰이는 class라면, function convention을 따른다.&lt;/p&gt;
&lt;h3&gt;Typing Variable Names&lt;/h3&gt;
&lt;p&gt;typing hint를 위한 variable &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Dict&lt;/code&gt;등 처럼, UpperCamelCase로 짧게 쓰는 것을 추천한다.&lt;/p&gt;
&lt;p&gt;suffix로 &lt;code&gt;_co&lt;/code&gt;, &lt;code&gt;_contra&lt;/code&gt;를 통해 covariance를 나타낸다.&lt;/p&gt;
&lt;h3&gt;Exception&lt;/h3&gt;
&lt;p&gt;class와 동일하게, 단, suffix로 &lt;code&gt;Error&lt;/code&gt;를 쓴다.&lt;/p&gt;
&lt;h3&gt;Global Variable Names (Not Extern)&lt;/h3&gt;
&lt;p&gt;function과 동일하게 사용&lt;/p&gt;
&lt;h3&gt;Functions and Variables&lt;/h3&gt;
&lt;p&gt;function: lower_snake_case&lt;/p&gt;
&lt;p&gt;variable: the same&lt;/p&gt;
&lt;h3&gt;Functions and Method Arguments&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;self&lt;/code&gt;, &lt;code&gt;cls&lt;/code&gt;는 항상 첫 번째 인자로 쓸 것&lt;/p&gt;
&lt;h3&gt;Method Names and Instance Variables&lt;/h3&gt;
&lt;p&gt;lower_snake_case&lt;/p&gt;
&lt;h3&gt;Constants&lt;/h3&gt;
&lt;p&gt;UPPER_CASE_WITH_UNDERSCORE&lt;/p&gt;
&lt;h2&gt;Naming Style Summary&lt;/h2&gt;
&lt;p&gt;package: lower case&lt;/p&gt;
&lt;p&gt;class, typing variable name, exception: UpperCamelCase&lt;/p&gt;
&lt;p&gt;function, method, global variable, variable, instance variable: lower_snake_case&lt;/p&gt;
&lt;p&gt;constants: UPPER_CASE_WITH_UNDERSCORE&lt;/p&gt;
&lt;h3&gt;Designing for Inheritance&lt;/h3&gt;
&lt;p&gt;python에는 C++의 private같은 단어가 존재하지 않는다. (&lt;code&gt;foo._foo__bar&lt;/code&gt;처럼 우회적으로 지원할 뿐)&lt;/p&gt;
&lt;p&gt;그래도 public/private이 헷갈린다면 private으로 가정하는 것이 좋다고 한다.&lt;/p&gt;
&lt;p&gt;class design에 대한 가이드로는&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;public attribute에 leading underscore를 쓰지 말 것&lt;/li&gt;
&lt;li&gt;public attribute가 keyword와 충돌한다면 trailing underscore를 쓸 것&lt;/li&gt;
&lt;li&gt;만약 subclass에서 사용하고 싶지 않은 attribute가 있다면 leading double underscore를 쓸 것&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Public and Internal Interfaces&lt;/h2&gt;
&lt;p&gt;반복되는 내용이 계속해서 나오는데, 문서화가 된 내용들 중실험용/내부용이라고 언급되지 않는 경우는 모두 public을 간주할 수 있다고 한다.&lt;/p&gt;
&lt;p&gt;또한, internal은 굳이 import하거나 접근하지 않아야 하며,&lt;/p&gt;
&lt;p&gt;작성자의 입장에서는 public과 internal을 &lt;code&gt;__all__&lt;/code&gt;에 명시하여 구분해야 한다고 한다.&lt;/p&gt;
&lt;h1&gt;Programming Recommendations&lt;/h1&gt;
&lt;h2&gt;General&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;다양한 Python Implementation 고려하기&lt;/p&gt;
&lt;p&gt;CPython 외에 Pypy나 JPython 등 다양한 Python 구현에 대해 동일하게 작동하는 코드를 작성해야 한다.&lt;/p&gt;
&lt;p&gt;이를 위해서는 공통적으로 사용할 수 있는 표현들에 대해서 공부해야 하는 조금 어려운 작업이고, 예시도 잘 떠오르지 않을 수 있다.&lt;/p&gt;
&lt;p&gt;대표적인 예시가 inplace string concatenation이다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;str = str1 + str2&lt;/code&gt; 혹은 &lt;code&gt;str1 += str2&lt;/code&gt;와 같은 구현은 CPython에서는 잘 작동할 수 있지만, 다른 파이썬 구현체에서는 잘 작동하지 않을 수 있다. (in linear time)&lt;/p&gt;
&lt;p&gt;따라서, 이런 경우에는 &lt;code&gt;&amp;#39;&amp;#39;.join(str_list)&lt;/code&gt;등을 사용해야 한다고 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Singleton 비교 시, is, is not 사용하기&lt;/p&gt;
&lt;p&gt;&lt;code&gt;None&lt;/code&gt;의 경우 Singleton이기 때문에 &lt;code&gt;==&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt;등을 사용하기 보다는 &lt;code&gt;is&lt;/code&gt;, &lt;code&gt;is not&lt;/code&gt;을 사용하는 것을 권장한다. (equality가 아닌 identity를 검사해야 하기 때문에)&lt;/p&gt;
&lt;p&gt;이는 &lt;code&gt;if x:&lt;/code&gt; 패턴에서 특히 중요한데,&lt;/p&gt;
&lt;p&gt;&lt;code&gt;if x:&lt;/code&gt;가 false로 판단될 때는 &lt;code&gt;x = 0, {}, []&lt;/code&gt; 등 여러 값이 가능하기 때문이다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;비교 연산자는 모두 구현하기&lt;/p&gt;
&lt;p&gt;비교 연산자로 (&lt;code&gt;__eq__&lt;/code&gt;, &lt;code&gt;__ne__&lt;/code&gt;, &lt;code&gt;__lt__&lt;/code&gt;, &lt;code&gt;__le__&lt;/code&gt;, &lt;code&gt;__gt__&lt;/code&gt;, &lt;code&gt;__ge__&lt;/code&gt;) 가 있는데, 이를 다 구현하는 것이 성능 최적화에 더 좋다고 한다.&lt;/p&gt;
&lt;p&gt;물론 이를 다 구현하는 것은 귀찮겠지만 &lt;code&gt;from functools import total_ordering&lt;/code&gt;에서 decorator를 통해 일부만 구현하더라도 나머지를 자동적으로 생성해준다.&lt;/p&gt;
&lt;p&gt;(&lt;code&gt;@total_ordering&lt;/code&gt;과 &lt;code&gt;__eq__&lt;/code&gt;, &lt;code&gt;__lt__&lt;/code&gt;만 있어도, 나머지가 정상 작동할 수 있다.)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Why?&lt;/p&gt;
&lt;p&gt;&lt;code&gt;x &amp;lt; y&lt;/code&gt;와 &lt;code&gt;y &amp;gt; x&lt;/code&gt; 는 PEP207에서 reflexivity를 가정하기 때문에 동일한 결과값을 얻을 수 있지만,&lt;/p&gt;
&lt;p&gt;&lt;code&gt;x &amp;lt; y&lt;/code&gt;는 &lt;code&gt;x&lt;/code&gt;의 &lt;code&gt;__lt__&lt;/code&gt;을 사용한 것이고, &lt;code&gt;y &amp;gt; x&lt;/code&gt;는 &lt;code&gt;y&lt;/code&gt;의 &lt;code&gt;__gt__&lt;/code&gt;를 사용한 것이기 때문에 내부 동작에서 차이가 나타날 수 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lambda Expression with Assignment&lt;/p&gt;
&lt;p&gt;&lt;code&gt;f = lambda x: 2*x&lt;/code&gt; 처럼 lambda expression을 대입해서 사용할 경우, &lt;code&gt;def&lt;/code&gt;를 사용하는 것이 더 이득이 크다고 한다.&lt;/p&gt;
&lt;p&gt;인자에 대해 헷갈리거나, 디버깅 시 나오는 trace 등에서 불이익이 생길 수 있다고 한다.&lt;/p&gt;
&lt;p&gt;또한, lambda 자체가 더 큰 expression에서 사용하기 위한 임시 expression인데, 대입하여 사용하는 것 자체가 lambda expression의 장점을 덮어버리는 일이라고 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;About Exception&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;BaseException&lt;/code&gt;이 아닌 &lt;code&gt;Exception&lt;/code&gt;을 상속받아 사용할 것&lt;/p&gt;
&lt;p&gt;&lt;code&gt;BaseException&lt;/code&gt;은 최상위 Exception이지만, &lt;code&gt;KeyBoardInterrupt&lt;/code&gt;등 다른 중요한 시그널도 잡아버리는 경우가 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;예외는 발생한 위치가 아니라, 예외를 처리할 코드 내용 기준으로 작성하고 사용할 것&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;예외 체이닝을 통해 Trace를 보존할 것&lt;/p&gt;
&lt;p&gt;&lt;code&gt;raise NewException from OriginalException&lt;/code&gt; 형식을 사용하면, 원본 traceback을 유지할 수 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;BaseException&lt;/code&gt;과 마찬가지로 bare exception은 사용하지 않는 편이 좋다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;try:
    perform_operation()
except:
    log_error()
    raise  # 예외를 다시 발생시킴  &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 형태 같은 bare exception은 &lt;code&gt;KeyBoardInterrupt&lt;/code&gt;와 같은 다른 중요한 시그널들도 모두 잡아버린다. 따라서, 사용하지 않거나, 구체적인 Error를 잡는 편이 좋다.&lt;/p&gt;
&lt;p&gt;모든 에러를 처리해야 한다면 차라리 &lt;code&gt;except Exception as e&lt;/code&gt;를 통해 처리한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;then, when to use bare exception?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;traceback을 통해 유저에게 에러 사실을 알릴 때&lt;/li&gt;
&lt;li&gt;clean-up 후 예외를 다시 작동시킬 때, 단 이때는 &lt;code&gt;try ... finally&lt;/code&gt;를 사용하는 것이 좋다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;local/particular section에서 필요한 resource를 얻는 경우 &lt;code&gt;with&lt;/code&gt; 혹은 &lt;code&gt;try ... finally&lt;/code&gt;를 사용한다.&lt;/p&gt;
&lt;p&gt;자동적으로 할당 해제를 해준다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;return&lt;/code&gt; statement는 최대한 일관성 있게 작성하자&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct:
def foo(x):
    if x &amp;gt;= 0:
        return math.sqrt(x)
    else:
        return None

def bar(x):
    if x &amp;lt; 0:
        return None
    return math.sqrt(x)

# Wrong:
def foo(x):
    if x &amp;gt;= 0:
        return math.sqrt(x)

def bar(x):
    if x &amp;lt; 0:
        return
    return math.sqrt(x)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;만약 해당 라인까지 닿을 수 있다면 명시적으로 &lt;code&gt;return None&lt;/code&gt;을 써주도록 하자 (만약 리턴 값이 없다면) value/expression/no-return 등 여러 가지를 혼합해서 리턴할 수 있는 것은 파이썬의 장점이지만, 사람은 헷갈린다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;slicing 대신 &lt;code&gt;&amp;#39;&amp;#39;.startswith()&lt;/code&gt; and &lt;code&gt;&amp;#39;&amp;#39;.endswith()&lt;/code&gt;를 통해 체크하자&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;object type checking은 &lt;code&gt;isinstance&lt;/code&gt;를 사용하자&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct:
if isinstance(obj, int):
# Wrong:
if type(obj) is type(1):&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sequence에 대해서 empty check는 직접적으로 쓰자 (sequence임에 확신이 있다면)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct:
if not seq:
if seq:
# Wrong:
if len(seq):
if not len(seq):&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;finally&lt;/code&gt; of &lt;code&gt;try ... finally&lt;/code&gt;에서 &lt;code&gt;return&lt;/code&gt;/ &lt;code&gt;break&lt;/code&gt;/ &lt;code&gt;continue&lt;/code&gt;를 사용하지 말 것&lt;/p&gt;
&lt;p&gt;finally 안의 구문은 항상 실행되기 때문에 위의 return/break/continue가 사용된다면 에러가 발생되었는지 모르고 컨트롤이 적용되지 않을 수 있기 때문에 사용을 지양하는 것이 좋다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;try 구문은 최대한 적게 유지할 것. masking bug가 생길 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct:
try:
    value = collection[key]
except KeyError:
    return key_not_found(key)
else:
    return handle_value(value)

# Wrong:
try:
    # Too broad!
    return handle_value(collection[key])
except KeyError:
    # Will also catch KeyError raised by handle_value()
    return key_not_found(key)&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Function Annotations&lt;/h2&gt;
&lt;p&gt;PEP-484 참조&lt;/p&gt;
&lt;p&gt;Function Annotators에 관한 내용이다 Type Hint, Type Checker, How to ignore Type Checker 등의 내용이 있다.&lt;/p&gt;
&lt;h2&gt;Variable Annotation&lt;/h2&gt;
&lt;p&gt;PEP-526 참조&lt;/p&gt;
&lt;p&gt;동일하게, variable type과 관련된 내용이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct:
code: int

class Point:
    coords: Tuple[int, int]
    label: str = &amp;#39;&amp;lt;unknown&amp;gt;&amp;#39;

# Wrong:

code:int  # No space after colon
code : int  # Space before colon

class Test:
    result: int=0  # No spaces around equality sign&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;소감&lt;/h1&gt;
&lt;p&gt;생각보다 예쁜 코드를 쓰는 건 귀찮은 일 같다. 마음 편하게 포매터를 쓰는 것도 좋을 것 같다. (사실 그러면 굳이 이 글을 읽을 필요도 없다.)&lt;/p&gt;
&lt;p&gt;다만, 스타일 가이드의 개념 자체가  “더 가독성이 좋은 코드를 쓰기 위한 방법이 있다면 그것을 선택하는 것이 좋다.” 라는 뜻을 가지고 있으므로, 여기에 정리된 방법이 항상 정답은 아닐 것이다.&lt;/p&gt;
&lt;p&gt;PEP8 대로 썼을 때 복잡해지는 코드도 있을 것이고, 포매터로 인해 정리했을 때, 복잡해질수도 있다.&lt;/p&gt;
&lt;p&gt;이를 적당히 센스있게 쓰고 깊거나, 팀 내 규칙도 따로 있는 경우에는 한 번쯤 읽어봐도 좋을 것 같다.&lt;/p&gt;
&lt;/div&gt;</description>
      <category>Python</category>
      <category>PEP</category>
      <category>pep008</category>
      <category>Python</category>
      <category>style guide</category>
      <category>파이썬</category>
      <author>Jaedey</author>
      <guid isPermaLink="true">https://jayde.tistory.com/6</guid>
      <comments>https://jayde.tistory.com/6#entry6comment</comments>
      <pubDate>Sun, 2 Feb 2025 22:51:18 +0900</pubDate>
    </item>
    <item>
      <title>[PEP series] PEP-008 Style Guide (1)</title>
      <link>https://jayde.tistory.com/5</link>
      <description>&lt;div class='markdown-body'&gt;
&lt;h1&gt;Introduction - What is PEP?&lt;/h1&gt;
&lt;p&gt;PEP는 Python Enhancement Proposal의 약자이다.&lt;/p&gt;
&lt;p&gt;즉, 파이썬이 발전하는 과정 중에 논의된 내용들을 정리한 문서들을 의미한다.&lt;/p&gt;
&lt;p&gt;Python을 사용하는 유저라면 필독이 권장되는 중요한 문서부터, 한 번쯤 읽어볼만한 문서까지 여러 종류가 있다.&lt;/p&gt;
&lt;p&gt;그런 PEP 문서 중에서 몇 가지 흥미를 끄는 것을 읽고 정리를 해보려고 한다.&lt;/p&gt;
&lt;p&gt;(사실 Style을 다루는 PEP 8, Docstring 컨벤션을 다룬, PEP 257이 메인 목표고 나머지는 잘 모르겠다.)&lt;/p&gt;
&lt;p&gt;다른 PEP에 대해서는 &lt;a href=&quot;https://peps.python.org/pep-0000/&quot;&gt;PEP-0000&lt;/a&gt;을 참고하자.  &lt;/p&gt;
&lt;h1&gt;A Foolish Consistency&lt;/h1&gt;
&lt;p&gt;파이썬을 비롯해 많은 언어에서 코드를 작성하는 것보다 읽는 것이 더 많을 것이라고 가정한다.&lt;/p&gt;
&lt;p&gt;파이썬의 스타일 가이드는 파이썬 코드의 가독성(readability)과 일관성(consistency)을 유지하고, 향상하기 위한 방법론이다.&lt;/p&gt;
&lt;p&gt;따라서, 이 스타일 가이드를 따르기 위해 기존 모듈이나 함수에서 따르던 스타일 가이드를 망치는 것은 PEP 문서에서도 권하지 않는다.&lt;/p&gt;
&lt;p&gt;이 문서에서는 스타일 가이드를 따르지 않아도 되는 몇 가지 경우에 대해 소개해준다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;가이드 라인을 적용하는 경우, 코드가 더 읽기 어려워지는 경우&lt;/li&gt;
&lt;li&gt;주변, 혹은 이전 코드와 일관성을 유지해야 하는 경우&lt;/li&gt;
&lt;li&gt;스타일 가이드에서 권장하지 않는 기능을 지원하지 않는 이전 버전의 파이썬과의 호환성을 유지해야 하는 경우&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;대부분 굳이 스타일 가이드를 도입해서 일관성을 망가뜨려 가독성을 떨어뜨리는 경우이다. 꼭 이런 경우가 아니더라도, 팀 내부 스타일 가이드와 충돌하는 경우 등 다양한 상황이 있을 것이다.&lt;/p&gt;
&lt;h1&gt;Code Lay-out&lt;/h1&gt;
&lt;h2&gt;Indentation&lt;/h2&gt;
&lt;p&gt;기본적으로 Indentation은 4 spaces를 쓴다.&lt;/p&gt;
&lt;p&gt;파이썬은 def, if 등 여러 구문의 구분을 위해서 indentation을 쓰지만, 그 외에도 (), {}, [] 같은 괄호를 사용할 때, indentation을 사용한다.&lt;/p&gt;
&lt;p&gt;이런 괄호 안의 줄들은 1) Python’s implicit line joining 2) hanging indent 를 사용해서 수직으로 정렬해야 한다.&lt;/p&gt;
&lt;h3&gt;Implicit line joining이 뭔데?&lt;/h3&gt;
&lt;p&gt;파이썬 코드 작성할 때, &lt;code&gt;\&lt;/code&gt; 없이도 연속된 줄이라는 것을 인식하는 것을 말한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Error occur!
result = 10 + 20
                 + 30 + 40

# Correct Code
result = 10 + 20 \
                 + 30 + 40&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;반면, &lt;code&gt;() {} []&lt;/code&gt; 을 사용하면 &lt;code&gt;\&lt;/code&gt; 없이도, 코드가 연속된 것이라는 것을 알게 된다.&lt;/p&gt;
&lt;h3&gt;Hanging Indent&lt;/h3&gt;
&lt;p&gt;PEP 8 Style guide에서 권장하는 스타일 중 하나로, 여는 괄호 &lt;code&gt;( { [&lt;/code&gt; 다음 두 번째 줄 부터 들여쓰기 및 변수 등을 넣는 스타일이다.)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Correct Use Case&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Python’s Implicit Line Joining
foo = bar(var_one, var_two,
                    var_three, var_four)

# Hanging Indent
def func_name(
            var_one, var_two, var_three,
            var_four):
        print(var_one)&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Wrong Use Case&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Python’s Implicit Line Joining
# vertically align 되어야 한다.
foo = bar(var_one, var_two,
    var_three, var_four)

# Hanging Indent
# variable과 function content 구분이 어려우므로 further indentation이 필요하다.
def func_name(
        var_one, var_two, var_three,
        var_four):
        print(var_one)&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;조건문의 Indentation&lt;/h3&gt;
&lt;p&gt;if문 내부의 조건이 너무 길어 나누게 된다면, 자연스럽게 indentation이 들어가게 되는데, 이 경우 if 문 내부의 내용과 겹치게 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;if (condition1 and
        condition2):
        do_something()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt; 따라서, 이를 구분하기 위해 여러 방법을 쓸 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# 1. Add a comment
if (condition1 and
        condition2):
        # this function does blah blah
        do_something()

# 2. Add some extra indentations
if (condition1 and
            condition2):
        do_something()

# 2.1. Add some extra indentations with hanging indent
if (
            condition1 and condition2
            condition3 and condition3
):
    do_something()&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;최대 글자 수&lt;/h2&gt;
&lt;p&gt;한 라인 당 최대 79 characters를 권장하며, docstring이나 comment같은 경우는 72 char를 권장한다고 한다.&lt;/p&gt;
&lt;p&gt;다만, 팀 내 합의가 있다면 99 char도 상관이 없다고 한다.&lt;/p&gt;
&lt;p&gt;이렇게 제한하는 이유는 IDE나 여러 툴에서 여러 탭을 놓아서 비교하기 편하게 하기 위해서라고 한다.&lt;/p&gt;
&lt;p&gt;코드 리뷰나 유지보수 툴들 내에서 사용편의성을 위해서 권장하는 내용이다.&lt;/p&gt;
&lt;p&gt;(다만, 다른 책에서는 최근 모니터나 다른 툴들의 발전으로 인해 더 늘어나도 상관이 없다고 한다. 즉, 앞서 말했듯, 팀 내 합의나 사용자 편의성을 위해 꼭 지켜야 하는 룰은 아니라는 것이다.)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;assert&lt;/code&gt;나 &lt;code&gt;with&lt;/code&gt;문 등에서 &lt;code&gt;\&lt;/code&gt;를 통해 라인을 나눠 위의 컨벤션을 잘 맞출 수 있다고 한다.&lt;/p&gt;
&lt;h3&gt;Line Break Before/After a Operator?&lt;/h3&gt;
&lt;p&gt;라인을 나눌 때, operator를 쓰고 나눌지, 아니면 나누고 쓸지에 대해 PEP8는 라인을 나누고 쓰라고 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Wrong Line Break
result = wage +
                 number +
                 loan_interest

# Correct Line Break
result = wage
                 + number
                 + loan_interest&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Blank Lines&lt;/h2&gt;
&lt;p&gt;파일 내 class, method를 나누기 위한 빈 줄의 갯수까지 제안해준다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Class, Top-level function: 2 blank lines로 둘러싼다.&lt;/li&gt;
&lt;li&gt;member function, variable: single blank line으로 둘러싼다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;class Person:

    def say_hello():
        do_something()

    def say_goodbye():
        do_something()

# After 2 blank lines, define new class/top-level function
# TBH, It is better to define new class in new file
# unless it is deeply related to each other.
class    Man:

    def something():
        pass

    def nothing():
        pass &lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Source File Encoding&lt;/h2&gt;
&lt;p&gt;별 다른 이유가 없다면 파이썬 내 인코딩은 &lt;code&gt;UTF-8&lt;/code&gt;을 쓰도록 한다.&lt;/p&gt;
&lt;p&gt;(별 다른 이유의 예시: Non-UTF-8 문자에 대한 테스트)&lt;/p&gt;
&lt;p&gt;다시 말하면 그냥 &lt;code&gt;UTF-8&lt;/code&gt; 을 쓰라는 소리다. &lt;/p&gt;
&lt;p&gt;여기에 더해, Python Standard Library의 경우에는 Non-ASCII Identifier를 쓰지 말아야 하며, 무조건 영어를 써야 한다고 한다. Python Standard Library에 컨트리뷰션 할 때가 되면 기억하도록 하자.&lt;/p&gt;
&lt;h2&gt;Import Convention&lt;/h2&gt;
&lt;p&gt;Import에 대한 가이드도 있는데, 한 줄에 하나씩 임포트하며, 만약 같은 라이브러리에서 가져온다면 여러 개도 허용 된다고 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct Case
import os
import sys

from math import pow, sqrt

# Wrong Case
import os, sys&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;또, import하는 순서는 아래와 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Standard Library&lt;/li&gt;
&lt;li&gt;Third Party Library&lt;/li&gt;
&lt;li&gt;Local app, library specific imports&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Absolute Import vs. Explicit Relative Import&lt;/h3&gt;
&lt;p&gt;대부분의 경우 Absolute Import를 장려하며, Standard Library에서는 무조건 Absolute Import를 사용해야 한다.&lt;/p&gt;
&lt;p&gt;반면, 자신의 패키지가 복잡하게 구성되어, Absolute import를 쓰는 경우가 오히려 복잡해지는 경우, explicit relative import를 사용한다고 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Absolute Import
import os
import sys
from mypkg.family import Sibling

# Explicit Relative Import
from ./family import Silbing&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;단, &lt;code&gt;from os import *&lt;/code&gt;과 같은 wild-card import는 권장하지 않는다.&lt;/p&gt;
&lt;p&gt;그 이유는 어떤 것이 추가되는지 모르기 때문에 name space 내 충돌이나, automated tools 내에서의 충돌을 감지하기 어렵기 때문이다.&lt;/p&gt;
&lt;p&gt;허용되는 경우도 있다. 조금 특별한 경우일 수 있겠지만, 내부 인터페이스를 public하게 노출하는 경우이다.&lt;/p&gt;
&lt;p&gt;말 그대로, 문제가 되는 필요하지 않은 것들이 무차별적으로 import되는 것이다. 반면, 해당 파일 내의 인터페이스들을 모두 사용하거나, 로딩해야 하는 경우에는 허용된다는 것이다.&lt;/p&gt;
&lt;p&gt;예시 몇 가지를 통해서 자세히 알아보자.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;내부 인터페이스를 퍼블릭으로 노출해야 하는 경우&lt;/p&gt;
&lt;p&gt;기본적으로 특정 모듈이 python 구현체로 존재하지만, 일부 함수에 대해 C로 최적화 구현된 모듈도 존재하는 경우&lt;/p&gt;
&lt;p&gt;동일한 function에 대해 최적화된 결과를 내부적으로 결정해서 호출할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;try:
    from optimized_c_version_module import *
except:
    from pure_python_version_module import *&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;plug-in 시스템에서 자동으로 로딩할 때&lt;/p&gt;
&lt;p&gt;플러그인 시스템을 만들 때, 특정 폴더 내의 모듈을 자동적으로 로드해야 할 경우가 있다고 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# plugins/__init__.py
import glob
import importlib

# plugins 폴더 안의 모든 Python 파일을 찾음
modules = glob.glob(&amp;quot;plugins/*.py&amp;quot;)

for module in modules:
    module_name = module[:-3].replace(&amp;quot;/&amp;quot;, &amp;quot;.&amp;quot;)  # &amp;quot;plugins.module_name&amp;quot; 형태로 변환
    imported_module = importlib.import_module(module_name)
    globals().update(imported_module.__dict__)  # Wildcard Import처럼 모든 요소를 가져옴
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 코드 대신&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from plugins import *&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;를 통해 간단하게 자동적으로 import할 수 있다. 대신 &lt;code&gt;__all__&lt;/code&gt;가 정의되어 있어야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;__all__&lt;/code&gt;을 사용해 공개 API를 지정할 때&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# my_module.py
__all__ = [&amp;quot;function_a&amp;quot;, &amp;quot;function_b&amp;quot;]  # Wildcard Import 시 이 리스트에 있는 것만 공개

def function_a():
    return &amp;quot;Function A&amp;quot;

def function_b():
    return &amp;quot;Function B&amp;quot;

def internal_function():
    return &amp;quot;Internal Function (숨겨짐)&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;대형 패키지의 서브 모듈을 한 번에 관리/사용 할 때 &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;my_package/
│── __init__.py
│── module_a.py
│── module_b.py&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# __init__.py (패키지 진입점)
from .module_a import *
from .module_b import *

__all__ = [&amp;quot;func_a&amp;quot;, &amp;quot;func_b&amp;quot;]  # 네임스페이스를 제한&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# main.py
from my_package import *  # func_a와 func_b만 import됨

print(func_a())  # ✅ 정상 작동
print(func_b())  # ✅ 정상 작동&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Module-level DUnder Names&lt;/h2&gt;
&lt;p&gt;DUnder는 &lt;code&gt;_&lt;/code&gt;가 두 개 둘러 쌓여진 &lt;code&gt;__all__&lt;/code&gt;, &lt;code&gt;__init__&lt;/code&gt;등을 말한다.&lt;/p&gt;
&lt;p&gt;이것들이 놓여지는 순서는&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Docstring of File&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__Future__&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;normal DUnders   &lt;/li&gt;
&lt;li&gt;import&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&amp;quot;&amp;quot;&amp;quot;This is the example module.

This module does stuff.
&amp;quot;&amp;quot;&amp;quot;

from __future__ import barry_as_FLUFL

__all__ = [&amp;#39;a&amp;#39;, &amp;#39;b&amp;#39;, &amp;#39;c&amp;#39;]
__version__ = &amp;#39;0.1&amp;#39;
__author__ = &amp;#39;Cardinal Biggles&amp;#39;

import os
import sys&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What is &lt;code&gt;__future__&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;하위 python version에서 상위 버전의 내용을 사용할 수 있도록 하는 모듈이다.&lt;/p&gt;
&lt;p&gt;예를 들어, print의 경우, python 2에서 &lt;code&gt;print &amp;quot;hello World&amp;quot;&lt;/code&gt;로 표현했다. (assert 문처럼)&lt;/p&gt;
&lt;p&gt;python 3에서는 &lt;code&gt;print(&amp;quot;hello World&amp;quot;)&lt;/code&gt;로 표현하는데,&lt;/p&gt;
&lt;p&gt;python2에서 import를 통해 가능해진다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# in python 2.0
from __future__ import print_function

print(&amp;quot;hello World&amp;quot;) # --&amp;gt; possible&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;즉, python의 구 버전에서 default로 세팅된 값들을 신버전에서 기본값으로 사용될 것들로 바꿔주는 역할이다.&lt;/p&gt;
&lt;p&gt;이를 통해서, 아래의 효과를 꾀할 수 있다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;기존 기능이 새로운 기능과 충돌이 일어나는지 체크할 수 있다.&lt;/li&gt;
&lt;li&gt;정식 출시 이전에 일부 기능을 미리 사용해볼 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;String Quotes&lt;/h1&gt;
&lt;p&gt;python에서 &lt;code&gt;&amp;#39;hello&amp;#39;&lt;/code&gt;와 &lt;code&gt;&amp;quot;hello&amp;quot;&lt;/code&gt;는 차이가 없다.&lt;/p&gt;
&lt;p&gt;하지만, 하나를 정해서 사용하는 것을 권장하며, &lt;code&gt;\&lt;/code&gt; 를 사용하는 경우에만 다른 하나를 사용하는 것을 권장한다. &lt;code&gt;&amp;#39;she said \&amp;quot;hi\&amp;quot;&amp;#39;&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;다만, docstring에서는 &lt;code&gt;&amp;quot;&lt;/code&gt;를 사용하는 것을 기본으로 한다.&lt;/p&gt;
&lt;h1&gt;Whitespace in Expressions and Statements&lt;/h1&gt;
&lt;p&gt;이 섹션에서는 코드 내에서 공백(=스페이스)를 어떻게 써야하는지에 대해 알려준다.&lt;/p&gt;
&lt;p&gt;나는 대체로 스페이스에 후한 편이어서 남발하는데 좀 줄여야 할 것 같다.&lt;/p&gt;
&lt;h2&gt;() {} [] : ; ,&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;(), {}, []&lt;/code&gt;의 뒤에는 바로 문자가 나와야 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct
func(ham[1], {eggs: 2})

# Wrong
func( ham[ 1 ], { eggs: 2 }) &lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;() []&lt;/code&gt;를 function call, indexing, slicing으로 쓰는 경우, 이전 문자 바로 뒤에 붙어서 나와야 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct
spam(1)
dct[&amp;#39;key&amp;#39;] = value

# Wrong
spam (1)
dct [&amp;#39;key&amp;#39;] = value&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;comma(,) 뒤에는 바로 닫는 괄호가 나와야 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct
foo = (0,)

# Wrong
foo = (0, )&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;; : ,&lt;/code&gt; 는 이전 문자 바로 뒤에 붙어서 나와야 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct
if x == 4: print(x, y); x, y = y, x

# Wrong
if x == 4 : print(x , y) ; x , y = y , x&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;단, &lt;code&gt;:&lt;/code&gt;는 slice에서 binary operator와 같은 역할을 하기 때문에, &lt;code&gt;:&lt;/code&gt;의 양쪽에서 동일한 만큼의 공백을 줘야 한다. (단, slice parameter가 생략되는 경우에는 공백을 사용하지 않는다.)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct:
ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
ham[lower:upper], ham[lower:upper:], ham[lower::step] # Okay with no space
ham[lower+offset : upper+offset] # either okay with same amounts of space in both side.
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]

# Wrong:
ham[lower + offset:upper + offset]
ham[1: 9], ham[1 :9], ham[1:9 :3]
ham[lower : : step]
ham[ : upper]&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Operators&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;변수 선언 시, alignment를 위해 2개 이상의 공백을 쓰지 않는다. 이는 C나 다른 언어와는 또 다른 것 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct
x = 1
long_variable = 6

# Wrong
x             = 1
long_variable = 6&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;line continuation을 위한 &lt;code&gt;\&lt;/code&gt;뒤에 공백을 넣는 경우 compile error가 나온다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Compile Error bcs of the space following \
a = 6 + \ 
        1&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Binary operator의 양쪽에 single space를 넣을 것&lt;/p&gt;
&lt;p&gt;assignment(&lt;code&gt;=&lt;/code&gt;), augmented assignment(&lt;code&gt;+=, -=&lt;/code&gt;), comparison(&lt;code&gt;==, &amp;lt;&amp;gt;, in&lt;/code&gt;, …etc), Boolean(&lt;code&gt;not&lt;/code&gt; …ect), even mathmatical operator(&lt;code&gt;+&lt;/code&gt;, ..etc)에 대해 single space를 넣으면 좋다.&lt;/p&gt;
&lt;p&gt;단, 다른 priority를 가진 operator들이 섞이는 경우에는 lowest priority를 가지는 operator에게만 공백을 준다. 하지만 매우 복잡해지면 사용자의 재량에 맡긴다고 한다. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt; # Correct:
i = i + 1
submitted += 1
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)

# Wrong:
i=i+1
submitted +=1
x = x * 2 - 1
hypot2 = x * x + y * y
c = (a + b) * (a - b)&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Function annotation에 대해서도 양쪽에 single space를 넣어주자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct
def func(s: str) -&amp;gt; int: ...

# Wrong
def func(s: str)-&amp;gt;int:&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;단, &lt;code&gt;=&lt;/code&gt;이 function의 keyword argument에 쓰이거나, default value notation에 쓰이는 경우, 공백을 쓰지 않는다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct:
def complex(real, imag=0.0):
    return magic(r=real, i=imag)

# Wrong:
def complex(real, imag = 0.0):
    return magic(r = real, i = imag)&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;근데 또, argument annotation (argument typing hint)와 결합되는 경우에는 space를 쓴다고 한다. 알쏭달쏭한 PEP세상..&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct:
# format of keyword: type = default_value or, keword=default_value
def munge(sep: AnyStr = None): ...
def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...

# Wrong:
def munge(input: AnyStr=None): ...
def munge(input: AnyStr, limit = 1000): ...&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if/for/while의 same line에 바로 내용 넣는 것을 지양할 것. (단 적은 내용은 상관없다.)&lt;br&gt;대신, 그러한 절들이 여러 개가 나오거나 복잡한 경우에는 하지 말 것&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Wrong:
if foo == &amp;#39;blah&amp;#39;: do_blah_thing()
for x in lst: total += x
while t &amp;lt; 10: t = delay()

# Wrong:
if foo == &amp;#39;blah&amp;#39;: one(); two(); three()&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compound statement도 동일하다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Wrong
one(); two(); three(); ... n()&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;When to Use Trailing Commas&lt;/h1&gt;
&lt;p&gt;주로 파이썬에서 comma(,)를 사용하는 것은 tuple을 만들 때, 혹은 여러 값을 동시에 사용할 때이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;pair = (1,2) # tuple
x = (1) # int

first, second = 1, 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;하지만, 이 섹션에서 말하는 Trailing Comma는 list, tuple, dictionary의 끝에 나오는 ,를 말한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;score_list = [
    100,
    96,
    30, # &amp;lt;--- Here&amp;#39;s the trailing comma
]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 trailing comma를 사용하는 이유는 Git같은 versioin control system에서 유용하기 때문이다.&lt;/p&gt;
&lt;p&gt;trailing comma가 없는 상태에서 새로운 데이터를 추가한다고 하자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# list without trailing comma
score_list = [
    100,
    96,
    30
]&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# new data added
score_list = [
    100,
    96,
    30,
    70
]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 경우, &lt;code&gt;30&lt;/code&gt; 라인이 삭제되고, &lt;code&gt;30,&lt;/code&gt; 라인과 &lt;code&gt;70&lt;/code&gt;라인이 추가된다.&lt;/p&gt;
&lt;p&gt;사실은 &lt;code&gt;70&lt;/code&gt;데이터 하나만 추가된 것인데 말이다. 이러한 차이는 소스코드의 차이를 확인하는데 불편함을 준다.&lt;/p&gt;
&lt;p&gt;따라서, 시스템 상으로 추가된 혹은 삭제된 데이터만 확인하기 위해서 trailing comma를 사용한다.&lt;/p&gt;
&lt;p&gt;그렇다면 이 trailing comma는 어떻게 표현해야 좋을까?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Correct:
FILES = [
    &amp;#39;setup.cfg&amp;#39;,
    &amp;#39;tox.ini&amp;#39;,
    ]
initialize(FILES,
           error=True,
           )

# Wrong:
FILES = [&amp;#39;setup.cfg&amp;#39;, &amp;#39;tox.ini&amp;#39;,]
initialize(FILES, error=True,)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</description>
      <category>Python</category>
      <category>PEP</category>
      <category>pep008</category>
      <category>Python</category>
      <category>style guide</category>
      <category>파이썬</category>
      <author>Jaedey</author>
      <guid isPermaLink="true">https://jayde.tistory.com/5</guid>
      <comments>https://jayde.tistory.com/5#entry5comment</comments>
      <pubDate>Sun, 2 Feb 2025 22:40:16 +0900</pubDate>
    </item>
    <item>
      <title>[논문 읽기] Be Your Own Teacher - Improve the Performance of Convolutional Neural Networks via Self Distillation</title>
      <link>https://jayde.tistory.com/4</link>
      <description>&lt;h1 style=&quot;color: #000000; text-align: left;&quot;&gt;Before the Start&lt;/h1&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;Knowledge Distillation의 컨셉에 대해서 알고 있어야 편합니다&lt;/p&gt;
&lt;h1 style=&quot;color: #000000; text-align: left;&quot;&gt;0. Abstract&lt;/h1&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;Accuracy를 조금이라도 더 올리기 위해서 deeper, wider network를 설계하는게 하나의 트렌드였다&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;구조를 키워서 정확도는 올라갔지만, Computational cost가 높아졌다. Self KD는 구조를 줄이면서 성능은 올렸다. 아이디어는 하나의 모델을 여러 section으로 나눠, deeper section에서 shallow section으로 distillation을 적용해주는 것이다.&lt;/p&gt;
&lt;h1 style=&quot;color: #000000; text-align: left;&quot;&gt;1. Introduction&lt;/h1&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;최근 나온 구조들은 cost가 굉장히 크고, 이전에 비해 acc를 올리기 위해 필요한 cost의 증가량이 커졌다. (ex. 이전에는 1% 올리기 위해 5GFLOPS가 필요하다고 했을때, 지금은 10GFLOPS가 필요하다. 단순 예시입니다.)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 최근에는 경량화 기술이 많이 나왔는데, 대표적으로 pruning, quantization, Knowledge Distillation(이하 KD)이 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;KD는 teacher, student model이 따로 있어서, student model로 하여금 teacher model을 approximation하게 한다. 놀랍게도 student가 teacher보다 좋은 성능을 내는 경우도 있다고 한다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;1.1. Problem of KD&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 KD에도 몇 가지 문제가 있는데,&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333333; text-align: left;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;low efficiency: knowledge transfer과정에서, student가 teacher을 뛰어넘는 경우는 드물다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;design problem: teacher와 student를 design하기 어렵다. 특히, 어떤 student 모델에 대해 좋은 성능을 보여주는 teacher model을 디자인하는 것은 pretrain을 시키고, 검증해야하기 때문에 오래 걸린다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;1.2. Merits of Self KD&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333333; text-align: left;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;간단한 학습 step:self KD: one step ( 스스로 학습하면서 distillation을 주기 때문에)&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;기존 KD: pretraining teacher &amp;rarr; knowledge transfer to student&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;faster training time&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;student model이 스스로 teacher 역할도 하기 때문에 더 빠르게 학습이 가능하다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;Accuracy&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;더 정확하다고 하다. ( traditional KD에 비해서 )&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 style=&quot;color: #000000; text-align: left;&quot;&gt;2. Related Works&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;2.1. KD&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;모델 경량화에 주로 쓰이는 기법으로, Teacher Model과 Student Model을 두어서, Teacher Model의 판단을 가르치는 방식이다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;2.2. Adaptive Computation&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;Dropout과 유사하게, 특정 계산을 건너뛰는 방식이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;1) layer 자체를 건너뛰거나, 2) feature map의 몇몇 channel을 스킵할 수도 있으며, 3) 혹은 pixel단위로 스킵하는 연구가 있다고 한다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;2.3. Deep Supervision&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;Gradient Vanishing 문제를 해결하기 위한 것으로, 내 기억으로는 GoogleNet인가에서도 비슷한 테크닉을 썼던 것 같다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;Deep supervision은 layer 중간중간에 supervision을 넣어주는 방식으로 Gradient Vanishing을 예방한다. Supervision을 넣어준다는 건, 중간중간마다 Loss를 계산하고 Back-Prop을 진행해준다는 소리다.(사실 이건 더 specific한 방법이고, supervision을 넣어주는 다른 방법도 있을 것이다.)&lt;/p&gt;
&lt;h1 style=&quot;color: #000000; text-align: left;&quot;&gt;3. Self Distillation&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gnc5V/btsL3SILMgk/GDHh3tIa1b8TAy6gON4mKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gnc5V/btsL3SILMgk/GDHh3tIa1b8TAy6gON4mKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gnc5V/btsL3SILMgk/GDHh3tIa1b8TAy6gON4mKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGnc5V%2FbtsL3SILMgk%2FGDHh3tIa1b8TAy6gON4mKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;701&quot; height=&quot;314&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;위의 사진에 모든 것이 들어있다&amp;hellip;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;먼저 모델을 section으로 나눠서, 그 사이마다 Classifier(Bottleneck + FC layer + softmax)를 둔다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 Deepest Classifier가 shallow classifier에 guidance를 주는 형식이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이 때, loss의 source는 총 3 곳이 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333333; text-align: left;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;from Label ( Green Line )이 때, CE는 각각의 classifier가 얻은 output에 대해 계산한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;label 정보를 사용해서 얻은 Cross Entropy를 얻고, 이를 loss로 활용한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;from distillation ( BLue Line )&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;Deepest Classifier가 얻은 softmax 값과 다른 classifier가 얻은 softmax value를 KL-divergence로 유사한 분포가 되게끔 한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;from hints ( Gray Line )&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;Deepest Classifier가 사용하는 feature map과 shallow classifier가 사용하는 feature map 사이의 L2 loss를 사용한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;605&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LJOEm/btsL4OZM3CW/xkhckESWRd2lgjbafJkMgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LJOEm/btsL4OZM3CW/xkhckESWRd2lgjbafJkMgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LJOEm/btsL4OZM3CW/xkhckESWRd2lgjbafJkMgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLJOEm%2FbtsL4OZM3CW%2FxkhckESWRd2lgjbafJkMgK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;399&quot; height=&quot;189&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;605&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;결론적인 loss는 위와 같고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;alpha;는 distillation ratio라고 할 수 있고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lambda;는 L2 loss를 위한 ratio라고 볼 수 있다.&lt;/p&gt;
&lt;h1 style=&quot;color: #000000; text-align: left;&quot;&gt;4. Experiment&lt;/h1&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;Skip! (아직 내가 디테일한 Setting까지는 필요하지 않다..)&lt;/p&gt;
&lt;h1 style=&quot;color: #000000; text-align: left;&quot;&gt;5. Discussion and Future Works&lt;/h1&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;Experiment로부터 얻은 결론(혹은 statement)가 세 가지 있다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;5.1. Self distillation can help models converge to flat minima which features in generalization inherently&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;한줄요약) sharp minima보다 flat minima에 converge하는 경향이 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;그렇다면 이게 왜 좋은 특성인가?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;807&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5pdHM/btsL4zWg6NE/LGT0zHk9B2AVA4swC3OnA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5pdHM/btsL4zWg6NE/LGT0zHk9B2AVA4swC3OnA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5pdHM/btsL4zWg6NE/LGT0zHk9B2AVA4swC3OnA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5pdHM%2FbtsL4zWg6NE%2FLGT0zHk9B2AVA4swC3OnA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;474&quot; height=&quot;299&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;807&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;위와 같은 Training function이 있고, training function을 사용해서 test function을 estimate했다고 하자. sharp minima인 경우, 최적의 파라미터에서 조금만 bias가 생기면 loss가 크게 늘어난다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 flat minima인 경우에는 조금 bias가 생기더라도, 여전히 loss가 작게 유지된다. 즉 stable한 training이 가능해진다는 의미이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이걸 어떻게 증명했냐?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1813&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EGwRi/btsL5qREPzM/H3xWKPGoqFb0m5pSFNEREk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EGwRi/btsL5qREPzM/H3xWKPGoqFb0m5pSFNEREk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EGwRi/btsL5qREPzM/H3xWKPGoqFb0m5pSFNEREk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEGwRi%2FbtsL5qREPzM%2FH3xWKPGoqFb0m5pSFNEREk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;453&quot; height=&quot;642&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1813&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;바로 parameter에 gaussian noise를 줘 가면서 accuracy와 loss를 측정해나갔다. (flat minima, sharp minima는 parameter space에서 일어나는 문제니까 이렇게 측정하는게 맞는 것 같다.)&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;5.2. Self distillation prevents model from vanishing gradient problem&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;567&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zf4S7/btsL3m4B3JL/C6dkM5R21oM3aFFDzqpZ1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zf4S7/btsL3m4B3JL/C6dkM5R21oM3aFFDzqpZ1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zf4S7/btsL3m4B3JL/C6dkM5R21oM3aFFDzqpZ1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzf4S7%2FbtsL3m4B3JL%2FC6dkM5R21oM3aFFDzqpZ1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;731&quot; height=&quot;324&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;567&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;그 다음은 gradient vanishing 문제를 해결했다고 하는데, 이건 somehow obvious한게, Deep Supervised Network처럼 중간중간마다 gradient를 수급해주는 Classifier가 있고, 특히나, Deepest Classifier, label과도 연결되었기 때문에 더 smooth하게 학습이 가능할 것이다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;5.3. More discriminating features are extracted with deeper classifiers in self distillation&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d4BVdk/btsL4La2QPl/XVCM6RzZBBROKnCTw9LPt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d4BVdk/btsL4La2QPl/XVCM6RzZBBROKnCTw9LPt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d4BVdk/btsL4La2QPl/XVCM6RzZBBROKnCTw9LPt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd4BVdk%2FbtsL4La2QPl%2FXVCM6RzZBBROKnCTw9LPt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;568&quot; height=&quot;548&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1234&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;deeper classifier일수록 더 분류가 잘 되는 feature들을 뽑아내는 것을 알 수 있고, 이를 통해서 각 classifier마다의 discriminating principle에 대해서도 알 수 있다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;5.4. Future Works&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333333; text-align: left;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;loss에서 소개되었던 두 hyper parameter,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;alpha;,&amp;lambda;가 성능에 크게 영향을 미친다고 한다. 하지만, 이 부분에 대해서 충분히 조사하지 못했다고 한다&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;self KD를 통해서 relatively flat minima에 converge하는 것은 밝혀냈지만, 이 flat minima가 과연 ideal flat minima인지는 밝혀냈다고 하지 못했다고 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마치며..&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글 역시 2023년도에 썼던 건데, 참 세상 많이 바뀌었다는 걸 느낀다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;self-distill이 살아남아 이래저래 적용이 되는 것 같다.&lt;/p&gt;</description>
      <category>AI</category>
      <category>Ai</category>
      <category>self-distillation</category>
      <category>논문읽기</category>
      <author>Jaedey</author>
      <guid isPermaLink="true">https://jayde.tistory.com/4</guid>
      <comments>https://jayde.tistory.com/4#entry4comment</comments>
      <pubDate>Sun, 2 Feb 2025 00:28:05 +0900</pubDate>
    </item>
    <item>
      <title>[논문 읽기] Efficiently Identifying Task Groupings for Multi-Task Learning</title>
      <link>https://jayde.tistory.com/3</link>
      <description>&lt;div style=&quot;color: #333333; text-align: left;&quot;&gt;
&lt;h1 style=&quot;color: #000000;&quot;&gt;0. 왜 골랐는가&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Open Review에서 굉장히 좋게 평가해주었길래 어떤 아이디어가 그렇게 참신한가 싶어서 골랐다.&lt;/p&gt;
&lt;h1 style=&quot;color: #000000;&quot;&gt;1. Multi Task Learning이 낯선 사람들을 위해&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;1.1. 간단한 소개&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티 태스크 러닝(이하 MTL)은 이름에서 알 수 있듯이, 하나의 모델이 여러 task를 수행해준다. 하나의 모델이 여러 task를 동시에 수행하기 위해서, 구조를 공유하거나, parameter를 유사하게 만들어준다. 아래는 동일한 parameter를 공유하는 &amp;ldquo;Hard Parameter Sharing&amp;rdquo;, 그리고 동일하지는 않지만, 유사한 parameter를 사용하는 &amp;ldquo;Soft Parameter Sharing&amp;rdquo;의 예시이다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpzdZ2/btsL4plSpU5/Wp4TXeUrLr3jzCPkg9iQ3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpzdZ2/btsL4plSpU5/Wp4TXeUrLr3jzCPkg9iQ3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpzdZ2/btsL4plSpU5/Wp4TXeUrLr3jzCPkg9iQ3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpzdZ2%2FbtsL4plSpU5%2FWp4TXeUrLr3jzCPkg9iQ3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;904&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;578&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig1. Hard Parameter Sharing과 Soft Parameter Sharing에 대한 모식도 Soft Parameter Sharing의 경우는 결국 서로 다른 Parameter를 사용하기 때문에 Memory Efficient한지는 의문이다.
&lt;p data-ke-size=&quot;size16&quot;&gt;Fig1. Hard Parameter Sharing과 Soft Parameter Sharing에 대한 모식도&lt;br /&gt;Soft Parameter Sharing의 경우는 결국 서로 다른 Parameter를 사용하기 때문에 Memory Efficient한지는 의문이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;Soft Parameter Sharing은 어떻게 Parameter를 유사하게 하는가?&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;아의 수식처럼, Loss function에서 Regularization term을 넣어서 Parameter 간 차이가 크지 않도록 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VqfIx/btsL38EGmfh/PdMggX5jhZR18X17bl3UVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VqfIx/btsL38EGmfh/PdMggX5jhZR18X17bl3UVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VqfIx/btsL38EGmfh/PdMggX5jhZR18X17bl3UVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVqfIx%2FbtsL38EGmfh%2FPdMggX5jhZR18X17bl3UVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;351&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;MTL의 예시로는 흔히들 자율주행을 많이 들고는 한다. 하나의 장면에서, object detection이나, edge detection 등을 다양한 task를 한 번에 수행해야하기 때문에 자율 주행에 이를 적용할 수 있다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;956&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FkZsT/btsL4HGCAC7/5ivp5gfsiKimHfpTQkiZA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FkZsT/btsL4HGCAC7/5ivp5gfsiKimHfpTQkiZA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FkZsT/btsL4HGCAC7/5ivp5gfsiKimHfpTQkiZA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFkZsT%2FbtsL4HGCAC7%2F5ivp5gfsiKimHfpTQkiZA1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;1494&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;956&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig2. Application of Multi Task Learning: Autonomous Driving
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 여러 모델을 동시에 돌린다면, 동일한 결과를 얻을 수 있겠지만, 여러 모델을 Parallel하게 돌릴 수 있는 Computing Resource가 있거나, Sequential하게 돌리려면 그 만큼 시간이 소요될 것이다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;1.2. 사기는 아닌가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 Task마다 최적의 Parameter가 있을 것이라는 건 자명한데, 여러 가지 Task를 같이 학습하는 건 Performance 측면에서 굉장히 안좋은게 아닐까? 라는 생각을 할 수 있다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;721&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfmGnM/btsL4AgyTQm/bgxb9ASvt5Uts8KcSVouG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfmGnM/btsL4AgyTQm/bgxb9ASvt5Uts8KcSVouG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfmGnM/btsL4AgyTQm/bgxb9ASvt5Uts8KcSVouG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfmGnM%2FbtsL4AgyTQm%2Fbgxb9ASvt5Uts8KcSVouG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;1128&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;721&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig3. MAML의 모식도. 각 Task에 대한 최적의 Parameter가 서로 다르다는 가정 하에 진행된 연구이다. MAML은 각 Task에 대해 최적화된 Parameter까지의 거리가 작은 공통의 Parameter를 찾고자 한 연구이다.
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 여러 개의 Single Task Learning을 동시에 진행하는 것이 더 좋은 Performance를 보여줬다. 하지만, [1]에서는 Fixed Resource인 상황을 가정하여, n-task일 때, Single Task Learning에 1/n만큼의 Resource를 부여해서 실험했다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vOTC6/btsL2QrbwJ6/0NYFRZy5gZt0nvghRJv181/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vOTC6/btsL2QrbwJ6/0NYFRZy5gZt0nvghRJv181/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vOTC6/btsL2QrbwJ6/0NYFRZy5gZt0nvghRJv181/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvOTC6%2FbtsL2QrbwJ6%2F0NYFRZy5gZt0nvghRJv181%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;417&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;266&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig4. 고정된 Computing Resource(Memory)상에서 MTL과 STL의 비교 MTL이 더 좋아지기도 하지만 STL의 성능이 급격하게 떨어지는 것이 눈에 띈다.
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로는 Fixed Memory 상황에서 여러 가지의 Task를 수행해야 한다면, MTL은 좋은 선택이 될 수 있다는 것을 보여준다.&lt;/p&gt;
&lt;h1 style=&quot;color: #000000;&quot;&gt;1. Introduction&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;1.1. 당시 MTL의 연구 방향[2]&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 오래된 Survey논문이라 현재의 동향과는 동떨어져 있을 수 있지만, 당시에는 크게 MTL의 연구 방향은 3가지로 나뉘어져 있다고 한다. ( 또 다른 분류 방식도 있으나, 이번 논문과는 관계가 없기 때문에 나중에 다루도록 한다. )&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lPdFK/btsL5BZPXBK/iyKOaBFmsjomU2klIp5SK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lPdFK/btsL5BZPXBK/iyKOaBFmsjomU2klIp5SK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lPdFK/btsL5BZPXBK/iyKOaBFmsjomU2klIp5SK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlPdFK%2FbtsL5BZPXBK%2FiyKOaBFmsjomU2klIp5SK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;1001&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig5. Cross Stitch Network[3]의 모식도
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;Architecture ( Fig 5 )&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;MTL을 더 잘 수행할 수 있는 Architecture 자체를 연구하는 방향&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;Optimization ( Fig 6)&lt;br /&gt;여러 Task들이 더 잘 최적화될 수 있도록 도와주는 방법론에 대한 연구가 이뤄졌었다. 여러 Task에 대해 학습 속도가 일정하지 않으면, 한 Task가 충분히 학습되지 않은 상태에서 다른 Task가 최적점에 도달하는 문제가 발생한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;Grouping Method ( Fig 7)&lt;br /&gt;마지막으로 Task들을 어떻게 분배하는지에 대해서 연구하는 방향이다. Grouping에 대한 연구가 당시 가장 희소했다고 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;2477&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zrFbd/btsL3lEDFdn/5U4XKiY4uvbRVfRkMfKku1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zrFbd/btsL3lEDFdn/5U4XKiY4uvbRVfRkMfKku1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zrFbd/btsL3lEDFdn/5U4XKiY4uvbRVfRkMfKku1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzrFbd%2FbtsL3lEDFdn%2F5U4XKiY4uvbRVfRkMfKku1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;342&quot; height=&quot;424&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;2477&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig6. GradNorm[4]의 모식도. 학습 속도가 서로 다른 여러 Task들의 Gradient를 유사한 Scale로 맞춰줘서 동일한 속도로 학습이 가능하도록 도와준다.당시 MTL에서 가장 활발한 연구 분야였다.&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;764&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkAZ8M/btsL4abnrS1/0xd8q6h9ef4LqNJU6Yk631/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkAZ8M/btsL4abnrS1/0xd8q6h9ef4LqNJU6Yk631/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkAZ8M/btsL4abnrS1/0xd8q6h9ef4LqNJU6Yk631/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkAZ8M%2FbtsL4abnrS1%2F0xd8q6h9ef4LqNJU6Yk631%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;764&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;764&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig7. [1]의 결과로, 5가지 Task에 대해서 어떻게 Group을 만들었을 때 가장 좋은 성능을 보여주는지에 대한 연구였다.
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;1.2. 왜 Grouping이 중요한가?&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;1.2.1. Negative Transfer&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Fig7.에서 알 수 있듯, 하나의 Group은 Encoder를 공유한다. 만약 Group내의 여러 Task의 Loss가 서로를 방해하는 방향으로 최적화된다면, 아무리 최적화를 잘한다고 하더라도, Loss의 하한선이 존재할 것이다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1421&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xD8BV/btsL4OMgb9h/wSJbr6ABrREg3TpNxqJTKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xD8BV/btsL4OMgb9h/wSJbr6ABrREg3TpNxqJTKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xD8BV/btsL4OMgb9h/wSJbr6ABrREg3TpNxqJTKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxD8BV%2FbtsL4OMgb9h%2FwSJbr6ABrREg3TpNxqJTKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;484&quot; height=&quot;344&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1421&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig8. 만약 각 Task에 대한 optimal parameter point가 A, B, C라고 했을 때, (A, C) 보다는 (A, B)로 Group을 만드는 것이 더 좋은 성능을 보여줄 것임을 알 수 있다.
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;1.2.2. Undeveloped Fields&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논문이 나올 당시, Grouping 분야의 연구가 많이 진행되지 않았었다. Brute Force를 막 벗어난 정도였고, 대부분의 MTL Grouping은 Heuristic하게 이뤄졌었다.&lt;/p&gt;
&lt;h1 style=&quot;color: #000000;&quot;&gt;2. Prior Works&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;2.1. Brute Force&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말 그대로 그냥 찾는거다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;2.2.Which Tasks Should Be Learned Together in Multi Task Learning?[1]&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;2.2.1. HOA(High Order Approximation)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Idea: Higher Order Set을 Lower Order Set으로 approximation한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 자세히 설명하자면, 2 task로 묶어서 Loss를 측정한 다음, 평균값으로 해당 Task의 단일 Loss를 예측한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;Example&lt;span&gt;&amp;nbsp;&lt;/span&gt;(B,C)=(0.2,0.3)&lt;span&gt;&amp;nbsp;&lt;/span&gt;then,&lt;span&gt;&amp;nbsp;&lt;/span&gt;A=0.1+0.72=0.4,B=0.2,C=0.4&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;Approximate&lt;span&gt;&amp;nbsp;&lt;/span&gt;(A,B,C)=(0.4,0.2,0.4)&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;(C,A)=(0.5,0.7)&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;(A,B)=(0.1,0.2)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 방식의 Approximation은 각 Pair의 조합에서의 Loss만을 신경쓰기 때문에, 세 개 이상의 Task를 묶었을 때의 시너지는 무시하지만, 그래도 어느 정도 잘 예측한다고 한다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;2.2.2 ESA(Early Stopping Approximation)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게, Fully Trained Netowrk와 20%의 데이터만 학습시킨 Network와 Validation Loss의 Pearson 계수가 굉장히 높게 나온다는 사실을 발견하고 이를 활용한 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히, Brute Force처럼 모든 Combination을 20%의 데이터만 사용해서 학습시킨 후, 가장 좋게 나온 Combination을 사용하는 것이다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1159&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dWZINC/btsL3PyHa6r/YlrQRkdykXhqnSK8vdSoR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dWZINC/btsL3PyHa6r/YlrQRkdykXhqnSK8vdSoR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dWZINC/btsL3PyHa6r/YlrQRkdykXhqnSK8vdSoR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdWZINC%2FbtsL3PyHa6r%2FYlrQRkdykXhqnSK8vdSoR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;1159&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1159&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig 9. 동일한 Task set에 대해서 HOA, ESA를 실험한 결과
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;2.3. Forward/Backward Selection&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;feature selection기법 중 forward/backward selection과 유사하게,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Empty Set에서부터 task를 하나씩 추가하거나, Entire Set에서부터 하나씩 task를 drop하는 방식으로도 측정을 하는데, 이 경우는 random하게 정하기 때문에 유의미한 결과를 얻으려면 반복이 필요하다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;2210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RBH4k/btsL3Sozeto/HnMKsDiopXHYdTu1m3CMF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RBH4k/btsL3Sozeto/HnMKsDiopXHYdTu1m3CMF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RBH4k/btsL3Sozeto/HnMKsDiopXHYdTu1m3CMF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRBH4k%2FbtsL3Sozeto%2FHnMKsDiopXHYdTu1m3CMF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;490&quot; height=&quot;541&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;2210&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig10. Overview of Forward Selection. Backward는 반대 과정이다.
&lt;h1 style=&quot;color: #000000;&quot;&gt;3. Problem Definition&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Task,Set;T=&amp;tau;1,;&amp;hellip;;,&amp;tau;n&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A Group of K Multi Task Network&lt;span&gt;&amp;nbsp;&lt;/span&gt;M=m1,;&amp;hellip;;,mk&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 있다. ( 즉,&lt;span&gt;&amp;nbsp;&lt;/span&gt;mi&amp;sube;T,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;cup;imi=T,mi&amp;cap;mj=\empty;where;i&amp;ne;j)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;shared parameter:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;theta;s&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;task-specific parameter:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;theta;i;for;&amp;tau;i&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 어떤 multi task group으로 나눴을 때 Task의 Performance를&lt;span&gt;&amp;nbsp;&lt;/span&gt;P(&amp;tau;i|M)로 나타낸다면, 우리의 목적은&lt;span&gt;&amp;nbsp;&lt;/span&gt;Mmax&amp;larr;argmaxM;&amp;Sigma;P(&amp;tau;i|M)을 구하는 것이다.&lt;/p&gt;
&lt;h1 style=&quot;color: #000000;&quot;&gt;4. Idea - Grouping Tasks by Measuring Inter-Task Affinity&lt;/h1&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;858&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WbDl3/btsL3yjqp9r/vkIxbikW3Slcy7X7CI0qyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WbDl3/btsL3yjqp9r/vkIxbikW3Slcy7X7CI0qyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WbDl3/btsL3yjqp9r/vkIxbikW3Slcy7X7CI0qyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWbDl3%2FbtsL3yjqp9r%2FvkIxbikW3Slcy7X7CI0qyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;858&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;858&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig 11. Overview of grouping process
&lt;p data-ke-size=&quot;size16&quot;&gt;전체적인 Processs는 위와 같다. 하나의 네트워크에서 모든 Task를 훈련시키며 Inter Task Affinity를 계산하고, 이를 통해 Network를 고른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 고른 Network를 기반으로 다시 학습시킨다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;4.1. Definition of Inter Task Affinity&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hard Parameter Sharning의 경우, Shared Network가 하나의 Shared Encoder 역할을 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ltotal=&amp;Sigma;Li에 대해 Gradient descent하는 과정에서, 각 task는 서로에게 영향을 주는데, 이 영향을 수치화시켜보고자 한 것이 이번 논문의 핵심 아이디어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수치화시키기 위한 아이디어는 MAML[5]에서 가져오게 되었는데, 간단하게 설명하자면, 전체 Task&lt;span&gt;&amp;nbsp;&lt;/span&gt;T&amp;tau;i의 Gradient로 업데이트한 파라미터를 이용해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;tau;j를 평가해서 수치화하는 것이다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;260&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMkDVS/btsL3lxS5Wo/OyIM6cFPIbnOybE2rYi3N0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMkDVS/btsL3lxS5Wo/OyIM6cFPIbnOybE2rYi3N0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMkDVS/btsL3lxS5Wo/OyIM6cFPIbnOybE2rYi3N0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMkDVS%2FbtsL3lxS5Wo%2FOyIM6cFPIbnOybE2rYi3N0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;260&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;260&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Eq1. Shared Parameter를 task i에 대해 update하는 식
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, 수치화할 때, Loss에 대해 상대적인 scale이 있을 것이기 때문에 ratio로써 표기한다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;497&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b23xn7/btsL5s9L7mb/cAk3nGPvIjRk8Ev0CLi35k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b23xn7/btsL5s9L7mb/cAk3nGPvIjRk8Ev0CLi35k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b23xn7/btsL5s9L7mb/cAk3nGPvIjRk8Ev0CLi35k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb23xn7%2FbtsL5s9L7mb%2FcAk3nGPvIjRk8Ev0CLi35k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;497&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;497&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Eq2. step t에서 task i에 대한 update가 task j에 대해 미치는 영향을 ratio로 표현하는 식. 만약 Z가 양수라면, 긍정적인 update가, 음수라면 부정적인 update라고 볼 수 있다.
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이를 training step에 대해 average한 수치로도 평가한다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;871&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ymZbD/btsL4PqOkNR/seMj2fv0jUA0NTN10eX7T0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ymZbD/btsL4PqOkNR/seMj2fv0jUA0NTN10eX7T0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ymZbD/btsL4PqOkNR/seMj2fv0jUA0NTN10eX7T0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FymZbD%2FbtsL4PqOkNR%2FseMj2fv0jUA0NTN10eX7T0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;871&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;871&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Eq3. Average of Inter Task Affinity over training step t
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 Averaged Score가 필요한지는 Experiment에서 따로 설명한다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;4.2. Network Selection, TAG(Task Affinity Grouping)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 번의 Training Step으로 Affinity Score Matrix를 얻을 수 있을 것이다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;779&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tMSPt/btsL2RDCsci/QAj1MAdKxxcKJxvDjWjGfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tMSPt/btsL2RDCsci/QAj1MAdKxxcKJxvDjWjGfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tMSPt/btsL2RDCsci/QAj1MAdKxxcKJxvDjWjGfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtMSPt%2FbtsL2RDCsci%2FQAj1MAdKxxcKJxvDjWjGfk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;680&quot; height=&quot;265&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;779&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig12. Inter Task Affinity Matrix의 예시. Task i에 대한 gradient로 update한 후 Loss를 측정한 결과. i to j와 j to i는 다르다.
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 얻은 Matrix에 대해서 앞서 언급했던 Inter Task Affinity가 최대가 되도록 grouping을 하면 된다. 이 문제는 Set Cover와 같이 NP HARD에 속하지만, Branch-and-Bound-like Algorithm(or Prune and Search)를 통해 해결할 수 있으며, task set에 대해 검색하는 것보다는 더 빠르게 할 수 있다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;Example 1.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 (A, B), C로 Grouping하게 되는 경우,&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;781&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceyECY/btsL38YYcuS/H1ALDCPMv4gBKboKv2BRM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceyECY/btsL38YYcuS/H1ALDCPMv4gBKboKv2BRM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceyECY/btsL38YYcuS/H1ALDCPMv4gBKboKv2BRM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceyECY%2FbtsL38YYcuS%2FH1ALDCPMv4gBKboKv2BRM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;760&quot; height=&quot;297&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;781&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig13. (A,B), C일 때 Affinity Score Group
&lt;p data-ke-size=&quot;size16&quot;&gt;각 Group에서 Task가 받는 Affinity Score를 모두 합한다. 위의 경우는 A가 받는 영향은 0.4, B가 받는 영향은 0.1이다. C는 혼자 있기 때문에 영향을 안받으므로, Sum of Affinity Score는 0.5이다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;Example 2.&lt;/h3&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;798&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cA7lTI/btsL36UnMlk/d7QGGzort3Ev1KBVPDMdXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cA7lTI/btsL36UnMlk/d7QGGzort3Ev1KBVPDMdXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cA7lTI/btsL36UnMlk/d7QGGzort3Ev1KBVPDMdXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcA7lTI%2FbtsL36UnMlk%2Fd7QGGzort3Ev1KBVPDMdXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;798&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;798&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig14. (A,B,C)의 경우 Affinity Score Group
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우는 (A, B, C)의 경우로, A가 받는 Affinity Score는 B&amp;rarr;A: 0.4, C&amp;rarr;A: 0.5 이므로, average를 해서 0.45로 계산한다. 이와 비슷하게 B와 C는 0.35, 0.3으로 계산이 되며 total summation은&lt;span&gt;&amp;nbsp;&lt;/span&gt;0.45+0.35+0.3=1.1이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 example은 모든 element가 양수이기 때문에 다 같이 훈련시키는 경우가 좋지만, 일반적인 경우 Score가 음수가 될 수 있기 때문에 항상 같은 Group으로 두는 것이 이득은 아니다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;4.3. Theoritical Analysis&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논문에서는 길게 적어놓았지만, 결국 이 Section에서 밝히고자 하는 것은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if;Zb&amp;rarr;a&amp;gt;Zc&amp;rarr;athen,La,b&amp;lt;La,c;?&lt;span&gt;&amp;nbsp;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Affinity Score가 큰 것이 더 작은 Loss를 보증하냐는 질문인데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;La;be;&amp;alpha;&amp;minus;strongly;convex,;&amp;beta;&amp;minus;strongly;smooth&lt;span&gt;&amp;nbsp;&lt;/span&gt;라는 assumption이라는 가정 하에 증명할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 증명은 논문에 있으나, 위의 가정 하에 Lemma1을 증명할 수 있고,&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lnOLT/btsL4YOMuZP/ziAQzfNKUkXjN2VJCFOFz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lnOLT/btsL4YOMuZP/ziAQzfNKUkXjN2VJCFOFz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lnOLT/btsL4YOMuZP/ziAQzfNKUkXjN2VJCFOFz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlnOLT%2FbtsL4YOMuZP%2FziAQzfNKUkXjN2VJCFOFz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;309&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;이 Lemma를 통해 명제1을 증명할 수 있는데&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ck4tMK/btsL4FB0oUk/mKw9dsw83ZMooHTnKCt6Xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ck4tMK/btsL4FB0oUk/mKw9dsw83ZMooHTnKCt6Xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ck4tMK/btsL4FB0oUk/mKw9dsw83ZMooHTnKCt6Xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fck4tMK%2FbtsL4FB0oUk%2FmKw9dsw83ZMooHTnKCt6Xk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;366&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;이 명제는 간단히 설명하자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if;Zb&amp;rarr;a&amp;gt;Zc&amp;rarr;athen,La,b&amp;lt;La,c;이 명제를&lt;span&gt;&amp;nbsp;&lt;/span&gt;cos(ga,gc)에 대한 상한선이 있다는 가정하에 참임을 밝혀낸 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, (A, C) 대신 (A, B)를 Grouping할 때, A, C가 충분히 서로를 닮지 않아야 기대한 효과를 볼 수 있다는 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+) Cosine Similarity에 대한 조건은 Hessian number가 작을 때 mild한 조건이라고 한다.&lt;/p&gt;
&lt;h1 style=&quot;color: #000000;&quot;&gt;5. Experiment&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;5.1. Before Experiment&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각종 그래프에서 Notation들을 축약해서 사용해서, 한 번 정리하고 넘어가고자 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;Grouping Methods:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;TAG: 이 논문에서 제안한 방법&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;CS: Inter Task Affinity를 Gradient간의 Cosine Similarity로 측정한 경우&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;RG: Random Grouping&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;HOA: Prior Work 참조&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;MTL: all tasks in single network&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;STL: a network per task&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;Optimization Methods: ( MTL에 optimization technique를 가한 결과)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;UW: Uncertainty Weight&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;GN: GradNorm[4]&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;PCGrad&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외 디테일한 실험의 설정은 논문에서 찾아보도록 하자.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;5.2. Supervised Task Grouping Evalutation&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저, Grouping을 찾는 시간에 대해 측정하고자 한다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;667&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7MGnY/btsL2Py0RGm/rGTy74otKNgREuHBKmVgB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7MGnY/btsL2Py0RGm/rGTy74otKNgREuHBKmVgB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7MGnY/btsL2Py0RGm/rGTy74otKNgREuHBKmVgB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7MGnY%2FbtsL2Py0RGm%2FrGTy74otKNgREuHBKmVgB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;667&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;667&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig15. 다양한 Group에 대해서 Grouping까지 걸리는 시간. Random하게 정하는 RG를 제외하고는 TAG가 가장 빠른 것을 볼 수 있다.&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;733&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dUyFr7/btsL26HEXhU/6zKNV61pJ1CcZCqIvepaq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dUyFr7/btsL26HEXhU/6zKNV61pJ1CcZCqIvepaq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dUyFr7/btsL26HEXhU/6zKNV61pJ1CcZCqIvepaq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdUyFr7%2FbtsL26HEXhU%2F6zKNV61pJ1CcZCqIvepaq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;733&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;733&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig16. Runtime과 Test Error에 대한 비교. MTL setting이 시간에 대한 기준이 되고, 다른 setting은 이에 대한 relative runtime으로 표시했다.
&lt;p data-ke-size=&quot;size16&quot;&gt;runtime과 test error 부분에서도 굉장히 준수한 성능을 낸 것을 알 수 있다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;677&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pDi5d/btsL36tlt9R/CwMvTAKjEQhcNZ6UzRCWn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pDi5d/btsL36tlt9R/CwMvTAKjEQhcNZ6UzRCWn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pDi5d/btsL36tlt9R/CwMvTAKjEQhcNZ6UzRCWn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpDi5d%2FbtsL36tlt9R%2FCwMvTAKjEQhcNZ6UzRCWn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;677&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;677&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig17. Latency Contraint에 대한 제한이 없을 경우 Test Error에 대한 비교
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;Latency Contraint, Memory Budget이렇게 부르는 이유는 Parallel하게 Network를 돌리게 되면, Latency는 각 네트워크의 파라미터에 비례할 것이며, Memory 자체는 전체 네트워크를 감당할 수 있어야 하기 때문이다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;MTL은 네트워크의 크기가 커질수록 더 좋은 성능을 보여주는 경향이 있다. 따라서, 이를 비교하기 위해서, 각 Network의 크기를 Latency Contraint, 전체 네트워크의 크기를 Memory Budget이라고 하여, Parameter의 수로 이를 판단한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 각 네트워크에 대한 파라미터 갯수에 대한 제한이 없는 경우, (대신 전체 네트워크의 크기에 대해서는 제한이 있는 경우)에는 GradNorm이나 다른 Optimization 방법보다 더 좋은 효과를 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 Grouping 방법이, Optimization만큼이나 더 효율적으로 MTL의 성능을 향상시킬 수 있는 방법임을 보여준다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;5.3. Ablation Study&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 알고리즘을 CelebA Dataset에서 수행해, 총 5가지의 질문에 대해 대답할 수 있었다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;5.3.1. Affinity와 Loss는 Align되는가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체적으로 Affinity와 Loss가 잘 Align되는 것을 알 수 있으며, 이는 수치적으로 Pearson 계수로 체크해볼 수 있는데, 0.93으로 상당히 높게 나타난다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HGa5R/btsL3RJTVer/KUSQGV6YduqCflodWn4J9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HGa5R/btsL3RJTVer/KUSQGV6YduqCflodWn4J9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HGa5R/btsL3RJTVer/KUSQGV6YduqCflodWn4J9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHGa5R%2FbtsL3RJTVer%2FKUSQGV6YduqCflodWn4J9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;1634&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1634&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Table1. optimal network와 TAG, 그리고 worst network에 대한 결과를 보여준다. a8을 제외하고는 대부분 비슷한 경향성을 보여준다.
&lt;p data-ke-size=&quot;size16&quot;&gt;a8이 exception으로 나타나는데, 이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://www.notion.so/MTL-Grouping-Efficiently-Identifying-Task-Groupings-for-Multi-Task-Learning-c46406980a194052b2f22cc675bbfc2f?pvs=21&quot;&gt;theoritical analysis&lt;/a&gt;에서 나왔던 것처럼 inter task affinity의 차이가 크지 않은 경우이기에 이런 Limitation이 나타나게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(a3의 best-worst affinity 차이가 0.16인데 반해, a8은 0.04라고 한다.)&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;5.3.2. Affinity는 매 Step마다 측정해야하는가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;every 10 step까지는 성능 저하 없이 작동하기 때문에 grouping speed를 늘릴 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 그보다 더 큰 step size나, 초반/중반/후반에만 체크하는 것은 성능 저하를 일으킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;\&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;991&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OTpO7/btsL38ScaGN/1uUH8mj9vvLLOelKgGc47K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OTpO7/btsL38ScaGN/1uUH8mj9vvLLOelKgGc47K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OTpO7/btsL38ScaGN/1uUH8mj9vvLLOelKgGc47K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOTpO7%2FbtsL38ScaGN%2F1uUH8mj9vvLLOelKgGc47K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;991&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;991&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Table2. 다양한 간격에 대해서 Affinity를 체크했을 때의 relative performance. 10 step까지는 performance degradation 없이 더 빠르게 수행할 수 있다.
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;5.3.3. Affinity를 계산할 때, Training Set과 Validation Set을 이용하는 것 사이에 차이가 있는가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 값은 비슷하게 변화한다고 한다. Pearson 계수로 0.98이 넘는 값을 보여주며, Grouping 역시 동일한 결과가 나온다고 한다. validation set을 사용하는 것이 더 informative할 수 있으나, 큰 차이는 없으며, cost가 더 들기 때문에 training set을 사용하는게 더 좋을 것 같다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;5.3.4. Traning동안 Affinity는 어떤 양상으로 변하는가&lt;/h3&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;742&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Oa8je/btsL2Rcx98s/whpjXBl7dUHFK4J702X9uK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Oa8je/btsL2Rcx98s/whpjXBl7dUHFK4J702X9uK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Oa8je/btsL2Rcx98s/whpjXBl7dUHFK4J702X9uK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOa8je%2FbtsL2Rcx98s%2FwhpjXBl7dUHFK4J702X9uK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;742&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;742&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Fig18. epoch에 따른 Affinity의 변화 양상
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;특정하게 변하는 패턴은 없으나, 변하는 양상은 비슷하다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;초기 값은 유사한 경우가 많은데, 이 경우는 common representation vector에 대한 affinity를 배우기 때문이라고 해석했다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;5.3.5. Hyper-parameter가 변하면 TAG를 통한 Grouping도 바뀌나?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TAG의 Grouping이 Hyper parameter variant한지를 체크해보는 실험인데, batch size와 learning rate를 변화시킬 때, 가장 좋은 선택이 바뀌는 것을 체크했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;total 511 possible combination 중에서 optimal grouping을 체크해서 relative performance를 체크했다고 하는데, 굳이 relative performance로 체크할 필요는 있었을까 싶다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;972&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRd6Q0/btsL2PlysIn/MZyPYOQ7ukEFhKyyKYKzRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRd6Q0/btsL2PlysIn/MZyPYOQ7ukEFhKyyKYKzRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRd6Q0/btsL2PlysIn/MZyPYOQ7ukEFhKyyKYKzRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRd6Q0%2FbtsL2PlysIn%2FMZyPYOQ7ukEFhKyyKYKzRK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;972&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;972&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Table3. 각 Group 숫자마다의 Optimal Groupings에 대한 상대적인 Performance Batch가 x0.5일 때는 3 groups가 가장 좋고, lr이 x2일 때는 2 groups가 optimal한 선택이 된다.
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼, hyper parameter에 따라서, 가장 좋은 option이 바뀌기 때문에, hyper parameter에 따라 TAG가 다르게 Grouping하는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 마지막 실험의 경우는, 이 TAG가 hyper parameter에 대해서 variant하다는 별로 좋지 않아보이는 특성임에도 불구하고, 논문에 당당하게 적어놓은게 조금 신기했다.&lt;/p&gt;
&lt;h1 style=&quot;color: #000000;&quot;&gt;Reference&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[1] Trevor Standley et al., Which Tasks Should Be Learned Together in Multi-task Learning?, ICML 2020&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[2] Yu Zhang et al., A Survey on Multi-Task Learning, IEEE 2017&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[3]&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://arxiv.org/search/cs?searchtype=author&amp;amp;query=Misra%2C+I&quot;&gt;Ishan Misra&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;et al., Cross-stitch Networks for Multi-task Learning, CVPR 2016&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[4]&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://arxiv.org/search/cs?searchtype=author&amp;amp;query=Chen%2C+Z&quot;&gt;Zhao Chen&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;et al., GradNorm: Gradient Normalization for Adaptive Loss Balancing in Deep Multitask Networks, ICML 2018&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[5] Chelsea Finn et al., Model-Agnostic Meta-Learning for Fast Adaptation of Deep Networks, ICML 2017&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #333333; text-align: left;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마치며..&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2023년도에 썼던 글을 블로그 이전하며 옮겨왔는데, 2025년의 시각에서 보는 논문과 이 때 읽으며 느낀 것들이 참 다르다고 생각된다. AI업계... 무진장 빠르다..&lt;/p&gt;</description>
      <category>AI</category>
      <category>Multi-task learning</category>
      <category>논문읽기</category>
      <author>Jaedey</author>
      <guid isPermaLink="true">https://jayde.tistory.com/3</guid>
      <comments>https://jayde.tistory.com/3#entry3comment</comments>
      <pubDate>Sun, 2 Feb 2025 00:25:46 +0900</pubDate>
    </item>
    <item>
      <title>ABCI and ABCI++</title>
      <link>https://jayde.tistory.com/2</link>
      <description>&lt;div style=&quot;color: #333333; text-align: left;&quot;&gt;
&lt;h1 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot;&gt;&lt;span&gt;&lt;br /&gt;ABCI, and its Connection&lt;/span&gt;&lt;/h1&gt;
&lt;h1 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot;&gt;&lt;span&gt;들어가기 전에..&lt;/span&gt;&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;1.&lt;/span&gt;&lt;/h2&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 글은 텐더민트 컨센서스에 대한 기초적인 이해가 있다고 가정하고 작성된 글이다.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;그렇다고, 따로 공부하고 읽어야할 정도는 아니고, 중간중간 모르는 것들을 찾아보면서 읽는 정도로도 충분할 것이다.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;또한 이전 포스팅&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://trytrytry-all.tistory.com/3&quot;&gt;&lt;span&gt;텐더민트와 ABCI&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;span&gt;을 읽는다면 더 편하게 이해할 수 있을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;2.&lt;/span&gt;&lt;/h2&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 글은 PDAO(Postech DAO) 세미나를 준비하면서 만든 자료를 근거해 쓴 글이다. 만약 이 글에 대한 동영상 자료를 보고 싶다면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://www.youtube.com/watch?v=dXnZE3qtoFs&amp;amp;t=415s&quot;&gt;&lt;span&gt;링크&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;span&gt;에서 세미나를 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h1 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot;&gt;&lt;span&gt;What is Tendermint, Not Tendermint Core&lt;/span&gt;&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Goal of Tendermint&lt;/span&gt;&lt;/h2&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;많은 곳에서 텐더민트에 대해서 검색하면, 컨센서스 알고리즘에 대한 설명이 나온다.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;그 이유는 단순히 그것이 텐더민트의 핵심이기 때문이다. 그렇다면, 핵심이 아닌 전체는 뭘까?&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;세부적으로 들어가기 이전에, 텐더민트의 목적에 대해서 살펴보고 넘어가도록 하자.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;텐더민트의 목적은 &quot;Being General Consensus Engine&quot;이다.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;즉, 텐더민트는 General Consensus Engine에 대한 솔루션을 제공해줌으로써, 사람들이 더 Application layer에 집중하게 도와주는 프로그램이다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;어떤 Dapp을 만들기 위해서는, 앱이 체인 위에 올라가야 한다. 즉, app을 만들기 위해서 그 아래 레이어인 새로운 체인을 만만들어야 한다. 당연하게도, 쉽지 않고, 코스트가 많이 드는 일이다. 왜냐하면, 컨센서스나, 네트워크를 다 짜야 하기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;true&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;layerOfBlockchain.png&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJFzaq/btsL47EMMXQ/JwJkwdCmckELUBTaM8QXDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJFzaq/btsL47EMMXQ/JwJkwdCmckELUBTaM8QXDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJFzaq/btsL47EMMXQ/JwJkwdCmckELUBTaM8QXDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJFzaq%2FbtsL47EMMXQ%2FJwJkwdCmckELUBTaM8QXDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;602&quot; height=&quot;385&quot; data-filename=&quot;layerOfBlockchain.png&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서, 네트워크와 PoS-BFT스타일 컨센서스를 구현해서 컨센서스 엔진으로 만든 것이 Tendermint Core이고, 그러한 Core를 사용하기 위한 Generic Application Interface가 바로 Application Blockchain Interface, ABCI이다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;true&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ABCI_relation.png&quot; data-origin-width=&quot;503&quot; data-origin-height=&quot;437&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bruztp/btsL4I6zYMa/9g5DxmY5xBE4FF3S3cxQX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bruztp/btsL4I6zYMa/9g5DxmY5xBE4FF3S3cxQX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bruztp/btsL4I6zYMa/9g5DxmY5xBE4FF3S3cxQX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbruztp%2FbtsL4I6zYMa%2F9g5DxmY5xBE4FF3S3cxQX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;503&quot; height=&quot;437&quot; data-filename=&quot;ABCI_relation.png&quot; data-origin-width=&quot;503&quot; data-origin-height=&quot;437&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고, 텐더민트의 장점이라고 할 수 있는것이 바로, application layer에 대한 언어제한이 없다는 것이다. Go, Rust, C++, Python등 아무런 언어를 사용해도 된다. 이를 위해서 텐더민트는 몇 가지 방법을 지원해주는데 이는 뒤에서 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;텐더민트에 대해서 정리를 해보자면, 텐더민트는 두 가지 구성요소로 이뤄져 있고,&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;Tendermint=TendermintCore+ABCI&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각 요소는&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;Tendermint Core: Network, Consensus 기능을 구현한 Consensus Engine&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;ABCI: Tendermint Core를 사용하기 위한 General Application Interface(API와 유사한 개념이라고 생각하면 이해가 편할듯 하다.)&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 프로그램의 목적은, Dapp을 구현할 때, 언어, 네트워크, 컨센서스 등 앱이 아닌 다른 문제를 해결해주는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;h1 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot;&gt;&lt;span&gt;More details in ABCIs&lt;/span&gt;&lt;/h1&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;텐더민트 코어는 메세지 시스템으로 그 상태가 변화한다. 노드들 사이에 메세지를 주고 받고, 그 주고 받은 메세지를 로그로 기록하면서, 특정 상태가 되면 변화하는 시스템이다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가장 대표적으로, PREVOTE stage에서 특정 value(proposal)에 대해 prevote하는 메세지가 2f+1이상 오게 된다면, PRECOMMIT stage로 넘어가게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ABCI 역시 이러한 메세지 시스템을 사용한다. ABCI는 메세지 타입의 메소드 집합이라고 말할 수 있는데, 이러한 메세지 타입을 사용해서 app과 core(Tendermitn Core)가 소통한다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ABCI 메소드는 두 가지로 분류할 수 있다. Request, Response이다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;RequestAndResponse.png&quot; data-origin-width=&quot;1105&quot; data-origin-height=&quot;241&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMLsRD/btsL4z2Z1xf/Kk7DGt72nu5PSxUhgKaqa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMLsRD/btsL4z2Z1xf/Kk7DGt72nu5PSxUhgKaqa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMLsRD/btsL4z2Z1xf/Kk7DGt72nu5PSxUhgKaqa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMLsRD%2FbtsL4z2Z1xf%2FKk7DGt72nu5PSxUhgKaqa0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1105&quot; height=&quot;241&quot; data-filename=&quot;RequestAndResponse.png&quot; data-origin-width=&quot;1105&quot; data-origin-height=&quot;241&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Tendermint Core에서 Request의 메세지를 보내면, App에서는 Response 메세지를 보낸다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;e.g. RequestFlush&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;⟹&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;ResponseFlush&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Types of ABCI&lt;/span&gt;&lt;/h2&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ABCI 메소드는 사용처에 따라서 몇 가지로 나뉠 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;Executing Tx(Transactions)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;Validating Tx&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;Query&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;for StateSync: 이후에 설명&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;General functionality&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이는 이후에 Connection과 관련이 있기 때문에 이러한 종류로 나뉠 수 있다 정도로 알아두면 좋을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;h1 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot;&gt;&lt;span&gt;How to support language-free option?&lt;/span&gt;&lt;/h1&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이전 챕터에서 텐더민트는 Dapp을 언어와 상관없이 짜게 해준다고 했다. 그렇다면 이 기능을 어떻게 지원할까?&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Case of Golang&lt;/span&gt;&lt;/h2&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 Dapp을 Golang을 사용하여 짜는 경우, 그냥 ABCI메소드를 함수를 부르듯이 쓰면 된다. 텐더민트가 Go로 만들어진 프로그램이기 때문에, 단순히 import해서 사용하듯 간단하게 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 경우, 아무래도, ABCI를 사용하는 방법이 단순하기 때문에 개발 시간/성능 면에서 뛰어나다고 말할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Case of gRPC&lt;/span&gt;&lt;/h2&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;gRPC는 google에서 만든 RPC framework이다. (간단히 말하자면, 정해진 규격(protobuf in gRPC)를 사용하여 데이터의 형식을 맞춰주고, 그 데이터를 이용하여 함수를 호출해주는 시스템이다.) 구글의 척척박사님들이 만들어준 프로그램답게, 성능이 좋지만, 다른 프로그램을 하나를 끼고 작동하는 것은 오버헤드가 분명한 작업이다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 경우, 어느정도 메이저한 언어라면 gRPC에서 지원을 해주기 때문에 왠만한 언어를 다 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Case of TSP&lt;/span&gt;&lt;/h2&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;TSP(Tendermint Socket Protocol)는 텐더민트에서 만든 Socket Protocol로, 아무 언어와 protobuf를 사용해 직렬화한 데이터를 처리하는 방식이다.&lt;/span&gt;&lt;/p&gt;
&lt;h1 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot;&gt;&lt;span&gt;Connection&lt;/span&gt;&lt;/h1&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그렇다면 Go/gRPC/TSP로 나눠서 생각하면 되는걸까?&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;답은 &quot;아니오&quot;이다. 언어의 종류외에도 고려해야할 사항이 하나 더 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;바로 &quot;호출 환경&quot;이다. Dapp은 체인 위에 올라가는만큼, 사용자가 컨센서스에 참여해 계속해서 체인을 따라가거나, 풀 노드에게 요청하거나 하는 방법을 써야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, SMR(State Machine Replication) Engine과 Dapp의 실행환경(프로세스)이 동일한지가 관건이다. 서로 다른 장소에서 실행하게 된다면, Dapp을 직접 호출할 수 없을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그렇다고, SMR과 Dapp을 항상 같은 프로세스에서 실행하기는 어려운 법이다. 예를 들어, 사용하는 Dapp의 종류가 여러가지가 된다면, 한 프로세스에서 그 모든 것들을 처리하기 어려울 것이고, Dapp끼리 소통한다면 더더욱 힘들 것이다,&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이러한 경우 gRPC or TSP를 사용해서 SMR과 Dapp을 연결해준다. 그리고, 이런 소통 환경은 불안정할 수 있기 때문에 Core와 ABCI 사이에 state를 만들어서 안전한 실행을 지원해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 때, 안전한 실행을 지원하기 위해서, 특정 타입의 ABCI를 맡아서 처리하고, state를 가지는 것이 바로 Connection이다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Connection의 종류&lt;/span&gt;&lt;/h2&gt;
&lt;div contenteditable=&quot;true&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Specific_Connection.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;511&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3cFrS/btsL3zP9N7N/Nx5cVOh83fFtQ9hTZlwZgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3cFrS/btsL3zP9N7N/Nx5cVOh83fFtQ9hTZlwZgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3cFrS/btsL3zP9N7N/Nx5cVOh83fFtQ9hTZlwZgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3cFrS%2FbtsL3zP9N7N%2FNx5cVOh83fFtQ9hTZlwZgk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1866&quot; height=&quot;745&quot; data-filename=&quot;Specific_Connection.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;511&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Connection에 대해서 더 자세히 알아보자. 앞서, ABCI가 app과 Core를 연결하는 인터페이스라고 설명한 바 있다. 이러한 연결 방식을 Connection을 사용하여 더 구체화시킨 것이 오른쪽의 그림이다. App과 Core 사이에서 ABCI Connection이 존재하고, 이 중간 과정을 거쳐서 통신한다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Connection의 종류로는&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;Consensus Connection&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;Mempool Connection&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;Query Connection&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;Snapshot Connection&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;true&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Connections.png&quot; data-origin-width=&quot;805&quot; data-origin-height=&quot;420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTt2LK/btsL4QQNGUY/1ImewFP6BlpEkTtoTCO07K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTt2LK/btsL4QQNGUY/1ImewFP6BlpEkTtoTCO07K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTt2LK/btsL4QQNGUY/1ImewFP6BlpEkTtoTCO07K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTt2LK%2FbtsL4QQNGUY%2F1ImewFP6BlpEkTtoTCO07K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;805&quot; height=&quot;420&quot; data-filename=&quot;Connections.png&quot; data-origin-width=&quot;805&quot; data-origin-height=&quot;420&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각 Connection들은 ABCI Type에 해당되는 일을 수행한다. 그리고 5번의 경우는 General하게 모든 Connection에서 처리되어야 하는 ABCI Method이다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각각 Connection이 어떤 역할을 하는지 더 자세히 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Connection's Role&lt;/span&gt;&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Consensus Connection&lt;/span&gt;&lt;/h3&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;**&lt;/span&gt;&lt;b&gt;&lt;span&gt;DeliverTxState&lt;/span&gt;&lt;/b&gt;&lt;span&gt;**&lt;/span&gt;&lt;/span&gt;&lt;span&gt;라는 state를 유지하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;주로 블럭(Transactions)을 실행하는 ABCI method를 실행하는 메소드들을 담당하고, 그런 메소드들에 의해서 state가 업데이트된다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;[BeginBlock&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;&amp;rarr;&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;bunch of DeliverTx&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;&amp;rarr;&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;EndBlock] 에 의해서 state 변화가 일어나고, Commit을 할 경우, 변화된 state가 disk로 저장된다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Mempool Connection&lt;/span&gt;&lt;/h3&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Mempool connection에 대해서 알아보기 전에, Mempool이 무엇인지 모르는 사람을 위해 설명하고 넘어가고자 한다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote style=&quot;background-color: #000000; color: #333333; text-align: center;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;h3 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Mempool?&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #666666;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Peer 혹은 Client로부터 동의 혹은 처리해줬으면 하는 Tx들이 들어오게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그렇게 받은 Tx들은 악의적이거나 조작된 것일 수 있기 대문에 검증하는 작업이 필요한데,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그런 검증 작업을 거친 후, 안전하고, 아직 처리되지 않은 Pending 상태의 Tx들을 모아두는 장소가 바로 Mempool이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Tx를 받고, 저장하고, 검증하고, 다시 전달하는 역할을 모두 수행한다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Mempool connection은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;**&lt;/span&gt;&lt;b&gt;&lt;span&gt;CheckTxState&lt;/span&gt;&lt;/b&gt;&lt;span&gt;**&lt;/span&gt;&lt;/span&gt;&lt;span&gt;라는 state를 유지하며, 이 state는 Tx를 검사하는 CheckTx에 의해서 상태가 변하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;내 생각에 이 커넥션의 가장 중요한 역할은 Replay Protection이다. mempool에 포함할 때나, Commit을 할 때, 이 커넥션은 Mempool안의 Tx를 수 차례 반복해서 검사하게 된다. 여기서 발생하는 문제는 이미 검사했거나, 검사할 필요가 없는 Tx까지 중복해서 검사를 하게 되는 것이다. 이를 막기 위한 방법이 Replay Protection이고, Type parameter(e.g. Recheck_type, or New_type)를 argument로 쓰는 등의 방법을 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Query Connection&lt;/span&gt;&lt;/h3&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Query Connection은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;**&lt;/span&gt;&lt;b&gt;&lt;span&gt;QueryState&lt;/span&gt;&lt;/b&gt;&lt;span&gt;**&lt;/span&gt;&lt;/span&gt;&lt;span&gt;를 유지하며, 이 state는 DeliverTxState가 disk로 업데이트 될 때, 동일하게 업데이트 된다. 즉, 안정되게 저장된 상태를 항상 유지하며, 그에 대한 정보를 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한, 저장하는 정보에는 past/current height를 비롯해, merkel proof등을 같이 저장하기 때문에 이 정보를 통해서 특정 peer나 노드를 필터링할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Snapshot Connection&lt;/span&gt;&lt;/h3&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Snaptshot Connection은 State Sync만을 위한 커넥션이다. 이 기능은 필수적이지 않기 때문에 이 커넥션을 만드는 것 역시 선택적인 옵션이다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote style=&quot;background-color: #000000; color: #333333; text-align: center;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p style=&quot;color: #666666;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;State Sync란?&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Genesis부터 시작하는 노드가 빠르게 현재 Height까지 따라잡기 위한 옵션이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Snapshot이라고 하는 가장 필수적인 데이터를 피어로부터 제공받아서, 적용하는 방식이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Snapshot을 적용하는 과정은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;Peer들에게 Snapshot을 요청한다&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;각 Peer들의 Height나 다른 부가적인 요소를 고려해 Snapshot에 우선순위를 부여한다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;가장 높은 우선순위를 가진 Snapshot을 적용한다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;적용을 완료한 이후, 다른 Peer에게 쿼리를 보내서 올바른 상태로 왔는지 확인한다.(Through Query Connection)&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #666666;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 작업은 Deterministic, Asynchronous, Consistent해야만 한다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Connections When Commit&lt;/span&gt;&lt;/h2&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;평소 커넥션들은 concurrent하게 작동한다. 단순하게 생각해봤을 때, 이는 당연하다. 쿼리를 하기 위해서 블럭 실행을 멈추거나 늦출 필요가 없기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서, 커넥션들은 distinct하고, concurrent한 state를 유지한다. 하지만, Commit을 수행할 때는 예외가 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Commit은 Tx들을 실행하고 저장하는 작업이다. 그리고 우리는 항상 Deterministic하고 Consistent한 결과물이 저장되기를 바란다. 따라서 모든 커넥션들은 synchronized되어야할 필요가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h1 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot;&gt;&lt;span&gt;ABCI++&lt;/span&gt;&lt;/h1&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ABCI가 어떤 것이고, 어떻게 전달되는지에 대해서 알아봤다. 그렇다면, ABCI에 단점은 없을까?&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;저 설명만 듣고, 뭐가 잘못되었는지 알아채기는 쉽지 않은 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 텐더민트에서 설명해주길, 몇 가지 개선안이 있다고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;크게&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;App과 Core의 interaction을 늘려 Scalability 증가&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;Vote Extension을 통한 State Sync의 Scalability 증가&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;span&gt;ABCI Method 개편&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;으로 나눌 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;1.&lt;/span&gt;&lt;/h2&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기존 ABCI 구조에서 Block을 실행할 수 있는 때는 Commit때밖에 없었다. 이는 App과 Core의 interaction이 단 한 번, 그것도 커밋 때이다. 그래서 ABCI++에서는&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;1.1 When Proposal is created&lt;/span&gt;&lt;/h3&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 때는 Core가 App에 Primitive proposal을 보내서 batch optimization을 실행시킨다. 그리고 App이 modified proposal을 돌려주면, modified proposal을 전파한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;1.2 When Proposal is received&lt;/span&gt;&lt;/h3&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;batch optimized proposal을 받게 되면, 이 proposal 안의 Tx를 먼저 실행해볼 수 있게 바뀌었다. 이를 통해서 실행할 수 있는 때를 늘리고, 동시에 invalid Tx를 걸러내고, 실행된 상태를 Cache해서 나중에 finalized할 때, Cache된 정보를 기반으로 더 빠른 finalize를 진행할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;2.&lt;/span&gt;&lt;/h2&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Vote Extend라는 메소드와 Vote Extension이라는 binary data가 추가되었다. 이 Vote Extension 데이터는 Non-nil value Precommit을 진행할 때, Vote Extend 메소드를 통해서 Precommit 메세지에 덧붙일 수 있는 데이터이다.(0-length data가 될 수 있다.)&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 Vote Extension은 Proposal에 non-deterministic을 준다고 하는데, 이게 어떤 장점을 가지는지는 나도 잘 이해하지 못했다. 다만, 텐더민트 깃헙의 PR에서 알 수 있었던 것은 이 Vote Extension이 State Sync 혹은 Node Recovery에 중요한 역할을 한다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;3.&lt;/span&gt;&lt;/h2&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;마지막으로 Proposal을 실행할 때, [BeginBlock&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;&amp;rarr;&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;DeliverTx&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;&amp;rarr;&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;EndBlock] 순으로 메소드가 진행되었는데, 굳이 이렇게 보낼 필요가 없었던 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;중간에 어떠한 이유로 끊기더라도, 어떤 Tx가 실행되었는지 체크해야하고, 혹은 처음부터 다시 실행해야하는데, 굳이 저렇게 나눠놓을 필요가 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 FinalizeBlock이라는 하나의 메소드로 합쳐서 사용하게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;h1 style=&quot;color: #000000;&quot; contenteditable=&quot;true&quot;&gt;&lt;span&gt;마치며.&lt;/span&gt;&lt;/h1&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ABCI, ABCI++에 대해 배우면서 이게 뭔가 싶었다. 배워도 배우는 느낌이 나지 않는 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이게 Application Layer에 덜 신경쓰게 해주려고 만든 건데, 원래는 얼마나 귀찮았을지 상상도 안간다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 포스팅으로는 아마 PoW, PoS 혹은 Tendermint BFT algorithm(Latest gossip on BFT)중에서 할 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p contenteditable=&quot;true&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;PDAO활동을 하면서 배우는 것들도 많은데, 정리가 되지 않아서 뭘 잘 알고 뭘 잘 모르는지 모르겠다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #333333; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div id=&quot;reaction-4&quot; data-tistory-react-app=&quot;Reaction&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>abci</category>
      <category>abci++</category>
      <category>tendermint</category>
      <category>텐더민트</category>
      <author>Jaedey</author>
      <guid isPermaLink="true">https://jayde.tistory.com/2</guid>
      <comments>https://jayde.tistory.com/2#entry2comment</comments>
      <pubDate>Sun, 2 Feb 2025 00:23:01 +0900</pubDate>
    </item>
    <item>
      <title>텐더민트, 그리고 ABCI</title>
      <link>https://jayde.tistory.com/1</link>
      <description>&lt;h1 style=&quot;color: #000000; text-align: left;&quot;&gt;1. 텐더민트란 무엇인가?&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;1.1 텐더민트의 구성요소&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;간단히 말하자면, 텐더민트는 어떤 언어로든 블록체인을 만들기 위한 소프트웨어이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;텐더민트는 크게 블록체인 합의 엔진(a.k.a 텐더민트 코어)와 Generic Application Interface(a.k.a ABCI)로 이뤄져 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;텐더민트 사이트의 설명에 의하면, 합의 엔진은 모든 State Machine(=node)에 동일한 Transaction이 동일한 순서로 기록되게 하고, ABCI(&lt;b&gt;A&lt;/b&gt;pplication&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;B&lt;/b&gt;lock&lt;b&gt;c&lt;/b&gt;hain&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;I&lt;/b&gt;nterface)는 어떤 언어로든 이 작업이 이뤄질 수 있게 해준다. 조금 더 가볍게 설명하자면, 텐더민트 코어는 비잔틴이 1/3 이하일 때, 모든 노드가 올바른 Transaction에 합의하고, 기록하는 작업을 도와주는 모듈이고, ABCI는 이 합의과정 중에서 필요한 작업들을 구현하기 편하게 하기 위한 API라고 생각하면 좋다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;1.2. 왜 이런 구조를 가졌을까?&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;텐더민트는 다른 블록체인과는 다르게 합의 엔진과 ABCI로 나뉘어진 구조를 가지고 있다. 텐더민트는 이런 구조를 통해서 기존 블록체인(비트코인, 이더리움)의 단점을 개선하고자 했다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;텐더민트 페이지에서 기술된 단점은 다음과 같다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;1.2.1코드를 재사용하기 어렵다&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;비트코인이나 이더리움의 경우, p2p connectivity, mempool bradcasting of transactions 등의 모든 작업을 하나의 프로그램에서 모두 다룬다. 따라서, 이 중 하나의 작업을 바꾸고자 한다면 아무리 추상화 작업이 잘되었다고 하더라도, 프로그램 전체에 대한 전반적인 이해가 필요하다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;1.2.2. 블록체인을 구성하는 언어를 강제한다.&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 이더리움의 경우, Turing Computable Byte Code를 사용한다. 따라서, 이더리움을 사용하고자 한다면, 이 Byte Code로 컴파일할 수 있는 언어를 선택해야만 한다.&lt;/p&gt;
&lt;h1 style=&quot;color: #000000; text-align: left;&quot;&gt;2. Intro to ABCI&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;2.1 ABCI에 대한 간단한 이해&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;텐더민트 코어는 ABCI를 만족하는 Socket Protocol을 사용하여 Application과 소통한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;더 자세하게 설명을 하자면, 우리가 사용하는 Application이 있고, 실제로 블록체인에 대한 합의가 이뤄지고, Broadcasting하는 엔진이 있는데, 이 사이를 ABCI를 사용한 어떤 Protocol로 연결한다는 의미이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;(더 구체적인 예시로 핸드폰을 생각해보자. State Machine에 해당하는 핸드폰 단말에서 앱 버튼 하나를 누르면 그 버튼에 연결된 일련의 API들이 실행되어서 실제 서버에 작업을 요청하고 그 결과를 보여준다고 생각하면 이해가 편할 수도 있겠다.)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;따라서, ABCI는 텐더민트(State Machine Replication Engine)과 Application(The Actual State Machine)사이의 인터페이스이다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;2.1.1 더 자세한 이해&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;ABCI의 실체는 set of methods로 이뤄져 있으며, 각 method는&lt;span&gt;&amp;nbsp;&lt;/span&gt;Request&lt;span&gt;&amp;nbsp;&lt;/span&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;Response&lt;span&gt;&amp;nbsp;&lt;/span&gt;Message Type으로 이뤄져 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;뜬금없이 Message Type이 나와서 이해가 가지 않는 사람을 위한 부가설명을 하자면, 실제 State Machine과 Engine 사이에서 ABCI가 각 State Machine과 Engine사이에서 요청하고 응답하는 시스템으로 이뤄지고 있다. 그래서 이를 Message라고 부르고 있다. 아래의 그림에서 Mempool과 Application Logic사이에 ABCI를 통해 서로 요청하고 응답하는 것을 볼 수 있다. 이 그림에 대해서는 나중에 더 자세히 알아볼 예정이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1112&quot; data-origin-height=&quot;907&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9I7db/btsL37Z1FMb/wEXWyUTbb65nJK7VoIaQ3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9I7db/btsL37Z1FMb/wEXWyUTbb65nJK7VoIaQ3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9I7db/btsL37Z1FMb/wEXWyUTbb65nJK7VoIaQ3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9I7db%2FbtsL37Z1FMb%2FwEXWyUTbb65nJK7VoIaQ3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1112&quot; height=&quot;907&quot; data-origin-width=&quot;1112&quot; data-origin-height=&quot;907&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;2.1.2 예시) Bitcoin-like System with Tendermint&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;비트코인의 노드는 UTXO(Unspent Transaction Output) Database를 모두 유지하며 따라간다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;만약 누군가 ABCI를 사용해서 Bitcoin-like system을 만들고자 한다면, 텐더민트 코어는 다음과 같은 역할을 수행한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;노드 간 Block과 Transaction을 공유&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;Canonical하고 Immutable한 Order of Transaction을 만들기.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;반면 Application은 다음과 같은 역할을 해야할 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;UTXO Database 유지하기&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;Transaction의 암호학적 서명을 증명하고, 서명하기&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;클라이언트가 UTXO Database에 쿼리를 보내게 해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;2.2 Type of ABCI&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.2 파트는 ABCI의 primitive한 타입에 대해 다루는 파트로, 텐더민트의 세부내용이 아닌 개괄적인 내용에 대해 관심이 있다면, 이런 타입이 있구나 하고 넘어가도 좋고, 그냥 넘어가도 좋습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;앞서 언급했던, ABCI의 Message type에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;Request&lt;span&gt;&amp;nbsp;&lt;/span&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;Response&lt;span&gt;&amp;nbsp;&lt;/span&gt;가 있다. 그리고 조금 더 자세히 들어가면 세 가지의 primitive message type이 존재한다. 각각,&lt;span&gt;&amp;nbsp;&lt;/span&gt;DeliverTx&lt;span&gt;&amp;nbsp;&lt;/span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;CheckTx&lt;span&gt;&amp;nbsp;&lt;/span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Commit&lt;span&gt;&amp;nbsp;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;각 Type이 의미하는 바는 아래에서 설명하고자 한다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;2.2.1 DeliverTx&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;DeliverTx는 말 그대로 Transaction을 Deliver해주는 메세지 타입을 추상화한 타입이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 이 메세지들은 Transaction을 담고 있으며, Application이 DeliverTx message를 받은 경우, 메세지에 있는 Transaction(e.g. Current State, Application protocol and cryptographic credentials of the transaction)을 입증해야한다. 만약 transaction이 입증된다면, 그 transaction들은 application state를 업데이트해줘야 한다. (KV Store에서 value를 잡아준다던지, UTXO database를 업데이트한다던지하는 방식으로)&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;2.2.2 CheckTx&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;CheckTx는 말 그대로, 어떤 transaction을 validating하기 위한 메세지 타입이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;블록체인내에서 많은 작업들은 증명을 필요로 한다. 그런 경우에 사용한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;예시로는 텐더민트 코어의 mempool은 transaction은 transaction의 validity를 CheckTx로 확인한 이후에야 p2p network를 통해서 valid transaction을 전파한다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;2.2.3 Commit&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;Commit은 현재 application state에 대한 암호학적 commitment를 계산할 때 사용된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;DeliverTx와 CheckTx에 비해 불명확하게 보일 수 있다. 더 자세히 설명하자면, 블록체인에서 주로 다음 블록 헤더에는 현재 블록에 대한 내용이 들어가있다. 그래야 체인이 연속적으로 유지될 수 있기 때문이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;Commit은 이 과정을 계산해준다. 다음 블록 헤더에 들어가야할 내용, 그 중 현재 Application state의 cryptographic commitment를 계산해준다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;CheckTx와는 달리 블록 자체에 대한 검증을 가지고 있다고 보면 더 쉽게 이해할 수 있을 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;Commit은 몇 가지 편리한 특성을 가지고 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333333; text-align: left;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;쉽게 에러를 간파할 수 있다.&lt;br /&gt;current state를 계산하는 과정에서 Inconsistency가 발견된다면, 포크된 블록에 대해서 계산되었음을 알 수 있다.&lt;br /&gt;(이전 블록헤더의 내용이 잘못되었다면, 현재 계산하고 있는 블록은 forked chain위에 있는 블록임이 자명하다.)&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;이 특성을 통해, light client의 보안성을 더 간편하게 발전시킬 수 있다. 예시를 들자면, Merkle-hash proof는 block hash를 체크함으로서 쉽게 증명될 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 style=&quot;color: #000000; text-align: left;&quot;&gt;3. 어디에서 ABCI가 사용되는가?&lt;/h1&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;텐더민트 코어에서는 크게 3곳에서 ABCI connection이 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1112&quot; data-origin-height=&quot;907&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m41AP/btsL442kWop/fI7MKVhoPnZGAk1Oe4CEz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m41AP/btsL442kWop/fI7MKVhoPnZGAk1Oe4CEz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m41AP/btsL442kWop/fI7MKVhoPnZGAk1Oe4CEz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm41AP%2FbtsL442kWop%2FfI7MKVhoPnZGAk1Oe4CEz1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1112&quot; height=&quot;907&quot; data-origin-width=&quot;1112&quot; data-origin-height=&quot;907&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333333; text-align: left;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;b&gt;Mempool Connection&lt;/b&gt;: validation of transactions when broadcasting in the mempool&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;b&gt;Consensus Connectoin&lt;/b&gt;: consensus engine to run block proposals&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset; color: #000000;&quot;&gt;&lt;b&gt;Info(Query) Connection:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;querying the application state&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;3곳이라고 했는데, 막상 그림에서는 ABCI가 2곳밖에 없다. Mempool과 Consensus Logic사이에 ABCI가 하나 더 있어야 할 것 같지만, 다시금 되새겨보자면, ABCI는 Application과 Consensus Engine사이의 Interface이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;조금 더 자세히 보면, 1번이 Application과 Mempool사이에서 작용한다. 2번, 그리고 3번이 Application과 Consensus Logic사이에서 작용한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;Transaction을 Mempool로 보내고, 해당 Transaction이 valid한지 확인하는 과정이 1번이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;새로운 블록이 commit되었을 때, 다른 State Machine들도 이 블록에 대한 정보을 통해 State를 따라가는 것이 2번&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;마지막으로, Consensus Engine에서 Application으로 쿼리를 보내거나 그 역이 3번이라고 생각하면 될 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;추가적으로, 4번째의 경우인, Snapshot Connection에도 ABCI Connection이 있다고 하는데, 이는 optional connection이기 때문에 나중에 기회가 되면 알아보고자 한다.&lt;/p&gt;
&lt;h1 style=&quot;color: #000000; text-align: left;&quot;&gt;Reference&lt;/h1&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;What is Tendermint:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://docs.tendermint.com/master/introduction/what-is-tendermint.html&quot;&gt;https://docs.tendermint.com/master/introduction/what-is-tendermint.html&lt;/a&gt;&lt;/p&gt;</description>
      <category>블록체인</category>
      <category>abci</category>
      <category>tendermint</category>
      <category>블록체인</category>
      <category>텐더민트</category>
      <author>Jaedey</author>
      <guid isPermaLink="true">https://jayde.tistory.com/1</guid>
      <comments>https://jayde.tistory.com/1#entry1comment</comments>
      <pubDate>Sun, 2 Feb 2025 00:22:05 +0900</pubDate>
    </item>
  </channel>
</rss>