'전체 글'에 해당되는 글 42건

  1. 2022.02.23 Notion 입문 1달차
  2. 2022.02.03 tensorflow에서 시작하는 pytorch 작동 방식 (iris example)
  3. 2022.01.11 Notion 입문 1일차
취미/Technology | 2022. 2. 23. 11:11 | /42
 

Notion 입문 1일차

#스타트업 #힙스터 #팀워크 #생산성 스타트업'스러움'이 하나의 문화컨텐츠로 떠오르면서 온갖 제품과 서비스들이 이러한 분위기에 맞추어지고 있다. 마치 Helvetica 폰트가 디자이너들에게 사랑

blog.knowblesse.com

이전에 Notion을 하루 써보고 소감을 간략히 적어봤었는데 이제 사용을 시작한지 한달이 되었다. 지금쯤이면 평이 달라지지 않았을까.

 

장점

1. Markup

이 기능이 생각보다 편리하다. [ / ]버튼 하나로 각종 형식들을 만들 수 있고 evernote에 비하면 적은 노력을 들이고도 읽기 편한 문서를 만들 수 있다는 점이 가장 큰 강점으로 작용한다. 사실 낙서를 포함하는 자유도가 높은 메모는 실제 종이에서 하는 것이 가장 좋다. 디지털화가 필요한 문서의 경우 어느정도 구조화된 아이디어인 경우가 많은데 evernote는 이를 표현하기에는 '동기화가 가능한 메모장'에 지나지 않았다. Notion은 이 '구조화된 아이디어'를 정리하기에 정말 적합한 서비스이다.

구조화된 아이디어 정리에 적합한 Notion

2. Page 구조

이것은 Notion의 장점이라기 보다는 OneNote가 구현해내지 못한 단점에 가까울까. OneNote도 hierarchical 구조를 가지고 있기는 하다만 제한적인 depth를 가지고 있고 최상위 객체인 전자 필기장이 로딩이 느리다는 인상을 자주 받는다. 그에 비해서 Notion은 무한히 Page를 확장할 수 있고, 가볍다는 것이 확실히 느껴진다.

 

Notion과 OneNote의 구조

단점

1. Spell check

아니 Spell check가 제대로 안된다는게 있을 수 있는 일인가. 어째서인지 내 환경에서는 spell check 기능이 작동하지 않고 turn on/off 메뉴도 나타나지 않는다. 그리고 공식 설명에 따르면 setting page에 따로 spell check 기능 관련 메뉴가 없다던데 이 부분은 정말 아쉽다. 아쉬운대로 Grammarly 의 윈도우 add-on을 사용하고 있는데 이 부분은 시급히 개선해야할 것 같다. 

 

2. Keyboard Shortcut

한컴오피스에 익숙한 한국인이라 그런지 키보드 단축키의 부족함을 느낀다. 다른 앱들도 별반 다를 것이 없겠다만 이러한 기능도 구현이 되었으면 하는 아쉬움이 남는다.

 

 

총평

사용 1일차에 느꼈던 감상과 다르지 않다.

'이렇게 참신하고 대단한게 나오다니!' 보다는 '이런게 왜 이제야?'에 가깝다.

사실 노트 작성 프로그램이 '참신하다'라는 평을 받을 가능성이 거의 없음을 감안하면 최고의 평가가 아니었나 싶다. Vim 정도 되면 악랄함을 포함한 참신성을 느낄 수 있겠다만 글쓰고 동기화 시켜주는 에디터에 더 바랄게 뭐가 있으랴. 전반적으로 크게 불편함을 느끼는 부분이 존재하지 않고, 깔끔하게 완성되는 output이 흡족함을 준다. 무엇보다 notion을 쓰면서 evernote가 괘씸해졌다. 초반의 무료정책에 반하게 점점 가격이 올라가고 기능은 변하지 않는 모습에 결국 Notion 사용 한달차에 올 8월까지 결제가 되어있는 유료 플랜을 해지했다. Notion도 이제 시장에 진입한 초기 서비스라 나중에 결제 플랜이 어떻게 바뀔지는 모르겠으나 지금 수준의 가격만 유지된다면 사용료 때문이라도 이쪽으로 넘어올 가치가 충분히 있는 것 같다. 

Posted by Knowblesse

Intro

협업하는 팀의 사정으로 원래 쓰던 tensorflow를 놔두고 pytorch로 갈아타게 되었다. 때문에 포스트의 제목이 이런 식이다.

사실 tf v1 때는 변수 만드는 방법부터 배워야 할 정도로 사용성이 아주 부족했는데 keras의 등장 및 v2에서의 편입 이후로 레토르트 식품 데우듯이 쉽게 ML 모델 개발이 가능해졌다. 이러나 저러나 복잡한 모델을 만들지 않는 이상tensorflow와 pytorch 모두 주인장에게는 cuda를 편하게 쓰게 해주는 도구에 지나지 않고 이쯤 시간이 흘렀으면 사용성이 엇비슷하지 않을까 하는 생각에 1시간 정도 걸리리라 생각했다.

 

당장 튜토리얼부터 마음에 안들었다.

 

pytorch tutorials

동영상 자료는 재끼고, Basic에는 대뜸 Tensor 설명부터, Example에는 간단한 Iris, MNIST는 있지도 않다. 그나마 있는 example은 Image Classification. numpy랑 연동이 잘 된다고 하기엔 받아먹는 data형 제한이 너무 귀찮았고 (Linear function은 float32가 아니면 안받더라) 구조도 와닿지 않는다. keras에 익숙한 사람은 누구나 pytorch로 넘어가며 고구마 100개 순간을 경험하리라 생각해 간단한 Iris classification tutorial을 여기에 올려둔다. 구조적 특성이나 보는 관점은 전부 tensorflow에 익숙한 사람의 의견이라 처음부터 pytorch를 쓴 경우 '이 사람은 왜 이런 소리를 하나?' 생각을 할 수 있겠으나 주인장과 같은 전처를 밟은 사람이라면 이해하리라 기대한다.

 

Example

import torch
from torch import nn as nn
import torch.nn.functional as F
from sklearn import datasets
import numpy as np

# Define Model
class Clf(torch.nn.Module):
    def __init__(self):
        super(Clf, self).__init__()
        self.fc1 = nn.Linear(4,10)
        self.fc2 = nn.Linear(10,3)

    def forward(self,x):
        return self.fc2(F.relu(self.fc1(x)))

# Load Data
iris = datasets.load_iris()

X = torch.tensor(iris.data, dtype=torch.float32)
y = torch.tensor(iris.target)

# Setup Model, Optimizer, Loss function
clf = Clf()
optimizer = torch.optim.Adam(clf.parameters(), lr = 0.01)
loss_fn = nn.CrossEntropyLoss()

# Train
for _ in range(1000):
    y_pred = clf(X)
    loss = loss_fn(y_pred, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

print(np.argmax(y_pred.detach().numpy(),1))

dataset은 scikit-learn에서 들고오는 방식을 택했다. train test split, metric 등은 모두 무시하고 150개 데이터 전체를 한번에 학습시키는 단순무식한 코드임을 감안해서 보면 좋겠다.

 

Model

tensorflow 의 keras와 동일하게 모델을 정의하고 모델 구조를 짜서 넣어준다. 하나 차이점은 one-line으로 모델을 만들지는 못하고, nn.Module을 상속받는 class를 만들고, forward 함수를 구현해서 모델을 짜야한다는 점이다. forward 함수를 한줄로 짠 것을 보면 주인장의 귀찮음을 볼 수 있다. 모델은 별 문제없이 넘어갈 수 있다.

 

Data Loading

data를 넣을 때부터 슬슬 짜증이 나기 시작한다. scikit-learn에서 제공하는 iris 데이터는 numpy.ndarray 형태이다. X데이터는 float64, y데이터는 int64의 형태를 가지고 있다. 문제는 모델에서 사용한 nn.Linear가 망할 float32만 받는다는 것이다.

 

# Load Data
iris = datasets.load_iris()

X = torch.tensor(iris.data, dtype=torch.float32)
y = torch.tensor(iris.target)

때문에 tensor로 바꿀 때 dtype 을 명시하거나 처음부터 np.astype 함수를 사용해서 float32로 바꾸어서 들고와야한다.

 

Model setup

loss function을 정하고 optimizer를 정하는 것은 tensorflow와 유사하다. 원하는 것을 가져다가 쓰면 된다.

한가지 유의점은 keras의 경우 model 안에 loss function과 optimizer가 같이 포함되는데 pytorch에서는 이들이 다 따로 논다.

clf = Clf()
optimizer = torch.optim.Adam(clf.parameters(), lr = 0.01)
loss_fn = nn.CrossEntropyLoss()

 

Training

# Train
for _ in range(1000):
    y_pred = clf(X)
    loss = loss_fn(y_pred, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

tutorial의 training 파트의 코드를 볼 때는 문제가 없었는데 막상 짜다보니 멘붕이 왔다.

 

잠깐, 나 optimizer에 아무것도 안 넣었는데..?

 

더보기

clf(X) 호출을 통해서 y_pred를 구한다. foward 함수가 아마 호출이 될 것이다.

loss_fn도 이해가 된다. y_pred와 y_true(=y)를 넣어서 loss를 구한다.

optimizer.zero_grad()는 아마도 무언가 initialize를 하는 부분일 것이고,

loss.backward()는 함수명으로 보아 error를 통한 미분값을 구할 것 같은데(backward propagation) weight을 어떻게 알아서 미분값을 구하지?

심지어 loss 값은 optimizer에게 전달되지도 않았는데 혼자서 step() 함수를 호출하고 있다.

 

keras에서는 하나의 모델 안에 loss 함수와 optimizer가 같이 존재한다.

model = keras.Sequential(
    [
        keras.Input(shape=(4,)),
        layers.Dense(200, activation="relu", kernel_initializer=keras.initializers.random_normal(mean=1)),
        layers.Dense(200, activation="relu", kernel_initializer=keras.initializers.random_normal(mean=1)),
        layers.Dense(2,name='output')
    ]
)

model.compile(
    optimizer=keras.optimizers.SGD(learning_rate = 0.001),
    loss=keras.losses.MeanSquaredError(),
    metrics=[keras.metrics.MeanSquaredError()]
    )

심지어 metric 함수까지 포함되어 compile 과정을 거치면 model.fit()을 호출하는 것으로 loss와 optimizer가 작동하고 metric을 알려주는 기능까지 겸하고 있다. keras는 model만 들고다니면 그 안에 모든 함수와 weight들이 묶여서 돌아다니는 구조인데 pytorch는 쉽게 납득하기 어려운 형태를 취하고 있다.

 

pytorch 내부를 뜯어보고 document를 뒤적이고, pytorch를 많이 쓰는 아는 동생에게 물어본 결과 겨우 작동 방식을 이해했다.

왜 이렇게 만든 것인지는 전혀 와닿지는 않지만 말이다.

 

먼저 gradient descent를 위해서는 세 step이 필요하다. 1) error, 혹은 loss를 계산하고, 2)이를 통해 gradient 값을 구한 뒤, 3) 일정한 learning rate을 유지하든 momentum을 더하든 실제로 weight을 수정하는 것이다.

 

keras의 경우 loss function은 loss를 계산하는 부분(1)만 담당하고, gradient를 구하고, 적절한 learnint rate에 맞게 수정하는 부분(2,3)은 optimizer가 담당하고 있다.

 

pytorch는 다르다. loss function에서 1과 2를 담당하고, optimizer가 gradient만 사용해서 실제 parameter를 수정한다.(3)

 

코드 실행 순서를 거꾸로 올라가면 다음과 같다.

1. optimizer가 주어진 gradient 값을 사용해서 parameter를 수정한다.

optimizer.step()

optimizer가 처음 만들어졌을 때 clf.parameters()를 넣었는데, 이는 모델의 parameter를 참조하는 값이다. 때문에 optimizer는 clf 의 parameter를 수정할 수 있다. 수정에 사용하는 gradient 값은 parameter 안에 들어있다.

params = [i for i in clf.parameters()]
print(type(params[0]))
print(params[0].grad)

위 코드를 실행하면 torch.nn.parameter.Parameter 형태로 clf 내부가 표현되는 것을 알 수 있으며, 이는 Tensor의 일종으로, backward 함수를 실행하면 grad 값이 생긴다. loss.backward()를 실행하지 않으면 params[0].grad는 None으로 설정되어 있을 것이다.

 

2. loss 값을 사용해서 gradient를 구한다.

loss.backward()

그렇다면 어떻게 loss를 통해 구한 gradient가 clf의 weight까지 가는가?

loss는 Tensor type이다. 중요한 점은 이 Tensor가 단순히 data만을 담고 있지 않고, 어느 과정을 통해서 이 값들이 구해졌는지에 대한 정보를 가지고 있다는 것이다. 설마설마 하긴 했는데 이 변수 안에 어떻게 보면 이 값이 나오게 된 역사(?)가 담겨있다. (이러면 memory issue는 괜찮나...?)

tutorial에서도 제대로 알려주지 않는데 이를 확인하는 방법은 다음과 같다.

(Deep Learning with PyTorch: A 60 Minute Blitz 글 안에는 있다!)

loss.grad_fn.next_functions

Tensor object인 loss에는 grad_fn이라는 필드가 있는데, 이 function 안의 next_functions field에는 이 뒤에 호출해야할 function들의 참조가 달려있다. 물론 이 순서는 해당 Tensor가 만들어진 순서의 역순이다. 이렇게 next_functions 를 따라가면 아래의 순서로 loss가 구해졌음을 알 수 있다.

 

grad_fn 호출 stack

때문에  loss.backward()만 호출하면 각 parameter Tensor에 grad 값이 전파된다.

각 grad_fn에 대한 자세한 설명은 공식 document에도 나와있지 않지만, AccumulateGrad가 있는 부분마다 실제 error에 의한 grad 값들이 존재하는 것으로 보인다 (각 linear layer마다 weight에 해당하는 Tensor와, bias에 해당하는 Tensor가 있을 것이다.)

3. clf를 구성하는 Tensor들의 grad 값을 초기화 한다.

optimizer.zero_grad()

optimizer와 loss function이 따로 놀기 때문에 현재 parameter가 가지고 있는 gradient를 초기화 시켜주는 함수가 존재한다. 때문에 이 함수를 먼저 호출하고, 이 뒤에 loss를 backpropagation 시키는 방식으로 코드를 작성해야한다.

 

이 이후는 keras를 쓰던 유저도 쉽게 이해하리라 생각한다.

 

마치며

pytorch를 사용한 ML 논문이 이미 tensorflow를 사용한 논문의 수를 넘었다고 한다. 익숙하지 않은 구조 때문에 하루를 날리며 대체 왜 pytorch를 쓰는가에 대한 글을 찾다가 pytorch의 장점으로 동적인 computation graph를 언급하는 글을 보았다. 어쩌면 keras처럼 Model 종속적인 형태가 아니라 연산 값에 연산과정이 들어있는 구조 때문에 동적 computation graph가 가능한 것인가 하는 생각이 든다. 하나의 작은 산은 넘은 것 같다.

 

 

Posted by Knowblesse
취미/Technology | 2022. 1. 11. 11:58 | /40

#스타트업 #힙스터 #팀워크 #생산성

스타트업'스러움'이 하나의 문화컨텐츠로 떠오르면서 온갖 제품과 서비스들이 이러한 분위기에 맞추어지고 있다. 마치 Helvetica 폰트가 디자이너들에게 사랑받기 시작하면서 세계를 장악하는 현상을 보는 것만 같다. 실제 생산성을 높이기 위함이든, 본인의 '힙함'을 보여주기 위함이든 여러 제품을 구입하고, 서비스를 구독하기 시작하면 월 구독료로 나가는 돈은 적지 않을 것이다. 또한 개중에는 이러한 문화적 흐름에 편승해서 그럴듯하게 포장한 예쁜 쓰레기를 제공해주는 곳도 많아서 사용자로 하여금 더 많은 판단을 요구한다. 자칫 생각없이 모든 것을 수용하다가는 생산성 앱으로 도배된 생산적이지 않은 본인의 기기를 보게 될 것이다.

 

변화에 슬슬 더디게 반응하기 시작하는듯한 기분을 떨쳐내기 위해 오래전부터 이야기를 듣고 추천을 받아온 Notion을 쓰기 시작했다. 당장에 연구실 지식베이스와 소통을 위한 목적으로 어렵게 도입했던 Slack부터 스타트업에 잠시 참여했을 때 접했던 트렐로, 2011년 1월부터 사용중인 에버노트와 iOS 한글 지원문제로 갈아탔던 OneNote까지 온갖 유사 프로그램들 접했는데 각자 지향하는 바가 분명하게 다른 것 같다. 다른 앱과 함께 하루 Notion을 써본 소감을 간략히 적는다.

 

* 트렐로 : 협업용 TODO 리스트

* Keep : 동기화 되는 포스트잇 게시판

* Evernote : 동기화 되는 간단한 메모장

* OneNote : 화이트보드

* Slack : 조금은 DB의 형태를 갖춘 카카오톡

* Todoist / TickTick : 혼자쓰는 TODO 리스트

Notion : 잘 정리된 Blog 글 같은 Evernote

현재 각자 사용목적성이 뚜렷하고 열심히 쓰고 있는 두 앱이 OneNote와 Evernote여서 그런지 자꾸 이 둘과 비교를 하게 된다. Evernote의 경우 기사를 대충 스크랩해서 처박아두거나, 짧은 메모, 일기 등의 줄글 위주의 게시물, 혼자 보는 용도의 설명서를 담아둔다. '동기화가 되는 간단한 메모장'이 가장 확실한 설명인 것 같다. 노트를 예쁘고 깔끔하게 만들기 위해서는 추가적으로 서식을 변경하거나 하는 등의 노력이 많이 들어간다. 그런데 그럴 일은 없다. 대충 넣어두고 나중에 필요하면 찾으면 되고, 잘 정리된 문서가 필요하면 워드로 작성하면 된다. 첫 번째 책상서랍 같은 존재다. 때문인지 유료플랜을 결제할 때는 매번 망설인다. 해주는 기능도 얼마 없으면서 이 가격을 받아야 하나 싶다.

 

OneNote의 경우는 아이디어 상자이다. 화면 아무 곳이나 클릭하면 바로 글이 써지고 Indent 조절이 쉽게 되고 이리저리 컨텐츠 박스를 끌고 다닐 수 있다는 점이 매력이다. 화이트보드 같은 매력이 있다. 하지만 이러한 점은 화면이 작은 모바일 기기로 볼 때 확실히 단점으로 작용한다. 화면안을 이리저리 돌아다니면서 글을 읽는 것은 정말 불편하다. 그래도 Evernote에 비해서는 깔끔한 문서정리가 가능하기 때문에 자주 꺼내보아야 하는 자료의 경우는 OneNote에 정리해서 넣어둔다.

 

짧은 메모, 텍스트 위주의 정보, '대충 넣어두어도 나중에 필요하면 뒤지겠지...' 하는 수준의 정보는 Evernote.
빠른 아이디어 작성, 위계관계가 확실한 정보, 조금은 정리해서 넣어두어야 하는 정보는 OneNote.

 

 

Notion은 OneNote와 Evernote 어딘가에 어중간하게 있다. 많은 사람들이 마크업 기능을 장점 중 하나로 꼽는데 확실히 여타 다른 앱들에 비해서 월등히 편리하다. 그 외에 sorting이 지원되는 깔끔한 표 삽입 기능과 댓글기능, 페이지 간 링크 등은 앞서 언급한 많은 앱들의 필수 기능들을 하나로 통합해서 왜 이런 앱이 이제야 나왔는지 싶다. 하지만 '이렇게 참신하고 대단한게 나오다니!' 보다는 '이런게 왜 이제야?'에 가깝다. 다양한 템플릿을 지원한다는 점에서는 OneNote와 가깝고 심플하다는 것에 Evernote와 비슷한 느낌을 준다. 하지만 전반적인 감상은 OneNote보다는 Evernote에 가깝다고 할까. OneNote의 '화이트보드'스러움이 있었다면 Evernote와 OneNote를 통합해서 사용할 수 있었겠으나 아이디어를 이리저리 끌고다니는 기능은 없는듯 하다. 하긴 앞서 언급한 모바일환경에서의 불편함을 생각하면 좋지 않은 방법일 수도 있겠다. Notion에서는 확실히 '협업용'의 분위기가 물씬 풍긴다. 내 난잡한 Evernote 글을 동료에게 준다면 한소리 들을 것이 분명하고, 마크업이 제대로 되지 않고 외부자료를 넣기 힘든 OneNote는 장기적인 데이터 유지 관점에서는 분명 좋지 않은 선택이다. Notion은 원활한 정보전달에 필요한 만큼의 미적 요소를 가미해서 글 작성이 가능하다. 왜 이렇게 붐을 일으켰는지 알법하다.

 

하지만 Notion이 얼마나 내가 쓰는 기존 프로그램들을 대체할 수 있을지는 의문이 든다. '협업'의 필요성이 크지 않기에 기존 두 프로그램들로도 충분한 목적을 달성했다. 또한 마크업 기능도 미를 위해 할애하는 시간을 해치지 않을 만큼 쉽게 되어있기는 하지만 미가 필요할 수준의 내용이면 아에 문서로 작성을 하고, 그런 것이 아니라면 짤막한 메모로도 충분하다. 그나마 이번에 진행하는 프로젝트의 일원이 Notion을 쓰는 것 같던데 이 프로젝트를 위해서 사용하는 것이라면 Notion을 충분히 쓰겠으나 OneNote나 Evernote를 내려놓기에는 조금 힘들 것 같다. 다만 메모장 프로그램에 매달 돈을 지불해야하는 점이 괘씸하기에 Evernote는 Notion로 대체를 시도하려고 한다.

Posted by Knowblesse