서론

종교를 가지고 있지만 불가지론을 지향하는 과학자로서 (제목과는 다르게 아이러니 하게도) “종교 서적”으로 분류된 이 책을 스스로 읽을 이유는 전혀 없었다. 단지 최근에 읽은 Ray Dalio의 <Principle>에서 이 책을 인용했다는 점과, 종교 최대 지도자가 종교를 “넘어”라는 표현을 썼다는 점이 신경쓰여서 책을 잡아들게 되었다. 전체적으로는 내가 자기개발서에 기대하는 수준을 넘기지는 못했으나, 여러가지 생각할 점들을 주었다는 것과, 얇은 책 두께 때문에 읽은 시간이 아깝지는 않았다.

 

종교의 몰락.

종교에는 신에 의해 진실이 보장된 도덕이 있고, 사후세계에서의 심판이든 다음 생에서의 삶이든 옳음을 강요하는 강력한 힘이 존재한다. 그러나 세계화로 종교간의 의견 충돌이 보이기 시작했고, 종교들이 제시하던 도덕 또한 ‘상대적 진실’에 불과하다는 점이 드러나면서 종교는 예전처럼 힘을 쓰지 못하게 되었다. 또한 순기능에 비해서 점점 비대해지는 종교에 반해서 생겨난 과학의 등장으로 종교의 가치는 점점 하향세를 걷고 있다. 확실하지 않으면 존재 자체를 부정하는 과학을 하는 하는 내 입장에서 이러한 변화는 자연스러운 것이며, 종교는 결국 일부 쇠퇴하리라고 생각한다.

 

마음챙김은 그러면 이제 누가 어떻게?

문제는 종교의 몰락이 아니라 종교가 원래 수행하던 일을 어떤 객체가 이어서 수행을 하냐는 것이다. ‘마음’이든, ‘내적 가치’든, ‘자비’든 인간의 온전한 정신상태는 인류에게 단 한번도 중요하지 않았던 적이 없었다. 단지 과거에는 종교가 이러한 일들의 일부를 담당하고 있었으나 종교의 몰락과 함께 마음챙김(이 단어를 매우 싫어하지만 적절한 단어를 찾지 못해서 그대로 사용한다)을 담당할 무언가가 사라지고 있다. 이 책에서 마음챙김의 중요성을 첫 챕터에서 지적을 하는데, 달라이 라마도 종교의 한계를 인정하지만, 그렇다고 종교가 원래 해오던 일들까지도 함께 무시해서는 안된다고 이야기한다. 때문에 이 책의 제목이 종교를 “넘어” 인 것이다. 역자의 후기를 읽어보면 달라이 라마가 어느날 갑자기 이러한 이야기를 한 것이 아니라 꽤 오래전부터 종교 그 이상의 가치를 지켜야한다고 역설해온 것으로 보인다. 어쩌면 불교가 종교의 많은 구성 요소를 자기 수행과 온전한 정신상태에 초점을 두고 있기에 가장 먼저 종교의 부재로 발생하는 문제점들을 인식한 것이 아닌가 생각한다. 개신교에 익숙한 나로서는 단 한번도 종교의 약체화가 인류에게 이러한 영향을 미치리라고 생각을 해본 적이 없었다. 확실히 다양한 가치가 자유와 다양성이라는 이름하에 수용이 강제되고 있고, 더이상 흑백논리적 도덕적 판단이 어려워지는 현재에 있어서 설사 그것이 상대적 진실이라고 하더라도 기준점이 되어줄 무언가가 절실히 필요하다. 무엇이 옳고, 우리가 어떤 정신을 가지고 어디에 더 중점을 두어야 하는지를 생각하는 것이 더 중요해졌다.

 

달라이 라마의 대책

그렇다면 어떤 객체가 기존의 종교가 맡아서 하던 마음챙김의 역할을 대신 해줄 수 있을까. 우리가 나아가야할 방향을 확실히 제시해주고, 좀 더 일관되고 올곧은 현세적 도덕관을 제시해주며, 한 사람 한 사람을 위로해줄 수 있는 무언가가 나타난다면 그 형태가 어떻든 간에 21세기에 가장 강력한 ‘종교’가 될 것임이 분명하다. 책의 2/3을 할애하는 부분은 달라이 라마의 대책이다. 안타깝게도 달라이 라마 본인에게 가장 익숙한 불교적 방법, 스스로의 수행과 명상을 통한 자비에 기반한 마음챙김을 해법으로 제시한다. 인류를 하나로 묶어주는 강력한 대상이 없어지는 만큼 ‘각자도생으로 자기 마음은 자기가 챙기자’의 논리가 틀린 것은 아니겠으나, 뻔한 자기 개발서의 흐름을 벗어나지 못했다는 생각에 아쉬움이 앞섰다. 아무리 자애로운 마음이 무엇인지, 절제와 덕이 무엇인지를 설명해도 달라이 라마 본인의 말처럼 이는 ‘지식의 문제가 아니라 행동의 문제’이다. 책을 통해 조금이나마 방향을 잡아주지 않을까 하는 기대를 했으나, 스스로 깨닫고 행동하지 않으면 알 수 없는 내용들에 대한 설명만이 마지막 페이지까지 이어졌다. 그나마 다루는 내용의 무게에 비해 얇은 두께로 그가 이런 한계를 인지하고 최대한 ‘절제’를 해서 글을 썼다는 점을 느낄 수 있었다.

 

총평

전혀 관심을 주지 않을 법한 주제와, 다른 종교의 사고관을 간접적으로 나마 접할 수 있었다는 점에서 충분히 읽을 만한 책이었다. 특히 종교의 부재로 일어나는 일에 대해서는 단 한번도 생각을 해본 적이 없었으나, 이 책을 읽고 달라이 라마의 염려에 확실히 동의할 수 있었다. 그리고 내가 접해본 종교인들은 본인의 ‘옳음’에 심취되어 있거나, 다른 분야에 대한 무지로 헛소리를 하는 경우가 대부분이었는데 달라이 라마는 확실히 다른 것 같다. 열린 마음으로 다양한 학문을 탐구하고, 자신의 종교와의 공통점을 찾고, 더 나아가서 자신의 종교 그 이상의 메타적인 시각에서 인류를 조망하는 것이 확실히 느껴졌다.

'Mind Storage > As a Scientist' 카테고리의 다른 글

[TED]A mouse. A laser beam. A manipulated memory.  (0) 2015.10.06
Posted by Knowblesse
0 Comments

2D Gaussian Convolution filter

2D space에서 image smoothing, noise 제거 등을 위해서 Gaussian filter를 적용할 때가 있다.

Matlab에는 워낙 다양한 toolbox들이 있어서 간혹 유사한 기능을 하는 함수들이 존재하기도 하는데, 때문에 같은 기능을 다양한 방식으로 구현을 할 수 있다.

오늘 imgaussfilt 함수와 mvnpdf 함수를 사용해서 Gaussian filter를 적용을 하다가 몇가지 차이점과 유의점을 발견하여 이곳에 적는다.

 

Original Image

코드 설명에 사용할 Original Image를 만드는 코드이다.

100 x 100 이미지에 (50, 50) 과 (20, 50) 의 pixel만 1의 값이 들어가있다.

originalImage = zeros(100,100);
originalImage(50, 50) = 1;
originalImage(20, 50) = 1;

Method 1: imgaussfilt

함수 개발 목적 자체가 2D 이미지에 Gaussian filter를 적용하기 위한 것이기 때문에 가장 간단하게 원하는 목적을 달성할 수 있다.

figure(1);
clf;
sigma = 1;
fimage1 = imgaussfilt(originalImage, sigma, 'FilterSize', 101);
imagesc(fimage1);

여기서 중요한 것은, 'FilterSize' Name-Value pair인데, 이 값을 입력하지 않거나, 작은 값으로 설정하는 경우 convolve 하는 kernel의 크기가 작아서 빠르지만 조금은 부정확한 결과가 나올 수 있다.

참고로 fimage1의 합은 2가 된다.

 

Method 2: mvnpdf로 kernel을 만든 뒤 conv2

직접 2D Gaussian kernel을 만든 뒤에 원본이미지와 conv2 함수를 사용해서 적용하는 방식이다.

[X,Y] = meshgrid(1:101, 1:101);
X = X(:);
Y = Y(:);
mu = 51;
sigma = [1, 0; 0, 1];
kernel = reshape(mvnpdf([X,Y],mu,sigma),101, 101);

fimage2 = conv2(originalImage, kernel, 'same');

figure(2);
imagesc(fimage2);

51의 값은 101 크기의 kernel의 중간값이다.

 

위 결과는 imgaussfilt의 결과와 정확히 일치한다.

 

 

 

함수 개발 목적 자체가 2D 이미지에 Gaussian filter를 적용하기 위한 것이기 때문에 가장 간단하게 원하는 목적을 달성할 수 있다.

Posted by Knowblesse
0 Comments

들어가며

  안전한 보안을 위한 좋은 방법 중 하나는 Two Factor Authentication (2FA)를 계정에 설정해두는 것이다. 사이드마다 다른 비빌먼호 생성, 주기적인 비밀번호 변경보다 훨씬 쉽게 보안 수준을 높게 유지할 수 있다. 그런데 github에 2FA 인증을 설정해두면 서드파티 앱이나 shell에 있는 git 에서 remote repository (remote)에 접근을 하기 어려워진다. 또한 지난 2021년 8월 13일부로 github 계정을 사용한 remote 접근이 완전히 차단되어서 더이상 단순히 비밀번호를 입력해서 접근하기가 어려워졌다. 때문에 아래와 같은 방법을 통해 remote에 접근 할 수 있다.

 

1. Token 발급 : sub-password의 역할을 하는 token을 발급받아 비밀번호 대용으로 쓰는 방식으로, 각 token 마다 유효기간, 권한등을 설정할 수 있다. 기존의 github 계정 비빌번호를 사용하는 방법을 완전히 대체 가능하다.

2. OAuth : Open Authentication. 로컬 git, 서트파티앱에 github 로그인 정보를 제공하지 않고 github에 연결하게 해주는 인증방식이다.

3. SSH : 이 글에서 다룰 내용으로 한번 설정만 제대로 한다면 편리하고 보안성도 좋다.

 

설정 난이도만 생각하면 Token을 발급받는 방법이 가장 쉽다. Token을 발급받아서 필요한 권한을 준 뒤, 어딘가에 적어두고 remote를 연결할 때 사용하면 된다. 그러나 더 높은 보안과 편리성을 위해서는 SSH를 사용하는 것을 추천한다.


SSH 연결 특징

  SSH는 Secure SHell의 약자이며 구체적인 SSH 통신 방법은 여기에서 다루지 않겠다. 대신, SSH 를 사용하면 어떤 것들이 필요하고, HTTPS를 사용하는 방식과는 어떻게 다른지 비교를 하겠다.

 

사용자 이름을 knowblesse, repository 이름을 myrepo라고 했을 때 HTTPS와 SSH에서 필요한 것은 아래와 같다.

 

  HTTPS SSH
remote repository 주소 https://github.com/knowblesse/myrepo git@github.com:knowblesse/myrepo.git
ID knowblesse@gmail.com X
PSW (Token) ghp_********* X
Public Key / Private Key X SHA256:e/***************
(옵션) credential 저장 git config credential.helper store
git config --global user.name Knowblesse
git config --global user.email knowblesse@gmail.com
eval "$(ssh-agent -s)"
ssh-add

 

차이점 1 : remote 주소

SSH는 인증방식이 아니라 (보안 인증 프로토콜을 포함하고 있는) 통신 방식이다. 때문에 일반적으로 알고 있는 https로 시작하는 주소가 아닌 git@github.com 으로 시작하는 주소를 입력해야한다.

차이점 2 : 인증

SSH에서는 public keyprivate key, 두 가지 파일을 사용하는 공개키 암호화 방식을 기본으로 택하고 있다. 처음에 key 생성기를 사용해서 서로 매치가 되는 public key와 private key를 생성하고, 인증을 원하는 곳에 public key를 제공하면 이후 접속시 private key를 이용해서 인증받을 수 있다.

차이점 3 : Credential 저장

token을 사용하는 HTTPS 방식에서는 credential.helper를 사용해서 token을 저장해둘 수 있다. SSH에서는 ssh-agent를 사용해 credential을 저장한다.


SSH 연결 설정

SSH 연결 설정 순서는 다음과 같다.

 

1. SSH 키가 없는 경우 : SSH 키 생성

2. Github에 SSH 등록

3. local repository에 SSH 기반 remote 주소 등록

4. ssh-agent 셋업 및 연결 방법


1. SSH 키 생성

    SSH 키 생성은 다양한 프로그램이 지원하고 있는데, Window와 Linux 모두 기본으로 설치되어있는 ssh-keygen을 사용하는 방법이 가장 보편적이다.

 

먼저 기존에 생성해둔 ssh키가 없는지 간단히 확인한다.

Window ("C:\Users\Knowblesse") 와 Linux ("\home\Knowblesse") 의 유저폴더 안에 ".ssh" 라는 명칭의 폴더 안에 .pub로 끝나는 파일이 있는지 확인해보면 된다. 키 생성을 한번도 안한경우 폴더 자체가 없을 것이다.

 

Window cmd나 Linux shell에서 다음과 같이 ssh-keygen을 실행하자.

> ssh-agent -t ed25519

ssh-agent는 기본 옵션으로 rsa key pair를 만드는데 최신 방식은 ed25519라고 한다. 기본 옵션으로 키를 생성하려면 "ssh-agent"만 실행하면 된다.

 

이후 파일을 저장할 위치를 묻는데 default 위치를 그대로 사용해야지, 다른 곳에 저장을 했다가는 추가로 key 위치를 입력해주는 작업을 해야한다. 가능하면 ~/.ssh 폴더 안에 생성하도록 그대로 두자.

> ssh-keygen -t ed25519
Generating public/private ed25519 key pair.
Enter file in which to save the key (C:\Users\Knowblesse/.ssh/id_ed25519):

다음으로는 password를 묻는다.

> ssh-keygen -t ed25519
Generating public/private ed25519 key pair.
Enter file in which to save the key (C:\Users\Knowblesse/.ssh/id_ed25519):
Enter passphrase (empty for nopassphrase):

이 passphrase는 private key를 한번 더 암호화 하는데에 사용된다. private key에도 암호를 걸어두는 것을 적극 권장한다.

Q. 왜 passphrase를 설정하나요?
A. 행여나 private key가 노출되었을때를 방지하기 위함입니다. 실질적인 보안은 사실 public/private key 쌍이 담당하고 있기에 passphrase를 복잡하게 설정할 필요는 없습니다. 때문에 명칭도 password가 아니라 phrase 입니다.

 

private key에 암호설정 과정을 마치면, 아래와 같은 출력 메시지 후에 public key와 private key가 생성된다.

예시 화면

.pub 확장자를 가진 파일이 public key, 아무런 확장자가 없는 파일이 private key 이다.

생성된 두 파일은 텍스트 편집기로 열 수 있는 plain text 파일이며 private key는 절대 인터넷 상에 노출이 되면 안된다.

 

Q. 어차피 private key는 public key와 인증을 거치는 과정 중에서 인터넷 상에 노출되지 않나요?
A. SSH 인증에 사용하는 비대칭 공개키 암호화 방식은 1) 서버가 랜덤한 메시지를 호스트로 보내고, 2) 이를 받은 호스트는 private key로 암호화를 해서 다시 서버에게 보내고, 3) 암호화된 메시지를 받은 서버가 자신이 가지고 있는 public key를 사용해 복호화 한 뒤, 원래 보냈던 메시지와 비교하는 방식입니다. 때문에 private key는 인터넷 상에 절대 노출되지 않습니다.

2. Github에 SSH 등록

    생성한 public키는 Github에 등록할 수 있다.

 

 

새로운 SSH 키 등록 버튼을 누른 뒤, 텍스트 편집기로 .pub 파일을 열어서 내용을 붙여넣으면 된다.

public key 입력

3. local repository에 SSH 기반 remote 주소 등록

    여기서부터 살짝 까다로워 진다.

3-1. 처음 repository를 생성하는 경우 (clone 하는 경우)

https 기반 주소가 아니라 아래처럼 SSH 기반 주소를 입력하면 끝난다.

> git clone git@github.com/knowblesse/myrepo

 

3-2. 기존에 생성된 repository를 변경하는 경우

remote에 연결된 url 을 SSH 형식으로 수정하는 작업이 필요하다.

> git remote
origin

먼저 git remote 커맨드로 어떤 remote 와 연결되어있는지 확인한다. 위의 예시에서는 origin만 연결되어 있다.

 

추가로 아래 커맨드를 사용하면 origin의 url을 볼 수 있다.

> git remote get-url origin
https://github.com/knowblesse/myrepo.git

url의 변경은 set-url을 사용하면 된다.

> git remote set-url origin git@github.com:knowblesse/myrepo.git

형식에 주의하자

git@github.com:knowblesse/myrepo.git

Q. 여러 개의 SSH key를 사용할 경우에는 어떻게 하죠? 어떤 key를 쓰라고 지정할 수는 없나요?
A. ~/.ssh 폴더 안에 config 파일을 만들어서 어느 사이트에 연결할 때 어떤 key 파일을 사용할지 정해줄 수 있습니다. 이 방법 외의 다른 방법도 있지만, git command 안에서 "어떤 key 파일을 써라" 라고 명시적으로 알려주는 방식은 없는 것으로 알고 있습니다. config 파일을 생성하는 방법은 아래 접은 글을 참고해 주세요.
더보기

config 파일 만드는 법

open SSH 에서 사용하는 config 파일은 여러 요소로 구성되어 있으나, 복수의 key를 사용하기 위한 목적이면 Host, HostName, IdentityFile 3개의 키워드만 사용하면 된다. 구체적인 작성법은 다음 사이트를 참고하자.

https://www.ssh.com/academy/ssh/config

 

SSH config file syntax and how-tos for configuring the OpenSSH client

SSH config file syntax and how-tos for configuring the OpenSSH client

www.ssh.com

config 파일을 사용해서 복수의 key를 사용하는 원리는 Host의 alias 생성이 가능하다는 점을 이용하는 것이다.

git@github.com:knowblesse/myrepo.git

 

위의 주소에서 git 은 사용자명(knowblesse가 아니다!), github.com 은 Host의 위치, knowblesse/myrepo.git은 호스트 서버 내의 내 remote의 위치이다(정확히는 remote 정보를 담고 있는 git 파일).

 

중요한 점은 github.com 이 실제 주소가 아니라 Host의 이름 이라는 것인데 open SSH는 config 파일에서 해당 이름을 가진 Host가 없으면 이를 실제 Host 주소로 사용해서 실제 github.com과 통신을 시작한다.

 

반면, Host를 지정해주고 실제 Host의 주소를 config 파일에 명시하면 다른 형태로 접속이 가능하다.

Host myhub
	HostName github.com

예를들어, 위와 같이 config 파일을 설정해주면 이후 github.com을 입력하지 않고 단순히 아래처럼 입력할 수 있다.

git@myhub:knowblesse/myrepo.git

주의점은 HostName이 alias가 아니라 Host가 alias이다. HostName은 실제 주소다!

 

또한 config 파일에서는 각 host 마다 사용할 IdentityFile의 위치를 지정할 수 있다.

 

여기까지 설명을 하면 이미 눈치를 챘을 것이다. IdentityFile만 다르게 지정한 alias를 여러개 만들어 두면 remote의 set-url을 진행할 때 사용하는 alias에 따라 다른 key 파일을 사용하도록 할 수 있다.

 

다음은 account1_private 과 account2_private key 파일을 사용하는 config 파일의 예시이다.

#keyfile 1
Host account1
         HostName github.com
         IdentityFile ~/.ssh/account1_private
#keyfile 2
Host account2
         HostName github.com
         IdentityFile ~/.ssh/account2_private

이후 git remote set-url 함수를 사용해서 repo 마다 remote의 주소를 설정해주어야 한다.

예를 들어 account1_private key 파일을 repo1에 사용하려면 아래와 같이 url을 변경한다.

> git remote set-url origin git@account1:knowblesse/repo1.git

4. ssh-agent 셋업 및 연결 방법

    여기까지 설정을 완료했고, key 파일이 기본 위치인 ~/.ssh 안에 들어있다면 정상적으로 remote와 연결이 될 것이다. 그러나 매번 passphrase를 물어본다는 단점이 있다. 이를 해결하는 방법은 ssh-agent를 사용해서 잠시동안 passphrase를 저장해두는 것이다. 이 경우 한동안 passphrase 없이 SSH 통신을 할 수 있다. 마치 credential.helper 를 사용해서 token을 저장해두는 것과 동일하다.

 

순서는 두 과정을 거치는데, 1)ssh-agent를 실행하고, 2) ssh-add를 통한 key 등록이다.

Linux

> eval `ssh-agent -s`
Agent pid 12345
> ssh-add

Windows (PowerShell)

> Set-Service ssh-agent -StartupType Manual
> Start-Service ssh-agent
> ssh-add
Q. 왜 그냥 ssh-gent를 실행하면 안되고 꼭 eval 함수 사용해서 실행해야하죠?
A. eval을 쓰지 않고 ssh-agent 명령을 실행해도 ssh-agent 프로세스는 정상적으로 시작된다. 그런데 그 이후에 ssh-add가 정상작동하지 않는다. 그 이유는 ssh-add가 SSH 소켓에 대한 정보를 필요로 하기 때문이다.

ssh-agent 명령을 실행하면 다음과 같은 출력이 나온다.

> ssh-agent -s
SSH_AUTH_SOCK=/tmp/ssh-XXXXXXmj93qJ/agent.36991;
export SSH_AUTH_SOCK;
SSH_AGENT_PID=36992;
export SSH_AGENT_PID;
pid 36992;

눈치 챘겠지만, ssh-agent 명령은 ssh-add 에게 매번 긴 SSH_AUTH_SOCK에 해당하는 값을 전달해주지 않도록 SSH 소켓과 ssh-agent 관련 정보를 bash 코드로 출력한다. 때문에 출력 텍스트를 그대로 코드처럼 실행시키는 eval 함수를 사용하여 ssh-agent를 실행하면, ssh-agent의 출력결과인 소켓과 pid 설정을 자동으로 할 수 있다!

때문에 굳이 eval을 쓰고 싶지 않다면, ssh-agent를 돌려서 나온 소켓과 pid 정보를 아래와 같이 변수로 입력해주면 된다.

> SSH_AUTH_SOCK=/tmp/ssh-XXXXXXmj93qJ/agent.36991
> SSH_AGENT_PID=36992
> ssh-add
Q. 왜 윈도우에서는 서비스 시작 방법을 바꾸나요?
A. Startup Type 이 Manual이 아니면 수동 시작이 안되는 것 같다. 윈도우는 UI가 잘 되어 있으니 수동시작을 하지말고 시작시 자동 시작을 하게 하면 더 편할 것 같다.

마치며

SSH 설정이 단순하지는 않지만, 한번 설정만 해두면 높은 보안수준을 유지하며 쉽게 데이터 공유가 가능하다.

Posted by Knowblesse
0 Comments

 

심리학과 답게 진행한 Negative Punishment. 효과는 없었다.

사용 후 꼭 레버를 올려주세요

 연구실에 사비로 캡슐 커피머신을 비치해두었는데, 공유지의 비극으로 관리의 문제가 심각해진 적이 있었다. 캡슐을 사용하고 레버를 올리지 않는 경우 캡슐이 그대로 기기안에 남는데, 기온이 높은 여름에는 따뜻하고 눅눅한, 곰팡이가 번식하기에 최적인 조건이 만들어진다. 특히 금요일 오후즈음 이런 상황이 발생하면 주말내내 커피머신은 곰팡이 배양기로써 그 역할을 충실히 수행한다. 월요일 아침에 커피를 마시기 위해 레버를 올리는 순간, 떨어지는 캡슐에 핀 곰팡이를 보게되면 결국 기기 분해 세척은 주인인 내 몫이 되었다.

 

 다들 범행(?)을 부인하는 통에 전체 공지도 돌리고 사진처럼 Negative Punishment도 해봤으나 인간은 쉽사리 바뀌지 않는법. 결국 Raspberry Pi를 사용해 커피 머신 사용 중 동영상을 촬영하고, 2분내로 레버를 올린 경우 동영상은 삭제, 레버를 올리지 않은 경우는 동영상을 저장한 뒤, 내게 이메일로 노티를 주는 장치를 만들었다. (코드)

 

GitHub - knowblesse/BlueberryPi

Contribute to knowblesse/BlueberryPi development by creating an account on GitHub.

github.com

 

 원래 계획은 범인의 커피 내리는 영상을 (이게 생각보다 우스꽝스럽다) 반복 재생시켜두려고 했으나, 매우 안타깝게도 높으신 분의 반복범행임이 밝혀져서 깔끔히 포기했다. 10개의 범행장면을 모은 뒤 '두근두근 범인 공개 상영회'를 연 것으로 만족했으며, 그냥 스스로 자주 확인을 하기로 했다.

 

코드 다 돌아가면 알려줘!

 앞서 언급한 프로젝트를 진행하던 중 처음 겪은 불편함은 범인이 걸렸는지 확인하려면 직접 기기에 가서 파일 생성 여부를 체크해야 했다는 점이다. 터치스크린을 연결해두기는 했지만 매일 기기 체크하기가 귀찮아서 범인이 잡히면 이메일을 보내는 스크립트를 만들었는데, 이는 생각보다 단순하다. (코드) 구글, 네이버 등의 이메일 SMTP 서버를 사용해서 내 계정에서 내 이메일로 메일을 보내도록 설정하면 된다. 단점으로는 이메일 자체가 느리고, 내 핸드폰의 이메일 동기화 주기가 그렇게 짧지 않아서 즉각적인 메일 확인이 어렵다는 점이다. 물론 커피 머신 범인을 확인하는게 급한 문제는 아니었기에 만족하면서 사용했다.

 

그러나 다른 컴퓨터에서 코드를 돌리고 실행이 완료되거나, 문제가 발생하면 알려주는 기능은 커피 머신보다는 급한일이다. 더욱이 이메일로 보내는 경우 다른 중요치 않은 이메일에 섞여서 묻힐 수 있다. 때문에 기존 메신저 앱들 중 편리한 API 구성을 제공하는 것이 없나 검색하다가 Telegram의 bot을 활용하는 방법이 군더더기 없이 제일 깔끔해서 이를 소개하려고 한다.

 

Why Telegram?

 사실 텔레그램하면 지난 몇 년간 언론을 달군 사건이 생각나서 설치 자체가 조금 꺼려지기는 했으나 군더더기 없이 깔끔하다는 말에 이를 택했다. 카카오톡이 추가앱 설치도 필요없어서 가장 유력한 후보였으나, 플러스친구, 로그인 등 각종 기능 등과 같이 묶여있어서 그런지 너무 복잡해 반쯤 만들다가 포기했다. 또한 정확히 "코드 다 돌아가면 알려줘!"의 목적에 부합하는 bot 기능을 가지고 있기에 Telegram을 택했다.

 

How to

먼저 핸드폰에 Telegram 앱을 설치하고 계정을 만든다. 연락처 동기화를 자꾸 요구하는데 그닥 메인 메신저로 쓸 생각이 없어서 차단했다.

1. 먼저 BotFather를 사용자에서 찾아서 새로운 bot을 만든다.

계정명을 꼭 확인하자

2. BotFather 와 대화를 시작하고 /newbot 을 보내면 이름과 id를 물어보는 작업을 거쳐 bot을 만들어준다.

이름은 그렇다쳐도 id는 중복이 있으면 안되는 점이 조금 귀찮다.

해당 token은 이미 비활성화 했으므로 괜찮다.

해당 과정을 완료하면 HTTP access token을 발급해준다. 이 정보가 있어야 해당 봇을 통해 본인의 핸드폰으로 메시지를 보낼 수 있다. 함께 알려주는 api 사이트에 들어가면 생각보다 많은 기능을 지원한다는 것을 확인가능하다. 하지만 우리는 단 세 가지 함수만 사용할 예정임으로 굳이 들어가볼 필요는 없다.

 

3. HTTP 호출을 통해서 bot 생성여부를 체크한다.

HTTP GET, POST 등의 method 테스트를 위해서 예전에 Postman이라는 프로그램을 배웠고, 이런 프로젝트마다 디버깅 목적으로 사용하는데 간단한 튜토리얼임으로 기본 웹브라우저를 사용해서 설명하려한다. 별개로 Postman 프로그램이 꽤 유용하니 시간되면 꼭 살펴보시길.

https://www.postman.com/

 

Postman API Platform | Sign Up for Free

Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.

www.postman.com

웹 브라우저(본인은 파이어폭스) 주소창에 아래와 같이 입력을 하면 생성한 bot과 연결이 잘 되는지 확인할 수 있다.

https://api.telegram.org/bot아까발급받은토큰/getMe
# 예시 : https://api.telegram.org/bot5413916344:AAE88PzAed9FCOxygDEeSsEQaggKd8-F81o/getMe

문제가 없다면 아래와 같은 ok 사인을 받을 수 있다.

이름과 id를 얻을 수 있다

4. bot에게 말을 걸자.

핸드폰으로 돌아가서 bot 생성시 두번째로 입력했던 id로 사용자를 검색하면 해당 bot을 찾을 수 있다. 이 bot과 대화를 시작하고, 메시지 하나를 보내두자. bot은 자체적으로 사용자에게 최초로 메시지를 보낼 수 없다. (스팸방지)

 

5. 생성된 대화방의 id를 불러온다.

https://api.telegram.org/bot아까발급받은토큰/getUpdates
# 예시 : https://api.telegram.org/bot5413916344:AAE88PzAed9FCOxygDEeSsEQaggKd8-F81o/getUpdates

다시 브라우저로 돌아가서 위 주소로 간다. 성공적으로 호출이 되면 아래와 같이 대화내용을 불러올 수 있을 것이다.

 

 

getMe를 호출하기 이전에 먼저 대화부터 보내고 나중에 getUpdates를 호출했더니 앞선 대화가 누락되는 문제를 확인했다. (첨부한 이미지에서도 보낸 메시지는 hi there부터 시작하는데  불러온 대화내용은 그뒤에 보냈던 "ㅁㅁ"만 보인다.) 다시 메시지를 보내면 getUpdates에서 잘 보이는 것 같으니 큰 문제는 아닌 것 같다.

 

이렇게 성공적으로 대화를 받으면, id 값을 확인한다. 이 경우 55201이다.

 

6. http request를 통해 메시지를 보내자

모든 과정이 끝났다. 메시지를 보내는 함수는 sendMessage이며 아래와 같이 사용하면 된다.

https://api.telegram.org/bot아까발급받은토큰/sendMessage?chat_id=아이디&text=보낼메시지
# 예시 : https://api.telegram.org/bot5413916344:AAE88PzAed9FCOxygDEeSsEQaggKd8-F81o/sendMessage?chat_id=55201&text=Code Finished

 

python의 경우는 request 패키지를 설치한 후, 아래의 함수를 넣어주면 된다.

import requests
requests.get('https://api.telegram.org/bot5413916344:AAE88PzAed9FCOxygDEeSsEQaggKd8-F81o/sendMessage?chat_id=55201&text=Code Finished')

text 뒤에 코드가 돌아갔다는 정보 외에 시간, 에러가 발생한 경우 그 에러 내용등의 첨부가 가능하다.

 

무엇보다 모든 과정이 핸드폰으로 진행이 가능하며, access token, 본인 telegram 대화방의 id, 단 두 개 정보만 확인되면 메시지를 바로 보낼 수 있다.

 

주의

github가 금광산이라는 말을 들은 적이 있다. 특히 요 얼마전에는 아마존 AWS에 스타트업에서 사용하는 기업용 계정 access token을 실수로 github에 그대로 올렸다가 수 십억에 달하는 사용료가 부과되었다는 뉴스가 나온적이 있다. 모르는 사람은 바보 같다고 생각하겠지만 평상시 버전 관리 프로그램을 쓰는 습관 때문에 나도 충분히 할법한 실수라고 생각한다. Telegram bot token으로는 그러한 짓을 할 수 없겠지만 access token이 어딘가에 공개가 되지 않도록 꼭 주의하자. 본 예시에 사용된 계정은 전부 비활성화 처리를 완료했다.

Posted by Knowblesse
0 Comments

취미/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
0 Comments

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
0 Comments

취미/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
0 Comments

3rd-generation Antihistamine

항히스타민제만큼 구하기 쉬우면서 부작용을 신경써야하는 약은 없을 것이다. 비염이나 알레르기 증상을 완화하려고 먹었다가 쏟아지는 졸음을 겪거나 나른해진 경험은 누구나 한번쯤 해봤을 것 같다. 아스피린의 최대의 부작용인 속쓰림을 개선해서 다양한 진통제가 나왔듯이 항히스타민제도 '세대'라는 말이 붙을 만큼 다양한 약들이 나오고 있다. 그렇게까지 알레르기 반응이 심하게 나와 본적이 없고, 가능하면 알러젠을 차단하거나 보호장구를 사용해서 대처를 하기에 항히스타민제에 관심이 없었으나 우연한 사건으로 관련 정보를 찾아보게 되었다.

 

나는 몸 상태에 따라 적절한 약을 먹을 수 있도록 단일제제의 약을 구비해두는 것을 좋아하는데, 3세대 항히스타민제 중 일반의약품으로 분류되어 판매가 되는 약은 펙소페나딘염산염인 '알레그라'가 거의 유일했다. 일부 커뮤니티에서는 카피약도 나와있다고 하고 실제 한미약품에서 펙소나딘정으로 제네릭 약품이 나와있기는 하다만 구하기 쉽지 않아 보였다.

 

왜 120mg만 일반일까? 약학계도 상품의 유통구조와 제약회사의 이익관계, 안정성 등이 복잡하게 엮긴 것 같다.

 

이전에 우루사를 구입하려고 했는데 200mg는 전문, 100mg는 일반 이라는 설명을 듣고 의야해 했는데 알레그라는 더욱 웃겼다. 30mg과 180mg는 전문, 120mg은 일반이라고 한다. 병원을 방문할 시간이 없었기에 일단 근처 약국 6개를 돌며 120mg 알레그라를 사기 위해 돌아다녔는데 전부 전문의약품 형태만 있다며 구입을 하지 못했다.

 

비염에 고통받는 사람들이 많은지 관련 커뮤니티에서도 약을 구하기 힘들다는 반응을 털어놓았는데, 한독약품에 문의를 한 결과 120mg은 일반의약품이 맞지만 판매형태가 조제용이라 처방을 받고 사야한다는 답변을 받았다. 조제용 포장을 소분해서 판매하는 행위는 불법이라는 점(처방 제외)은 아는데 조제용 포장을 그대로 파는 것도 불법인지는 모르겠다. 몇몇 사람들이 120mg 일반의약품을 30정이 든 조제용 포장으로 샀다는 글을 올렸는데 조제용 포장으로 판매하는지 여부는 약사 재량인가보다. 아니면 얼렁뚱땅 판매를 하셨거나.

 

한독약품 홈페이지에 관련 문의글은 많았으나 전부 비밀글로 올라와 있었는데 본인처럼 약을 구하시는 분들이 헛걸음하지 않도록 아래 답변 내용을 적어둔다.

 

한독 의약품은 (주)쥴릭 도매상을 통해 전국 유통되고 있으므로
쥴릭으로(전화: 080-2006-080) 연락하시어 거주지역에서 구입 가능한 약국을 문의해 주시기 바랍니다.

참고로, 현재 일반의약품으로 분류되는 알레그라정120mg은 처방조제용 포장(30정,100정)으로만
유통중인 관계로 일반 판매가 어려운 상황입니다.
번거로우시겠지만, 가까운 병원을 통해 처방 후 조제 받으시길 안내 드립니다.

22년 01월 10일 기준 답변

 

 

 

 

 

[1] Olasińska-Wiśniewska, Anna & Olasiński, Jerzy & Md, Phd. (2014). Cardiovascular safety of antihistamines. Postepy Dermatologii I Alergologii. 31. 182. 10.5114/pdia.2014.43191. 

Posted by Knowblesse
0 Comments

Mind Storage/Short Thoughts | 2021. 12. 12. 15:22 | /38

비로소 바닥이 보일 때야 관리 계획을 마련하게 된다.

 

지난 생각도 그렇고 오늘 생각도 시간 관리에 대한 이야기이다.

 

시간 관리와 관련된 가장 잘 알려진 방법 중 하나로 스티븐 코비의 시간관리 매트릭스를 꼽을 수 있을 것이다. 모든 일들을 중요함과 긴급함이라는 두 축을 가진 평면에 늘어놓고 급박하고 중요한 일, 급하지 않지만 중요한일, 급박하지만 중요하지 않은일, 그리고 급박하지도 중요하지도 않은 일 순으로 처리하라는 이야기이다. 고등학생 때인가 아버지의 권유로 프랭클린 플래너를 쓰면서 이 매트릭스를 사용해본 적이 있었는데 지금와서 봐도 전형적인 그것이다.

 

경영학의 Bullshit.

 

애시당초 중요하지 않은 일은 하지 않으면 된다. 해야할 일이었다면 중요한 일이었겠지. 그리고 급박함과 중요함은 양의 상관관계가 매우 커서 급박한데 중요하지 않은 일은 없다. 스티븐 코비의 매트릭스를 보아도 '급박하지만 중요한 일'로 SNS 메시지 따위를 예로 들고 있다. 이런 것은 안하면 되는 것이다. 또한 일의 중요함은 그렇게 쉽고 빠르게 평가되지 않는 것 같다. 아이디어 회의는 중요도가 떨어질 수 있겠지만 이 회의에서 미래 프로젝트 방향에 중요한 영향을 끼치는 아이디어가 나올 수도 있는 일이고, 무언가를 결정하는 회의는 내가 없어도 옳은 방향으로 결정되어 잘 돌아갈 수도 있다.

 

'공부법' 키워드로 검색을 하면 수 십만건의 책과 글들이 쏟아져 나오지만 정작 공부를 오래 해본 사람은 자기에게 딱 맞는 방법을 이미 형성시킨다고 믿는다. 시간 관리 또한 시행착오를 통해 내게 맞는 방법을 찾을 수 있으리라 생각한다. 하나의 시행착오 중 하나로 아래의 분류법을 만들어 보았다.

 

P0 : 지금 당장 착수해야하는 일 || 안했을 시 이를 되돌리기 위해 두 배 이상의 자원을 투자해야하는 일

P1 : 3일 이내에 해결해야하는 일 || 언젠가는 해야만 하는 일

P2 : 일주일 이내에 해결해야하는 일

P3 : 한달 이내에 해결해야하는 일

PX : 안해도 상관 없는 일

 

 

'Mind Storage > Short Thoughts' 카테고리의 다른 글

[키워드 에세이] 즐거움  (0) 2021.11.25
일요일을 혼자 보내는 방법.  (0) 2021.10.10
자취방 생필품 리스트  (3) 2019.03.01
Posted by Knowblesse
0 Comments

  가깝게 지내는 작가 선생님께서 매일 하나의 키워드를 받아 짧은 에세이를 쓰는 작업을 하시고 있다는 이야기를 듣고 뱁새가 황새 따라가듯 같이 참여해보기로 하였다. 1년동안 쓴 글보다 쓴 코드가 더 긴 과학하는 사람에게 과연 얼마만큼의 글재주가 있겠냐 싶겠지만 자꾸 황새를 따라다녀야 몸은 뱁새더라도 정신만큼은 황새가 되지 않을까. 그리고 솔직히 뱁새가 외관은 더 귀엽다.

  삶에 영향력을 주고 있다고 생각하는 말과 실제로 영향력을 끼친 말 사이에는 큰 차이가 있을 것 같지만 확실히 이 둘 모두에 해당된다고 생각하는 문구가 있다. "아름다운 것을 봐야 아름다운 일을 해내고, 위대한 것을 느껴야 위대한 일을 해낸다." 때로는 분수에 맞지 않은 와인을 사거나, 과한 가격의 취미생활을 정당화 하는 변명으로 오용하지만 아름답다고 느끼는 것들의 범주가 넓고 다양해지는 것을 체감할 때면 이론(論)은 생각나지 않는다.

 

  즐거움은 내 삶의 가장 중심이 되는 키워드이다. 때문에 오랫동안 나에게 있어서 즐거움의 의미를 생각해왔었다. 마약이라는 아주 간단하고 확실한 즐거움이 있음에도 시작하지 않는 이유가 과연 두려움 때문인지, 위대함을 느끼기 위해 소비하는 것과 즐거움이 어떻게 연결되는지, 무언가를 만드는 일들이 내게 큰 즐거움을 주는 이유가 무엇인지 등 다양한 주제로 생각을 해서 내린 결론은 결국 확장성이었다.

 

  사람 수 만큼 다양하게 즐거움을 느끼는 방법들이 있으나, 일부는 일회성의 즐거움으로 끝이나고, 일부는 반드시 즐겁지 않음이 뒤따라오며, 거의 대부분의 경우는 반복할 경우 그 즐거움이 사라진다. Reward expectation과 Dopamine과의 상관관계를 보여준 Schultz의 연구를 보면(Schultz, 1997) 처음에는 과일 주스에 반응하던 원숭이의 VTA 뉴런이 과일 주스가 곧 나옴을 알려주는 소리에만 반응하기 시작하는 것을 볼 수 있다. 물론 VTA 뉴런과 즐거움이 완벽히 대응되지는 않겠지만, 이전에 좋아했던 일들에 대한 선호가 사라지는 만큼 그 즐거움과 연결된 다른 일들로 즐거움이 확장되지 않을까? 어쩌면 과일 주스만 좋아하던 원숭이가 소리에 대한 선호를 확립하고 나서부터는 '좋은' 소리와 '나쁜' 소리에 대한 뚜렷한 취향이 발현될지도 모르는 일이다. 나도 이처럼 즐거움이 또 다른 즐거움을 불러일으킬 때 비로소 진정한 즐거움을 느낀다고 생각한다.

 

  다소 대하기 어렵더라도 독특한 경험을 주는 이상한 사람을 만나는 것을 좋아하는 이유도, 홍차를 마시면서 다양한 맛과 향의 세계로 여행을 하는 이유도 결국 지금의 즐거움이 또 다른 새로운 즐거움으로 이어질 것이라는 확장성에 대한 기대 때문인것 같다. 더 자극적인 즐거움, 더 컬러풀한 즐거움에 대한 욕망은 항상 느끼고 있으나 이후에 다른 즐거움을 가져다 줄 것이라는 기대가 없으면 시도를 망설이게 된다. 이렇게 글을 쓰기 시작한 것도 당장은 강렬한 즐거움을 가져다 주지 않지만 글을 쓰면서 이후에 발견하지 못한 또 다른 즐거움을 주지 않을까 하는 기대 때문이지 않을까?

'Mind Storage > Short Thoughts' 카테고리의 다른 글

21DEC12  (0) 2021.12.12
일요일을 혼자 보내는 방법.  (0) 2021.10.10
자취방 생필품 리스트  (3) 2019.03.01
Posted by Knowblesse
0 Comments