package(디렉토리) 아래에는 무조건 __init__.py를 넣어줘야 합니다. __init__.py가 index.md로 변환됩니다.
mkdoc.yml
site_name: docs_name
docs_dir: "docs/"
plugins:
- search
- gen-files:
scripts:
- script/gen_ref_pages.py # mkdocs serve할 때 자동으로 md 파일 생성
- literate-nav:
nav_file: SUMMARY.md # API 구조가 적힌 파일. gen_ref_pages.py로 생성
- section-index
- mkdocstrings:
handlers:
python:
options:
docstring_style: numpy # 다른 스타일: google, sphinx
theme : material # 다른 테마: readthedocs
nav:
- Code Reference: code_reference/ # documentation의 컨텐츠를 표출하기 위한 md 파일을 지정
# rest of the navigation...
plugin을 넣어주지 않으면 코드가 제대로 동작하지 않을 수 있습니다.
script/gen_ref_pages.py
"""Generate the code reference pages and navigation."""
from pathlib import Path
import mkdocs_gen_files
nav = mkdocs_gen_files.Nav()
root = Path(__file__).parent.parent
src = root
for path in sorted(src.rglob("*.py")):
module_path = path.relative_to(src).with_suffix("")
doc_path = path.relative_to(src).with_suffix(".md")
full_doc_path = Path("code_reference", doc_path)
parts = tuple(module_path.parts)
if parts[0] != 'package_name' or parts[-1] == "__main__" :
continue
elif parts[-1] == "__init__":
parts = parts[:-1]
doc_path = doc_path.with_name("index.md")
full_doc_path = full_doc_path.with_name("index.md")
nav[parts] = doc_path.as_posix()
with mkdocs_gen_files.open(full_doc_path, "w") as fd:
ident = ".".join(parts)
fd.write(f"::: {ident}")
mkdocs_gen_files.set_edit_path(full_doc_path, path.relative_to(root))
with mkdocs_gen_files.open("code_reference/SUMMARY.md", "w") as nav_file:
nav_file.writelines(nav.build_literate_nav())
python 파일을 실행해보면 docs/code_reference 디렉토리 아래에 package의 구조에 맞춰 f"::: {ident}" 가 적힌 markdown 파일이 생기는 것을 확인할 수 있습니다.
SUMMARY.md는 파일의 구조가 적혀있고 navigation할 때 활용합니다.
mkdocs build 명령어를 실행하면 docs 디렉토리에 실제 파일들이 생성되지는 않고 site 디렉토리가 생성됩니다.
# docstring numpy style 예시
def foo(a, b):
"""Foo.
Parameters
----------
a
Here's a.
Continuation line 1.
Continuation line 2.
b
Here's b.
"""
google
# docstring Google style 예시
def add(a, b):
"""Compute and return the sum of two numbers.
Examples:
>>> add(4.0, 2.0)
6.0
>>> add(4, 2)
6.0
Args:
a (float): A number representing the first addend in the addition.
b (float): A number representing the second addend in the addition.
Returns:
float: A number representing the arithmetic sum of `a` and `b`.
"""
return float(a + b)
AWS S3 정적 호스팅
Github Pages
처음에는 github pages를 사용하려 했지만 github enterprise 요금제를 써야 웹 페이지의 visibility도 private 설정이 가능하다고 합니다. 그래서 다른 방법을 검색해보았습니다.
데이터와 관련해 취준생, 주니어 분들을 위한 강의를 해달라는 요청을 받았습니다. 사실, 2년차 개발자라 수강생 분들께 유익한 강의를 할 수 있을까, 수강생 분들이 시간 낭비하는게 아닐까 하는 걱정부터 앞섰지만 좋은 기회를 놓치면 안되겠다는 생각이 들었습니다.
강의 준비
강의 준비 기간까지 약 한달 반 정도가 남았고 12시간 분량의 라이브 수업을 준비해야 했습니다. 네OO AI 교육 과정의 멘토를 맡아본 적은 있었지만 강의를 직접 제작해 본 경험은 없었기에 저에게는 굉장히 챌린징했었습니다. 일단은 닥치는대로 데이터와 관련된 책을 찾아보기 위해 서점을 들락거리기 시작했습니다. 여러 군데의 서점에서 데이터 관련 책들을 살펴보았는데 대부분 기술적인 내용을 다루는 책들이었습니다. 그러다보니 다루는 내용들이 비슷비슷했고 데이터를 다루는 기술에 대해서는 많이들 설명해주고 있었지만 그래서 왜 비즈니스에서 데이터 기반의 의사결정을 해야하는지는 설명해주지 않아습니다. 그러던 중 정말 보석 같은 귀한 책들을 몇 권 발견하였는데요.
이 책들에서 공통적으로 이야기하는 점들은 다음과 같았습니다.
데이터를 통해 사람의 행동을 이끌어내는 것이 데이터를 다뤄야 하는 근본 이유다.
위 책들을 통해 제가 알지 못했던 것들을 깨닫게 되고 인사이트를 정말 많이 습득할 수 있었습니다. 한 분야에서 몇년 동안 경험하고 학습하셨던 것들을 한권의 책에 담아 제 시간을 아끼게 해주신 저자분들께 감사의 말씀을 드립니다. 특히, 데이터 드리븐 분석비법 책은 스승과 제자가 대화하는 형태로 글이 작성되어 있어서 무척 재미있게 읽었던 기억이 납니다.
커리큘럼 구성
1회당 3시간, 총 4회를 준비했는데요. 1일차에는 데이터 드리븐 의사결정이 왜 필요한지 배우고 설득력을 높이는 데이터 시각화 기초 이론에 대해 강의를 준비했습니다. 데이터는 책과 마찬가지로 내가 경험해보지 못했던 것들을 간접적으로 경험할 수 있게 해주어 경험, 정보의 폭을 증대할 수 있습니다. 코끼리를 눈을 감고 만질 때 다리만 만져본 사람과 얼굴만 만져본 사람은 코끼리의 부분밖에 모르지만 코끼리를 눈으로 본 사람은 코끼리에 대해 더 잘 알 수 있게 되는 거과 같은 이치입니다. 데이터를 통해 결국에 해야하는 건 사람의 행동(액션)의 변화를 이끌어내는 것이 중요합니다. 따라서 어떻게 하면 데이터에서 유용한 의미를 뽑아 누구나 납득할 수 있는 설득력 있는 데이터 시각화를 하는 방법에 대해 알아야합니다. 독자의 인지부하를 낮추는 시각 속성들, 게슈탈트 원칙 등에 대해서 학습합니다.
2일차에는 python의 matplotlib을 활용하여 막대그래프, 선그래프, 산포도를 그리는 방법에 대한 학습 내용을 준비했습니다. 1일차 때 학습했던 기초 이론을 응용하여 실제 데이터 분석에서는 어떤 식으로 표현하는지 파악하고 보다 나은 데이터 시각화에 대해 학습합니다. 무의식적으로 사용하던 시각 속성들을 의식적으로 사용하며 보다 의미 있는 정보를 독자에게 전달할 수 있습니다.
3일차에는 seaborn, plotly에 대해 배우며 matplotlib보다 훨씬 편리한 사용법과 다양한 기능들을 소개하였습니다. Interactive 시각화를 통해 독자가 시각화 작품에 직접 마우스 클릭, 도구를 통한 조작 등을 할 수 있게 되면서 정적인 그래프에서는 담지 못했던 여러가지 정보를 깔끔하게 담을 수 있다는 것을 알게 됩니다.
4일차에는 지금까지 배웠던 시각화 기초 이론과 코딩을 통해 현업과 비슷한 느낌으로 실전 프로젝트를 수행합니다. 문제 정의, 데이터 수집/정제, 데이터 시각화를 통한 유용한 사실을 파악하고 또 다시 문제 정의의 사이클을 돕니다. 이를 통해 현업에서는 어떤 식으로 데이터 분석을 하는지 감을 잡을 수 있습니다.
정규 교육 외 소개했던 내용
데이터 관련 직군에 대한 소개를 하였고 데이터 엔지니어, 데이터 사이언티스트, 데이터 분석가라는 직무가 어떤 일을 수행하는지에 대해 소개하였습니다. 데이터가 중요한 건 알겠는데 어떤 직무가 도대체 무슨 일을 하는지 도통 알기 어렵습니다. 채용 공고를 봐도 이해가 잘 안되는데 이런 부분들에 대해 예시를 들어가며 설명을 했습니다.
현업에서 데이터 분석을 하며 겪었던 어려움에 대해 소개하는 시간을 가졌습니다. 수강생 분들께서 현업에서는 어떤 일을 하게 되고 어떤 문제를 해결할까라는 궁금증이 생길텐데 제가 겪었던 문제점에 대해 소개하고 이를 해결하기 위해 어떤 노력을 했었는지 소개했었습니다.
마지막으로는 이력서와 포트폴리오에 관한 작성법과 제 이력서를 예시로 보여드렸는데요. 이력서를 어떻게 작성해야하는지 자주 질문이 들어왔기에 한 번 소개를 하면 좋겠다 생각했었습니다. 포트폴리오 작성을 위해 프로젝트를 권장했고 강의에서 학습했던 내용을 토대로 지원하고자 하는 회사와 관련된 산업 분야의 데이터셋을 찾아보시길 추천드렸습니다.
강의 피드백
챌린지의 난이도(매우 쉬움-1 매우 어려움-7) : 4.04
커리큘럼(주제) 만족도(매우 불만족-1 매우 만족-7) : 5.15
멘토의 세션 진행 적극도(매우 소극적-1 매우 적극적-7) : 5.93
멘토의 세션 진행을 위한 분야 전문성(매우 부족함-1 매우 충분함-7) : 5.76
긍정적인 피드백
"지금까지 국비지원으로 들었던 수업과 프로젝트 경험보다 더 알찼던 수업이에요 ㅠㅠ 파이썬 강의도 해주세요~!! 감사합니다"
"시각화 방식, 분석 사례를 꼼꼼하게 잘 알려주셔서 좋았습니다 많은 도움이 된 거 같아요"
"감사합니다 정규수업 외 커리어에 대한 이야기들도 많이 도움이 됐습니다"
"기초적인 부분들이지만 놓치기 쉬운 부분들, 이 데이터가 왜 필요한지를 생각해서 데이터 표현 및 시각화하는 걸 배울 수 있었습니다. 또, 어렵지 않게 차근차근 설명해주셔서, 잘 따라갈 수 있었어요. 감사합니다~"
"질문에 대해 상세하게 답변해주셔서 도움이 많이 됐습니다. 감사합니다."
"실무에서는 어떻게 일을 하는지 알 수 가 없었는데 교육을 통해 대략적인 느낌을 알게 되었습니다."
"꼼꼼히 설명해주시려 하고 피드백도 잘해주셔서 이해하기 수월했습니다. 그동안 감사했습니다!"
보완이 필요한 피드백
"해당 주 강의 주제 및 수준에 맞는 과제가 있으면 좋을 것 같습니다. ex. 1주(1일차, 2일차) 강의 목적에 부합하는 과제"
"데이터 분석이라하여 스킬적인 것보다는 데이터를 해석하고 의사결정에 적용하는 일련의 과정들에대한 교육을 기대했는데 코드 위주라살짝 아쉬움이 있었어요ㅠㅠ"
"코드 일부분은 시간이 부족해 넘어간 부분이 있습니다. 그래서 코드에 자세한 설명이 적힌 주석이 달리면 좋겠습니다."
"세션 구성 및 중간 과제도 있으면 좋을 것 같아요"
"사전과제말고도 주차별 과제가 있으면 더 좋을꺼같아요!/사전질문을 받는것도 좋은 방법 같아요"
KPT(Keep Problem Try)
Keep
사전 과제, 실전 프로젝트, 다양한 수업자료 업로드 등은 많은 분들께서 좋은 피드백을 주셔서 계속 유지하는게 좋을 것 같습니다.
강의 난이도는 쉬웠다는 분도 있구 어려웠다는 분도 있었는데 평점을 내보니 거의 가운데였습니다. 수강생들의 편차가 굉장히 크다보니 어쩔 수 없는 부분인 것 같고 그래도 난이도 부분은 평타 친 것 같습니다. 이러한 난이도로 수업을 진행해도 큰 문제 없을 것 같다는 생각이 듭니다.
Problem
커리큘럼(주제) 만족도가 조금 아쉬운 부분인 것 같습니다. 아무래도 짧은 시간 내 준비하다보니 더 양질의 내용을 추가하지 못했던 게 아쉬움이 남습니다. 스킬적인 것보다 데이터를 해석하고 의사결정에 적용하는 과정을 기대하셨다는 피드백에 공감하고 있고 다음에도 강의할 기회가 생긴다면 그러한 것들을 체험할 수 있는 실전 프로젝트를 더 많이 포함하는 것이 좋아보입니다.
Try
또 생각 못했던 부분인데 주차별 과제, 사전 질문도 추가하면 좋을 것 같습니다. 학생 분들의 참여도도 많이 높일 수 있을 것 같고 나와있는 예제를 그냥 실행하는 것보다 직접 코드를 짜보고 만들어보면 좋을 것 같다는 생각이 들었습니다. 코딩을 처음 해보시는 초보자 분들은 수업 때 아무리 설명을 하더라도 어려움을 많이 겪고 계셨습니다. 그래서 강의 자료에 좀 더 자세한 주석을 써두어 복습하실 때 도움이 되도록 해야겠습니다.
요즈음 개발자 뿐 아니라 비개발자인 분들도 SQL을 공부하고 계시는 분들이 많은데요. 사내에서 SQL 세미나를 진행했고 실제로 서비스팀 멤버분들은 QUERY를 날려 필요한 데이터를 직접 export하고 있습니다. 이번 포스팅을 통해 개발자 뿐 아니라 비개발자분들도 DBMS(DataBase Management System)를 이해하고 기본적인 QUERY문을 작성하여 사내의 데이터 베이스가 있다면 실제로 사용해보시면 좋을 것 같습니다. DBMS는 데이터 저장소로 여러 사용자들이 접근하여 데이터를 저장 및 관리할 수 있는 소프트웨어 프로그램을 의미합니다.
MySQL-Server와 MySQL-WorkBench를 설치하셨다는 가정하에 들어가도록 하겠습니다. 계정과 권한 부여 등을 수행하시면 다음과 같은 기본적인 쿼리를 따라하실 수 있습니다.
기본 쿼리
CRUD는 기본적인 데이터 처리 기능인 Create(생성), Read(읽기), Update(갱신), Delete(삭제)를 묶어서 일컫는 말입니다. 순서대로 기본 쿼리에 대해서 살펴보도록 하겠습니다.
데이터베이스 생성
# CREATE DATABASE 데이터베이스 이름;
CREATE DATABASE nuvilab;
Local에서 MySQL-Server를 실행하면 당연히 사용할 데이터베이스를 생성해주어야 합니다. 저는 nuvilab이라는 이름을 가진 데이터베이스를 생성하겠습니다. WorkBench에서 명령어를 실행하고자 한다면 Ctrl + Enter 단축키를 사용합니다.
참고로 #은 주석을 의미해요! 주석을 해둔 쿼리는 WorkBench가 실행하지 않기 때문에 보통 실행하고 싶지 않은 쿼리나 설명을 주석으로 써둡니다. 또한 세미콜론(;)은 쿼리의 끝을 의미하고 보통은 적어주어야 프로그램이 어디가 끝인지를 인식하고 해당 쿼리를 실행합니다.
Default Schema
# USE 데이터베이스 이름;
USE nuvilab;
데이터베이스를 생성했으면 해당 데이터베이스를 사용하기 위하여 Default Schema 로 설정해줍니다.
nuvilab 데이터베이스 안에 2개의 테이블을 생성하는 쿼리입니다. 테이블에 사용될 컬럼과 그 자료형을 표시해줍니다. id 오른쪽에 쓰여있는 PRIMARY KEY는 아래에서 알아보도록 하겠습니다. ERD(Entity Relationship Diagram)는 테이블간의 관계를 설명해주는 다이어그램입니다. 예를 들어, 생성한 2개의 테이블을 ERD로 표현하면 아래와 같은 그림일 것입니다.
데이터 생성(Create)
데이터를 새로 생성하는 명령어입니다. 어떤 어플리케이션의 사용자가 새로 가입했을 경우에 데이터베이스에 데이터를 추가해주어야 합니다. users 테이블의 각 컬럼에 데이터를 삽입합니다.
# INSERT INTO 테이블 이름 (컬럼1, 컬럼2) values (값1, 값2);
INSERT INTO users (id, full_name, country_code) value (1, ‘홍길동’, 81);
데이터 읽기(Read)
위에서 추가한 데이터가 잘 들어갔는지 확인해봐야겠죠? 테이블의 데이터를 조회하는 명령어입니다.
# SELECT * FROM 테이블 이름;
SELECT * FROM users
데이터 변경(Update)
데이터베이스에 들어간 데이터가 잘못 입력됐거나, 변경사항이 있을 때 데이터를 업데이트하는 명령어입니다.
# UPDATE 테이블 이름 set 컬럼1=값1
UPDATE users set country_code=82 where full_name='홍길동'
UPDATE 문은 보통 조건문과 같이 사용되는데요. 위에서 where~ 이후의 조건문이 없다면 users 테이블에 있는 모든 country_code 컬럼의 값이 82로 변경이 됩니다. 그러면 사용자의 이름이 “홍길동”인 사람 뿐 아니라 다른 모든 사람의 country_code가 82로 변경이 되어 상상하기 싫은 순간이 오게 됩니다. 따라서 데이터를 변경하거나 삭제할 때는 해당 쿼리가 맞는지 dev 데이터베이스에서 테스트 해보는 등 재차 점검하고, 제약조건을 걸어두는 등의 조치를 취해야 합니다.
데이터 삭제(Delete)
사용자가 회원탈퇴를 하는 경우에 데이터베이스에서 데이터를 삭제하는 명령어입니다.
# DELETE FROM 테이블 이름
DELETE FROM users where full_name='홍길동'
마찬가지로 조건문 없이 DELETE 쿼리를 사용한다면 users 테이블의 모든 데이터가 삭제가 되버리는데요. 사용자의 이름이 “홍길동”인 것만 데이터를 제거한다는 조건문을 걸어두도록 합니다.
KEY
Primary Key
정의 : Primary Key는 테이블의 기본키를 의미합니다. null을 허용하지 않고 unique 한 옵션을 포함하며 테이블에서 한개의 필드에만 설정할 수 있습니다.
예를 들어, 위 users 테이블에서 ‘full_name’, ‘country_code’가 중복될 때 각 데이터를 구별해주는 것이 바로 Primary Key인 ‘id’입니다.
Foreign Key
정의 : 두 개 이상의 테이블을 연결해주는 값입니다.
필요한 이유 : 한 테이블에 너무 많은 정보가 들어가게 되면 가독성이 떨어지고, 필요없는 정보가 많이 삽입될 수 있습니다. 이를 방지하기 위해 사용합니다.
예를 들면 users 테이블과 countries 테이블은 각각 ‘country_code’와 ‘code’로 연결이 되어있는데요. 만약에 users 테이블에 countries 테이블 컬럼인 ‘name’, ‘continent’까지 들어가게 되면 users 테이블에 2개의 컬럼이 늘어나 데이터가 쌓일 때마다 저장 공간을 더 빠르게 잡아먹을 수 있습니다. 하지만 countries 테이블을 두어 FK를 사용한다면 users 테이블에 데이터가 쌓인다 하더라도 저장 공간을 덜 차지하게 됩니다.
Constraint
부모 테이블이 PK이거나 UNIQUE 때만 사용할 수 있습니다.
Restrict
일반적으로 FK를 설정하면 Restrict 제약이 걸리게 됩니다. users의 ‘country_code’ 컬럼에 FK를 설정하면 부모 테이블인 countries 테이블의 PK인 ‘code’ 컬럼을 참조하게 되므로 INSERT, UPDATE, DELETE 할 때 제약이 걸리게 됩니다.
users 테이블에 insert를 하게 될 경우 ‘coutry_code’는 null이 될 수 없으며 countries 테이블의 ‘code’ 컬럼을 참조하여 데이터 값이 있는 것만 집어넣을 수 있습니다. 예를 들면 ‘code’ 컬럼에 81,82,83이라는 값만 있다면 users 테이블에 ‘country_code’에도 81, 82, 83만 들어갈 수 있는 식입니다.
FK 제약이 걸린 경우에 별도의 옵션이 없다면 users 테이블에서는 ‘country_code’ 컬럼을 UPDATE, DELETE를 할 수 없습니다. 반면, countries 테이블에서는 users 테이블에서 참조하지 않는 값이 있다면 그 값에 대해서는 UPDATE, DELETE가 가능합니다. 예를 들면, countries 테이블에서 ‘code’ 컬럼이 5,6,7 인 row는 users 테이블에서 참조하고 있지 않을 때, UPDATE, DELETE가 가능합니다.
Cascade
UPDATE와 DELETE를 할 때 각각 Cascade를 설정할 수 있습니다.
users 테이블에 FK Cascade 제약을 UPDATE, DELETE 할 때 모두 설정했다고 가정해봅시다. 부모 테이블인 countries 테이블에서 ‘code’가 81인 데이터를 82로 update를 수행하게 되면 users 테이블의 ‘country_code’도 81에서 82로 부모 테이블과 똑같이 변경됩니다. countries 테이블에서 ‘code’가 82인 데이터에 대해 DELETE를 수행한다면 users 테이블에서 ‘country_code’가 82인 데이터 또한 마찬가지로 삭제가 되는것이죠.
프로시저
장점
여러 쿼리를 한번에 실행할 수 있는 명령어입니다.
미리 구문 분석 및 내부 중간 코드로 변환을 끝내야 하므로 처리 시간이 줄어듭니다.
파이썬 등의 호스트 언어에서 사용할 경우 쿼리를 여러번 호출하기보다 프로시저 한번만 호출할 수 있어 코드 관리에 유용합니다.
단점
업무 변경으로 인해 저장된 프로시저를 변경해야할 때 변경 실수로 서비스 장애가 있을 수 있습니다.
디버깅이 어려워 에러가 발생했을 때 대처하기가 까다롭습니다.
프로시저 옵션
본인이 생성한 프로시저를 다른 유저가(해당 유저의 권한으로) 실행할 수 있도록 하는 옵션
SQL SECURITY INVOKER
예시 : 회원가입을 했을 경우 full_name, country_code를 받아 users 테이블에 데이터를 입력하는 프로시저
CREATE DEFINER=`jinyoung.kim`@`%` PROCEDURE `signup`(f_name VARCHAR, c_code INT)
SQL SECURITY INVOKER
BEGIN
INSERT INTO users (full_name, country_code) value (f_name, c_code); select * from users where full_name=f_name and country_code=c_code;
END
실무에 사용되는 유용한 꿀팁
누비랩에서 실제로 많이 사용하는 쿼리를 정리해보았는데요. 알고 계시면 두고두고 쓸 수 있을 것이라 생각합니다.
Foreign Key를 활용하여 2개 이상 테이블 Join하기
SELECT * FROM users as u
INNER JOIN coutry as c
on c.code = u.country_code
‘k’로 시작하는 나라 검색
SELECT * FROM countries where name like 'k%'
중복 데이터가 있는지 확인
SELECT
full_name,
country_code,
COUNT(id) c
FROM
users
GROUP BY
full_name,
country_code;
having
c>1;
중복 데이터 없애는 쿼리
create table users_temp
LIKE users;
insert into users_temp
select * from users
group by
full_name, country_code;
계층적인 클래스 구조를 가져가기 위해 DB에 저장하는 방식이 여러가지가 있습니다. 총 4가지의 방식이 있고 위의 표에서 각 방식의 장단점을 나타내고 있습니다.
1. Adjacency List
Adjacency List는 테이블 1개로 계층적 구조를 나타낼 수 있습니다.
1.1 장점
스키마를 이해하기가 쉽습니다.
Parent_id 컬럼을 두어 해당 row의 부모가 어떤 row인지 쉽게 파악이 가능합니다.
예를 들어 comment_id가 2인 row는 parent_id가 1이고 comment_id가 1인 row가 부모인 것을 알 수 있습니다.
1.2 단점
트리의 깊이가 깊어질수록 시간복잡도가 증가한다는 단점이 있습니다.
물론 현재 음식 계층은 3단계로 트리의 깊이가 깊지는 않지만 다른 방식에 비해 데이터가 많아질수록 조회하는데 시간이 오래 걸릴 수 있습니다.
성능이 다른 방식들에 비해 좋지 않습니다.
2. Path Enumeration
path 컬럼에 각 계층 구조 경로를 string 형태로 명확하게 적어줌으로써 전체 경로를 빠르게 파악할 수 있습니다. 예를 들어 comment_id가 3인 경우는 path가 “1/2/3”으로 되어있고 comment_id가 2인 row가 부모 노드임을 알 수 있습니다.
2.1 장점
path enumeration 방법은 path라는 컬럼을 통해서 전체 계층적인 구조가 어떻게 이루어지고 있는지 명확하게 바로 알 수 있습니다.
2.2 단점
트리가 깊어질수록 path의 string이 길어집니다.
쿼리를 할 때 string parsing이 필요해 큰 데이터셋에서 성능 저하를 일으킬 수 있습니다.
• SELECT * FROM mydata WHERE path LIKE ‘windows\system32\%’
참조 완결성이 없는 string 형태이므로 path가 잘못될 경우 어디가 잘못되어있는지 파악하기 힘듭니다.
실제로 119라는 데이터가 없더라도 “1/2/3/119” 라는 데이터가 생성될 수 있습니다.
계층 구조를 변경할 때 cost가 비쌉니다.
1/2/3/4 → 1/5/3/4 로 변경할 때 “1/2/3/”, “1/2/3/4”을 각각 “1/5/3”, “1/5/3/4/”등으로 수정해야하는데 string이라 변경하기가 어렵습니다.
큰 데이터셋에 대해 스케일링하기가 어렵습니다.
3. Nested Sets
nested set 모델은 맨 상위부터 아래쪽으로 왼쪽에서 오른쪽으로 순서로 가며 번호를 붙입니다. 예를 들어 맨 위의 계층은 left가 1, right가 14이며 그 자식 노드는 left가 2 right가 5입니다. 자식 노드인지를 확인하는 방법은 자식 노드의 left가 부모 노드의 left와 right 사이에 있는지를 판단하여 그 안에 있으면 자식 노드인 것을 알 수 있습니다.
3.1 장점
트리의 깊이가 3단계 이상인 경우 조인의 오버헤드를 줄여 데이터 검색을 위해 발생하는 쿼리의 수가 매우 줄어듭니다.
매우 크고 동적인 계층 구조라면 Adjacency list보다 훨씬 낫고 다뤄보면 직관적입니다.
3.2 단점
참조 완결성이 없습니다. left와 right는 comment_id를 참조하는 것이 아니라 단지 노드의 숫자를 의미합니다. 따라서 nsleft, nsright가 잘못 들어갈 경우가 생깁니다.
left와 right값이 모두 변경되어야 하므로 add/delete/move 에 대한 cost가 큽니다.
구조 상 멀티 쓰레드 환경에서 데이터를 변경할 경우 데이터의 손상이 있을 수 있기 때문에 해당 테이블의 데이터 변경을 여러 사용자가 동시에 진행할 수 없습니다.
4. Closure Table
Closure Table은 테이블을 2개를 활용합니다. 왼쪽 테이블의 comment_id를 참조하여 오른쪽 테이블의 ancestor, descendant에 데이터를 삽입합니다. ancestor는 조상 노드, descendant는 후손 노드로 각 노드의 관계를, length 컬럼은 관계를 맺은 노드 간의 깊이 차이를 나타낸 것입니다. 3번 노드의 조상 노드를 찾는다면 descendant가 3인 ancestor를 찾아야 합니다. 2와 3이 있고 length가 1인 2가 부모 노드입니다.
4.1 장점
참조 완결성이 존재하므로 오른쪽 테이블의 ancestor, descendant 컬럼은 왼쪽 테이블의 comment id를 foreign key 로 참조하여 실제 있는 데이터를 참조하도록 설정 할 수 있습니다. path enumeration과 같은 문제점은 발생하지 않습니다.
top/middle/leaf node 의 계층 구조에서 middle을 조작하기 쉽습니다.(add, move, delete)
자료형이 중요하다는 것을 다들 아시겠지만 많이 신경쓰지는 못했었는데요. RMSE를 구하면서 값이 낮게 나오길래 디버깅하면서 확인해보았고 540^2이 29456으로 나왔습니다. 자료형이 uint16은 65535가 넘어가면 오버플로우가 발생해 540^2이 291600가 아니라 29456이 나왔습니다. 저와 같은 실수를 하지 않길 바라는 마음에서 공유드립니다~
이미지 형성 프로세스를 노이즈를 제거하는 오토인코더 순차적인 어플리캐이션으로 분해하면서 diffusion model은 이미지에서 SOTA 합성 결과를 얻었습니다. 기존에는 픽셀 공간에서 연산을 하여 막대한 GPU 연산이 필요했지만 사전학습된 오토인코더의 latent space를 활용하여 제한된 컴퓨팅 리소스로도 재학습할 수 있게 했습니다. LDM(Latent Diffusion Model)은 pixel 기반의 DM보다 연산량을 상당히 줄이면서, image inpainting, class-conditional image synthesis, 그리고 text-to-image 합성, unconditional image generation, super-resolution과 같은 다양한 분야에서 SOTA를 달성했습니다.
1. Introduction
확산(Diffusion)은 시간이 지남에 따라 분자들이 퍼져나가는 현상을 의미합니다. 이런 현상에 착안하여 이미지에 노이즈를 점차적으로 추가하여 최종적으로 노이즈를 만들고 이를 다시 복원하도록 학습하는 것이 Diffusion Model의 핵심입니다.
2. Related Work
Generated Models for Image Synthesis
GAN 모델은 고해상도의 이미지를 좋은 품질로 잘 생성하지만 모델을 최적화하기 어렵고, 데이터 분포를 잘 잡아내는 것이 힘듭니다.
반면 Likelihood 기반의 모델인 VAE(Variational Auto Encoder)나 flow 기반의 모델은 최적화가 잘 이루어지도록 하는 밀도 추정을 잘하지만, GAN보다 성능이 뛰어나지는 않습니다.
ARM(Auto Regressive Model)은 밀도 추정에서 좋은 성능을 내지만 저해상도 이미지에서만 사용할 수 있다는 제한이 있습니다.
Diffusion Probabilistic Models
DM은 밀도 추정과 샘플의 품질에서 훌륭한 성능을 보여주며 노이즈를 제거하는 과정에서 U-Net이 활용되어 이미지와 같은 데이터에서 inductive bias를 학습할 수 있습니다.
DM은 압축 능력과 샘플의 품질이 서로 trade off의 관계를 가지며, pixel 공간에서 모델을 평가하고 최적화하는 것은 추론 속도 저하와 많은 컴퓨팅 비용이 발생합니다.
LDM은 이러한 단점들을 해결하며 이미지 품질 저하 없이 연산량을 줄이면서 추론 속도를 높일 수 있습니다.
Two-Stage Image Synthesis
two stage 접근을 통해 단점들을 극복하려는 많은 연구들이 있었습니다.
VQ-VQE는 이산화된 latent space로 prior를 학습하는 auto regressive model을 사용합니다.
dall-e는 VQ-VAE에서 더 나아가 이산화된 image와 text의 representation의 결합 분포를 학습하여 text-to-image를 수행합니다.
net2net은 가역 네트워크를 사용하여 다양한 도메인의 latent spaces들 간에 일반적인 transfer를 제공합니다.
VQ-VQE와 VQ-GAN은 큰 이미지에 auto regressive transformer를 스케일링하기 위해 first stage로 adversarial과 perceptual objective를 사용합니다.
높은 압축률은 ARM이 학습을 가능하게 하지만 성능에 제한이 생기고, 낮은 압축률은 연산 비용이 매우 커지게 됩니다.
LDM은 좋은 품질의 이미지를 생성하는 것을 보장하면서 first stage에서 perceptual한 압축을 너무 많이 하지 않고 강력한 첫 번째 단계 학습 사이를 최적으로 중재하는 압축 수준을 자유롭게 선택할 수 있다.
3. Method
Fig2는 디지털 이미지에서 대부분의 bits가 사람이 인지할 수 없는 것들이라는 것을 나타냅니다. DM이 의미 상 필요 없는 정보를 제거하여 불필요한 계산을 최소화하려 해도 학습이나 추론 시에 모든 픽셀에 대해 평가를 해야 하기 때문에 불필요한 계산을 해야합니다. LDM은 효과적인 생성 모델로, 인간이 지각할 수 없는 영역을 제거하는 압축 단계를 분리합니다.
3.1 Perceptual Image Compression
perceptual loss와 patch-based loss adversarial objective로 오토인코더를 학습하여 local realism을 강제하고 L2와 L1 objectives와 같은 픽셀 공간에 의존함으로써 생기는 블러를 피하게 해줍니다.
디코더는 latent로부터 이미지를 재현하고, 인코더는 $2^m$ factor로 이미지를 다양하게 downsample합니다.
latent spaces의 고분산을 피하기 위하여 KL-reg를 적용하며, 디코더에서 VQ-reg를 적용합니다.
기존의 DM은 임의의 1차원 latent를 사용하지만 LDM은 2차원의 latent space를 사용하여 가벼운 압축률과 detail한 정보를 보존하여 매우 좋은 재현성을 달성할 수 있었습니다.
3.2 Latent Diffusion Models
Diffusion Models
Diffusion Model은 길이가 T인 fixed Markov Chain의 역과정에 상응하는 정규 분포 변수의 노이즈를 점진적으로 제거하여 원래의 데이터 분포 $p(x)$를 학습하도록 고안된 확률 모델입니다. 이러한 모델들은 노이즈가 있는 $x_t$의 노이즈를 제거하여 원래의 입력값 x를 예측하도록 학습합니다. 이 때, x는 이미지 원본입니다.
Forward diffusion process
원본 이미지에 노이즈를 점진적으로 더해서 최종적으로 노이즈를 만드는 과정
Reversediffusion process
노이즈로부터 점차 원본 이미지로 되돌리는 과정
Generative Modeling of Latent Representations
LDM은 high-frequency, imperceptible details를 추상화한 정보가 담긴 저차원의 latent space에 노이즈를 추가하고 복원하는 과정을 거칩니다. LDM은 DM과 비교했을 때 여러가지 장점이 있습니다. 이 과정은 생성 모델에서 사용되는(데이터 분포의 확률을 최대화하는) likelihood에 DM보다 훨씬 적합하고 중요하고 의미가 있는 bits에 집중하며 저차원에서 효과적으로 전체 연산량을 줄일 수 있습니다.
U-Net 구조로 노이즈로부터 이미지를 복원하는 과정을 거치게 됩니다.
3.3 Conditioning Mechanisms
cross-attention mechanism을 통해 다양한 modality로 conditioning을 할 수 있게 되어 되었습니다.
텍스트가 conditioning으로 주어지면 $τ_Θ$는 트랜스포머와 같은 도메인별 전문가를 통해 매개변수화할 수 있습니다.
언어와 비전의 도메인별 전문가 조합은 복잡하고, 사용자 기반의 text prompt를 잘 일반화하여 좋은 결과를 산출할 수 있습니다.
Table2는 분류기가 없는 LDM-KL-8-G이 다른 모델들보다 파라미터 수가 적음에도 더 좋은 성능을 낼 수 있는 것을 볼 수 있습니다.
4.3.2 Convolutional Sampling Beyond
공간적인 conditioning 정보를 인코딩 입력 값과 concatenating하여 LDM은 image-to-image 모델링을 설계할 수 있습니다.
semantic synthesis, super-resolution, inpainting에 대해 모델들을 학습시킬 수 있습니다.
4.4 Super-Resolution with Latent Diffusion
super-resolution 학습을 위해 LDM은 저해상도의 이미지를 concatenation을 통해 conditioning 합니다.
Fig 10에서 보듯이, 이미지를 bicubic 방식으로 품질 저하를 시킨 후에 이를 원상 복구시키는 SR3 데이터 처리 파이프라인을 따라 학습을 시킵니다.
Table 5에서 보듯이, FID에서는 LDM-SR이 우위이지만, IS에서는 SR3가 우위임을 볼 수 있습니다.
4.5 Inpainting with Latent Diffusion
inpainting은 이미지에서 망가지거나 없애고 싶은 영역을 자연스러운 내용으로 대체하는 기술입니다. Fig 11은 LDM의 결과물입니다.
pixel 기반의 DM과 latent 기반의 DM은 속도 면에서 최소 2.7배, FID scores 면에서 최소 1.6배의 차이가 나는 것을 알 수 있습니다.
5. Limitations & Societal Impacts
Limitations
LDM은 pixel 기반의 DM 보다는 계산 필요량이 상당히 줄어들지만 GAN의 순차적인 샘플링 과정보다는 느립니다.
pixel 공간에서 fine-grained 정확도를 요구하는 task들에서는 재현성이 약간 떨어집니다.
super-resolution model은 다소 성능에 제한이 있습니다.
Societal Impact
이미지 생성 모델은 양날의 검입니다. 훈련, 추론 비용을 줄여 기술에 대한 접근성이 높아지고 많은 사람들이 연구할 수 있는 반면에 조작된 데이터나 잘못된 정보가 쉽게 퍼져 나갈 수 있습니다.
특히 deep fake와 같은 정교한 이미지 조작과 특히 여성과 관련된 불균형한 영향을 끼칠 수 있습니다.
또한 생성 모델은 민감하거나 개인적인 정보를 노출할 수 있고, 명확한 동의 없이 데이터가 수집될 수 있다는 문제점이 있습니다.
딥러닝 모듈들은 데이터에 담긴 bias를 재생산하거나 가중화시키는 경향이 있습니다.
6. Conclusion
LDM은 품질을 떨어뜨리지 않은 채로 노이즈를 제거하는 간단하고 효율적인 diffusion 방식으로 학습과 샘플링 효율을 향상시켰습니다. 이것들과 cross attention conditioning 방식으로 task-specific한 구조를 갖지 않고도 폭넓은 이미지 합성 분야에서 SOTA 방식들과 비교했을 때 좋은 결과를 성취할 수 있었습니다.
train 환경 : 32 epochs, the Adam optimizer, cosine schedule
3. Experiments
3.1 Zero-shot Transfer
3.1.4 Prompt Engineering AND ENSEMBLING
pretraining은 주로 문장으로 학습하기 때문에 단일한 단어보다는 어느 정도의 문맥을 살린 “A photo of a {label}.”, “A photo of a {label}, a type of pet.”과 같은 prompt 템플릿을 함께 사용하여 예측하는 것이 성능 향상에 좋습니다.
“A photo of a big {label}” , “A photo of a small {label}” 과 같은 다른 문맥을 가진 prompt를 활용하여 앙상블을 수행합니다.
3.1.5 Analysis of zeroshot CLIP performance
Fig5는 Zeroshot Clip과 각 데이터셋을 지도 학습한 ResNet-50을 비교한 것입니다. 초록색이 Zeroshot CLIP이 더 뛰어난 성능을 보인 데이터셋, 파란색이 ResNet-50이 더 뛰어난 성능을 보인 데이터셋입니다.
CLIP은 전문적이고, 복잡하며, 추상적인 TASK(인공위성 이미지 분류, 림프절 종양 검출, 합성 이미지에서 개체 카운트, 자율주행, 가장 가까운 거리의 차 인식)에 대해서는 약하다는 것을 보여줍니다.
CLIP의 zeroshot은 few shot 모델보다 훨씬 성능이 좋습니다. CLIP에 Logistic Regression Classifer를 달았을 때 4 shot(클래스당 학습 이미지 개수가 4개)의 성능이 zeroshot과 비슷한 것으로 나옵니다. BiT-M의 경우는 16shot일 때 zeroshot CLIP과 성능이 비슷하게 나옵니다.
Fig 7은 CLIP의 zeroshot 성능과 비슷하게 유지하려면 CLIP의 Linear Probe가 필요한 클래스당 라벨링 데이터 개수를 정리해둔 것입니다. FER2013 데이터셋의 경우 zeroshot CLIP과 비슷한 성능이 나오려면 Linear Probe CLIP은 클래스당 184개의 데이터가 필요합니다.
1개 이하인 데이터 셋에서는 zeroshot의 성능보다 Linear Probe CLIP이 1개 이상의 데이터로 fine tuning 했을 때 성능이 더 좋습니다.
클래스당 필요한 라벨링 개수를 1, 2, 4, 8, 16개 등으로 실험하여 log-linear interpolation으로 그래프를 그린 것입니다.
Zeroshot이 이상적으로 task-agnostic하려면 Fig8 그래프의 y=x에 수렴하는 직선이 나와야 합니다. 그렇게 되는 데이터셋은 5가지 정도(STL10, CIFAR10, ...)이고 대부분은 Linear Probe일 때 성능이 더 좋은 것으로 나옵니다.
3.2 Representation Learning
CLIP의 Linear probe의 성능은 CV SOTA 모델들을 여러 데이터셋에서 비교했을 때 훨씬 뛰어납니다.
CLIP의 linear probe는 Noisy Student EfficientNet-L2와 비교했을 때 27개 중 21개의 데이터셋에서 더 뛰어난 성능을 보여줍니다.
3.3 Robustness to Natural Distribution shift
ImageNet에서 pretraining한 후 linear probe를 수행한 모델들보다 CLIP의 linear probe가 여러 데이터셋에서 성능이 더 뛰어난 점으로 보아 전자의 모델들은 ImageNet에 과적합 되어있음을 알 수 있습니다.
반면, CLIP은 다양한 TASK에 강건하다는 것을 알 수 있습니다.
강건성을 파악하기 위해 distribution shift가 있는 여러 데이터셋(ImageNetV2, ImageNet-R, ObjectNet, ImageNetSketch, ImageNet-A, Youtube-BB, ImageNetVid)을 평가합니다.
왼쪽 그림에서 dashed line은 이상적인 강건 모델을 뜻합니다. distribution shift가 있는 여러 데이터셋에서 정확도와 ImageNet에서의 정확도가 일치한다는 의미입니다.
오른쪽 표에서 ImageNet 모델인 ResNet101은 ImageNet이 아닌 다른 데이터셋에서 성능 저하를 보이는 반면 zeroshot CLIP은 우수한 성능을 보입니다.
zeroshot CLIP은 distribution shift에도 다른 모델에 비해 약 75% 정도 강건함을 보입니다.
4. Comparision to Human Performance
zeroshot CLIP은 few shot CLIP보다 성능이 좋고, 강건성이 뛰어납니다. Fig15는 16 shot CLIP 모델과 Zeroshot 모델의 ImageNet에서의 성능이 비슷하지만 강건성 면에서는 zeroshot 모델이 훨씬 뛰어납니다.
Table2는 인간은 zeroshot보다 one, two shot에서 훨씬 더 높은 정확도를 보여주는 반면에 CLIP은 zeroshot이 few shot보다 더 뛰어난 것으로 볼 수 있습니다.
CLIP이 어려워 애완동물 종류 구분은 인간도 어려워하는 것을 Fig16에서 볼 수 있습니다.
5. Data Overlap Analysis
인터넷으로 받은 큰 데이터셋을 사전 학습하는 것은 평가 데이터셋과 overlap할 수 있는 가능성이 있습니다. 이럴 경우 의미 있는 일반화 평가가 힘들어지는데 4억장의 데이터를 모두 검수하기란 힘들기 때문에 다음과 같은 절차를 통해 overlap이 얼마나 발생하고 그에 따른 성능 차이를 분석합니다.
duplicate detector를 실행하여 유사도가 특정 threshold 이상이면 Overlap 집합에, 그 이하이면 Clean 집합에 포함시킵니다.
All 과 Clean을 metric으로 비교하여 데이터셋이 얼마나 오염되어 있는지를 분석합니다.
overlap 양이 적은 경우가 많기 때문에 Clean에 대한 정확도를 귀무 가설로 사용하고 Overlap 부분 집합에 대한 단일 꼬리(더 큰) p-값을 계산하는 이항 유의성 검정도 실행합니다. 또한 오염도에 대한 99.5% 클로퍼-피어슨 신뢰 구간을 또 다른 검사로 계산합니다.
합성 혹은 특수한 데이터 셋에서의 overlap은 검출되지 않았기 때문에 duplicate detector의 false positive의 비율이 낮다는 것을 알 수 있습니다.
왼쪽 그래프에서 보듯이 정확도 차이가 20% 정도로 분명히 나는 경우가 있지만, 대부분 overlap의 비율이 낮기 때문에 오른쪽 그래프에서 Clean 집합 대비 All 집합의 정확도 상승이 1% 미만임을 알 수 있습니다.
Country211은 overlap 비율이 21.5%로 높지만 CLIP이 학습했던 데이터셋과 다릅니다. Country211은 geo-localization을 위한 데이터셋을 측정하는 것으로 학습용 텍스트가 CLIP이 학습한 것과는 다릅니다.
분석의 한계
duplicate detector가 완벽하지 않고 4억장의 데이터를 모두 확인해본 것은 아닙니다.
Overlap 과 Clean 의 데이터 분포에 차이가 있어 정확한 비교가 어려울 수 있습니다. 예를 들면 Kinetics-700의 overlap에는 검정 화면이 많이 들어있었기에 clean에 비해 정확도 하락이 20%가량 달했습니다.
6. Limitations
zeroshot CLIP은 SOTA 모델에 비해 성능이 떨어집니다.
task-specific, fine-grained classification(차 종류, 꽃 종류, 비행선 구별), abstract/systematic task(개체 개수 세기), novel task(사진 상에서 가장 가까운 차까지의 거리 분류) 등에서 CLIP은 다소 성능이 떨어집니다.
MNIST와 유사한 데이터를 학습한 적이 없지만 Rendered SST2라는 OCR 데이터셋을 학습했습니다. CLIP은 MNIST에서 88%의 정확도가 나오는데 이는 단순한 logistic regression 지도 학습보다 떨어지는 성능입니다. CLIP은 일반화 문제에 취약하다는 것을 나타냅니다.
7.Broader Impacts
7.1 Bias
FairFace dataset은 기존의 face dataset에서 백인의 비율을 줄이고 성별과 인종이 고루 분포하도록 수집한 데이터셋입니다.
백인 카테고리에서 LR CLIP(Logistic Regression)은 FairFace Model, Linear Probe Instagram보다 성능이 잘 나왔고, ZL CLIP(Zeroshot CLIP)은 성능이 떨어졌습니다.
다양한 인종을 평가하면서 ZL CLIP은 성능이 상승하였습니다.
table 6은 남녀 각각에 7개의 인종, 3개의 범죄 관련 카테고리, 4개의 인간이 아닌 카테고리를 포함해 총 14개의 카테고리로 이미지를 분류하는 작업을 수행할 때 범죄 관련(’thief’, ‘criminal’, ‘suspicious person’) 혹은 인간이 아닌 카테고리(’animal’, ‘chimpanzee’, ‘gorilla’, ‘orangutan’)로 분류된 비율을 나타낸 것입니다.
table 7은 table 6을 연령별로 구분하고 child 카테고리를 추가했을 때 범죄 관련 혹은 인간이 아닌 카테고리로 분류된 비율을 비교한 표입니다.
Black 이 가장 높은 비율(14.4%)로 인간이 아닌 카테고리에 분류되었고, 남성의 16.5%, 여성의 9.8%가 범죄 관련 카테고리로 분류되었습니다.
child 카테고리를 추가했을 때 20세 이하에서 오분류된 비율이 크게 줄어들었다는 점을 볼 수 있습니다.
이는 class design이 모델의 성능과 unwanted bias를 결정하는 중요한 요인임을 알 수 있습니다.
7.3 Future Work
연구 프로세스 초기에 모델의 잠재적으로 유익한 다운스트림 사용을 식별하여 다른 연구자가 응용 프로그램에 대해 생각할 수 있도록 합니다.
상당한 민감성과 정책 입안자들의 개입이 필요할 수 있는 많은 사회적 이해관계자들의 작업 표면화.
모델에서 편견을 더 잘 특성화하여 다른 연구자에게 관심 영역과 개입 영역을 경고합니다.
CLIP과 같은 시스템을 평가하기 위한 테스트를 생성하여 개발 주기 초기에 모델 기능을 더 잘 특성화할 것.
9. Conclusion
CLIP은 폭넓은 task에 대해 사전학습을 하고, 자연어 prompting을 통해 많은 데이터셋에 대하여 zeroshot transfer를 가능하게 합니다. 성능 향상이 필요하지만 task specific한 모델들에 견주어 볼만합니다.
# CODE
Evaluation Code
Zeroshot evaluation
import os
import clip
import torch
from torchvision.datasets import CIFAR100
# Load the model
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load('ViT-B/32', device)
# Download the dataset
cifar100 = CIFAR100(root=os.path.expanduser("~/.cache"), download=True, train=False)
# Prepare the inputs
image, class_id = cifar100[3637]
image_input = preprocess(image).unsqueeze(0).to(device)
text_inputs = torch.cat([clip.tokenize(f"a photo of a {c}") for c in cifar100.classes]).to(device)
# Calculate features
with torch.no_grad():
image_features = model.encode_image(image_input)
text_features = model.encode_text(text_inputs)
# Pick the top 5 most similar labels for the image
image_features /= image_features.norm(dim=-1, keepdim=True)
text_features /= text_features.norm(dim=-1, keepdim=True)
similarity = (100.0 * image_features @ text_features.T).softmax(dim=-1)
values, indices = similarity[0].topk(5)
# Print the result
print("\\nTop predictions:\\n")
for value, index in zip(values, indices):
print(f"{cifar100.classes[index]:>16s}: {100 * value.item():.2f}%")
분류하고자 하는 이미지 한 장을 전처리하고 모든 텍스트에 a photo of prompt를 붙입니다.
모델에 넣어 이미지 피처와 텍스트 피처를 뽑아낸 후 torch.norm 을 사용하여 normalization하고, 행렬 곱을 통해 유사도를 계산합니다.
torch.topk 를 통해 유사도가 높은 5개를 뽑아 이미지와 유사한지 살핍니다.
Linear Probe evaluation
import os
import clip
import torch
import numpy as np
from sklearn.linear_model import LogisticRegression
from torch.utils.data import DataLoader
from torchvision.datasets import CIFAR100
from tqdm import tqdm
# Load the model
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load('ViT-B/32', device)
# Load the dataset
root = os.path.expanduser("~/.cache")
train = CIFAR100(root, download=True, train=True, transform=preprocess)
test = CIFAR100(root, download=True, train=False, transform=preprocess)
def get_features(dataset):
all_features = []
all_labels = []
with torch.no_grad():
for images, labels in tqdm(DataLoader(dataset, batch_size=100)):
features = model.encode_image(images.to(device))
all_features.append(features)
all_labels.append(labels)
return torch.cat(all_features).cpu().numpy(), torch.cat(all_labels).cpu().numpy()
# Calculate the image features
train_features, train_labels = get_features(train)
test_features, test_labels = get_features(test)
# Perform logistic regression
classifier = LogisticRegression(random_state=0, C=0.316, max_iter=1000, verbose=1)
classifier.fit(train_features, train_labels)
# Evaluate using the logistic regression classifier
predictions = classifier.predict(test_features)
accuracy = np.mean((test_labels == predictions).astype(np.float)) * 100.
print(f"Accuracy = {accuracy:.3f}")
서버를 올리고 잘 동작하는지 모니터링하는 등 서버를 관리하는데 많은 비용이 들어갑니다. serverless는 그러한 서버를 관리하는데 들어가는 리소스가 필요하지 않습니다. 트래픽이 많아지거나 줄어들 때 자동으로 스케일링해주며 사용한 만큼만 지불할 수 있습니다. AWS에서 관리를 해주기 때문에 보안에 큰 신경을 쓰지 않아도 된다는 장점이 있습니다.
2. Serverless Service 종류
AWS에서 제공하는 서비스로는 Lambda, Fargate, S3, Aurora serverless, DynamoDB, API Gateway, SQS, SNS, Kinesis 등이 있습니다.
3. Lambda 함수
3.1 Lambda 함수란?
Lambda 함수는 함수 기반의 실행환경을 제공합니다. 실행환경을 작성할 때 여러 언어(Node.js, Python, Java, C#, Go, Ruby, Runtime API)를 사용할 수 있습니다.
3.2 Lambda 함수 실행 프로세스
Lambda 함수의 실행 프로세스는 아래 이미지에 나온 것과 같습니다. 데이터 상태의 변화, endpoints로의 요청, 리소스 상태의 변화 등을 트리거로 설정하여 이러한 이벤트가 발생할 경우 Lambda 함수를 호출할 수 있습니다. 그 후에 여러 서비스들과 함께 어울려 business logic을 수행합니다.
3.3 Handler function
Handler function은 Lambda 함수 1개마다 1개의 handler function이 있어야 합니다. 트리거로 Lambda 함수가 호출됐을 때 handler function으로 요청이 들어오게 됩니다. event 객체는 Lambda 호출 시 들어오는 데이터(s3 트리거 시 해당 파일 이름 등등)가 들어오게 되고, context는 runtime과 관련된 정보(reqeust ID, log group 등)들이 들어있습니다.
Lambda 함수는 한 개당 실행환경 한 개를 가집니다. Lambda 함수가 여러 개가 호출될 경우 여러개의 실행환경이 실행됩니다. 다만, 실행환경은 재사용이 가능해서 초기화와 관련된 함수들은handler function 밖에 두는 것이 함수의 사용 시간을 줄이는 방법입니다.
3.6 Lambda 설정
1) Power Rating
- 메모리 128MB ~ 10GB 사이에서 선택 가능
- CPU는 메모리에 따라 성능 향상 가능
- CPU, 메모리, 네트워크는 성능에 따라 가격 변동
2) Timeout
- 15분까지 설정 가능
- 동기 vs 비동기
- API Gateway timeout은 30초
3) Network Access
- VPC로 접근 설정
- 보안 그룹 역할 적용
- VPC는 함수의 보안 향상 X
3.7 The function lifecycle
1) cold start : Lambda 함수가 처음 호출되어 실행환경을 준비하는 시간으로 코드 다운로드, 실행환경 시작, 런타임 부트스트랩하는 시간을 의미합니다. 이때, 앞단계는 AWS에서 최적화해주는 시간이고, 런타임 부트스트랩은 사용자가 직접 최적화할 수 있습니다.
2) warm start : cold start 이후로 실제 코드가 실행되는 시간을 의미합니다.
3) 재사용시 시간을 단축시키는 방법
- handler function을 어떻게 작성하느냐에 따라 Lambda 함수의 실행시간이 크게 단축될 수 있습니다.
- Lambda Language(Java는 로드하는 시간이 길어서 대체할 수 있는 스크립트 언어가 있다면 대체하는 것이 좋습니다.)
- Provisioned Concurrency
4. Lambda Concurrency
4.1 concurrency 이해하기
1) 사용자 요청이 들어오면 cold start를 마치면 함수가 실행이 됩니다.
2) 이 때, 사용자의 요청이 끝나기 전까지는 해당 실행환경은 blocking 되므로 새로운 요청이 발생했을 때에는 새로운 실행환경이 생깁니다.
3) request6 생길 당시에 request1의 실행환경이 요청이 끝난 free 상태(=warm 상태)이므로 cold start 없이 warm start를 할 수 있습니다.
4) concurrency count는 시간당 처리한 요청의 수가 아닌 요청을 처리 중인 실행환경의 수를 의미합니다.
4.2 Lambda function scaling
1) 요청이 들어오면 실행환경들이 빠르게 생성이 되다가 Burst limit에 도달하면 분당 500개의 실행환경들이 새롭게 생성되도록 제한됩니다.
2) 이 때, 실행환경의 생성 개수가 제한됨에 따라 요청량이 실행환경 개수보다 많아 throttling 될 수 있는데 이는 다른 기법을 활용하여 제어할 수 있습니다.
3) concurrency limit보다 많은 요청량이 들어올 경우에도 마찬가지로 throttling이 발생할 수 있습니다. concurrency limit은 region별로 다르며, aws support에 요청하면 상한선을 높일 수 있습니다.
4) 요청량이 줄어듦에 따라 Lambda의 실행환경 수도 같이 줄어듭니다.
5) Provisioned concurrency : cold start 없이 warm 상태인 실행환경을 만들어두어 급격하게 대량의 요청(쇼핑몰 이벤트)이 들어올 때를 대비할 수 있습니다.
6) Reserved concurrency : 해당 Lambda 함수에 대해서만 사용할 수 있는 pool을 미리 만들어두어 다른 Lambda 함수가 급격하게 호출되더라도 실행환경 할당량을 보장받을 수 있습니다.
5. Lambda - More Features
1) Lambda Layers - cold start를 줄일 수 있는 방법 중 하나입니다. 문자 인코딩하는 라이브러리, 크기가 큰 패키지 등을 불러올 때, 빈번하게 잘 바뀌지 않는 코드일 경우 한 번 업로드해놓고 여러 Lambda 함수에서 이를 참조하여 실행환경을 실행할 수 있습니다.
2) Dead-Letter Queue - 비동기 방식으로 요청을 처리할 때 요청이 끊어지거나 예외가 발생할 때 내부적으로 2번 재시도를 한 후 실패하면 버리게 됩니다. 이러한 실패한 요청들을 Dead-Letter Queue에 모아두어 나중에 확인하여 재처리를 할 수 있습니다. Dead-Letter Queue에 알람 설정을 해두어 한건이라도 들어오면 어떤 에러가 발생했는지 어떤 처리를 하다가 발생했는지 알 수 있게 구성할 수 있습니다.
3) RDS-Proxy
관계형 DB에서 Lambda 함수를 사용하는 것은 적합하지 않습니다. 1000개의 요청이 들어와 Lambda 함수가 호출되었을 때 1000개의 DB connection을 잡고 있는 상태가 되고 RDS는 이를 효율적으로 관리하는데 적합하지 않습니다. RDS proxy는 Shared connection pool을 사용하여 connection을 줄여주고, secret manager로 간단한 인증을 할 수 있습니다.
4) Versioning, Aliasing
versioning을 통해 쉽게 배포, rollback 등을 할수 있습니다. aliasing을 통해 Lambda 함수에 태그를 달아 참조할 수 있습니다.
5) Monitoring and debugging Lambda functions
1) 기본적으로 monitoring을 제공하며 throttling이나 error에 대한 알람 설정을 하는 것이 좋습니다.