[컴] 언제 마이크로서비스를 사용하는 것이 맞는가

microservices / 전환 / 모노리식 / 언제 분리 / 왜 사용 /

언제 마이크로서비스를 사용하는 것이 맞는가

우리는 처음에 구조를 잡을 때 고민을 많이 한다. 특히나 확장성에 대한 고민들을 한다. 그런데 어디까지 확장을 고민해야 하는가. 이 물음에 대해 어느정도 정리를 해줄만한 글들에 대한 링크다.

  • Modules, monoliths, and microservices · Tailscale, 2021-02-23 이야기는 길지만, 결론은 가장 마지막 문단인듯 하다. 계속 쉬운길을 유지하다가 어려운길을 해야만 하는 경우가 오면 그것을 해라.
  • Keep the monolith, but split the workloads | incident.io
    • 한 코드에서 workload 를 나눠서 옵션으로 해당역할을 해서 띄울 수 있게 하고, 
    • db처럼, 모두가 사용하는 것은 각 application 마다 pool size 에 제한을 둘 수 있게 했다.
    • 대부분의 경우 '가드레일'을 추가하거나 코드에 '제한을 구축'하여 마이크로서비스의 장점을 모방하는 동시에 단일 코드베이스를 유지하고 RPC 복잡성을 피할 수 있다.

이전 github CTO였던, Jason Warner의 트위터 글, 2022-11-15

이전 github CTO였던, Jason Warner의 트위터 글, 트위터 글이 읽기 불편해서 퍼왔다.

I’m convinced that one of the biggest architectural mistakes of the past decade was going full microservice

On a spectrum of monolith to microservices, I suggest the following:

Monolith > apps > services > microservices

So, some thoughts

First, these are thoughts, not rules. Anyone that has built a large distributed system knows they don’t really work that way and have to adapt with it

Second, stage will be important. If you are reading this at a 5-50 person company…just stick with a monolith. Trust me

If you are reading this at a 10k person company, likely have all of these to some degree but here is where my quick thoughts might differ from what has been done in the past

Now, diversion. Let’s talk definitions. There exist no exact definitions for these all

I think a challenge we dist systems engineers have is we really like to not have duplication so we see something being done in a few places and think “let’s just pull this out and make a microservice out of it”.

In theory this is fine. And if done for a few tens of instances, it is fine. When it goes to several dozen microservices or…way worse…across massive company boundaries (think one color service for all of Microsoft/Google/Apple) it becomes less technical and more org challenge

And I know what I’m presenting so many feels like some false dichotomies but in practice I find there are definite tech challenges with microservices, but there are even more org challenges with them

And of all the things I worry about it’s this

First, infra (unless company is led by unusually with-it CEO) almost always gets short end of priority stick

Second, too many services typically leads to a lack of ownership problem and boundary issues

Third, you introduce even more tooling to deal with too many microservices

And most importantly, each microservice that could/should have been a library or sdk or something introduces production risk

more code is indeed overhead, more services is customer facing prod/experience risk. Both approaches have overhead/risk but the % distribution is diff

So this is typically what I recommend

  1. Be a monolith as long as possible
  2. Services start in infra for infra reasons, not app eng typically
  3. If breaking out mono, break to large apps, not small services
  4. Think that each new app is a virtual wall in your company
  5. Prefer libraries to microservices where possible

The classic “we introduced a color service” is my favorite extreme example of where I would choose a library over a service. Yes extreme example but hey, it gets very talked about as quintessential example

“But Jason, what about Amazon and Uber and ..?”

  1. Hey, you do you. I’m just saying what I’ve gone through in experience
  2. If you have the success of Amazon when that mandate came down for services, go nuts
  3. These are more guidelines than rules

90% of all companies in the world could probably just be a monolith running against a primary db cluster with db backups, some caches and proxies and be done with it

For the 10% of companies that hit planet scale (no pun intended here Sam) it’s gonna be art figuring this out

Distributed systems combined with scaling companies is so complex and so few people have done it that it’s hard to draw specific lessons from those companies. Each context and instance is different. What I’m talking about here is more thoughts on how to approach the problems

And going back to this

Monolith > apps > services > microservices

It’s basically an approach to scale: be one big thing for as long as possible. Never overcorrect to too small of things, go through it as you grow (even hyper growth). This is for org and tech

Again, it’s art


I was trying to get that with this: Monolith > apps > services > microservices

But I realize now that the ‘>’ means “over” and not “prefer before going to”. monolith with several apps around it & 10-12 services over dozens of small services is great

Should draw a pic probably

[컴][머신러닝] ChatGPT 의 동작에 대한 글, 번역

머신러닝/ ai / machine learning / openai

ChatGPT 의 동작에 대한 글, 번역

아래내용은 다음 링크의 글에 대한 번역과, 읽고 정리한 내용이 섞여있다. 개인적인 이해를 바탕으로 적어놓은 글이기에 틀린부분이 많이 있을 수 있다. 정확한 내용은 원문을 참고하자.

chatGPT 가 항상 본질적으로 하는 작업은 지금까지 만들어진 text의 ‘합리적인 이어짐’(resonable continuation)을 생성하는 것이다. 여기서 ’합리적인’이라는 것은 “수십억개의 웹페이지등에 작성한 것들을 본 이후 누군가가 쓸(write) 법한 것”이란 의미라고 한다.

me: 결론부분에도 나오지만 뭔가 그럴싸한 단어들을 계속해서 이어가는 것이 chatGPT 가 하는 일이라는 이야기로 해석해도 되지 않을까 싶다.

The best thing about AI is its ability to ?

라는 문장이 있을 때 ? 에 어떤 단어가 오면 좋을지에 대해 분석을 한다면, 인터넷에서 저 글이 들어간 모든 문장을 찾고, 그 다음에 어떤 단어가 왔는지 목록을 만드는 것이다. 그리고 얼마나 자주 단어가 나왔는지 빈도를 가지고 확률을 만들어낼 수 있다.

이것을 ChatGPT 는 매순간 한다. 즉, 단어(token 이 더 정확한 표현)가 추가될 때마다 이런 작업을 한다. 예를 들어 위의 예제에서 다음 단어가 ‘learn’ 으로 추가되면, 이젠 learn 다음에 어떤 단어가 나오면 좋을지를 알기위해서 ’The best thing about AI is its ability to learn’가 나온 모든 페이지들을 분석하는 작업을 한다는 것이다.

The best thing about AI is its ability to learn ?

이때 가장 높은 확률의 단어만 택하면, 그것은 항상 같은 문장이 되어 버린다. 그래서 여기에 어느정도 random 으로 단어를 선택하게 된다. 그래서 항상 다른 결과를 만들어내게 된다.

낮은 순위의 단어가 얼마나 자주 사용될 것인지를 결정하는 ‘온도’(temperature) parameter 가 있다. 에세이 생성은 0.8의 온도가 가장 좋은 것으로 나타났다. 왜 0.8이 좋은지에 대한 이론은 없다. 대체로 0.8을 사용할 때 가장 좋은 결과가 나왔다는 정도이다. 0 은 항상 가장 높은 확률의 단어를 택하는 것이다. 0.8 의 온도를 택하면, 선택지가 너무 많은 것은 아닐까 걱정되지만, 이것은 점점 단어(token) 이 쌓이면서, 그 다음에 나올 단어의 선택지의 폭이 대폭 줄어든다.(power-low decay)

아래 GPT2 Transformer 링크에서 직접 테스트 해 볼 수 있다. wolframcloud.com 에서 계정을 만들어서 사용해 보면 된다.

ChatGPT 는 확률에 따라 다음 단어를 선택하게 되어 있는데, 그러면 이 확률은 어떻게 구하는가? 예를 문자하나, 즉 a, b, c, … 등이 문장에서 얼마나 많이 나오는가를 구해 볼 수 있다. 표본이 커질수록 각 문자하나(character) 가 나오는 확률은 특정값에 가까워질 것이다. 그래서 나온 확률이 만약 다음과 같다고 해보자.(ref. 1 에서 )

  • e가 나올 확률: 12.7%
  • i가 나올 확률: 6.97%

그런데 이 개별 character 의 확률을 가지고는 단어가 만들어질 수 없다. 그래서 현재문자(character) 다음에 올 문자의 확률을 구하는 작업을 한다.

즉 모든 word 들을 조사해서 a 다음에 a 가 나올 확률, b 가 나올확률, … 등을 모든 2-grams(2개의 연속되는 것들이 모여있는 것) 의 확률을 구하는 것이다.

그러면 좀 더 단어(word) 에 가까워진다. 즉, 좀 더 긴 n-gram 에 대한 확률을 구해놓으면, 더 나은 모양의 단어(word) 를 만들 수 있다. 즉 컴퓨터가 다음에 뭐가 나와야 word 가 되는지를 알 수 있게 되는 것이다.

하지만 이것만 가지고는 문장을 만들기가 어렵다. 그래서 word 에 대한 n-gram 에 대한 확률을 구해야 한다. 즉, 어떤 단어뒤에 어떤 단어가 올 때 문장이 되는가를 컴퓨터가 알 수 있도록, 모든 text 들을 뒤져서 특정단어뒤에 어떤 단어들이 나오고, 그 단어가 얼마나 자주 나오는지를 구해놓는 것이다. (n-gram of words 의 확률을 구하는 것이다.)

영어는 대략 40,000개의 단어가 주로 쓰인다고 한다. 그런데 이 단어의 2-gram 만 되어도 이미 16억개(4만x4만) 이고, 3-gram 의 수는 60조개이다. 결국 문장을 만들기 위해 n-gram 의 확률을 구하는 것은 거의 불가능하다.

그래서 방법을 달리했다. 즉 모든 단어에 대해 앞으로 나올 확률을 계산하는 것이 아니라, 단어의 순서들(sequences)이 어떤 식으로 발생해야만 하는지에 대한 확률을 추정할 수 있는 model 을 만든 것이다.

me: 이것은 ’알파고’를 생각해보면 이해할 수 있다. 바둑도 그 바둑돌을 놓는 방법이 너무 많아서 계산을 해볼 수 없었다. 그래서 체스와 달리 컴퓨터가 인간을 이기기 쉽지 알았다. 하지만 ’알파고’는 방법을 달리했다. 현재 나와있는 ’기보’들을 공부하게 했다. 그래서 그 기보를 바탕으로 어떤 식으로 바둑돌을 놓는 것이 좋은지를 추정할 수 있는 식(model)을 만들것이다. 이 LLM(large language model) 도 비슷한 idea 를 적용했다고 보면 될 듯 하다.

모델(model)없는 모델은 없다는 것을 이해해야 한다.(me: 모든 모델은 특정 모델을 기본으로 잡고 시작한다는 뜻인듯) 모든 모델은 특정한 기본 구조가 있다. 그리고 여기에 데이터에 맞게 ‘돌릴 수 있는 손잡이(knob)’(즉, 설정할 수 있는 매개변수)가 있다. ChatGPT의 경우, 많은’knob’가 있고, 1,750억 개에 달한다.

그런데, 놀라운 점은 단순히 많은 parameter들만 가지고 있는 ChatGPT 의 기본 구조만으로도, ’다음 단어의 확률을 충분히 만족스럽게 계산할 수 있는 model’을 만들 수 있고, 그것으로 에세이 길이의 합리적인 text 를 제공할 수 있다는 점이다.

수학적으로, 논리적으로 사람이 이런 식으로 인식한다. 그것은 이런 수학공식을 사용해서 설명이 되고, 그런 이유로 이 model 이 동작하는 것이다. 라는 식으로 이 모델은 만들어지지 않는다. 그 이유는 사람이 어떤 식으로 인식하는지에 대한 수학적 모델이 없기 때문이다. 사람의 인식은 어느정도 주관적인 부분도 있다. 2라는 그림에서 몇개의 픽셀을 이상한 위치에 배치한다고 해도 사람은 대체로 2로 인식할 것이다. 하지만, 그것은 사람마다 다를 수 있고, 사람이 아닌 다른 동물이라면 다르게 해석할 수 있다. 그렇기에 이것을 수학적으로 증명하는 것은 쉽지 않다.

그래서, 단순히 어떤 수식(model) 의 결과가 사람이 판단하는 것 또는 말하는 것과 일치한다면, ’좋은 모델’을 가지고 있다고 판단하는 것이다. 좀 과장해서 이야기하면, 어떤 그럴싸한 로직이 있는 coding 을 하는 것이 아니라, 그저 모든 현상에 대한 if 문을 적용한 프로그램이 있다고 볼 수 있다.

신경망

신경망(neural net) 이라 불리는 것은 4개의 core layer들을 여러번 사용해서 11개 layer를 거친다. 이 신경망이 ‘사람이 판단하는 것같은, 사람이 말하는 것과 같은 model’ 을 수학적으로 구현해 준다. 이것이 이론적으로 도출된 것은 없으며, 1998년 공학적으로 작동하는 것으로 밝혀졌을 뿐이다.

그럼 신경망은 어떻게 사물을 인식할까? notion of attractors이 신경망의 핵심이다.

인식(recognition)이라는 것은 결국 구분이다. 하나의 사각형을 반으로 나누고, 1이 들어오면 왼쪽에, 2가 들어오면 오른쪽에 놓는다고 해보자. 1이라는 써여있는 희미한 글자가 들어올때, 우리는 그 글자가 1이 있는 왼쪽에 들어가게 하고, 2라는 희미한 글자가 있을 때 그것이 오른쪽 영역에 들어가게 한다. 그러면, 우리는 비슷한 모양들이 들어올때 1과 2를 구분지을 수 있게 된다. 즉, 왼쪽에 있는 것들은 1로 인식하게 되고, 오른쪽에 있는 것들은 2로 인식할 수 있게 된다. 즉, 우리는 어떤 사물을 한 영역으로 몰아서 넣을 수 있다면, 우리는 그것을 구분한다고 볼 수 있다.

하나의 다른 예를 가지고 이야기해보자. 사각형을 임으로 나누고, (x, y) 라는 값이 들어올때 이 값이 어느 부분에 속하는지를 파악한다고 해보자.

신경망은 여러개의 node 로 구성됐다. 그 node들이 한방향으로 흘러간다. 하나의 node 의 output 은 다른 node의 input 으로 들어간다. 그리고 다른 node 의 output 을 input 으로 받을 때는 각 node마다 다른 가중치를 준다. 이런식으로 여러개의 layer 를 거치게 된다.

node 에서 input x 를 받을 때 하는 일을 수식으로 나타내면, 아래처럼 x라는 input 이 오면, 거기에 가중치(w) 를 주고, 상수 b 를 더한다. 이 값에 thresholding function (또는 activiation function) 을 대입하게 된다.

 f[w . x + b],

w . x + b을 계산하는 것은 단순히 행렬에 대한 곱하기, 더하기 이다. ’activation function’은 비선형성을 가져온다. 그래서 궁극적으로 이것이 nontrivial 행동을 만들어내게 된다. 다양한 activation function들이 일반적으로 사용된다.

우리가 신경망이 수행하길 원하는 각 task 에 대해서 우리는 여러 가중치들(weights)을 갖게 된다. 이러한 가중치들은 일반적으로 신경망을 ’훈련’함으로써 결정된다. 이 신경망의 훈련은 우리가 원하는 출력들을 이용한 머신러닝을 통해서 이뤄진다.

우리가 알 수 있는건 각 신경망의 layer 마다 어떤 결과를 보여준다를 알 수 있다. 즉, ‘고양이’ 이미지를 찾는 중간중간의 결과물은 확인할 수 있지만, 이것이 왜 이런 과정을 거치면, 고양이를 찾을 수 있는지는 모른다. 그냥 그것이 잘 동작하기에 사용하는 수준이다.

이것은 ChatGPT 도 마찬가지다. 다만 ChatGPT 는 그것이 보여주는 중간단계가 ’언어’와 관련돼 있어서, 우리들이 그 중간 중간의 layer 의 결과를 통해 더 많은 insight 를 얻을 수 있을 수 있다.

신경망(neural net)들이 유용한 이유는 모든 종류의 일을 할 수 있다는 것만이 아니라, 그들이 ’예시’들에 의해 훈련되어서 그런 task들을 할 수 있게 되는 것이다.

그럼 neural net training 은 실제로 어떻게 동작할까?

우리는 항상 가중치들(weights)를 찾기위해 노력하는 것이다. 이 가중치들은 neural net 이 우리가 준 예시들을 성공적으로 재현하도록 만들어준다. 그러고 난후, 합리적인 방법으로 이 예시들 사이에서 interpolate (또는 generalize, 일반화) 하기 위해 신경망에 의존한다.

간단한 함수를 learn 하는 neural net 을 만든다고 해보자.

이 함수 모양과 비슷한 것을 얻기 위한 neural net 이 있는데, 이것의 가중치를 random 으로 할당해서 결과를 뽑아보자. 우리가 원하는 모양의 함수모양을 얻을 수 없다.

많은 “input –> output” 예시들을 제공해서 그것으로부터 배우라고 하고 싶다. 그러러면, 이 많은 예시들을 통해서 가중치를 조정해 나갈 수 있어야 한다.

이 훈련의 각 단계(stage) 에서 network 안의 가중치(weights)는 점진적으로 조정되며, 결국 우리가 원하는 기능을 성공적으로 재현할 수 있는 network 를 얻게 된다.

가중치 조정은 어떻게 할까? 기본적인 idea 는 각 stage 마다 우리가 원하는 기능으로 부터 “얼마나 멀리 떨어져 있는지”를 확인하고, 더 가까워질 수 있도록 weight들을 업데이트하는 것이다.

“얼마나 멀리 떨어져 있는지”를 알아내기 위해 “loss function”(또는 cost function) 이라는 것을 계산한다. 간단한 loss function 의 예를 들면, 우리가 원하는 함수 그래프의 위치에서 현재 그래프의 위치까지의 거리를 제곱, 즉 실제로 얻은값과 우리가 계산해서 얻은 값과의 차이의 제곱의 합을 이용할 수 있다. 이 손실함수 값이 학습이 진행돼서 가중치가 수정될 수록 줄어드는 것을 볼 수 있다.(ref. 1 의 그림 참고)

신경망들을 이용하면, 복잡한 문제들을 푸는것이 간단한 문제를 푸는 것보다 더 간단하다. 가중치가 여러개가 있어야 ‘최소치’(minimum) 로 이끄는 많은 다른 방향이 존재하기 때문이다. 가중치가 적으면 다른 곳으로 갈 수 없는 local minimum 에 갇히게 된다.

함수에 영향을 주는 요소를 많이 파악할 수록, 즉 이 함수에 적용되는 많은 변수를 알 수록 더 정확한 함수를 얻을 수 있다고 이야기하는 것 같다. 우리가 날씨를 예측할 때도, 날씨에 영향을 주는 많은 요소를 동시에 고려할 수 있어야 더 정확한 날씨를 예측할 수 있는것과 같다.

비슷한 성능을 보여주는 다양한 가중치 모음들(collections of weights) 이 있다. 실질적인 neural net 훈련에서는, 다르지만 비슷한 해결책들로 인도하는 많은 random 한 선택들이 있다. (그림 참고)

그림에서 보듯이 비슷하지만, 조금씩 다르다. 이 그래프들의 양끝단을 확장해서 볼때, 그래프가 완전히 달라 보일 수도 있다. 하지만 좁은 범위에서 저 그래프들은 다 같은 답을 가져다 준다. 즉, 관찰된 데이터와 일치(‘consistent with the observed data’) 한다.

신경망 학습의 핵심은 주어진 훈련 예시들을 가장 잘 포착할 수 있는 가중치(weights)들을 결정하는 것이다.

미래에 neural net들을 훈련하는 더 나은 방법이 나올 것이라 본다. 신경망들(neural nets)의 기본 아이디어는 구분되는 큰 수의 간단한 구성요소들에서 유연한 ‘computing fabric’ 을 만드는 것이다. 그리고 예시들로 부터 점차적으로 수정되어질 수 있는 fabric 을 만드는 것이다. 현재의 neural net들에서는 점진적 수정(incremental modification) 을 위해서, 필수적으로, 실수들이 적용된 미적분학의 개념들을 사용한다.

그런데 점차 높은 정확도의 숫자들은 문제가 되지 않는 것이 명확해 지고 있다. 현재 방법들에서는 8 비트 또는 더 낮은 값으로도 충분할 수 있다.

기본적으로 현재의 신경망들은 치명적인 한계가 있다. 각 예시 batch들의 효과들이 다시 weight들을 update 하는 곳으로 보내져서 처리된다. 그렇기에 신경망 훈련은 기본적으로 순차적(sequential) 이다. 실제로, 현재 컴퓨터 하드웨어는 신경망 훈련중 대부분의 시간동안 idle 상태에 있고, 한번에 한부분만 업데이트 된다. 이것은 현재 컴퓨터의 메모리가 CPU(또는 GPU) 와 분리돼 있기 때문이다. 이부분에 대한 개선의 여지도 있다.

인간의 것을 할 수 있게 됐지만, 이것이 모든 계산적인 한계를 넘었다는 것은 아니다. 많은 계산을 해야만 하는 것은 정복하지 못했다. 현재 인간이 할 수 있는 것들을 하게 된 것은 그것이 생각보다 계산을 적게하는 것이었다는 것을 발견했기 때문이다.

embedding 은 높은 차원의 input (high-dimentsional input)을 좀 더 낮은 차원의 vector로 변경하는 것을 이야기한다.(참고) 이것이 ChatGPT 에서는 ‘단어’(words)를 neural-net 에 친숙한 ‘숫자들의 모음’(collections of numbers)들로 방법을 바꾸는 방법을 이야기 한다고 볼 수 있다. 이것은 ’단어’에만 해당하지 않는다. sequence of words 를 collections of numbers 로 변경할 수도 있고, text 의 전체 block 을 collection of numbers 로 변경할 수도 있다. 이것이 ChatGPT 내부에서 이것들을 다루는 방식이다.

ChatGPT 는 text 를 가지고 와서, 그것을 표현할 수 있는 embedding vector를 만든다. 그리고 나서 그것은 목표는 다음에 나올 것 같은 다른 token들의 확률들을 찾는 것이다. 그리고 그것은 그것의 대답을 숫자들의 list 로 표현한다.

ChatGPT 내부

Transformer 는 글 한꼭지를 구성하는 token sequence 에 대해 어느정도 유사한 작업을 한다.그런데 여기에 attention 이라는 개념을 도입해서, sequence 의 일부에 다른 부분보다 더 많은 attention 을 기울이는 개념을 도입했다.

ChatGPT 가 실제로 하는 일은 현재 구성된 글을 합리적인 방법으로 이어가는 것이다.

3가지 기본 단계를 수행한다. 1. 지금까지의 글에 해당하는 token sequence를 가져오고, 이에 해당하는 embedding(즉, 숫자배열)을 찾는다. 2. 새로운 embedding(즉, 새로운 숫자 배열)을 생산하기 위해 이 embedding 에서 작업한다. - 이 작업은 표준 신경망 을 사용하고. - 네트워크에 있는 연속된 레이어들로 퍼져나가는 값들을 이용한다. 3. 그런 다음 이 배열의 마지막 부분을 가져와서 약 5만개 값들의 array 을 생성한다. 그리고 이 생성한 array 가 ’다른 가능한 다음 token들’에 대한 확률들로 변환한다.

중요한 점은 이 pipeline 의 모든 부분이 신경망(neural network)에 의해 구현되며, 이 신경망의 가중치(weights) 들은 네트워크의 end-to-end training 에 의해 결정된다는 점이다. 즉, 전체 아키텍쳐를 제외하고는 명시적으로 설계된 것이 없으며(explicitly engineered), 모든 것이 그냥 학습된다.

(me: 그냥 이렇게 저렇게 해보니 되는것이지, 논리적으로 이것을 짜서 만드는 개념이 아니다.)

하지만 아키텍처가 set up 되는 방식에는 모든 종류의 경험과 신경망 지식(lore)을 필요로 하는 세부사항(details)들이 있다.

그래서 이 details 가 뭔지를 알아보자.

  1. embedding module

신경망은 여러개의 layer 로 구성되어 있고, 이 layer 안에는 neuron 이 있다. 이 neuron 이 computational element 이다.

GPT-2 에 대한 Wolfram Language 표현의 도식을 보면,

<도식> : https://content.wolfram.com/uploads/sites/43/2023/02/sw021423img86.png

input 으로 n개의 token 으로 된 vector 1개가 들어오면, 이것이 한 신경망을 거쳐서 embedding vector 로 변환되고, 다른 신경망으로 또 보내져서 ’위치들의 sequence’를 가지고, 그것으로 부터 다시 embedding vector 를 뽑아낸다. 그리고 이 2개의 embedding vector 를 합치는 작업을 한다.

왜 이런 작업들을 하는지에 대한 과학적 이유는 없다. 그저 다양한 시도를 해봤고, 이것이 잘 작동하는 것이라서 이것을 사용하는 것이다. 설정한 값이 대략적으로 맞다면, 계속 훈련(training)해서 값을 좀 더 정교하게 맞춰갈 수 있다. 이 때 굳이 신경망이 어떻게 그리고 왜 이렇게 구성되었는지 이해할 필요가 없다. 이것이 신경망의 비법(lore)이다.

Embedding ?
embedding 은 수학에서 한 위상공간에서 다른 위상공간으로 ’동상사상’하는 것을 이야기한다고 한다. 이것은 말이 어려운데, 쉽게 예를 든다면, 지도에 있는 Stereographic projection 방법이 있다. 이것은 3차원의 ’지구’를 2차원으로 표현한 방법이다. 이런것이 embedding 의 한 예다. - Stereographic projection - the basics - Geological Digressions

embdding module 다음에, transformer 의 main event 인 ’attenion block들의 sequence’가 시작된다. 이 attention block 개수가 GPT-3 에서는 96개, GPT2 는 12개이다.

GPT2 의 attention block 한개를 표현한 도식이 아래이다.

<도식> : https://content.wolfram.com/uploads/sites/43/2023/02/sw021423img88.png

각 attention block 안에는 attention head들의 collection 이 있다. 이 attention head 가 GPT2 에서는 12개 GPT3 에는 96개가 있다. 각각은 embedding vector 안의 서로 다른 값들의 덩어리와 함께 독립적으로 동작한다. 우리는 왜 이 embedding vector 를 분리하는 것이 좋은 이유인지는 모른다. 그리고 그것의 각부분들이 의미하는 바를 알지 못한다. 이는 그저 ’동작하는 것으로 밝혀진’것 중 하나라서 쓰는 것이다.

그럼 attention head 가 하는 일은? 그것들은 token들의 sequence 에서 looking back 하는 방법이며, 다음 token 을 찾기 쉬운 모양으로 과거를 packing up 하는 방법이다. 위의 첫 번째 섹션에서는 2그램의 확률을 이용해 바로 앞의 단어를 기반으로 단어를 선택하는 방법이 있었다. transformer의 ‘attention’ 메커니즘은 훨씬 앞의 단어에도 ‘attention’(주의) 를 기울일 수 있도록 하는 것이다. 예를 들어 동사는 한문장 내에서 ’많은 단어들이 앞에 나오는 명사(noun)’들을 언급할 수 있게 된다.

me: 이것의 다른 예를 든다면, copilot 을 보자, 만약 내가 특정 site 에 request 를 하는 curl 이 필요하다고 하자. 그저 단순하게 앞의 글자에 따라서 뒷글자를 뽑아낸다면, 다음처럼 url 을 뽑아내는 순간에, 바로 뒤의 값만 보고는 어떤 url 을 제안해야 할 지 알 수 없다. 이 때 comment 를 포함한 전체 문장에 대해, 다음에 나오는 모든 token 을 확인하고 그 중 가장 높은 확률을 가져오는 것은 많은 연산을 필요로 한다. 그리고 앞에서 언급했지만, 그것이 좋은 결과일지는 알 수 없다. 대신에 attention 을 통해서 looking back 을 해서, 어느정도 합리적인 수준으로 다음 token 을 이어갈 수 있게 된다.

# request to the naver openapi
curl -X GET "https://openapi.naver.com/v1/papago/n2mt" \

좀 더 자세한 레벨에서 보면, attention head 는 ’서로 다른 token들과 관련된 embedding vector들’안있는 chucnk 들을 특정 weight 들을 이용해서 다시 묶는다.

attention head들에 의해 처리가 끝나면, ’re-weighted embedding vector’는 standard “fully connected” neural net layer 를 통과한 것이 된다. 이 layer가 무엇을 하는지는 알기 어렵다.

이 가중치 행렬(matrix of weights)를 보면, 어떤 구조가 보인다. 이 구조를 결정하는 것은 아마도 ‘인간언어’에 대한 ’neural net encoding’ 일 것이다. 하지만 현재는 그 특징이 알려져있지 않다. 즉, 우리는 신경망을 열어서 이 신경망이 복잡하구나를 알았지만, 이 신경망을 이해하지는 못하고 있다. 그것이 인간과 비슷한 언어를 생성하는구나 정도만 알고 있다.

하나의 attention block 을 지나간 이후에, 하나의 새로운 embedding vector 를 갖은 상태가 된다. 이 embedding vector 가 순차적으로 추가적인 attention block들을 지나가게 된다. GPT-2 에서는 attention block이 12개이다. 각각의 attention block 은 각자의 attetion pattern 이 있고, fully connected weights 가 있다.

도표를 보면, 가중치 행렬들(matrices of weights)은 매우 유사해 보이지만, 가중치 크기의 다소 다를 수 있다.

이 attention block 들을 전부 통과하고 난후 트랜스포머의 net effect 는 ‘token sequence 에 대한 ebeddings 의 original collection’ 을 최종 collection으로 변환하는 것이다. ChatGPT 가 동작하는 방식은 이 최종 collection 에서 last embedding 을 뽑고, 그것을 decode 한다. 이것을 decode하는 이유는 ‘다음에 올 token’ 에 대한 확률목록을 생성하기 위해서다.

이것이 ChatGPT 내부를 개략적으로 설명한 것이다. 실제로 관련된 궁극적인 요소는 간단하다. 우리가 다루고 있는 것은 인공 뉴런들로 구성된 신경망이다. 이 각각의 인공뉴런은 숫자 입력들의 collection 을 가지고, 그것을 특정 weight들과 결합하는 간단한 작업을 한다.

튜링머신을 보면, 동일한 computational element 가 하나있고, 모든 것이 이것들에 의해 반복적으로 처리된다. 하지만 이 신경망은 적어도 주어진 출력토큰을 생성할때 각 computational element(즉, 뉴론)은 한번만 사용된다. 하지만 여전히 outer loop 이 존재한다. ChatGPT가 새로운 token 을 생성할 때는 항상 이전의 전체 token sequence를 input 으로 사용 한다.(ChatGPT 가 작성한 것을 포함한) 우리는 그래서 이러한 setup 이 ChatGPT 가 feedback loop 을 한다라고 생각할 수 있다.

ChatGPT 가 새로운 token 한개를 만들때마다 이 모든 weight들을 포함한 계산을 해야만 한다는 것이다. 구현적으로 이런한 계산은 layer에 의해 높은 병렬 array operation 들로 조직화될수 있다.(organized) 이 병력 작업들은 GPU들에서 편리하게 수행될 수 있다. 그러나 생성되는 각 token 에 대해 여전히 1750억번의 계산들을 해야만 한다.(끝에는 좀 더 많다.) 그래서 ChatGPT 가 긴 글을 생성하는데 시간이 걸리는 것은 당연할 수 밖에 없다.

What Really Lets ChatGPT Work?

어떻게 ChatGPT 가 언어와 관련해서 이만큼 올 수 있었을까? 내 생각에 근본적인 답은 그것은 언어가 근본적인 수준에서 생각보다 단순하다는 것이다. 그리고 이것이 뜻하는 바는 ChatGPT 는 성공적으로 인간언어와 그리고 그 이면의 사고(thinking)에 대한 본질(essence)을 포착할 수 있다는 것이다. 심지어 그것은 근본적으로 복잡하지 않은(straightforward) 신경망 구조를 가지고 있지만 말이다. 그리고 추가로, 그것의 학습에서, ChatGPT 는 이것을 가능하게 하는 언어와 사고에 있는 규칙을(그것이 무엇이든지) 어떻게든 암묵적으로 발견한(‘implicitly discovered’) 상황이다.

ChatGPT의 성공은 과학의 근본적인 그리고 중요한 부분에 대한 증거를 우리에게 준다고 생각한다. 즉, 우리가 새로운 언어의 법칙, 실질적으로 ‘사고의 법칙’ 을 발견하는 것을 기대할 수 있음을 시사한다. 신경망처럼 구축된 ChatGPT 에서 이런 ’법칙’들은 기껏해야 암묵적으로 존재한다. 그러나 우리가 어떻게든 그 법칙들을 명시적으로(explicit) 만들수 있다면, ChatGPT가 하는 일들이 더 직접적이고, 효율적으로, 그리고 투명한 방법으로 수행할 수 있게되는 가능성을 갖게 될 것이다.

ChatGPT의 기본 개념은 어느 수준에서는 다소 간단하다. 웹, 책 등에서 사람이 만든 방대한 텍스트 샘플에서 시작합니다. 그런 다음 신경망을 훈련시켜 텍스트 샘플처럼 생긴 텍스트를 생성합니다. 특히 ‘prompt’에서 시작할 수 있고, ’학습된 것과 같은’ 텍스트를 계속 생성할 수 있도록 만들어야 한다.

지금까지 살펴본 바와 같이 ChatGPT의 실제 신경망은 매우 단순한 elements(요소들)로 구성되어 있다.(비록 그 수가 수십억개이지만.) 그리고 신경망의 기본 작동도 매우 단순하다. 근본적으로, 새로운 단어(또는 단어의 일부)가 생성될 때마다, ’지금까지 생성된 텍스트에서 끌어내진 입력(input)’을 그것의 elements로 한번씩 전달하는 것으로 구성된다.(loop 없이)

하지만 놀랍고 예상치 못한 점은 이 프로세스를 통해 웹이나 책 등에 있는 것과 성공적으로 ‘비슷한’ 텍스트를 생성할 수 있다는 것이다. 또한 일관된 인간 언어일 뿐만 아니라 ‘읽은’ 콘텐츠를 활용하여 ‘prompt에 따라’ ‘무엇인가를 말한다’. 그것은 항상 “전체적으로 말이 되는”(또는 올바른 계산에 해당하는) 말을 하는 것은 아니다.(또는 정확한 계산들에 적합한) 왜냐하면(예를 들어 Wolfram|Alpha의 “계산 능력”에 액세스하지 않고) 그것은 그냥 훈련 자료에 있는 내용을 기반으로(what things “sounded like” in its training material) “그럴싸하게 들리는”(sound right) 내용을 말하기 때문에 말하기 때문이다.

ChatGPT의 특정 엔지니어링은 chatgpt를 상당히 매력적으로 만들었다. 하지만 궁극적으로 (적어도 외부 도구를 사용할 수 있을 때까지는) ChatGPT는 축적된 “통념의 통계”에서 “일관된 텍스트의 실”을 “단지” 뽑아내는 것에 불과합니다. 하지만 그 결과가 얼마나 인간과 유사한지 놀랍다. 그리고 앞서 설명했듯이 이것은 적어도 과학적으로 매우 중요한 사실을 시사한다. 즉, 인간의 언어(와 그 이면에 있는 사고 패턴)는 우리가 생각했던 것보다 그 구조가 더 단순하고, “법칙과 같다”는 것입니다. ChatGPT는 이를 암묵적으로 발견했습니다. 하지만 우리는 앞으로 잠재적으로 이를 의미론적 문법, 계산 언어 등을 이용해서 명시적으로 드러낼 수 있다

ChatGPT가 텍스트를 생성할 때 수행하는 작업은 매우 인상적이며, 그 결과는 일반적으로 인간이 생성하는 것과 매우 유사하다. 그렇다면 ChatGPT가 뇌처럼 작동한다는 뜻일까? 기본 인공 신경망 구조는 궁극적으로 뇌를 이상적으로 모델링한 것이다. 그리고 인간이 언어를 생성할 때 일어나는 일의 많은 측면이 매우 유사할 가능성이 높다.

훈련(일명 학습)과 관련하여 뇌와 현재 컴퓨터의 서로 다른 “하드웨어”(그리고 아마도 아직 개발되지 않은 알고리즘 아이디어)로 인해 ChatGPT는 뇌와 다소 다른 (그리고 어떤 면에서는 훨씬 덜 효율적인) 전략을 사용하게 된다. 그리고 또 한 가지, 일반적인 알고리즘 계산과 달리 ChatGPT는 내부적으로 “루프”나 “데이터에 대한 재계산”을 하지 않는다. 이는 필연적으로 계산 능력을 제한할 수밖에 없는데, 이는 현재의 컴퓨터와 비교했을 때도 그렇지만 뇌와 비교했을 때도 마찬가지이다.

이 문제를 ’해결’하면서도 합리적인 효율로 시스템을 훈련할 수 있는 능력을 유지하는 방법은 명확하지 않다. 하지만 그렇게 함으로써 미래의 ChatGPT는 아마도 훨씬 더 많은 “뇌와 같은 일”을 할 수 있을 것이다. 물론 두뇌가 잘 하지 못하는 일들, 특히 환원 불가능한 계산과 관련된 일들이 많이 있다. 그리고 이러한 두뇌와 ChatGPT와 같은 것들은 Wolfram 언어와 같은 “외부 도구”를 찾아야 한다.

그러나 현재로서는 ChatGPT가 이미 무엇을 할 수 있는지 보는 것이 흥미롭다. 어떤 수준에서는 많은 수의 간단한 계산 요소가, 놀랍고 예상치 못한 일을 할 수 있다는 근본적인 과학적 사실을 보여주는 좋은 예이다. 그러나 그것은 또한 아마, 2천 년 동안 우리가 가지고 있던 자극중 가장 좋은 자극을 제공한다.

그것은 또한 2천 년 동안 우리가 가지고 있던 최고의 자극을 제공했을 것이다. 이 자극을 통해 우리는 ’인간 조건의 중심 특징인 인간의 언어’와 그 이면에 있는 사고 과정들의 ’근본적인 특성과 원리’가 무엇인지 더 잘 이해하고 싶어 하게될 것이다.

[컴] HikariCP의 maxLifeTime 과 MySQL의 wait_timeout

wait_timeout 확인법 / 설정 방법 / 히카리 / hikari cp / connection pool 과 연동 / 어떻게 연동

HikariCP의 maxLifeTime 과 MySQL의 wait_timeout

MySql 의 wait_timeout 과 interactive_timeout

  • https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_wait_timeout

thread 가 시작할때, session 의 wait_timeout 값은 global wait_timeout 값으로 초기화 된다. 또는 global interactive_timeout 값으로 초기화 된다. client 가 interactive client 이면, interactive_timeout 을 사용하고, 그렇지 않으면 wait_timeout 을 사용한다.

  • interactive_timeout : https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_interactive_timeout

서버가 interactive connection 에서 close 하지 않고 activity 를 기다리는 시간이다.(second 로 표현된다.) CLIENT_INTERACTIVE option 을 사용하는 client 가 interactive client 이다. (즉, mysql_real_connect() 를 사용해서 접속할때 CLIENT_INTERACTIVE 옵션을 사용하면 된다.)

  • wait_timeout : https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_wait_timeout

서버가 noninteractive connection 에서 close 하지 않고 activity 를 기다리는 시간이다.(second 로 표현된다, 기본값은 28800s 이다.)

다음 query 를 통해 확인할 수 있다.

SHOW variables like "%_timeout%";
SHOW global VARIABLES LIKE '%_timeout%';

wait_timeout 값 설정 요령

See Also

  1. HikariCP issue, #863, Keeping Connection Open in MySql Transactions
    • sql 을 수행하지 않고, wait_timeout 보다 connection 을 오래 잡아두면 transaction 중간에 connection 을 lost 할 수 있다.
    • deadlocks/lock timeouts
  2. Lost connection to MySQL server during query : Forums : PythonAnywhere

[컴] systemctl timer

 

systemd / systemctl 타이버 / scheduled job / 예약작업 / 주기적인 작업 / 백업 / rotate

systemctl timer

systemctl list-timers

  • systemctl list-timers --all , active 가 아닌 timer들도 보여준다. systemctl 에 등록된 scheduled job 을 보여준다.
  • /etc/systemd/system/ 에 없는 timer 는 보여주지 못하는 듯 하다.

systemctl start <timer_name>.timer

timer를 activate 하려면 아래처럼 하면 된다. enable 을 하면, booting 시점에 켠다는 이야기다. start 를 해야 바로 timer 가 동작한다고 보면 될 듯 하다.(ref.2 참고)

sudo systemctl start <timer-unit-name>.timer

timer 가 실행하는 service

systemd.timer man page 를 보면, 기본적으로 timer 와 같은 이름의 service 가 activate 된다.

만약 이름이 myservice라고 하면, systemctl start myservice.timer 를 하면, 정해진 시간에 myservice.service 가 실행된다고 보면 될 듯 하다.

Reference

  1. How to schedule tasks with systemd timers in Linux - Linux Tutorials - Learn Linux Configuration
  2. How do I properly install a systemd timer and service? - Ask Ubuntu: systemctl startsystemctl enable 의 차이

[컴] nuxt 의 dist file 을 가지고 test 시 주의할 점

 

nuxt page test 할때 주의할 점 /nuxtjs

nuxt 의 dist file 을 가지고 test 시 주의할 점

nuxt generate 를 한 후 생성된 파일을 static file 을 실행해서 접근하는 경우라고 하자.

그러면, MyPage라는 곳에 접근한다고 하면 아래처럼 2가지 path 로 가능하다.

  • http://localhost:3000/MyPage/index.html
  • http://localhost:3000/MyPage/

그런데 여기서 index.html 를 이용해서 접근하면, create() 등 vuejs 의 lifecycle 을 제대로 수행하지 않는다.

[컴] vendure 서버에 debugger 를 붙이기

vendure debug / debugger / how to attach / 디버거 / vendure server how to use debugger / vendure server

vendure 서버에 debugger 를 붙이기

dev server

"dev-server:start로 테스트 서버를 띄울 수 있다. 그 command 의 내용을 보면 아래와 같다.

  • "dev-server:start": "cd packages/dev-server && yarn start"

그래서 여기에 --inspect를 붙여서 yarn start --inspect 로 run 하면, 화면 log에 아래처럼 보인다.

...
Debugger listening on ws://127.0.0.1:9229/179b224a-ef0b-4ee9-ae2f-2710bfac71a4
For help, see: https://nodejs.org/en/docs/inspector

# debuuger 가 붙으면 아래처럼 log가 보인다.
Debugger attached.

debugger tip

console.log를 한 경우에 콘솔 화면에 로그가 보이지 않았다. 하지만 디버거 breakpoint 는 동작했다.

vscode debugger 붙이기

1. run 이후에 attach 하기

아래처럼 pickprocess 를 통해 process 를 선택하면 attach 가 된다.

다음과 같은 process 를 찾아서 선택하면 된다.

"C:\Users\myuser\AppData\Roaming\npm\node-modules\yarn\bin\yarnjs" start --inspect"

2. 바로 debugger 로 run 하기

아래 같은 vscode launch.json 을 실행하면 된다.

{
    "command": "yarn start",
    "name": "Run yarn start",
    "request": "launch",
    "type": "node-terminal",
    "cwd": "${workspaceFolder}\\packages\\dev-server"
},

vscode launch.json

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "server-Attach by Process ID",
            "processId": "${command:PickProcess}",
            "request": "attach",
            "skipFiles": [
                "<node_internals>/**"
            ],
            "type": "node"
        },
        // 바로 debugger 로 실행하려면 아래처럼 하면 된다.
        {
            "command": "yarn start",
            "name": "Run yarn start",
            "request": "launch",
            "type": "node-terminal",
            "cwd": "${workspaceFolder}\\packages\\dev-server"
        },
    ]
}

See Also

  1. 쿠…sal: [컴][웹] nextjs commerce 에 debugger 붙이기
  2. 쿠…sal: [컴][웹] next.js commerce + vendure 서버 실행

[컴] flywayMigrate 를 해서 checksum error 가 나온 경우

flyway checksum error / how to recover / spring / java

flywayMigrate 를 해서 checksum error 가 나온 경우

gradle flywayMigrate 를 이용해서 migration 을 실행했는데, checksum 이 달라서 error 가 났다. 이 checksum 은 db 내 flyway_schema_history table 에서 확인할 수 있다. 이 table 에 checksum column 을 보면, 각 script 에 대한 checksum 으로 보이는 값들이 들어가 있다.

이 checksum 값이 달라졌을 때 현재값으로 수정하려면, gradlew flywayRepair 를 하면 된다.

실행 내용

D:\a\prog\myproj>gradlew -Dflyway.configFiles=./conf/flyway.testdb.conf flywayMigrate
Configuration on demand is an incubating feature.
> Task :flywayMigrate FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':flywayMigrate'.
> Error occurred while executing flywayMigrate
  Validate failed: Migrations have failed validation
  Migration checksum mismatch for migration version 1.0.13
  -> Applied to database : -797331436
  -> Resolved locally    : 1114727104
  Either revert the changes to the migration, or run repair to update the schema history.
  Need more flexibility with validation rules? Learn more: https://rd.gt/3AbJUZE

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 2s
1 actionable task: 1 executed
D:\a\prog\myproj>gradlew -Dflyway.configFiles=./conf/flyway.testdb.conf flyway
Configuration on demand is an incubating feature.

FAILURE: Build failed with an exception.

* What went wrong:
Task 'flyway' is ambiguous in root project 'pa'. Candidates are: 'flywayBaseline', 'flywayClean', 'flywayInfo', 'flywayMigrate', 'flywayRepair', 'flywayUndo', 'flywayValidate'.

* Try:
Run gradlew tasks to get a list of available tasks. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 656ms
D:\a\prog\myproj>gradlew -Dflyway.configFiles=./conf/flyway.testdb.conf flywayRepair
Configuration on demand is an incubating feature.

BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed
D:\a\prog\myproj>gradlew -Dflyway.configFiles=./conf/flyway.testdb.conf flywayMigrate
Configuration on demand is an incubating feature.

BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed
D:\a\prog\myproj>

See Also

  1. 쿠…sal: [컴] gradle 에서 flyway 설정하기