코딩 인터뷰 준비

코딩 인터뷰 준비

##문제 1

66.Plus One

You are given a large integer represented as an integer array digits, where each digits[i] is the ith digit of the integer. The digits are ordered from most significant to least significant in left-to-right order. The large integer does not contain any leading 0’s.

Increment the large integer by one and return the resulting array of digits.

Example 1:

Input: digits = [1,2,3]
Output: [1,2,4]
Explanation: The array represents the integer 123.
Incrementing by one gives 123 + 1 = 124.
Thus, the result should be [1,2,4].

Example 2:

Input: digits = [4,3,2,1]
Output: [4,3,2,2]
Explanation: The array represents the integer 4321.
Incrementing by one gives 4321 + 1 = 4322.
Thus, the result should be [4,3,2,2].

Example 3:

Input: digits = [9]
Output: [1,0]
Explanation: The array represents the integer 9.
Incrementing by one gives 9 + 1 = 10.
Thus, the result should be [1,0].

Constraints:

1 <= digits.length <= 100
0 <= digits[i] <= 9
digits does not contain any leading 0's.

Solution

배열로 숫자가 전해지고 단순히 1을 더하여 그 결과의 숫자를 다시 배열로 내보내는 것.
배열을 숫자로, 숫자를 배열로 바꾸는 방법을 물어보는 듯했다.
나는 리스트의 전체 크기를 보고 몇자리수까지 채워지는지 보고, 10의 n승을 곱하면서 숫자를 만들어주고 작업을 진행했다.

1
2
3
4
5
6
7
8
9
class Solution:
def plusOne(self, digits: List[int]) -> List[int]:
sum = 0
length = len(digits)-1
for i, d in enumerate(digits):
sum += d*10**(length-i)
sum+=1
result = list(map(int, str(sum)))
return result

map을 어떻게 활용하는지 좀 헷갈린다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 리스트에 값을 하나씩 더해서 새로운 리스트를 만드는 작업
myList = [1, 2, 3, 4, 5]

# for 반복문 이용
result1 = []
for val in myList:
result1.append(val + 1)

print(f'result1 : {result1}')


# map 함수 이용
def add_one(n):
return n + 1


result2 = list(map(add_one, myList)) # map반환을 list 로 변환
print(f'result2 : {result2}')

함수의 동작은 두 번째 인자로 들어온 반복 가능한 자료형 (리스트나 튜플)을 첫 번째 인자로 들어온 함수에 하나씩 집어넣어서 함수를 수행하는 함수입니다.

출처: https://blockdmask.tistory.com/531 [개발자 지망생:티스토리]


내가 이렇게 할 수도 있지 않을까라고 해서 찾아본 솔루션.
각각 곱하기 더하기를 해주는 것으로 배열을 숫자로 가져오는 것이 아닌
더 단순한 방법으로 배열을 숫자로 가져오는 방법.

1
2
3
4
5
6
7
8
9
class Solution:
def plusOne(self, digits):
strings = ""
for number in digits:
strings += str(number) # digits안에 있는 숫자들을 str화 하여 빈 string안에 넣어주고

temp = str(int(strings) +1) # int로 잠깐 변환시켜 준 후 +1을 해준뒤

return [int(temp[i]) for i in range(len(temp))] # str들을 int 배열로 바꾼 뒤 리턴.

금방 풀 수 있었지만 조금 아쉬웠던 문제


하지만 이 문제에서 시간을 시간 정도 쏟아부었음에도 세번째 에러 케이스는 해결하지 못했다.
그 원인도 찾아보지 못함. 아마 내 알고리즘에서의 문제였을 것임.

##문제 2

833. Find And Replace in String)
Medium

You are given a 0-indexed string s that you must perform k replacement operations on. The replacement operations are given as three 0-indexed parallel arrays, indices, sources, and targets, all of length k.

To complete the ith replacement operation:

Check if the substring sources[i] occurs at index indices[i] in the original string s.
If it does not occur, do nothing.
Otherwise if it does occur, replace that substring with targets[i].

For example, if s = “abcd”, indices[i] = 0, sources[i] = “ab”, and targets[i] = “eee”, then the result of this replacement will be “eeecd”.

All replacement operations must occur simultaneously, meaning the replacement operations should not affect the indexing of each other. The testcases will be generated such that the replacements will not overlap.

For example, a testcase with s = "abc", indices = [0, 1], and sources = ["ab","bc"] will not be generated because the "ab" and "bc" replacements overlap.

Return the resulting string after performing all replacement operations on s.

A substring is a contiguous sequence of characters in a string.

Example 1:

Input: s = “abcd”, indices = [0, 2], sources = [“a”, “cd”], targets = [“eee”, “ffff”]
Output: “eeebffff”
Explanation:
“a” occurs at index 0 in s, so we replace it with “eee”.
“cd” occurs at index 2 in s, so we replace it with “ffff”.

Example 2:

Input: s = “abcd”, indices = [0, 2], sources = [“ab”,”ec”], targets = [“eee”,”ffff”]
Output: “eeecd”
Explanation:
“ab” occurs at index 0 in s, so we replace it with “eee”.
“ec” does not occur at index 2 in s, so we do nothing.

Constraints:

1 <= s.length <= 1000
k == indices.length == sources.length == targets.length
1 <= k <= 100
0 <= indexes[i] < s.length
1 <= sources[i].length, targets[i].length <= 50
s consists of only lowercase English letters.
sources[i] and targets[i] consist of only lowercase English letters.

Try

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import copy
import re

class Solution:
def findReplaceString(self, s: str, indices: List[int], sources: List[str], targets: List[str]) -> str:
result = ''
new_s = copy.deepcopy(s)
for i, c in enumerate(sources):
l = []
for z in re.finditer(c,s):
l.append(z.start())
if len(l) > 1:
for n in l:
if n not in indices:
l.remove(n)
if c in s:
if l[0] in indices:
new_s = new_s.replace(sources[i], targets[i])
return new_s

어떻게든 문제를 풀어가는 쪽으로 알고리즘을 짜다보니까 처음에 생각했던대로 코딩이 되지 않았다.
원래 문자열에서 시키는 대로 대체 시키고, 변화되지 않은 것들을 지우고 착실히 해나갔어야 했는데..
문제 조건을 제대로 읽지 못해서 indices, sources, targets의 길이가 항상 같다는 것도 못 알아챘다.

Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
def findReplaceString(self, S, indices, sources, targets):
"""
:type S: str
:type indexes: List[int]
:type sources: List[str]
:type targets: List[str]
:rtype: str
"""

modified = list(S)
for index, source, target in zip(indices, sources, targets):
if not S[index:].startswith(source):
continue
else:
modified[index] = target
for i in range(index+1, len(source) + index):
modified[i] = ""

return "".join(modified)

modified라는 배열을 하나 만들어 준다음,
모든 길이가 같은 indices, sources, targets를 같이 써주면서 modified를 철저하게 바꿔나갔다.

조건까지는 나도 초반에는 써봤지만, 감을 잃었던 것 같다.
1
2
3
4
5
아무튼 ```modified[index] = target```까지는 바로 이해가 갔는데, 

```python
for i in range(index+1, len(source) + index):
modified[i] = ""

가 잘 이해가 안 간다.
modified가 리스트니까, index부분을 targets로 바꿔준 뒤, modified[index+1]의 부분에 d가 남아있으면 안되기 때문에 source의 length만큼 “”빈칸으로 처리해준 것..
소스를 보면 바로 이해가 가지만, 저런 처리방법을 생각하지 못했다. 습득하기.

Share 0 Comments

M1 맥북 오류 / 크롬 오류 / 빨간 줄 / 빨간 썸네일 해결 방법

M1 맥북 오류 / 크롬 오류 / 빨간 줄 / 빨간 썸네일 해결 방법

갑자기 어느날부터 M1 맥북을 쓰는 나에게

크롬을 키면 이상한 현상이 일어나기 시작했다.

그 현상은 바로 밑과 같이

issue1

issue2

다른 브라우저에서는 잘만 보이던 이미지 / 사이트들이 이상하게 보인다는 것.

일단 간단하게 해결방법을 먼저 소개하겠다.

issue3

크롬에서 상단 오른쪽 맨 끝에 위치하고 있는 점 3개짜리 아이콘을 클릭하고나서

‘고급’탭을 누르고 ‘시스템’ 탭을 누르면 가능한 경우 하드웨어 가속 사용이라는 탭이 적용되어 있을 것이다.
( 위의 에러가 나타난다면)

issue4

위와 같이 하드웨어 가속 사용을 사용하지 않기로 설정을 하고

‘다시 시작’ 버튼을 누르게 된다면

issue5

위와 같이 에러가 없어진 상태로

복구가 될 것이다.

원인 분석을 해보자면 아마도

기존 Intel 코어를 기준으로 만들어진 웹 라이브러리나 코드가

하드웨어 가속(Intel 코어가 아닌 M1 코어를 사용할 때)을 쓸 때 나타나는 오류인 것 같다.

구글에서도 찾아보았는데

이는 random issue(정해지지 않은 정상적이지 않은 버그)에서 발견이 되는 것 같다.

정확한 해결책은 아래의 링크에서 제공해주었다.

Reference

#chrome #크롬 #크롬오류 #빨간줄 #빨간아이콘 #빨간화면 #빨간썸네일 #검은줄 #검은아이콘 #검은화면 #검은썸네일 #M1 #맥북

Share 0 Comments

[DL:scratch] 0 - basic python

Deep Learning from scratch : Plan

  1. Basic Python for Deep Learning
    • Deep Learning을 위한 python을 기본적으로 다루는 방법을 배웁니다.
  2. Perceptron
    • Perceptron을 통해 weight와 bias를 배우고 퍼셉트론의 한계, 그리고 다층 perceptron을 다룹니다.
  3. Neural Networks
    • Activation Function과 vector에 대한 계산을 다루며, Neural Network를 직접 구현해봅니다.
  4. Training Neural Networks
    • Neural Network를 학습시키기 위해 필요한 loss function과 간단한 미분/편미분에 대한 설명, 그리고 training algorithm을 구현합니다.
  5. Backpropagation
    • Neural Network를 Training 시키는 방법인 backpropagation에 대해 좀 더 심층적으로 다루고 이를 구현합니다.
  6. Training methods
    • Neural Network를 보다 잘 훈련시키기 위해 사용되어지는 여러가지 훈련방법을 소개하고 적용해봅니다.
  7. Type of Neural Networks
    • 다양한 Neural Network를 살펴보고 어떻게 적용되는지, 어떤 분야에 사용하는지에 대해 알아봅니다.
  8. Deep Learning
    • 여러가지 예제를 통해 직접 Deep Learning 모델을 만들어보고 이를 평가해봅니다.

Basic python for Deep Learning

Deep Learning을 직접 다루어보기 위해 쓰는 programming language는 다양한 것이 있지만, 본 블로그에서는 python을 다루기로 합니다.

Colab

python을 직접 실행하기 위해서도 다양한 방법이 있지만, google에서 지원하는 Colab을 사용하여 브라우저에서 손쉽게 실행할 수 있는 방법을 쓰기로 하겠습니다.

Colab

‘새 노트’를 눌러서 python을 실행시킬 수 있는 창을 띄운 뒤에 단순한 계산을 실행시켜보겠습니다.

simple_sum

1+2를 입력하고 왼쪽의 재생버튼을 누르시면, 3이라는 결과가 하단에 뜨게 됩니다.
화면에서 보시는 것처럼, 1+2를 입력하는 상자안에 입력하는 것을 ‘코드’라 하며, 한줄 뿐만 아니라 여러줄을 입력하여 한번에 실행시킬 수 있습니다.

이제부터는 화면으로 보여드리는 것보다 상자안에 입력할 것을 다음과 같은 포맷으로 보여드릴 예정입니다.

1
2
3
4
1+2
3*8
15/2
5 ** 4

위의 코드를 입력해보시고 결과를 확인해보면 다음과 같은 결과가 나오게 됩니다.

simple_calculations

625는 맨 마지막줄 계산의 결과입니다.
저희가 상단에 써놓았던 모든 수식의 결과를 보려면, 각각 계산의 결과를 ‘변수’라는 것에 저장한 뒤에, 확인하는 작업이 필요합니다. 다음과 같이 코드를 작성하여 봅시다.

1
2
3
4
5
6
7
8
9
a = 1+2
b = 3*8
c = 15/2
d = 5 ** 4

print(a)
print(b)
print(c)
print(d)

그렇다면 다음과 같은 결과가 나오게 됩니다.

using_variations

이와같이 프로그래밍은, ‘변수’라는 것을 선언하고 자신이 원하는 ‘작업’을 ‘변수’안에 저장한 뒤, 그 작업의 결과인 ‘변수’를 출력함으로써 원하는 결과를 얻는 것이라고 볼 수 있습니다.

Type of Data

python 안에서 사용할 수 있는 Data의 type에는 다양한 것들이 있습니다.

여러개의 data를 한줄로 줄세워서 저장할 수 있는 List형
여러개의 data를 key, value로 나누어서 원하는 value를 찾기 위해 key라는 것을 사용할 수 있는 dictionary형
참과 거짓을 뜻하는 bool형이 대표적이며, int, float와 같은 숫자 표현형, 그리고 ‘문자열’을 뜻하는 string형이 있습니다.

직접 결과를 확인해보면서 보도록 하겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
a = [0, 1, 2, 3, 4 ,5] # this is list
b = {'zero':0, 'one':1, 'two':2} # this is dictionary
c = True # this is bool
d = 10 # this is int
e = 10. # this is float
f = 'hello' # this is string
print(type(a))
print(type(b))
print(type(c))
print(type(d))
print(type(e))
print(type(f))

type(변수)는 변수의 type이 무엇인지를 확인할 수 있는 코드입니다.
위 코드의 결과는 다음과 같이 나옵니다.

1
2
3
4
5
6
<class 'list'>
<class 'dict'>
<class 'bool'>
<class 'int'>
<class 'float'>
<class 'str'>

list와 dictionary형의 내부에 접근하는 방법은 다음과 같습니다.
먼저 list인 a에서 첫번째 요소인 0에 접근하고 싶을 때와
dictionary안에서 ‘one’라는 key를 통해, 1이라는 value에 접근하고 싶을 때를 확인해보겠습니다.

1
2
3
4
5
6
7
8
a = [0, 1, 2, 3, 4 ,5] # this is list
b = {'zero':0, 'one':1, 'two':2} # this is dictionary
c = True # this is bool
d = 10 # this is int
e = 10. # this is float
f = 'hello' # this is string
print(a[0]) # print first element of list a
print(b['one']) # print value of key 'zero'

위의 코드를 통해 0과 1이라는 결과가 출력되는 것을 확인할 수 있습니다.
a와 b의 데이터를 바꿔보시면서 출력을 해보시거나, 대괄호 안에 들어가는 순서(index)나 key(‘one’)를 바꿔보며 익숙해지는 것이 좋습니다.

If else

~한 조건이 ‘참’일때, ~을 실행하고 싶을 때 쓰는 ‘조건문’입니다.
예를 들어, 사용자가 입력한 숫자가 10보다 작으면, 10보다 작다는 문구를 출력하고, 10이거나 10보다 크면 10보다 크다는 문구를 출력하고 싶다는 프로그램을 짜려면 어떻게 해야할까요?

1
2
3
4
5
number = input()
if number < 10:
print(f'{number} is less than 10')
else:
print(f'{number} is equal with 10 or greater than 10')

즉, if 바로 뒤에 오는 조건이 ‘True’일 경우에는 less than 문구를, False일 경우 그 이외의 경우인 ‘else’가 되어 출력되어지게 됩니다.
만약, 사용자가 입력한 숫자가 10이면, 10입니다. 라고 출력을 하고 싶다면 다음과 같이 조건을 걸어주시면 됩니다.

1
2
3
4
5
6
7
number = int(input())
if number < 10:
print(f'{number} is less than 10')
elif number == 10:
print(f'{number} is equal with 10')
else:
print(f'{number} is greater than 10')

Loop

0부터 9까지 숫자를 출력하고 싶으시다면, print를 여러번 써서 해결할 수도 있지만, 일정의 규칙이 있는 경우라면 loop 문을 쓰실 수 있습니다.

1
2
3
4
5
number = 0
for i in range(0,10):
print(i)
print(number)
number+=1

여기에서 i와 number의 차이는, i는 loop를 얼마나 반복할지를 참고하는 변수라는 것입니다.
원래 출력에서는 i와 number가 계속 같이 1씩 증가하는 모습을 보여주었지만, 만약 저 코드에서 number+=1 부분을 없앤다면 어떻게 될까요? i만 증가하고 number는 0에 멈춰있는 것을 볼 수 있습니다.

Function

위의 if else에서 작성한 코드가 있습니다. 사용자가 입력한 변수가 같으면, 크면, 작으면 ~이다를 출력해주는 작업을 반복하게 되었다고 생각해보면, 저 7줄의 코드를 매번 써줘야 할까요? 한줄로 해결할 수는 없을까요? ‘반복’해서 쓰이지만, 특정 ‘변수’만 달라지는 환경이라면 ‘function’기능을 사용할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

def isTen(number):
if number < 10:
print(f'{number} is less than answer')
return False
elif number == 10:
print(f'answer is : {number}')
return True
else:
print(f'{number} is greater than answer')
return False

for i in range(0,5):
number = int(input())
correct = isTen(number)
if correct:
break # end the loop

위의 코드는 사용자가 10을 입력하면 꺼지는 숫자 맞추기 게임입니다.
기회는 총 5번이 주어지며 (loop 5번) 5번 이내에 맞추면 승리하는 게임입니다.

이처럼 반복해서 필요한 기능들은 ‘function’화 하여서 코드를 더 간결하고 정확하게 만들 수 있습니다.

Class

Share 0 Comments

Google Certificate for ML

Google Certificate for ML

구글 Certificate에서 요구하는 능력은 다음과 같습니다.

(합격기준 100점만점 90점 이상)

  1. Basic / Simple model
  2. Model from learning dataset
  3. CNN with real world image dataset
  4. NLP text classification with real world text dataset
  5. Sequence model with real world numeric dataset

시험에 참여하기 위해서는 다음을 만족해야합니다.

  1. ML과 DL의 중요한 개념들을 사용할 줄 알아야함
  2. Tensorflow를 사용해서 ML models를 만들어야함
  3. DNN, CNN을 이용하여 Image Recognition을 할줄 알며, 현실이미지를 다루는 것에 익숙하며 loss, accuracy를 plot하고 overfitting을 방지하는 전략들을 알아야함(augmentation, dropout등)
  4. Image Recognition뿐만 아니라, object detection, text recognition을 사용할 줄 알아야함(RNN(GRU, LSTMS)을 위한 text tokenization 포함)
  5. NLP 문제를 해결하기 위한 neural network를 설계할 줄 알아야함.(using Tensorflow)

시험 환경은 다음과 같습니다.

  1. 파이참 IDE를 사용하여 인터넷이 되는 어디든 본인의 컴퓨터로 시험을 볼 수 있습니다.
  2. 시험은 온라인으로 진행되며, 파이참을 통해 tensorflow를 이용합니다.
  3. 시험은 5시간동안 진행됩니다.
  4. 시험을 치르기 위해 파이참 IDE를 이용하여 Tensorflow Exam Plugin을 설치하게 됩니다. 파이참 IDE를 이용하는 것에 익숙해지기를 추천합니다.
  5. 5시간이 지나기 전에 시험을 완료했다면, 일찍 submit하실 수 있습니다. 만약 5시간이 지나게 되면, 자동적으로 submit이 진행됩니다.
  6. 이 문서를 모두 읽어보셨다면, Exam URL에 방문할 수 있습니다.

참여자 identification and authentication

여권/운전면허증/주민등록증 중 1개 (primary)

시험 관련

  1. 시험을 보는 도중에는 브라우저를 이용하여 Tensorflow Documentation만을 참고 가능합니다.
  2. 반드시 혼자 시험을 치루셔야 합니다.
  3. 시험을 치르는 데에는 100불이 소요됩니다.

재시험 관련

  1. 1번째 시험 낙방 -> 2주가 지나야 시험을 칠 수 있습니다.
  2. 2번째 시험 낙방 -> 2달이 지나야 시험을 칠 수 있습니다.
  3. 3번째 시험 낙방 이후 -> 1년이 지나야 시험을 칠 수 있습니다.

Reference

Share 0 Comments

chatGPT의 놀라운 대화능력에 대한 실험

chatGPT의 놀라운 대화능력에 대한 실험

최근 openAI에서 발표한 chatGPT가 놀라운 대화능력을 보여주고 있다며 올라온 한 커뮤니티의 게시물을 보았다.

​보면 볼수록 놀랍고 이런 통찰력과 지식을 가지고 사람과 이야기 할 수 있다는 것이 너무 놀라웠다.

​해당 커뮤니티의 게시물처럼 나도 이 chatGPT와 서로 대화를 해보려는 시간을 가지게 되었다.


  1. 지금 현대인으로 봤을 때 성경의 많은 부분은 과학적으로 믿기 어려운 일이 일어났음을 보여주지만, 기독교인들은 이것이 모두 사실이라고 믿고있다. 나도 기독교인으로써, 이에 대해 어떻게 생각해야하는 것이 좋은가?

1A) 기독교인으로서 성경은 과학적 문서가 아니며 그렇게 해석되어서는 안 된다는 것을 기억하는 것이 중요하다.
그것은 우리가 하나님과 하나님과의 관계를 이해하는 것을 돕기 위한 이야기와 가르침을 포함하는 종교적인 본문입니다.
성경에 묘사된 사건들 중 일부는 과학적으로 불가능해 보일 수 있지만,
이러한 이야기들을 적절한 맥락에서 해석하고 문자 그대로 받아들이지 않는 것이 중요하다.
기독교인으로서 열린 마음과 마음으로 성경에 접근하고 기도와 공부를 통해 성경의 가르침과 메시지에 대한 더 깊은 이해를 구하는 것이 중요하다.

1-1. 그럼 기독교인이 아닌 사람으로써는?

1-1A) 기독교인이 아닌 사람으로서, 여러분은 성경과 성경의 가르침을 여러분에게 가장 이치에 맞는 어떤 방식으로든 자유롭게 해석할 수 있습니다.
어떤 사람들은 성경을 허구의 작품으로 보는 반면, 다른 사람들은 그것을 지혜와 지침의 원천으로 보는 것을 선택할 수 있다.
궁극적으로 성경을 어떻게 해석하느냐는 당신에게 달려 있으며,
무엇이 당신에게 옳은지, 무엇이 당신 자신의 가치관과 신념과 일치하는지에 근거해야 한다.
비록 다른 사람들의 믿음이 자신의 믿음과 다르더라도 그것을 존중하는 것은 중요하다.


과학력이 모여있는 chatGPT가 과연 종교적인 것과 과학적인 것을 구분 가능하고 무엇에 더 집중을 두는가를 확인하고 싶었다.

또한 각각의 입장에 따라 어떻게 생각해야할지를 구분하며 답변하는 부분도 볼 수 있었다. 놀라운 답변이었다.


Share 0 Comments

[Pytorch]MNIST DNN부터 CNN까지

MNIST DNN부터 CNN까지

Deep Learning을 공부함에 있어서 제일 처음으로 접하는 Data는 바로 MNSIT라고 할 수 있습니다. MNIST는 사람들이 직접 필기로 쓴 숫자로써 0부터 9까지 검은 배경에 하얀 글씨로 쓰여져있는 28 x 28 사이즈의 이미지 데이터입니다. 이 포스팅을 통해서 MNIST 데이터를 Deep Learning을 통해서 숫자들을 구별할 수 있는 모델을 설계하고, DNN을 이용한 모델과 CNN을 이용한 모델을 직접 구현해 볼 것입니다.

MNSIT 살펴보기

MNIST데이터는 다음 그림과 같은 이미지로 구성되어있습니다.
overview_mnist

위에서 설명한 바와 같이 위와 같은 이미지처럼 데이터가 구성되어 있으며, 데이터 하나하나는 다음과 같은 이미지를 구성하고 있습니다.

mnist_sample

Deep Learning 모델이 해야할 일은 input으로써 위와 같은 정보를 받고, 해당 데이터가 0부터 9라는 숫자중에 어떤 숫자인지를 알아맞추는 것입니다.

하지만 이 이미지 파일을 어떻게 Deep learning 모델이 받아들일 수 있도록 할 것인가? 보통 MNIST 데이터는 28 x 28의 숫자를 가진 텐서로 표현이 됩니다. 예를 들어서, 하나의 이미지 파일을 텐서로 표현한 데이터를 출력해보면 다음과 같이 나옵니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[...
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0.01171875 0.0703125 0.0703125 0.0703125
0.4921875 0.53125 0.68359375 0.1015625 0.6484375 0.99609375
0.96484375 0.49609375 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0.1171875 0.140625 0.3671875 0.6015625
0.6640625 0.98828125 0.98828125 0.98828125 0.98828125 0.98828125
0.87890625 0.671875 0.98828125 0.9453125 0.76171875 0.25
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.19140625
0.9296875 0.98828125 0.98828125 0.98828125 0.98828125 0.98828125
0.98828125 0.98828125 0.98828125 0.98046875 0.36328125 0.3203125
0.3203125 0.21875 0.15234375 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0.0703125 0.85546875 0.98828125
0.98828125 0.98828125 0.98828125 0.98828125 0.7734375 0.7109375
0.96484375 0.94140625 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0.3125 0.609375 0.41796875 0.98828125
0.98828125 0.80078125 0.04296875 0. 0.16796875 0.6015]

출력된 값 전부를 표현하기에는 너무 많은 숫자들이기에 약간의 데이터만 포스팅하지만, 간단하게 총 784개의 숫자를 가진 데이터임을 확인할 수 있습니다.(28*28=784)
DNN을 이용할 때에는 784의 길이를 가진 형태로 집어넣을 것이고, CNN을 이용할 때에는 28x28을 지닌 그대로의 형태로 집어넣을 것입니다.

MNIST Practice

Pytorch에서 제공하는 기본 MNIST 예제는 CNN으로 이루어져있지만 MNIST는 간단한 데이터이기 때문에, DNN만으로도 충분히 다룰 수 있습니다. 먼저 전체적인 코드를 큰 파트별로 먼저 크게 살펴보고, 그 다음에 하나하나의 파트들을 Line by Line으로 살펴보도록 하겠습니다.

DNN 모델 설계하기

먼저 Pytorch에서 제공하는 라이브러리를 사용하기 위해 각 라이브러리들을 Import 해주는 작업을 해줍니다.

1
2
3
4
5
6
7
8

#Importing Library

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms

그 다음으로는 DNN을 설계를 할 것인데, 우리가 가진 MNIST데이터는 (1,784)의 데이터 형태를 가지고 있고, 구분하려는 숫자의 종류는 총 10가지라는 것을 생각한 뒤 모델을 설계한다고 생각하면 간단한 DNN은 대략 다음과 같이 구성할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

#Define Neural Networks Model.

class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(784, 512)
self.fc2 = nn.Linear(512, 256)
self.fc3 = nn.Linear(256, 128)
self.fc4 = nn.Linear(128, 64)
self.fc5 = nn.Linear(64, 32)
self.fc6 = nn.Linear(32, 10)

def forward(self, x):
x = x.float()
h1 = F.relu(self.fc1(x.view(-1, 784)))
h2 = F.relu(self.fc2(h1))
h3 = F.relu(self.fc3(h2))
h4 = F.relu(self.fc4(h3))
h5 = F.relu(self.fc5(h4))
h6 = self.fc6(h5)
return F.log_softmax(h6, dim=1)

print("init model done")

여러층의 Feed Forward Network를 설계해서, input size는 784, output size는 10이 되도록 설정해줍니다.(input data는 (1, 784)의 형태이고 정답(숫자의 종류)는 총 10가지)

이 다음에는 DNN을 Training시키기 위해 필요한 여러가지 변수들 및 hyper parameter들을 설정해줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Set Hyper parameters and other variables to train the model.

batch_size = 64
test_batch_size = 1000
epochs = 10
lr = 0.01
momentum = 0.5
no_cuda = True
seed = 1
log_interval = 200

use_cuda = not no_cuda and torch.cuda.is_available()

torch.manual_seed(seed)

device = torch.device("cuda" if use_cuda else "cpu")

kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}

print("set vars and device done")

어느정도 필요한 변수들을 선언해줬다면, 그 다음으로는 pytorch의 torchvision이 제공하는 MNIST 데이터들과 데이터들을 읽어올 수 있는 Loader들을 선언해줍니다.
그리고 Training을 위한 데이터와 모델의 성능을 평가할 수 있는 Test를 위한 데이터 로더를 선언해줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#Prepare Data Loader for Training and Validation

transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))])

train_loader = torch.utils.data.DataLoader(
datasets.MNIST('../data', train=True, download=True,
transform=transform),
batch_size = batch_size, shuffle=True, **kwargs)

test_loader = torch.utils.data.DataLoader(
datasets.MNIST('../data', train=False, download=True,
transform=transform),
batch_size=test_batch_size, shuffle=True, **kwargs)

위와 같이 Data Loader들을 선언해주셨다면, 그 다음으로는 위에서 우리가 설계했던 DNN 모델을 불러오고, Training에 필요한 Optimizer를 선언해줍니다.

1
2
model = Net().to(device)
optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)

그 다음으로는 모델을 직접 Training시키는 함수과 Test하는 함수를 구현해줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#Define Train function and Test function to validate.

def train(log_interval, model, device, train_loader, optimizer, epoch):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
output = model(data)
loss = F.nll_loss(output, target)
loss.backward()
optimizer.step()
if batch_idx % log_interval == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))

def test(log_interval, model, device, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
test_loss += F.nll_loss(output, target, reduction='sum').item()
pred = output.argmax(dim=1, keepdim=True)
correct += pred.eq(target.view_as(pred)).sum().item()

test_loss /= len(test_loader.dataset)

print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format
(test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))

Training Data를 한차례 전부 학습에 사용했다면 그것을 하나의 Epoch이라고 부르는데, 모델을 학습시키는데에 하나의 Epoch보다 더 많은 Epoch이 필요하므로 Train과 Test의 과정을 반복하는 반복문을 선언해줍니다. 이 반복문이 끝나면, 마지막으로 Training된 모델을 저장합니다.

1
2
3
4
5
6
# Train and Test the model and save it.

for epoch in range(1, 11):
train(log_interval, model, device, train_loader, optimizer, epoch)
test(log_interval, model, device, test_loader)
torch.save(model, './model.pt')

여기까지가 Pytorch를 이용해서 DNN으로 MNSIT 데이터들을 분류하는 작업의 코드입니다.

이제는 각 파트별로 소스코드들이 무엇을 의미하는지를 알아보도록 하겠습니다.

DNN Model.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(784, 512)
self.fc2 = nn.Linear(512, 256)
self.fc3 = nn.Linear(256, 128)
self.fc4 = nn.Linear(128, 64)
self.fc5 = nn.Linear(64, 32)
self.fc6 = nn.Linear(32, 10)

def forward(self, x):
x = x.float()
h1 = F.relu(self.fc1(x.view(-1, 784)))
h2 = F.relu(self.fc2(h1))
h3 = F.relu(self.fc3(h2))
h4 = F.relu(self.fc4(h3))
h5 = F.relu(self.fc5(h4))
h6 = self.fc6(h5)
return F.log_softmax(h6, dim=1)

위의 DNN 모델은 총 6개의 Linear 레이어를 통해서 학습하게 됩니다.

MNIST data는 간단한 toy data이고, 간단한 데이터이기 때문에 위처럼

단순한 neural networks만으로도 가능합니다.

784 dimension을 가진 MNIST data를 512, 256, 128, … dimension으로

옮겨가며 feature extraction을 할 수 있도록 하며, 각 레이어마다 끝단에는

Relu라는 activation function을 통해 neural network에 nonlinearity를 추가해줍니다.

마지막 단에 Log Softmax를 통해 마지막 레이어를 지난 10개의 값들을 return하는데

Log Softmax의 역할은 마지막 나온 결과값들을 확률로 취급하여 해석하기 위한 하나의 연산입니다.

Hyper Parameters and Variables

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
batch_size = 64
test_batch_size = 1000
epochs = 10
lr = 0.01
momentum = 0.5
no_cuda = True
seed = 1
log_interval = 200

use_cuda = not no_cuda and torch.cuda.is_available()

torch.manual_seed(seed)

device = torch.device("cuda" if use_cuda else "cpu")

kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}

print("set vars and device done")

위의 parameter들은 보통 딥러닝 모델을 train할 때, 많이 쓰이는 변수들이며

딥러닝 모델에 큰 영향을 주는 parameter는 hyper parameter라고 합니다.

batch_size란, cpu 혹은 gpu에 한번에 몇개씩의 data를 넣어줄 것인지를 정하는 것입니다.

batch_size의 갯수에 따라서도 딥러닝 모델의 성능이 크게 달라집니다.

epochs같은 경우에는 training data를 1번씩 모두 썼을 때까지를 1 epoch이 지났다고 합니다.

즉, training data가 10개가 있고, 그 data들을 모두 한번씩 training에 썼다면, 1 epoch이 지난 것입니다.

Data Loader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#Prepare Data Loader for Training and Validation

transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))])

train_loader = torch.utils.data.DataLoader(
datasets.MNIST('../data', train=True, download=True,
transform=transform),
batch_size = batch_size, shuffle=True, **kwargs)

test_loader = torch.utils.data.DataLoader(
datasets.MNIST('../data', train=False, download=True,
transform=transform),
batch_size=test_batch_size, shuffle=True, **kwargs)

transform을 통해서 data를 어떻게 처리해줄지 결정을 해줍니다.

함수를 보면, 이미지 데이터를 .ToTensor()를 통해서 tensor형태로 데이터를 변환해준 뒤

Normalize과정을 해주기 위해서 standard deviation와 variation 값을 직접 입력해줍니다. (모든 MNIST이미지를 통해 미리 구해놓은 값입니다.)

그리고 위의 함수에 따라 training set과 test set을 구분해서 만들어줍니다.

현재 torchvision의 함수 자체가 ‘train’이라는 parameter를 통해 training set과 test set을 쉽게 준비할 수 있도록 설계해놨기 때문에, 이를 그대로 사용하시면 됩니다.

Optimizer

1
2
model = Net().to(device)
optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)

Optimizer를 통해서 모델이 어떤 방식으로 training할지를 고르게 됩니다.

대표적인 training방식은 SGD, RMSprop, Adam, AdaDelta 등 여러가지 방식이 있는데

위의 코드는 SGD와 momentum을 사용하는 optimizer를 설정해준 뒤, model내의 parameter들을 training하도록 했습니다.

Train and Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#Define Train function and Test function to validate.

def train(log_interval, model, device, train_loader, optimizer, epoch):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device) # send data to gpu or cpu
optimizer.zero_grad() # set gradient zero.
output = model(data) # get output from model
loss = F.nll_loss(output, target) # calculate nll loss
loss.backward() # do backpropagation
optimizer.step() # update weight and biases
if batch_idx % log_interval == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))

def test(log_interval, model, device, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
test_loss += F.nll_loss(output, target, reduction='sum').item()
pred = output.argmax(dim=1, keepdim=True)
correct += pred.eq(target.view_as(pred)).sum().item()

test_loss /= len(test_loader.dataset)

print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format
(test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))

train함수를 통해서 train data들을 한번씩 살피도록 합니다.

test함수를 통해서 test data를 통해 모델의 성능을 평가하게 됩니다.

Make machine works

1
2
3
4
5
6
# Train and Test the model and save it.

for epoch in range(1, 11):
train(log_interval, model, device, train_loader, optimizer, epoch)
test(log_interval, model, device, test_loader)
torch.save(model, './model.pt')

train 함수와 test함수를 통해 model을 트레이닝 시키고
모든 epoch이 끝나게 되면 torch.save를 통해 모델을 저장시켜줍니다.

CNN model

CNN 모델은 28x28의 MNIST data를 1x784로 고쳐서 쓰는 것이 아닌, 2d data의 형태 그대로 사용하게 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 32, 3, 1)
self.conv2 = nn.Conv2d(32, 64, 3, 1)
self.dropout1 = nn.Dropout2d(0.25)
self.dropout2 = nn.Dropout2d(0.5)
self.fc1 = nn.Linear(9216, 128)
self.fc2 = nn.Linear(128, 10)

def forward(self, x):
x = self.conv1(x)
x = F.relu(x)
x = self.conv2(x)
x = F.relu(x)
x = F.max_pool2d(x, 2)
x = self.dropout1(x)
x = torch.flatten(x, 1)
x = self.fc1(x)
x = F.relu(x)
x = self.dropout2(x)
x = self.fc2(x)
output = F.log_softmax(x, dim=1)
return output

CNN을 이해하기 위해서는 filter size, padding, stride 라는 개념을 알아두셔야 합니다.

Share 0 Comments

알파스타, 실시간 전략 게임 스타크래프트2 정복하기[딥마인드 소식 번역]

AlphaStar: Mastering 실시간 전략 게임 스타크래프트2

본문 LINK
어설프지만 공부겸 번/의역 해가면서 글을 작성했습니다. 모든 오역에 대한 지적은 감사히 받습니다. 도움이 되었으면 합니다.


게임은 수십 년 동안 인공 지능 시스템의 성능을 테스트하고 평가하는 중요한 방법으로 사용되어 왔습니다. 역량(capability)이 향상됨에 따라 연구 커뮤니티는 과학 및 실제 문제를 해결하는 데 필요한 다양한 지능 요소를 포착하는, 복잡성이 증가하는 게임을 찾아 왔습니다. 최근 몇 년 동안, 가장 도전적인 실시간 전략 (RTS) 게임 중 하나로 간주되는 스타크래프트는 가장 긴 시간 동안 행해지는 스포츠 중 하나였으며, 인공 지능 연구를 위한 “큰 도전”이라는 것으로 의견이 일치되었습니다.

Download 11 replays

최고의 프로 선수를 물리 칠 수 있는 최초의 인공지능 스타크래프트2 프로그램 AlphaStar를 소개합니다. 12월 19일에 열린 테스트 매치에서 AlphaStar는 세계 최강의 프로 스타크래프트 플레이어 중 하나인 팀 리퀴드의 Gregorz ‘ManA’ Komincz를 5-0으로 승리를 보이고, 그의 팀 동료 인 Dario ‘TLO’를 상대로도 승리를 거두었습니다. 경기는 프로 매치 경기에서 쓰이는 에서 경기를 하였고 게임에는 그 어떤 제약도 없었습니다.

인공지능 기술이 Atari, Mario, Quake Quake III Arena Capture the Flag, 그리고 Dota2에서는 뛰어난 성공 사례들이 있었지만, 아직까지는 스타크래프트와 같은 복잡성을 지닌 게임에는 좋은 결과를 내지 못했습니다. 가장 좋은 결과들은 시스템의 요소를 직접 제작하거나, 게임 규칙에 큰 제한을 걸거나, 초인적인 능력을 시스템에 주거나, 단순한 맵에서 게임을 진행함으로써 얻은 결과였습니다. 이런 노력에도 불구하고 그 어떤 시스템도 프로 선수들의 기술에 필적할만한 시스템은 거의 없습니다. 하지만, AlphaStar는 deep neural network(supervised learning and reinforcement learning)을 사용하여 게임의 raw data를 학습합니다.

MaNa와의 경기에 대한 기록

스타크래프트가 “큰 도전”인 이유

블리자드가 제작한 스타크래프트2는 공상과학세계를 배경으로 인간의 지성에 도전 할 수 있는 풍부한 멀티 플레이 게임을 지원합니다. 스타크래프트1과 함께, 스타크래프트2는 20년 이상 esports 토너먼트에서 경쟁하는 가장 크고 성공적인 게임중 하나입니다.

alphastar_play

게임을 플레이하는 방법은 여러 가지 방법이 있지만 가장 일반적인 방법은 5개의 게임에서 1v1 토너먼트를 하는 것입니다. 시작하려면 플레이어는 저그, 프로토스 또는 테란이라는 세 가지 “종족” 중 하나를 선택해야합니다. 각각의 종족들은 특색 있는 특성과 능력을 지니고 있습니다(프로 선수는 한 종족을 전문으로 하는 경향이 있지만요). 각 플레이어는 많은 유닛과 구조물을 만들고 새로운 기술을 창출 할 수 있는 기본 자원을 모으는 다수의 일꾼 유닛으로 시작합니다. 이것들은 플레이어가 자원을 수확 할 수 있게 해주며, 보다 정교한 기반과 구조를 만들고, 상대방을 속일 수 있는 새로운 능력을 개발합니다. 게임에서 이기기 위해서는 큰 그림을 그려 정교하게 자원을 관리해야 하며(Macro라 알려진 것), 각각의 유닛을 직접 컨트롤 하는 것(Micro라 알려진 것)을 잘 관리해야 합니다.

장단기 목표의 균형을 맞추고 예상치 못한 상황에 적응해야하는 필요성 때문에 시스템은 종종 불안정하며 융통성이 없기도 합니다. 이 문제를 해결하기 위해서는 다음과 같은 몇 가지 인공 지능 연구 과제에서 혁신이 필요합니다.

  • 게임 이론 : 스타크래프트는 가위바위보처럼 최고의 전략이 없는 게임입니다. 따라서 인공지능 교육 과정은 전략적 지식의 영역을 지속적으로 탐구하고 확장해야합니다.
  • 불완전한 정보 : 플레이어가 모든 것을 볼 수있는 체스나 바둑 같은 게임과는 달리, 중요한 정보는 스타크래프트 플레이어에게 숨겨져 있으며 “정찰”로 직접 발견해야 합니다.
  • 장기 계획 : 많은 실제 문제와 마찬가지로 인과 관계가 즉각적인 것은 아닙니다. 또한 게임을 완료하는 데 최대 1시간이 걸릴 수 있으므로 게임 초기에 수행한 작업이 오랜 기간 동안 성과를 내지 못할 수 있습니다.
  • 실시간 : 선수가 후속 동작을 번갈아 번갈아하는 전통적인 보드 게임과 달리 스타크래프트 플레이어는 게임이 실시간으로 진행됨에 따라 계속해서 작업을 수행해야합니다.
  • 대규모 작업 공간 : 수백 개의 다른 유닛과 건물을 실시간으로 한 번에 제어해야하며 조합 가능성이 생깁니다. 또한 행동은 계층적이며 변경 및 보완 될 수 있습니다. 인공지능은 매 time step마다 10개에서 26가지의 행동을 합니다.

이러한 엄청난 요구사항으로 인해 스타크래프트는 인공지능 연구를 위한 “큰 도전”으로 떠올랐습니다. 2009년 BroodWar API 출시 이후, 스타크래프트와 스타크래프트2가 현재 진행 중인 경쟁은 AIIDE 스타크래프트 AI 공모전, CIG 스타크래프트 공모전, 학생 스타크래프트 AI 토너먼트, 그리고 스타크래프트2 AI Ladder가 있습니다. 커뮤니티가 이러한 문제를 더욱 효과적으로 해결할 수 있도록 2016년과 2017년에 블리자드와 협력하여 PySC2로 알려진 오픈소스 도구 세트를 출시했습니다. 여기에는 지금까지 출시 된 익명의 게임 리플레이 세트가 포함됩니다. 저희는 AlphaStar를 제작하기위해 엔지니어링 및 알고리즘 혁신을 결합하여 이 작업을 수행했습니다.

alphastar_interface
MaNa와의 2번째 경기 중 AlphaStar가 플레이하는 게임을 시각화한 모습. 즉, neural network에 있는 그대로의 화면을 input으로 넣어주고, neural network를 활성화시키고, AlphaStar가 클릭 할 위치와 대상, 그리고 예측된 결과와 같은 출력 값을 가질 수 있다. 그림에는 MaNa의 화면이 보이지만, AlphaStar는 이에 접근할 수 없다.

AlphaStar는 어떻게 훈련되는가

AlphaStar는 있는 그대로의 게임 인터페이스(유닛과 유닛속성의 목록)로부터 input을 받고 게임 내에서 조작하는 명령어를 생성하게 됩니다. 자세히 이야기하자면, neural network 구조중에 하나인 transformer를 메인으로 deep LSTM core, pointer networkauto-regressive policy head, 그리고 centralised value baseline을 사용하였습니다. 저희는 이 진보된 모델이 long-term sequence와 큰 output spaces를 가지는 번역이나 언어 모델링, 그리고 시각적인 표현에 큰 도움을 줄 수 있을 거라 생각합니다.

AlphaStar는 새로운 멀티 에이전트 학습 알고리즘을 사용합니다. 이 Neural network는 한 익명의 사람이 처음에 supervised learning으로 학습을 시켰고 블리자드는 이를 공개하였습니다. 이를 통해서 AlphaStar는 사람들을 따라하며 기본적인 Macro, Micro 전략을 배울 수 있었습니다. 초기의 에이전트는 게임내의 인공지능 레벨 ‘엘리트’를 95%의 승률로 이기기 시작했습니다.

alpha_league
AlphaStar 리그. 에이전트는 처음에는 사람의 게임 리플레이에서 훈련을 한 후 리그내의 다른 경쟁자와 경기를 하며 훈련을 합니다. 각 iteration마다 새로운 경쟁자가 나타나고 원래의 경쟁자가 동결되며 각 에이전트의 매치를 결정하는 확률과 하이퍼 파라미터를 결정하는 학습 목표가 적용되며, 다양성을 유지하면서 난이도는 올라가도록 하였습니다. 에이전트의 parameter는 경쟁자에 대한 게임 결과로부터 강화 학습을 통해 업데이트됩니다. 최종 에이전트는 리그의 Nash 분포에서 샘플링됩니다.

그런 다음 멀티 에이전트 reinforcement learning을 통해 학습을 시작하였습니다. 지속적으로 리그가 생성되며 에이전트들은 경쟁자와 맞서 게임을 하게 됩니다. Starcraft Ladder와 같이, 에이전트들은 사람처럼 스타크래프트를 플레이하게 되는 것입니다. 새로운 경쟁자들이 계속해서 리그에 등장하게 되며, 새로운 경쟁자들은 원래의 에이전트들에게서 branch 되어 나옵니다. 각 에이전트들은 경쟁을 통해 학습을 진행하게 됩니다. Population-based reinforcement learning의 아이디어를 가져온 새로운 형태의 학습 과정으로, 각 에이전트가 가진 가장 강력한 전술을 상대하고, 빨리 상대방을 무릎을 꿇게 함과 동시에 지속적으로 스타크래프트의 방대한 양의 전술을 익히고 경험하게 됩니다.

MMR
추측 MMR(Match Making Rating)은 대략적인 플레이어의 실력을 측정한 것으로써, 현재 블리자드 온라인 리그와 비교를 해보았습니다.

리그가 진행되고 새로운 경쟁자가 만들어지면 이전 전략을 무력화 할 수 있는 새로운 대응 전략이 등장합니다. 일부 새로운 에이전트는 이전 전략을 단순화 한 전략을 실행하는 반면 다른 일부 에이전트는 새로운 빌드(전략)과 유닛 구성 및 micro-관리하는 방법 등 획기적인 새로운 전략을 발견했습니다.

예를 들면, AlphaStar 리그 초반에는 광자포암흑 기사를 이용하여 빠르게 적을 공략하는 “Cheesy”(역주: 싸구려) 전략이 선호되었습니다. 하지만 이러한 위험한 전략은 훈련이 진행됨에 따라 폐기되어 다른 전략을 이끌어 냈습니다. 예를 들어, 더 많은 일꾼들로 기지를 과도하게 확장함으로써 경제적 힘을 얻거나 두 마리의 예언자(역주. 일꾼 사냥에 좋은 유닛)을 통해 상대방의 일꾼과 경제를 혼란스럽게 합니다. 이 과정은 스타크래프트가 출시 된 이후로 플레이어가 새로운 전략을 발견하고 이전에 선호했던 전략을 버렸던 것과 유사합니다.

unit
훈련이 진행됨에 따라 AlphaStar가 만드는 유닛의 조합이 바뀌었습니다.

리그의 다양성을 장려하기 위해 각 에이전트는 자체 학습 목표를 가지고 있습니다. 예를 들어, 어떤 에이전트는 다른 한 에이전트를 이겨야만 하는 추가적인 내부 motivation을 추가해줍니다. 한 에이전트는 특정 경쟁자를 이길 수 있는 목표를 가질 수 있지만 다른 에이전트는 대다수의 에이전트를 이겨야하는 경우도 있습니다. 그렇게 하기 위해서는 특정 유닛을 더 많이 만들어야 합니다. 이러한 학습 목표는 학습 과정에서 조정됩니다.

strategy map
AlphaStar 리그의 경쟁자를 보여주는 visualization. TLO 및 MaNa와 경쟁을 한 에이전트에는 특별히 레이블이 지정됩니다.(html을 긁어오기가 힘들어서 사진 캡처로 대체. detail in 본문)

각 에이전트들의 neural network weight은 경쟁자에 대한 게임으로부터 reinforcement learning을 통해 업데이트되어 개인 학습 목표를 최적화합니다. Weight을 업데이트하는 규칙으로는, off-policy actor-critic 방법과 함께 experience replay, self-imitation learning, 그리고 policy distillation이 사용되었습니다.

MaNa Agent
이 그림은 MaNa와의 플레이를 위해 선택된 한 명의 에이전트(검은 점)가 훈련 과정에서 전략과 경쟁자(색이 있는 점)들을 발전 시켰음을 보여줍니다. 각 점은 AlphaStar 리그의 경쟁자를 나타냅니다. 점의 위치는 전략(inset)을 나타내며 점의 크기는 Mana 에이전트와 얼마나 자주 겨루며 학습을 했는지를 보여줍니다.

AlphaStar를 학습시키기 위해 저희는 구글의 스타크래프트2를 학습하는 수많은 에이전트들이 수천개의 병렬 instance들 안에서 학습할 수 있도록 지원하는 구글 v3 TPU를 사용하여 확장성이 뛰어난 distributed 학습 환경을 만들었습니다. AlphaStar 리그는 14일 동안, 16개의 TPU를 사용하며 훈련이 이루어졌고 각 에이전트들은 현실시간으로 약 200년의 스타크래프트 게임을 경험하게 되었습니다. 최종적인 AlphaStar 에이전트는 Nash 분포 리그를 구성하고 있으며, 이는 곧 가장 효율적인 전략들이 혼합된 모델이라는 것입니다. 그리고 이 모델은 단 한개의 GPU에서 구동이 가능합니다.

모든 기술적인 설명은 peer-reviewd 저널에 투고될 예정입니다.

progression
AlphaStar 리그가 진행되면서 Nash 분포 안에서도 새로운 경쟁자들이 등장했습니다. Nash 분포 안에서 상호 보완적인 경쟁자 중 가장 취약한 에이전트는 새로운 경쟁자에게 가장 큰 비중을 두고 있으며 이전 경쟁자들에 대한 지속적인 진전을 보여줍니다.

AlphaStar는 어떻게 게임을 플레이하며 게임을 관찰하는가

TLO와 MaNa같은 프로 스타크래프트 플레이어는 평균 분당 수백번의 동작(APM)을 실행할 수 있습니다. 이는 각 유닛을 독립적으로 제어하고 수천 또는 수만 개의 APM을 일관성 있게 유지 및 관리하는 기존 Bot들에 비해 현저하게 낮습니다. TLO와 MaNa와의 경기에서 AlphaStar의 평균 APM은 280으로 아무리 게임 플레이가 정교했다 하더라도 프로 선수보다 훨씬 낮았습니다. 이 낮은 APM은 부분적으로 AlphaStar가 리플레이를 사용하여 교육을 시작하기 때문에 인간이 게임을 하는 방식을 모방하기 때문입니다. 또한 AlphaStar는 관찰과 동작 사이의 평균 350ms의 지연시간을 가지고 있습니다.

APM
MaNa와 TLO에 대한 경기에서 AlphaStar가 가졌던 APM 분포와 총 지연 시간.

TLO와 MaNa와의 경기 도중 AlphaStar는 직접 게임의 인터페이스를 통해 스타크래프트 게임 엔진을 사용하였습니다. 즉, 카메라를 움직이지 않고도 직접 맵에서 자신과 상대방의 눈에 보이는 유닛의 속성을 직접 관찰 할 수 있었습니다. 반대로 사람은 카메라를 사용해서 어디에 집중해야 할지 명확하게 결정을 해야만 합니다. 하지만 분석해보니 AlphaStar의 게임은 AlphaStar 스스로가 어디에 집중을 해야 할지 암시적으로 관리하는 모습을 보였습니다. AlphaStar는 TLO나 MaNa와 비슷하게 평균적으로 분당 30회 정도의 “switched context”를 하였습니다.

또한, 경기 후에 저희는 AlphaStar의 두 번째 버전을 개발했습니다. 인간 선수와 마찬가지로 AlphaStar의 두 번째 버전은 카메라를 언제, 어디서 움직일지를 결정하며, 화면의 정보로만 인식되며, 동작 위치는 볼 수있는 영역으로 제한됩니다.

Comparison of interfaces for training
Raw 인터페이스와 카메라 인터페이스를 사용하는 AlphaStar의 성능. 새로 훈련된 카메라 에이전트가 raw 인터페이스를 사용하여 에이전트의 성능을 따르게 따라 잡을 수 있고 거의 동일하다는 것을 보여준다.

Raw 인터페이스를 사용하는 것과 AlphaStar 리그를 상대로 카메라 제어법을 배우는 두 가지 새로운 에이전트를 교육했습니다. 각 에이전트는 처음에 인간 데이터를 통한 supervised learning과 위에서 설명한 reinforcement learning을 통해 훈련되었습니다. 카메라 인터페이스를 사용하는 AlphaStar 버전은 내부 인터페이스에서 7000 MMR을 초과하는 raw 인터페이스와 거의 비슷했습니다. 전시회 경기에서, MaNa는 7일 동안 훈련된 카메라 인터페이스를 사용하는 프로토타입의 AlphaStar를 이겼습니다.

이 결과는 MaNa 및 TLO에 대한 AlphaStar의 성공이 우수한 클릭률, 빠른 반응 시간 또는 raw 인터페이스보다는 우수한 macro와 micro-strategic decision-making(역주. 컨트롤) 때문인 것으로 나타났습니다.

프로선수의 AlphaStar 평가

스타크래프트 게임을 통해 플레이어는 테란, 저그 또는 프로토스의 세 가지 종족 중 하나를 선택할 수 있습니다. 저희는 AlphaStar를 학습시키는 것에 교육시간과 편차를 줄이기 위해 현재 단 하나의 종족인 프로토스를 전문적으로 다루기로 결정했습니다. Note that, 동일한 교육을 모든 종족에 적용을 시킬 수 있습니다. 저희의 에이전트는 스타크래프트2(v4.6.2)에서 프로토스vs프로토스 게임을 진행하였고, CatalystLE라는 맵에서 진행되었습니다. AlphaStar의 성능을 평가하기 위해 저희는 TLO(저그가 주종족인 프로선수, 프로토스는 그랜드마스터의 실력)를 통해 테스트 하였고 AlphaStar는 다양한 빌드와 유닛으로 5-0으로 경기를 마무리했습니다. TLO는 “진짜 잘해서 놀랐어요. AlphaStar는 잘 알려진 전략과는 거리가 먼 플레이를 보여주었어요. 전혀 생각하지도 못한 전략으로 다가왔죠. 그 말은 곧 아직 우리가 경험하지 못한 새로운 방식의 전략들이 존재하다는 거겠죠” 라고 말했다.

AlphaStar:inside story

1주일간 에이전트를 교육 한 후, 저희는 세계에서 가장 강력한 스타크래프트2의 플레이어 중 하나인 MaNa 와 가장 강력한 10명의 프로토스 선수들과 대전했습니다. AlphaStar는 5경기에서 무패로 우승하여 강력한 전략 기술을 보여주었습니다. “AlphaStar의 놀라운 움직임과 매 경기 다른 전략으로 다가오는 것에 큰 감명을 받았다. 내가 전혀 생각하지 못했던 사람 같은 플레이를 보여주었다.” “나는 내 전략이 상대방의 실수를 유도하고 그의 인간적인(감정적인) 반응을 나에게 유리하도록 하는 것에 의존하고 있다는 사실을 깨달았다.”고 말했다.

AlphaStar, 그리고 다른 복잡한 문제들

스타크래프트는 그냥 게임이지만, 아주 복잡한 게임입니다. 저희는 AlphaStar를 뒷받힘 하는 기술들이 다른 문제 해결에 유용할 것이라 생각합니다. 예를 들면, 장시간 동안 많은 행동이 필요한 긴 sequence(때로는 수천, 수만의 움직임을 하는 1시간 경기 같은)같은 것들-완전하지 않은 정보들을 기반으로-에 도움이 될 수 있다고 생각합니다. 스타크래프트의 각 프레임은 입력의 한 단계로 사용되며, neural network는 매 프레임마다 나머지 게임에 대한 예상 동작 순서를 예측합니다. 매우 긴 데이터 sequence에 대해 복잡한 예측을 하는 근본적인 문제는 날씨 예측, 기후 모델링, 언어 이해 등과 같은 많은 실제 과제에서 나타납니다.

저희는 또한 우리의 훈련 방법 중 일부가 안전하고 견고한 인공지능 연구에 유용 할 수 있다고 생각합니다. AI에서 커다란 난제 중 하나는 시스템이 잘못 훈련 될 수 있는 가능성이 있으며 스타크래프트 프로 선수들은 이러한 실수를 유발할 창의적인 방법을 찾아 인공지능 시스템을 쉽게 이길 수 있음을 알았습니다. AlphaStar의 혁신적인 리그 기반 학습 과정은 가장 신뢰할 수 있고 잘못 될 가능성이 적은 접근 방식을 찾습니다. 저희는 AI 시스템의 안전성과 견고성을 향상시킬 수있는 이러한 접근법의 잠재력, 특히 에너지와 같이 안전성이 중요한 분야에서 복잡한 상황을 다루는 것이 필수적이라는 점을 기쁘게 생각합니다.

AlphaStar를 통해 만들어진 스타크래프트의 최고 수준의 플레이는 지금까지 만들어진 가장 복잡한 게임 중 하나를 돌파했다는 것을 의미합니다. 우리는 AlphaZeroAlphaFold와 같은 프로젝트와 함께 이러한 발전들은 언젠가는 세계에서 가장 중요하고 근본적인 과학적 문제에 대한 새로운 솔루션을 열어 줄 수 있는 지능형 시스템을 개발하려는 우리의 사명을 한 단계 진전시킨 것이라고 믿습니다.

Team Liquid의 TLO 및 MaNa에 대한 지원과 엄청난 기술에 감사드립니다. 우리는 블리자드와 스타크래프트 커뮤니티가 이 작업을 가능하게 하기 위해 지속적으로 지원해 주신 것에 대해서도 감사드립니다.


Download 11 replays here
Watch the exhibition game against MaNa
Watch a visualisation of AlphaStar’s entire second game against MaNa
AlphaStar Team:

Oriol Vinyals, Igor Babuschkin, Junyoung Chung, Michael Mathieu, Max Jaderberg, Wojtek Czarnecki, Andrew Dudzik, Aja Huang, Petko Georgiev, Richard Powell, Timo Ewalds, Dan Horgan, Manuel Kroiss, Ivo Danihelka, John Agapiou, Junhyuk Oh, Valentin Dalibard, David Choi, Laurent Sifre, Yury Sulsky, Sasha Vezhnevets, James Molloy, Trevor Cai, David Budden, Tom Paine, Caglar Gulcehre, Ziyu Wang, Tobias Pfaff, Toby Pohlen, Dani Yogatama, Julia Cohen, Katrina McKinney, Oliver Smith, Tom Schaul, Timothy Lillicrap, Chris Apps, Koray Kavukcuoglu, Demis Hassabis, David Silver

With thanks to:

Ali Razavi, Daniel Toyama, David Balduzzi, Doug Fritz, Eser Aygün, Florian Strub, Guillaume Alain, Haoran Tang, Jaume Sanchez, Jonathan Fildes, Julian Schrittwieser, Justin Novosad, Karen Simonyan, Karol Kurach, Philippe Hamel, Ricardo Barreira, Scott Reed, Sergey Bartunov, Shibl Mourad, Steve Gaffney, Thomas Hubert, Yuhuai Wu, the team that created PySC2 and the whole DeepMind Team, with special thanks to the RPT, comms and events teams.

Share 0 Comments

[챗봇] 페이스북 챗봇 만들기

나만의 페이스북 메신저 봇 만들기

2020.03.19 Updates

수정사항 : 원래 사용했던 nodejs 대신 python을 이용합니다.

이 글은 Python, Heroku server를 이용하여 자신만의 페이스북 챗봇을 만들어보는 템플릿 예제입니다.

챗봇이란?

챗봇은 사용자가 별도로 웹사이트나 앱을 따로 실행하지 않고도 대화하듯 정보를 얻을 수 있는 서비스다. 기존 사용자 자신이 쓰는 메신저를 통해 정보를 얻을 수 있다는 점이 현재 구글, 페이스북, 마이크로소프트, 텔레그램을 비롯해 국내 네이버, 다음 등 IT 분야 기업들이 챗봇을 기반으로 한 메신저 플랫폼을 선보이는 중이다.

[네이버 지식백과] 채팅봇, 챗봇 - 메신저 서비스 인공지능(AI)과 만나다 (용어로 보는 IT)

준비

  1. Python Version 3
  2. Terminal
    • 터미널 기반으로 배포하기 때문에 윈도우 사용자는 cmd나 터미널 환경을 갖추신 후에 따라하시면 됩니다. 윈도우 터미널 설치 가 도움이 되실겁니다.
  3. Git
  4. Heroku
    • heroku 에 가입합니다.
    • Heroku CLI가 필요합니다.
  5. Facebook Account
    • Facebook account가 필요합니다.
  6. Ngrok
    • Ngrok을 사용하여 Heroku에 배포하기 전, 내부 망에서 테스트를 하기 위해서 필요합니다.

디렉토리 설정 및 코드 작성

이 프로젝트를 위한 디렉토리를 하나 만들어줍니다.

1
2
3
4
mkdir chatbot
cd chatbot
pwd
/Users/username/chatbot

또한 python library들을 다운 받습니다.

1
sudo pip3 install Flask requests gunicorn

혹은

1
pip3 install --user Flask requests gunicorn

폴더를 만드셨다면 chatbot 폴더 내부에 파이썬 코드를 작성해줍니다.

app.py 라는 이름으로 코드를 작성해주시면 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
from flask import Flask, request
import requests
app = Flask(__name__)
FB_API_URL = 'https://graph.facebook.com/v2.6/me/messages'
VERIFY_TOKEN=''
PAGE_ACCESS_TOKEN=''
def send_message(recipient_id, text):
"""Send a response to Facebook"""
payload = {
'message': {
'text': text
},
'recipient': {
'id': recipient_id
},
'notification_type': 'regular'
}

auth = {
'access_token': PAGE_ACCESS_TOKEN
}

response = requests.post(
FB_API_URL,
params=auth,
json=payload
)

return response.json()

def get_bot_response(message):
"""This is just a dummy function, returning a variation of what
the user said. Replace this function with one connected to chatbot."""
return "This is a dummy response to '{}'".format(message)


def verify_webhook(req):
if req.args.get("hub.verify_token") == VERIFY_TOKEN:
return req.args.get("hub.challenge")
else:
return "incorrect"

def respond(sender, message):
"""Formulate a response to the user and
pass it on to a function that sends it."""
response = get_bot_response(message)
send_message(sender, response)


def is_user_message(message):
"""Check if the message is a message from the user"""
return (message.get('message') and
message['message'].get('text') and
not message['message'].get("is_echo"))


@app.route("/webhook", methods=['GET'])
def listen():
"""This is the main function flask uses to
listen at the `/webhook` endpoint"""
if request.method == 'GET':
return verify_webhook(request)

@app.route("/webhook", methods=['POST'])
def talk():
payload = request.get_json()
event = payload['entry'][0]['messaging']
for x in event:
if is_user_message(x):
text = x['message']['text']
sender_id = x['sender']['id']
respond(sender_id, text)

return "ok"

@app.route('/')
def hello():
return 'hello'

if __name__ == '__main__':
app.run(threaded=True, port=5000)

VERIFY_TOKEN와 PAGE_ACCESS_TOKEN은 이 다음 과정에서 페이스북 세팅 후, 채워넣을 예정입니다.

위와 같이 코드를 작성하셨다면 다음 단계로 넘어가겠습니다.

페이스북 설정

  1. Facebook Developer Page에 접속한 후 Create App을 눌러줍니다.

Create App

  1. App의 이름을 정해준 후에 Create App ID를 누릅니다.

Create App ID

  1. App이 만들어졌다면 다음과 같은 화면에서 Messenger의 Set Up 버튼을 눌러줍니다.

Messenger Set Up

  1. Access Tokens 내부 화면에서 Create New Page를 눌러서 페이지 생성을 진행합니다.

Access Tokens
Create New Page
Public Figure
Page Setting
Skip Photo
Page Done

  1. Page 생성이 완료되었다면 다시 Access Tokens 내부 화면으로 돌아와서 하단에 Add or Remove Pages를 눌러줍니다.

Access Tokens Add Page
What Pages
Allowed to
Add Page Done

  1. Generate Token을 눌러줍니다.

Add Page Done Generate

  1. I Understand에 체크표시하시고 밑에 생성된 Token을 복사한 뒤 따로 보관해둡니다.(나중에 코드에 들어가게 됩니다.)

Token Generated

Ngrok으로 테스트해보기

Ngrok으로 챗봇을 테스트 하기전에 먼저 app.py 파일 내부를 수정해줍니다.

1
2
3
4
5
6
from flask import Flask, request
import requests
app = Flask(__name__)
FB_API_URL = 'https://graph.facebook.com/v2.6/me/messages'
VERIFY_TOKEN='my_secret_token'
PAGE_ACCESS_TOKEN='ENNJLCNDJSLKABJVLNEJLKWANJLCNJEL.........'

위의 부분에서 VERIFY_TOKEN은 여러분이 원하는 비밀번호로, PAGE_ACCESS_TOKEN 안에는 아까 발급 받았던 그 token을 ‘’ 사이에 넣어주시면 됩니다.(이 파일을 open된 곳에 upload하지 마세요. 추후에 보안이 필요한 작업입니다.)

수정을 다 해주셨다면 Ngrok에 들어가셔서 Sign Up을 하신 뒤, ngrok을 다운받습니다. 저같은 경우에는 app.py가 위치하고 있는 폴더에 다운로드하였습니다.

ngrok

ngrok에서 설명하는 것 그대로 진행합니다.

다운로드 -> 압축해제를 진행한 뒤에 command 창에 3번 그대로 복사붙여넣기를 해주면, 접속을 위한 세팅이 완료되고 4번의 명령어와는 다르게 80대신 5000을 써줍니다.

1
./ngrok http 5000

을 실행하게 되면 다음과 같은 화면이 뜨게 됩니다.

ngrok_80

그리고 또 다른 터미널 창을 열어주신 뒤, app.py 파일을 실행해줍니다.

1
python app.py

run_app.py

이와 같이 ngrok과 app.py 가 모두 준비가 되었다면 다시 브라우저를 통해 access tokens 하단에 있는 webhook에서 Add Callback URL을 클릭합니다.

add_callback
set_callback
webhook
webhook_sub

이제 대략적인 세팅은 끝이 났습니다.

본인의 page에 hi라고 한번 메세지를 보내봅니다.

test_hi

성공적으로 제가 한 말을 따라합니다.

Heroku에 배포하기

Heroku에 배포하기 위해서 설치했던 Heroku CLI를 이용하여 배포해줄 것입니다.

heroku login을 실행하시고 기다리셨다가 press any key… 가 나오시면 enter 눌러주세요.

1
2
3
4
5
heroku login

heroku: Press any key to open up the browser to login or q to exit:
Opening browser to https://cli-auth.heroku.com/auth/cli/browser/.......................
heroku: Waiting for login... ⣷

heroku_login

로그인을 진행해주시면 다음과 같이 커맨드창에 나타납니다.

1
2
Logging in... done
Logged in as <your email address>

로그인이 성공적으로 완료되었다면 다음 명령어를 실행합니다.

1
heroku create

실행하면, heroku는 자동적으로 웹 서버를 만들기 시작합니다.

heroku_create

이제 생성된 Heroku App에 우리가 만든 소스를 배포시키려고 합니다.

배포하기 전에 다음과 같은 내용을 가진 requirements.txt을 만들어주고

1
2
3
Flask==1.0.2
requests==2.21.0
gunicorn==20.0.4

다음 내용을 가진 Procfile 을 만들어 줍니다.

1
web: gunicorn app:app

위의 과정까지 마치셨다면 다음 명령어들을 차례대로 실행합니다.

1
2
3
4
5
git init
git add .
git commit -m 'init'
heroku git:remote -a <your_project_name>
git push heroku master

밑의 사진들은 제가 실행시킨 결과입니다.

git_process
deploy_process

이와 같이 heroku에 배포를 완료했다면, 실행중인 ngrok을 꺼주시고 브라우저에서 callback을 수정합니다.

edit_callback
edit_callback_heroku

이 과정을 모두 수행하셨다면

마지막으로 page에 테스트 메세지를 보내봅니다.

final_test

마치며

기존 버전이 2017년 버전으로 되어있어서 많은 부분이 다르기 때문에

급하게 블로그 내용을 수정하였습니다.

추가적으로 내용 수정을 들어가겠으며 질문이 있으시면 얼마든지 코멘트 달아주세요.

제가 다룬 코드는 제 Github에서 확인하실 수 있습니다.

감사합니다.

Ref :

  1. https://github.com/davidchua/pymessenger
  2. https://hackernoon.com/beginners-guide-simple-chat-bot-fb-based-on-flask-and-heroku-2g7v32ab
Share 0 Comments

Hexo 시작하기

나만의 블로그

Github을 모르던 시절, 제가 만들었던 코드를 저장할 수 있고 설명할 수 있는 개인 블로그를 가지고 싶었습니다. 그래서 처음에는 네이버 블로그로 시작했지만, code를 적기에는 너무나 협소한 환경이었고 Tistory에 초청받아 사용해보았지만 불편한 것은 여전했습니다.

Github를 사용하기 시작하면서 markdown 언어를 알게 되었고 md를 통해서 블로그를 만들 수 있으면 좋겠다고 생각하고 Github Page를 통해 블로그를 만들기로 했습니다.


Github? Github Page? Hexo?

Github는 git을 사용하는 프로젝트를 지원하는 웹 호스팅 서비스이자 가장 인기있는 오픈소스 코드 저장소이기도 합니다. Github page는 사용자를 위해 static한 홈페이지(블로그)를 자동으로 만들어주고 이를 username.github.io으로 무료 호스팅해주는 서비스입니다. Hexo는 이 github pages를 이용한 블로그 프레임워크라고 말할 수 있죠. 초기 setting 후 간편한 명령어로 github에 deploy하면 자동으로 적용이 됩니다.


Hexo의 특징

  1. Blazing Fast
    Nodejs를 사용하여 빠른 속도로 생성하고, 빌드하는데에 필요한 수백개의 파일이 수초안에 해결이 됩니다.
  2. Markdown Support
    마크다운 언어를 지원합니다.
  3. One-Command Deployment
    하나의 명령어로 Github Page, Heroku, 다른 사이트에 배포가 가능합니다.
  4. Various Plugin
    Powerful한 플러그인들을 제공합니다.

다양한 기능과 특징이 있지만 웹프로그래밍언어 지식이 없으시다면 사용하기가 굉장히 어려울 것이라고 생각됩니다. HTML, CSS, JS, Git에 대한 이해가 요구됩니다.

Hexo 설치하기

Hexo를 설치하기 위해서는 다음 2개의 요소가 필요합니다.
-Node.js
-Git
이미 설치가 되신 상태라면 터미널에 다음과 같은 명령어를 입력하시면 됩니다.

1
$ npm install -g hexo-cli

자세한 설치 방법은 hexo hompage를 참고해주시기 바랍니다.

Hexo Setup하기

먼저 Blog를 구성하는 파일들을 저장할 폴더를 만듭니다. Github에 배포하실 분은 폴더명을 username.github.io로 만드시는 것을 추천해드립니다.

1
2
3
$ hexo init username.github.io
$ cd username.github.io
$ npm install

위의 절차를 거치셨다면 다음과 같은 디렉토리가 생성됩니다.

1
2
3
4
5
6
7
8
.
├── _config.yml
├── package.json
├── scaffolds
├── source
| ├── _drafts
| └── _posts
└── themes

가장 기본적인 테마로 만들어진 여러분의 블로그 파일입니다.
확인해보고 싶으시다면 로컬서버로 이를 확인할 수 있습니다.

1
$ hexo s

후에

1
2
INFO  Start processing
INFO Hexo is running at http://localhost:4000/. Press Ctrl+C to stop.

라는 문구가 뜨시면 localhost:4000으로 들어가셔서 확인하실 수 있습니다.

글쓰기

먼저 글의 종류에는 다양하지만 일단 2가지를 설명하겠습니다.
-draft
draft는 말 그대로 초안문서로써 posting은 하지 않으나 source폴더내의 _draft폴더 안에서 관리합니다.
-post
post는 나의 Blog에 들어갈 문서입니다. 배포시에 Blog에 바로 적용이 됩니다.

글을 쓸 때에는 터미널에서 명령어를 입력해서 시작할 수 있습니다.

바로 post할 글을 쓰기 위해서는

1
$ hexo new <filename>

초안문서를 먼저 만들고 싶으시다면

1
$ hexo new draft <filename>

로 글을 작성하실 수 있습니다.
draft완성 후에 post로 옮기고 싶으시다면

1
$ hexo publish <filename>

으로 _draft폴더에서 _post폴더로 옮길 수 있습니다.

먼저 위의 글생성 명령어를 실행하시면 폴더내에 해당 파일 이름을 가진 markdown형식의 파일이 생성될 것입니다.

1
2
3
4
5
6
title : hexo init
tags:
-hexo
date : 2017/02/23
---
My First Hexo!!

위와 같이 자신이 원하는 대로 글을 수정하시면 글을 생성하는 것이 완료되는 형식입니다.

Github에 배포하기

Github에 배포하기 위해서는 먼저 hexo-deployer-git이라는 플러그인이 필요합니다. 다른 플랫폼에 배포하기 원하시면 그에 해당하는 플러그인을 찾으신 후 설치하시면 됩니다.

1
$ npm install hexo-deployer-git --save

그리고 _config.yml에서 Github 정보를 입력해주셔야 합니다.

1
2
3
4
deploy:
type: git
repo: https://github.com/KorChris/korchris.github.io.git
branch: master

위와 같이 본인의 git repo의 정보를 입력해주신 후에

1
$ hexo generate

정적파일을 생성해줍니다.

혹시나 로컬서버에는 적용이 되는데 github에 적용이 되지 않으면 hexo clean 후에 hexo generate을 실행하시면 잘 되실꺼에요.

생성이 완료되었다면 마지막으로

1
$ hexo deploy

Deploy 명령어를 실행합니다. 디플로이가 완료가 되면 Github Repository와 Github Page에 적용된 것을 확인하실 수 있습니다.(약 1분의 시간이 걸릴 때도 있네요)

Share 0 Comments