취미/Programming | 2020. 5. 6. 23:02 | /24?category=733209

처음 Perceptron의 개념을 접한지 벌써 6년이 지났다. 

당시 Single Layer Perceptron (SLP)만 배웠었는데 신경망의 작동원리를 표방한 구조가 마음에 들어 다른 서적까지 뒤져가며 개념을 이해하려고 애썼다. 

 

선형대수도 제대로 알지 못했는데 구조가 단순해서 그런지 수학적으로 완벽하게 개념을 이해할 수 있었다. 

 

과제로 나온 문제 중 하나가 '왜 SLP는 XOR 문제를 풀지 못하는지 설명하라' 였는데 이에 대해서 완벽한 답을 내놓았을 때의 짜릿함이란...

 

4학년때 제출한 과제의 일부

SLP는 그 이후로도 다른 수업이나 특강에서 접할 기회가 많아서 익숙해졌지만 , 아직까지 Multi Layer Perceptron (MLP)를 완벽하게 이해하지 못했다. 수식을 외워서 어찌저찌 코드를 짤 수는 있었지만 왜 저런 수식이 나오는지 개념적으로 설명을 하지 못했다. 

 

지난 코드들을 정리하던 중 짜다 포기한 MLP 코드가 있길래 지금이라면 이해할 수 있지 않을까 하고 도전한 결과, 드디어 오랫동안 끝내지 못한 과제를 해결하게 되었다. 

 

이해한 개념을 잊지 않도록 SLP부터 정리하고 기록하려고 한다. 

 

Single Layer Perceptron

 Perceptron 구성에 필요한 것

  • input node의 수
  • output node의 수
  • 초기 weight 값
  • learning rate
  • epoch 수

먼저 network를 구성하기 위해서 필요한 것은 input node와 output node의 숫자다. 

 

input node의 수 : j
output node의 수 : k

 

일반적으로 "한 개"의 perceptron은 여러 개의 input을 받아서 하나의 output을 출력하는 대상을 말하기에 output node가 k개 있는 위의 예에서는 k개의 perceptron이 하나로 합쳐져 있는 것이라고 생각해야 한다.

 

하나의 Perceptron, 3개의 Perceptron

 

또 필요한 것은 사실상 학습이 일어나는 변수인 weight의 초기값이다. 

 

위와 같이 모든 node 들이 서로 연결된 fully-connect 조건인 경우 input node의 수 x output node의 수 (j x k) 만큼 weight 값이 필요하다. 

 

Output node에서는 이후 input node의 값들을 각각의 weight로 곱해주고 threshold를 넘냐 안넘냐로 output을 바꾸는데 이게 꽤 귀찮다. 

 

왜냐하면 이 threshold를 잘못 정하면 학습이 전혀! 일어나지 않기 때문이다. 

 

그래서 사용하는 방법이 input node가 비록 j개만큼 있지만 항상 1 값을 내놓는 가상의 node를 만들고 weight의 수를 (j x k)가 아닌 (j+1 x k) 로 설정하는 것이다.

 

이러면 모든 output node의 threshold를 0으로 설정해도 이 가상의 node를 통해 threshold 값이 조정된다.

 

이러한 가상의 node를 bias 라고 한다.

 

항상 1의 값을 출력하는 가상의 bias node를 도입하면 threshold를 생각할 필요가 없다.

 

이렇게 하면 나중에 weight update를 할 때 weight 값이 바뀌면서 각각의 node의 threshold가 바뀌게 되고, 각 node 별로 최적의 threshold가 구해질 것이다. 

 

weight matrix : W => (j +1 x k)

 

초기 weight 값을 구하는 것에는 다양한 방법이 있으나 편의상 -1과 1 사이의 무작위 값으로 쓰도록 하자. 

 

마지막으로 매번 학습마다 weight 값을 얼마만큼 바꿀지에 대한 learning rate (보통 0.1 정도면 충분) 와 전체 training sample을 몇번 돌려가며 학습을 시킬지에 대한 epoch ( 일단 100정도) 이 필요하다. 

 

import numpy as np

# Constants
num_input_node = 4
num_output_node = 3
learning_rate = 0.1
num_epoch = 100

# Variables
weights = np.random.rand(num_input_node + 1, num_output_node) * 2 -1
# rand 함수는 0~1 사이 값을 주기에 x2-1을 하면 -1과 1 사이의 값이 나온다.

Feed Forward 계산

j+1개의 값들을 각각의 weight들과 곱한 뒤, 합하는 작업을 총 perceptron의 수인 k번 해야한다. 

 

물론 Method 1처럼 for 문을 두 번 사용하면 해결이 되겠지만 Method 2처럼 코드 한줄로 모든 연산을 끝낼 수 있다. 

 

바로 선형대수를 이용하는 것이다. 

 

# Method 1
for perceptron in range(k):
    for node in range(j+1):
        output_node[perceptron] += weight[node, perceptron] * input_node[node]

# Method 2
output_node = np.dot(weight.T, input_node)

 

대학원 인공지능개론 수업에서는 교수님이 학생들이 전부 선형대수를 완벽히 알고있다고 가정하고 설명을 하시던데 물리/정보계 이과가 아니어서 그런지 나는 고등학교때 행렬 연산 지식이 전부다.

 

이 수업을 따라가려고 선형대수로 유명하다는 Strang 교수님의 선형대수 책 스터디도 진행을 했는데 정작 머릿속에 남아있는 개념은 딱 두 가지이다. 

 

행렬의 곱, dot product와 dot product 에서의 차원 계산

 

1. The dot product (행렬의 곱)

Dot product 계산

k x j 형태의 matrix와 j x 1 형태의 matrix (혹은 columnar vector) 의 Dot product는 위와 같이 계산된다. 

 

복잡해보이지만 좌측 matrix의 한 행의 원소들(총 j개)를 각각 같은 위치에 있는 우측 matrix의 열의 원소들(총 j개)로 곱해준 뒤 이를 전부 합해주면 한 행의 element가 완성이 된다. 

 

어짜피 하는 연산은 for 문 2개를 돌리는 것과 같지만, 이렇게 각각의 원소들을 다른 matrix의 대응하는 원소와 곱한뒤 이를 합하는 연산이 Perceptron 외에도 정말 자주 등장하기에 수학에서 이러한 연산을 dot product라고 따로 정의한 것 같다. 

 

물리에서 벡터 연산이나 간단한 선형 방정식에서도 자주 본 적이 있다. 

 

2. The dimension of the dot product

 

위에 언급한 부분을 잘 보면 두 matrix의 dot product를 구할 때 중요한 조건이 있다. 

 

 

"좌측 matrix의 한 행의 원소들(총 j개)를 각각 같은 위치에 있는 우측 matrix의 열의 원소들(총 j개)로 곱해준 뒤 이를 전부 합해주면 한 행의 element가 완성이 된다."

 

바로 좌측 matrix의 열의 수와 우측 matrix의 행의 수가 일치해야 연산이 가능하다는 것이다.

 

또한 연달아 dot product를 계산하면 최종 결과는 최좌단 matrix의 행의 수 x 최우단 matrix의 열의 수 가 된다. 

 

예를들어, matrix A, B, C가 각각 axb, bxc, cxd 의 차원을 가지고 이들은 전부 곱하면, 최종결과는 a x d가 된다. 

 

이 개념이 아주 중요하다. 

 

끽해야 2-3개의 행과 열로 된 matrix를 다루는 손으로 푸는 문제는 바로 어떻게 연산을 해야할지 보이는데, 수십, 수백개의 행과 열로된 matrix를 컴퓨터로 연산을 할 때는 matrix의 구조가 보이지 않아서 차원이 맞지 않는 오류가 나기 쉽다.

 

그래서 곱해야할 것들을 정하고, 원하는 결과의 차원을 정한뒤, matrix 자체는 보지 않고 matrix의 dimesion만 보면서 코딩을 해나간다.

 

다시 SLP로 돌아가서, 현재 weight은 (j +1 x k)로 되어있고, input node의 수는 j+1. 

 

원하는 연산을 위해서는 weight matrix의 행과 열을 바꾸고 bias를 포함한 input node와 곱해주면 된다. 

 

참고로 이렇게 행과 열을 바꿔주는 행위를 transpose 라고 하고 위에 작은 T 첨자를 붙인다.

 

W위의 작은 T 기호는 matrix를 행과 열을 바꿔서 뒤집었다는 뜻이다. 

처음 배울때 선형대수만큼 짜증나는 것은 없다!

 

덧샘과 곱샘만 있음에도 당장 위에 수식만 봐도 머리가 돌아버릴 것 같다. 

 

그런데 저런 모든 과정을 ∑ 기호를 쓰지 않고 아래와 같이 단순한 기호로 표시할 수 있다는 것은 정말 큰 장점이다.

 

심플 그 자체

처음에만 위에 기나긴 수식을 하나 하나 따라가면서 이해하고, 그 이후로는 각 matrix의 차원만 봐도(얘가 j x k 인지 k x j 인지) 전혀 문제가 없으니 걱정 마시라!

 

우리가 해야할 부분은 dot product를 언제 써야하는지 아는 것과, dot product를 낼 두 matrix의 차원을 맞춰주는 것 뿐이다. 

import numpy as np

# Constants
num_input_node = 4
num_output_node = 3
learning_rate = 0.1
num_epoch = 100

# Variables
weights = np.random.rand(num_input_node + 1, num_output_node) * 2 -1
# rand 함수는 0~1 사이 값을 주기에 x2-1을 하면 -1과 1 사이의 값이 나온다.

##############################여기부터##############################################

# Feed Forward
input_node = np.vstack([[[1]],x]) # input vector x 위에 bias를 위한 원소 1을 추가해준다.
a = np.dot(weights.T, input_node)

Backpropagation 계산

다음 단계는 총 k개의 perceptron마다 나온 a 값을 실제로 나와야 하는 값이랑 비교하는 것이다. 

 

desired output의 d를 따서 d라고 부르겠다. 

 

Error = desired output(d) - actual output(a)

값이 k x 1 의 형태로 나올 것이기에 desired output도 똑같이 모든 perceptron, 혹은 output node의 desired output 값을 column vector 화 해서 서로 빼주면 k x 1 의 형태로 error를 구할 수 있다. 

 

 

4개의 input node가 있는 perceptron. error 값 -2.173을 weight에 반영해주어야 한다. 

예로 위 처럼 input node가 총 4개 있는 perceptron은 총 5개의 weight 값(4+1)가질 것이다. 

 

feedforward 계산에 의해서 actual output은 3.173이 나왔다. 

 

desired output이 1이라고 할 때 위의 Error 정의대로라면 Error는 -2.173이 나오며 이는

 

"실제 나오는 값이 desired 보다 훨씬 크니, weight 값을 - 방향으로 움직여라(=줄여라)"

 

를 의미한다.

 

문제는 이 -2.173을 5개의 weight 값에 모두 동일하게 반영하면 안되고, input node의 값에 차등적으로 반영을 해야한다는 것이다. 

 

Error를 만드는데 기여도가 높은 node의 weight 일 수록 weight 변경을 많이 해야한다. 

 

bias를 제외한 첫 번째 node의 경우 7.7의 값이 들어왔다. 그에 비해서 두 번째 node는 0.3이 들어왔다. 

 

당연히 저 -2.173이라는 큰 error 값에 기여한 부분이 첫 번째 node가 두 번째 node보다 크므로, 더 큰 값을 weight 에서 빼주어야 할 것이다. 

 

어짜피 learning rate 때문에 한번에 많은 양의 weight 변화가 생기지는 않을 것이므로, 이러한 Error의 기여도의 차이를 단순히 error에 input node의 값을 곱해주는 식으로 계산하면 편하다. 다음과 같이 말이다. 

 

앞에 곱해진 0.1은 learning rate 이다. 

똑같은 짓을 k개의 perceptron에 대해 진행해야 하는데 이 역시 dot product로 할 수 있다. 

 

살짝 편법이기는 하지만, 궁극적으로 우리가 알고 싶은건 (j +1 x k) 형태로 있는 weight의 각각의 원소에 얼마만큼의 값을 빼주어야 하는지 이므로 weight 변화량 또한 (j +1 x k)형태일것이다.

 

bias를 포함한 input node => (j+1 x 1)
Error => k x 1
원하는 형태 => (j +1 x k)

어떻게 dot product를 계산해야할지 알겠는가?

 

bias를 포함한 input node와 Error의 행과 열을 바꾼 값을 서로 dot product 해주면 

(j+1 x 1) dot 1 x k  =j +1 x k 가 된다.

 

import numpy as np

# Constants
num_input_node = 4
num_output_node = 3
learning_rate = 0.1
num_epoch = 100

# Variables
weights = np.random.rand(num_input_node + 1, num_output_node) * 2 -1
# rand 함수는 0~1 사이 값을 주기에 x2-1을 하면 -1과 1 사이의 값이 나온다.

# Feed Forward
input_node = np.vstack([[[1]],x]) # input vector x 위에 bias를 위한 원소 1을 추가해준다.
a = np.dot(weights.T, input_node)

##############################여기부터##############################################

# Backpropagation
Error = desired_output - a
new_weights = weights - learning_rate*( np.dot(input_node, Error.T) )

 

이러한 과정을 모든 dataset에 대해서 epoch 번 만큼 반복해 주면 된다.

 

sklearn에 있는 가장 유명한 dataset인 iris 데이터를 사용해서 위의 모든 내용을 코드로 바꾸면 아래와 같다. 

 

코드가 전부 돌아가면 정확도 값이 나올 것이다.

 

import numpy as np
from sklearn import datasets

data = datasets.load_iris()
X = data.data
y = data.target

# Constants
num_input_node = 4
num_output_node = 3
learning_rate = 0.01
num_epoch = 1000

# Variables
weights = np.random.rand(num_input_node + 1, num_output_node) * 2 -1
# rand 함수는 0~1 사이 값을 주기에 x2-1을 하면 -1과 1 사이의 값이 나온다.
for epoch in range(num_epoch):
    for sample,target in zip(X,y):
        # Make input node to column vector
        x = np.reshape(sample, [4, -1])
        # Feed Forward
        input_node = np.vstack([[[1]],x]) # input vector x 위에 bias를 위한 원소 1을 추가해준다.
        a = np.dot(weights.T, input_node)

        # Make desired output to column vector
        desired_output = np.zeros([3,1])
        desired_output[target] = 1

        # Backpropagation
        Error = desired_output - a
        new_weights = weights + learning_rate*( np.dot(input_node, Error.T))
        weights = new_weights

score = 0
for sample,target in zip(X,y):
    # Make input node to column vector
    x = np.reshape(sample, [4, -1])
    # Feed Forward
    input_node = np.vstack([[[1]], x])  # input vector x 위에 bias를 위한 원소 1을 추가해준다.
    a = np.dot(weights.T, input_node)
    score += int(np.argmax(a) == target)
print(score / len(X))

 

이대로 코드를 짜면 정확도 값이 0.66을 넘기는 것을 본 적이 없다. 

 

이는 개념의 단순화를 위해서 activation function을 쓰지 않았기 때문이다. 

 

activation function을 쓰지 않으면 actual output 값이 한없이 크거나 작게 나오는 것이 가능하고, 이는 곧 한없기 크거나 작게 weight 값의 변경이 가능하다는 것이다. 

 

실제로 위에서 learning rate 을 0.01로 사용했는데, 이보다 커지면 어느순간 최종 weight 값들이 inf (무한대)로 뜨기 시작한다.

 

activation function을 쓰면 극단적인 weight 변화라는 문제를 해결할 수 있지만, Error를 weight 값에 반영해 주는 방법을 바꿔주어야 한다. 

 

여기서부터가 가장 어려운 개념이다. 

 

Partial Derivative (편미분)과 Error

최대한 쉽게 설명하려고 노력하겠다.

 

우리가 결국 Perceptron을 만들면서 궁극적으로 원하는 것은 단 하나다.

 

Weight 값을 변화, 즉 증가시키거나 감소시켜서 Error를 줄이는 것

"변화" 라는 단어만 나오면 수학에서 바로 튀어 나오는 것이 바로 미분이다. 

 

대체로 미분을 배울때 미분을 계산하는 부분에 많은 시간을 써서 그런지 미분이 의미하는 것을 잊는 경우가 있다. 

 

특정 함수 f(x)를 미분해서 새로운 함수 f'(x)를 만들고, x에 특정한 값, 예를들어 3, 을 넣어주면 f(x) 함수의 숫자 3에서의 기울기를 알려준다. 

 

f'(3)이 양수이면, f(3)인 지점에서 기울기가 오른쪽으로 증가한다는 뜻이니, f(3+아주 작은 수)의 값이 f(3)보다 클 것이다.

 

반대로 음수이면, f(3+아주 작은 수)의 값이 f(3)보다 작을 것이다.

 

만약에, X축이 weight, Y축이 Error인 아래의 좌측과 같은 그래프가 있다면 가장 적절한 weight 값은 어디일까?

 

선택한 weight 값에 따른 Error의 변화

당연히 중심부근에 있는 Error가 가장 작아지는 지점이다. 

 

하지만 이런 그래프를 쉽게 그릴 수 있었다면 고등학교 2학년 방학숙제로 알파고를 만드는 내용이 나갔을 것이다. 

 

대신 만약에 오른쪽과 같이 특정 weight 지점에서 weight-Error 그래프의 기울기라도 알 수 있으면 어떨까?

 

위의 예처럼 그래프의 기울기가 양수라면, weight을 증가시키면 Error가 증가하니 weight 값을 살짝 감소시키면 적어도 지금보다는 Error가 작아질 것이라고 확신할 수 있다. 

 

 

또한 weight 값을 얼마나 감소 시켜야 할지도 대략 알 수 있다.

 

아래의 그림 모두 미분값의 기울기가 음수라 weight을 증가시키는 것이 Error를 낮출 가능성이 높다. 

 

어느 경우 weight를 더 많이 증가시켜야 할까?

 

좌측의 경우 weight이 커지면 슬슬 그래프가 평평해질 것 같다. 

 

그에 비해서 우측의 경우는 신나게 아래로 내려가는 중인 것 같다. 

 

이런 경우 우측의 경우 많이 weight 값을 증가시켜도 될 것 같지만, 좌측의 경우 너무 많이 weight 값을 증가시켰다가는 Error가 더 올라가버릴지도 모른다. 

 

즉, weight은 Error를 weight로 미분한 값의 반대방향으로 움직어야 한다. 

 

길어진 n 모양의 기호는 eta 이며 learning rate을 뜻한다. 

 

W의 변화량 = learning rate * (W에 대한 Error의 기울기) 의 반대

 

 

여기까지 이해가 되었다면 Error를 weight로 미분한 값만 알면 weight을 어떻게 바꿔야 할지 알 수 있다는 것을 눈치챘을 것이다. 

 

기울기를 구하는 것이니 미분을 쓰면 될텐데, 편미분은 또 무슨 말일까?

 

편미분은 미분과 다른 것이 없다. 단지 미분을 하는데, 다른 변수는 다 무시해버리고 관심있는 변수로만 미분을 한다는 것이다. 

 

예를들어 아래와 같은 수식이 있다고 하자.

 

x는 그렇다고 해도 그 뒤가 무시무시하다.

 

함수 f는 x,y,z의 세 변수에 대한 복잡한 함수이다. 

 

이를 x에 대해서 편미분을 하라는 것은 x 이외의 변수는 모두 상수로 보고 x에 대해서만 미분을 하면 된다. 

 

뒷쪽 항에는 x가 없으므로 x에 대해서 편미분 하면 통째로 사라진다.

참고로 편미분의 기호는 d 가 아닌 6을 거꾸로 쓴 듯한 기호로 표기한다.

 

편미분의 의미는 다른 변수들은 내 알 바 아니고 원하는 변수의 증감이 전체 함수의 기울기에 어떤 영향을 미치는지를 알려주는 것이다. 

 

결론적으로 편미분 이야기를 꺼낸 이유는, weight의 변화에 따라 Error가 어떻게 달라지는지를 알기 위함, 즉, 아래의 값을 구하면 weight를 올릴지 내릴지 알 수 있다.

 

양이라면 weight을 줄이고, 음이라면 weight를 늘리고.

partial derivative의 또 다른 특성 중 하나는 chain rule 이다.

 

미분 가능한 함수들을 서로 연달아 배치해서 계산을 하는 방법인데, 수학적으로 말하자면 이 chain rule이 있기에 multi layer perceptron이 성립할 수 있다. 

 

위와 같이 partial derivative 하나를 두 개로 쪼개서 계산할 수 있다. 

 

그래서 SLP에 이를 적용해보자. 

 

뭔가 이상하다. 

 

저대로 가면 W가 있는 항이 우측 항 밖에 없으니 상수인 desired input은 W로 미분하면 사라진다. 

 

Error function의 정의가 partial derivative 를 사용한 weight update방식에 맞지 않아서 그렇다. 

 

desired output과 actual output의 차이의 제곱을 2로 나눈 것을 Error로 사용하기로 하면 문제가 해결된다. 

 

어? 맘대로 Error function을 바꿔도 되나?

 

상관 없다. desired output과 actual output의 차이가 줄어들 수록 Error function의 값이 줄어들기만 하면 어떤 Error function을 써도 문제가 없다. 

 

결과는 다음과 같다. 

 

(d-a)는 Error, 그 뒤의 항은 input node의 값이다. 

 

정확하게 우리가 위에서 본 식이다. 

 

눈치챘을 수도 있지만 Error function 앞에 붙여둔 1/2는 정말 아무 의미없는 숫자다. (1/100 로 해도 된다.)

 

대신 1/2로 해두면 미분할 때 위에 있던 2가 똑 떨어져 나오기 때문에 위처럼 식이 깔끔해질 수 있다.

 

Single Layer Perceptron - with activation function

activation function은 input node와 각각의 weight 들의 곱의 합, 즉 a 값이 특정 범위 내에 있도록 해주는 함수이다. 

 

가장 많이 사용하는 함수는 sigmoid, tanh, ReLU function 이며 output node의 값이 극단적으로 나오지 않도록 제한해주는 역할을 한다. 

 

빨강 : sigmoid, 파랑 : tanh, 보라 : ReLU

X 값에 따라 제한된 범위에서 Y값이 나오도록 하는 것 외에 activation function에는 한가지 요구사항이 붙는다. 

 

바로 미분 가능성이다. 

 

미분이 가능해야 나중에 partial derivative를 구할 수 있기에 위의 세 그래프 모두 X에 대해서 미분이 가능하다. 

 

이 이후로 부터는 activation function으로 sigmoid 함수를 사용하도록 하겠다.

 

 

이 sigmoid 함수는 미분을 하면 재미있는 모습을 보여주는데, sigmoid 함수 y=f(x)는 미분을 하면 y(1-y) 로 표현이 된다.

 

미분하기 전 값으로 미분 후의 값을 표현할 수 있는 것이다.

 

위에서 언급한 tanh 함수도 미분을 하면 자기 자신으로 표현을 할 수 있으며, 이런 특성은 이후 아주 편리하다.

 

Feed Forward 계산

activation function이 없는 경우와 똑같다.

 

단지 node와 weight의 dot product를 바로 output으로 쓰는 것이 아니라 이 값을 activation function에 집어넣어서 나온 값을 output으로 사용한다.

 

아래에서 각 node의 weighted sum을 구한 뒤, sigmoid 함수에 넣어서 0.9598 이라는 값을 뽑아내는 것을 볼 수 있다.

 

위에서 사용한 코드의 맨 아래 한 줄만 추가하면 feed forward 파트는 끝이다. 

 

import numpy as np

# Constants
num_input_node = 4
num_output_node = 3
learning_rate = 0.1
num_epoch = 100

# Variables
weights = np.random.rand(num_input_node + 1, num_output_node) * 2 -1
# rand 함수는 0~1 사이 값을 주기에 x2-1을 하면 -1과 1 사이의 값이 나온다.

# Feed Forward
input_node = np.vstack([[[1]],x]) # input vector x 위에 bias를 위한 원소 1을 추가해준다.
a = np.dot(weights.T, input_node)
##############################여기부터##############################################
output_node = 1 / (1+np.exp(a))

Backpropagation 계산

위에서 언급한 partial derivative를 쓰면 Error에 대한 weight의 영향을 아래처럼 계산할 수 있다.

 

참고로 a는 input node에 각각 해당하는 weight 값을 곱하고 합한 값

 

y는 이 a를 activation function을 통과한 값이다. 

 

x에 weight을 곱하고 합하기(=a). 이 결과를 sigmoid 함수에 넣기(=y)

 

마지막 식을 차원에 맞춰서 정렬한 후, 코드로 바꾸면 아래와 같다.

 

import numpy as np

# Constants
num_input_node = 4
num_output_node = 3
learning_rate = 0.1
num_epoch = 100

# Variables
weights = np.random.rand(num_input_node + 1, num_output_node) * 2 -1
# rand 함수는 0~1 사이 값을 주기에 x2-1을 하면 -1과 1 사이의 값이 나온다.

# Feed Forward
input_node = np.vstack([[[1]],x]) # input vector x 위에 bias를 위한 원소 1을 추가해준다.
a = np.dot(weights.T, input_node)
output_node = 1 / (1+np.exp(a))

##############################여기부터##############################################

# Backpropagation
delta = -(desired_output - output_node) * output_node * (1-output_node)
new_weights = weights + learning_rate*( np.dot(delta, input_node.T).T )

 

코드 중간에 delta 라는 변수를 따로 만들고 나중에 bias를 포함한 input node의 값을 곱해주었다. 

 

이를 반영해서 돌아가는 iris 코드는 다음과 같다.

 

import numpy as np
from sklearn import datasets

data = datasets.load_iris()
X = data.data
y = data.target

# Constants
num_input_node = 4
num_output_node = 3
learning_rate = 0.1
num_epoch = 1000

# Variables
weights = np.random.rand(num_input_node + 1, num_output_node) * 2 -1
# rand 함수는 0~1 사이 값을 주기에 x2-1을 하면 -1과 1 사이의 값이 나온다.
for epoch in range(num_epoch):
    for sample,target in zip(X,y):
        # Make input node to column vector
        x = np.reshape(sample, [4, -1])
        # Feed Forward
        input_node = np.vstack([[[1]],x]) # input vector x 위에 bias를 위한 원소 1을 추가해준다.
        a = np.dot(weights.T, input_node)
        output_node = 1 / (1 + np.exp(-a))

        # Make desired output to column vector
        desired_output = np.zeros([3,1])
        desired_output[target] = 1

        # Backpropagation
        delta = -(desired_output - output_node) * output_node * (1-output_node)
        new_weights = weights - learning_rate*( np.dot(delta, input_node.T).T)
        weights = new_weights

score = 0
for sample,target in zip(X,y):
    # Make input node to column vector
    x = np.reshape(sample, [4, -1])
    # Feed Forward
    input_node = np.vstack([[[1]], x])  # input vector x 위에 bias를 위한 원소 1을 추가해준다.
    a = np.dot(weights.T, input_node)
    output_node = 1 / (1 + np.exp(-a))
    score += int(np.argmax(output_node) == target)
print(score / len(X))

Multi Layer Perceptron

편미분과 말도 안되는 선형대수를 뚫고 위 까지 이해를 했다면, MLP도 정말 쉽게 넘어갈 수 있다. 

 

중간에 back propagation에 한 스텝이 추가될 뿐이다. 

 

node가 총 3개가 되고 이에따라 weight matrix도 두개가 필요하다. 

 

input, hidden, output으로 명명하면 혼돈의 여지가 있어서 순서대로 n1, n2, n3로 명명하고 weight 들은 첨자로 어느 노드 사이에 있는 weight 인지 달아두었다. 

 

Feed Forward 계산

import numpy as np

# Constants
num_n1_node = 4
num_n2_node = 3
num_n3_node = 4
learning_rate = 0.1
num_epoch = 100

# Variables
W_12 = np.random.rand(num_n1_node + 1, num_n2_node) * 2 - 1
W_23 = np.random.rand(num_n2_node + 1, num_n3_node) * 2 - 1

# Feed Forward
n1 = np.vstack([[[1]],x]) # input vector x 위에 bias를 위한 원소 1을 추가해준다.
a2 = np.dot(W_12.T, n1)
n2 = 1 / (1 + np.exp(-(a2)))
n2 = np.vstack(([[1]], n2))
a3 = np.dot(W_23.T, n2)
n3 = 1 / (1 + np.exp(-(a3)))

 

Backpropagation 계산

W23의 계산

W23은 output node인 n3와 직접 연결되어 있기에 Single Layer 처럼 구하면 된다.

 

문자들만 달라졌지 위에서 작성한 식과 똑같다. 

 

W12의 계산

 

W23의 경우는 바로 output node와 연결이 되어 있어서 어느 부분을 고치면 되는지 직관적으로 알 수 있는데, W12의 영향력은 W23을 한번 더 지나서 나타나기에 중간 연결고리를 모른다.

 

대신 우리는 각각의 값들의 아래의 연결고리를 안다.

 

a2랑 W12가 같이 있는 식이 있고, a2 & n2 | n2 & a3 | a3 & n3 | Error 와 n3가 같이 있는 식도 알고 있다.

 

따라서 이러한 연결구조를 활용해서 chain rule을 통해 아래의 식을 구할 수 있다. 

 

초록색 부분은 중간단계를 생략하고 바로 수식을 적었는데 앞에서 계산한 W 23에 같은 부분이 등장하기 때문이다.

마지막 식의 첫 파란 항에서 W23 위에 *이 붙어있는데, 이는 첫째행을 제외한 W23을 말한다.

 

이 행을 지워주는 이유는 두 가지 방법으로 설명할 수 있는데, 

 

일단, 편미분을 bias를 포함한 n2로 하는 것이 아니라 n2로만 하기에 Weight에서 bias 관련 부분을 빼고 나머지 값만 써주는 것이라고 설명할 수 있다. 

 

다른 방법으로는 W23의 첫째 행에는 n2의 bias와 n3를 연결하는 weight 값이 들어있는데, n1과 n2의 bias는 서로 연결되어 있지 않으므로 n2의 bias 관련 정보는 빼주는 것이라고도 설명할 수 있다. 

 

 

*을 붙인 W에서는 맨 윗행의 node2:bias와 연결된 weight 들이 빠져있다.

 

겨우 끝났다. 

 

이 모든 과정을 코드로 정리하면 아래와 같다.

 

import numpy as np

# Constants
num_n1_node = 4
num_n2_node = 3
num_n3_node = 4
learning_rate = 0.1
num_epoch = 100

# Variables
W_12 = np.random.rand(num_n1_node + 1, num_n2_node) * 2 - 1
W_23 = np.random.rand(num_n2_node + 1, num_n3_node) * 2 - 1

# Feed Forward
n1 = np.vstack([[[1]],x]) # input vector x 위에 bias를 위한 원소 1을 추가해준다.
a2 = np.dot(W_12.T, n1)
n2 = 1 / (1 + np.exp(-(a2)))
n2 = np.vstack(([[1]], n2))
a3 = np.dot(W_23.T, n2)
n3 = 1 / (1 + np.exp(-(a3)))

##############################여기부터##############################################

# Backpropagation
delta23 = -(desired_output - n3) * n3 * (1-n3)
W_23 = W_23 - learning_rate * np.dot(delta_23, n2.T).T

# 위에서 n2 변수를 bias를 포함해서 정의했기에 여기서는 [1:,:] 인덱싱을 사용해 맨 윗행 값을 뺀다. 
# 또한 W_23에서도 맨 윗행 값을 뺀다.
delta_12 = np.dot(W_23[1:, :], delta_23) * n2[1:, :] * (1 - n2[1:, :])
W_12 = W_12 - learning_rate * np.dot(delta_12, n1.T).T

 

iris 데이터에 적용한 코드는 아래와 같다. 

 

import numpy as np
from sklearn import datasets
from sklearn import model_selection

data = datasets.load_iris()
X = data.data
y = data.target

# Select node
num_n1_node = 4
num_n2_node = 12
num_n3_node = 3

# Generate model
W_12 = np.random.rand(num_n1_node + 1, num_n2_node) * 2 - 1
W_23 = np.random.rand(num_n2_node + 1, num_n3_node) * 2 - 1

num_epoch = 1000
learning_rate = 0.2

for epoch in range(num_epoch):
    for sample, target in zip(X,y):
        # Forward
        n1 = np.reshape(np.append([1], sample), [num_n1_node + 1, -1])
        a2 = np.dot(W_12.T, n1)
        n2 = 1 / (1 + np.exp(-(a2)))
        n2 = np.vstack(([[1]], n2))
        a3 = np.dot(W_23.T, n2)
        n3 = 1 / (1 + np.exp(-(a3)))

        # Backward
        DesiredOutput = np.zeros([num_n3_node, 1])
        DesiredOutput[target] = 1
        Error = 0.5 * (DesiredOutput - n3) ** 2
        delta_23 = -(DesiredOutput - n3) * n3 * (1 - n3)
        W_23 = W_23 - learning_rate * np.dot(delta_23, n2.T).T

        delta_12 = np.dot(W_23[1:, :], delta_23) * n2[1:, :] * (1 - n2[1:, :])
        W_12 = W_12 - learning_rate * np.dot(delta_12, n1.T).T

score = 0
for sample, target in zip(X,y):
    n1 = np.reshape(np.append([1], sample), [num_n1_node + 1, -1])
    y1 = np.dot(W_12.T, n1)
    n2 = 1 / (1 + np.exp(-(y1)))
    n2 = np.vstack(([[1]], n2))
    y2 = np.dot(W_23.T, n2)
    n3 = 1 / (1 + np.exp(-(y2)))
    score += int(np.argmax(n3) == target)
print(score / len(X))

아직 이것보다 더 쉽게 Multi Layer Perceptron을 설명하는 글을 보지 못했다.

Multi layer를 도입하기 위해서는 partial derivative 개념은 필수이며, 2차원 weight matrix에 대한 연산을 설명하기 위해서는 Sigma로 도배하거나, 선형대수로 머리를 터뜨려야 한다. 

 

그나마 선형대수를 사용하는 것이 겉으로 보기에 아주 깔끔하고 정돈되어 있어서 굳이 이 방법을 사용했다. 

 

하나 고백하자면 matrix와 matrix의 partial derivative는 제대로 정의가 되어있지 않다고 한다. (wiki 참고)

 

따라서 matrix calculus를 제대로 배운 사람이라면 말도 안되는 transpose, 맘대로 어기는 Commutative property에 혀를 찰 것이며 제대로 계산을 하기 위해서는 다른 방법을 써주어야 하는 것 같다. 

 

matrix calculus 부분은 다음을 위한 과제로 남겨두려고 한다. 

 

어찌되었건, dimension만 제대로 맞춰주면 위의 코드는 돌아간다!

 

마치며

 

기계학습에 대한 대중들의 관심이 높아져서 그런지 관련 사기꾼들도 같이 늘어나는 것 같다. 

 

내 연구 프로젝트에 대해서 생뚱맞게 4차 산업혁명이나 인공지능과 관련있는 점이 있냐고 물어보는 사람들이 있는가 하면, 기계학습과 인공지능의 차이도 모르는 사람들이 아무곳에나 "자율형", "인공지능" 등의 말을 붙이고 다닌다. 

 

물론, 어떠한 학문이든 진입 장벽은 낮을수록 좋고, 누구나 쉽게 분야에 참여해 배워보고, 그 유용성을 누려야 한다고 생각한다. 

 

하지만 가상악기와 MIDI를 사용해서 바이올린을 연주하는 사람이 "나는 바이올린을 잘 안다!" 라고 말하면 안되듯이 남이 만들어 놓은 코드 몇 줄로 classifier를 만들고 기계학습을 잘한다고 말하면 안된다. 

 

더욱이 기계학습을 연구에 사용하거나, 실무에 사용하는 경우 적어도 기저 개념을 한번이라도 유도해보지 않으면 주의점과 한계들을 놓쳐서 치명적인 오류를 범할 수 있을 것이다. 

 

자신과 관련된 분야에 대중의 관심이 많아질 수록, 보다 겸손하고 신중한 자세를 취하는 것이 옳은 것 같다.

 

 

- 부족한 글 읽어주셔서 감사합니다. 

- 오류나 오타가 있으면 댓글로 감사히 받겠습니다. 

Posted by Admin Knowblesse
0 Comments

이 시리즈를 포스팅하게 된 계기는 한달전부터 Ubuntu 를 사용을 시작한 것이다.

vim과 터미널 명령어들을 배우면서 슬슬 GUI보다 CUI에 익숙해지고 있어서 git도 이제 GUI 프로그램을 사용하지 않고 명령어를 외어서 사용하려는 중이다. 하지만 git에 입문하는 처음이라면 꼭 GUI 프로그램을 사용해라.하는 것을 추천한다.

대체 누가 git 입문 책에서 CUI로 알려주는지. git은 꼭 GUI로 시작해라.

 

처음에는 branch라는 개념이 직관적으로 다가오지 않으며, 여러 branch가 꼬이기 시작하면 머리도 같이 꼬일 수 있다. 

또한 아무리 CUI가 입력하기엔 편해도 visualize 하는 면에 있어서는 GUI를 이길 수 없다. 나는 CUI에 익숙해져도 GUI git을 지우지는 않을거라고 확신한다.

 

애용하는 GitKraken에서 제공하는 배경화면이다. 예쁘긴 하지만 실제로 branch가 이렇게 꼬이면.....

GUI로 git을 사용할 수 있게 해주는 프로그램은 그렇게 많지 않다. 

처음에는 GitHub에서 자체제작한 GitHub Desktop을 사용했는데 깔끔한 그래픽의 군더더기 없는 디자인이라 마음에 들었지만 git의 모든 기능을 구현하지 않은 것 같고, 전반적으로 UI가 휑한 느낌을 주었다.

단순한 기능들만 사용한다면 추천하기는 한다. 

 

GitHub Desktop

이후로 본격적으로 git을 사용하게 만든 장본인은 Sourcetree이다. GitHub Desktop과는 다르게 다양한 기능들을 구현을 해두었고, 구현한 기능들에 비해 디자인도 깔끔하게 만들어서 한동안은 정말 잘 썼으나... 2016년즈음 자꾸 내부 프로그램 문제가 발생해서 설치-재설치, GitHub Desktop으로 갈아탔다 다시 오기를 몇 번.. 아주 지쳐버렸다. 

지금은 그래도 그때보다는 더 안정화 되어있을 것이다. 하지만 돌아갈 생각은 없다. 

 

Sourcetree 한눈에 봐도 뭐가 많다.

시커먼 화면을 좋아해서 그런지 한번 적응하고 나서부터는 바꿀 생각을 전혀 안하고 있다. 

UI는 위의 두 프로그램의 딱 중간정도지만 복잡한 기능들도 다 구현이 되어있고 아직까지 한번도 크래시가 난적이 없다.

의외로 이 프로그램에 대한 소개가 별로 없는 것 같기에 프로그램에 대한 애정을 담아 이후 포스팅부터는 이 프로그램을 기준으로 설명하겠다. 

 

Gitkraken. UI의 복잡도가 딱 GitHub Desktop과 Sourcetree의 중간이다.

2017년 이후 거의 3년간 문제없이 쓰고 있는 것은 GitKraken이다. 

 

 

마무리

아마 직접 git을 설치하는 일은 없을 것이다. 혹시 리눅스 유저라면 이미 git이 기본으로 깔려있을 것이고, 윈도우 유저라면 바로 GUI 프로그램인 GitKraken을 깔자. 이 프로그램 역시 학생에게 무료로 Pro 버전을 제공한다. 

https://www.gitkraken.com/student-resources

 

Free Developer Tools for Students | GitKraken

Students can get a GitKraken Pro account free as part of the GitHub Student Developer Pack. The Git GUI client makes learning Git easier by providing a visual, intuitive experience. Glo Boards are great for working with student teams to track project progr

www.gitkraken.com

이전 포스트에서 GitHub에 가입을 하고, 이번 포스트에서 GitKraken을 설치했다면 이제 준비는 끝이다. 

다음 포스트부터 바로 실제 git에 구조와 사용법에 대해서 작성하도록 하겠다. 

Posted by Admin Knowblesse
0 Comments

취미/Programming | 2019. 11. 12. 19:00 | /22?category=733209

원래 두 번째 글은 왜 git 이 필요한지에 대해서 작성하려고 했으나 계획을 변경했다. 

 

첫째, 일단 난 왜 git이 필요한지 안다. 굳이 여기서 간증글을 쓸 시간은 없다.

둘째, 지금 이 글을 보는 사람이 git의 필요성을 모르고 들어왔을 거라고 생각하지 않는다. 

셋째, 행여 git의 필요성을 모르는 사람이 들어왔으면 아마 아직 짠 코드 양이 적어서 그럴 것이라고 추측한다. 
코딩을 더 하다가 오면 생각이 바뀌지 않을까.

 

그럼 바로 git과 GitHub의 관계부터 짚고 넘어가겠다.

 

git

git 은 버전관리(version-control) 프로그램이다.

버전 관리 프로그램은 말 그대로 파일의 "버전"을 관리해주는 프로그램이다. 

처음에 이 말을 들었을 때는 "뭔 버전? 워드 2013 뭐 이런 버전인가?" 했는데 다음 짤을 보고 한 번에 이해가 되었다. 

 

아... 이 버전~

한컴오피스나 Word의 검토 기능을 자주 사용해본 사람이라면 다음 그림도 익숙한 화면일 것이다. 

수정 전 내용을 보여주는 것과 함께 누가 어디를 어떻게 수정했고 왜 수정했는지에 대한 문구를 볼 수 있다. 

버전 관리 프로그램의 주된 목적은

  1. 첫 번째 사진과 같이 같은 파일을 여러 번 다양한 사람에 의해서 수정을 해야 하는 경우 각각의 파일들을 최신순으로 추적해 주며
  2. 두 번째 사진과 같이 각 파일이 이전 버전들과 어떻게 달라졌는지를 비교해주는 것이다. 

git은 이러한 버전 관리 프로그램의 한 종류이다. 

 

뭐 대충 2000년대 전에 개발되었을 거고 2005년에 개발이 되었고, 개발자는 리눅스의 개발자 Linus Torvalds이며 현재는 일본인 개발자 Junio Hamano에 의해 유지되고 있다. 

 

버전 관리 프로그램의 종류는 git 외에도 수 십 종이 있으나 현재 적극적으로 사용되고 있는 것은 많지 않고 굳이 하나를 더 알아야겠다면 CVS랑 Subversion 정도. CVS, Subversion, git 모두 오픈소스에 누구나 쉽게 사용할 수 있지만, git은 모든 사용자가 데이터를 가지고 있지만 CVS와 Subversion은 중앙집중형 시스템이라는 점에서 다르다.

 

기업에 들어가면 자체 버전관리 시스템을 사용하게 될 것이고, 그 외에는 거의 대부분이 git을 사용하고 있다고 생각해도 무방하다. 

 

하지만 이러한 버전 관리를 포함하는 모든 데이터 관리의 핵심 기능이 하나 빠졌다. 

 

바로 백업과 공유이다. 

 

 

GitHub

GitHub는 git을 더욱 손쉽게 사용할 수 있도록 해주는 온라인 서비스이다.

모든 프로그래머는 고양이를 좋아한다. (아마?)

 

GitHub는 git이 나온 지 3년 뒤에 론칭했다. git 프로그램이 이렇게 인기 있는 버전 관리 소프트웨어로 성장하도록 만든 중요 동력원 중 하나가 아닐까 하고 생각할 정도로 다양한 기능들을 제공하며 무엇보다 remote repository를 무료로 제공해준다. 

 

git은 앞서 설명했듯이 중앙집중형인 CVS와 다르기에 모든 데이터가 로컬 컴퓨터에 저장이 된다.(local repository) 때문에 만일 로컬 컴퓨터에 문제가 생기거나 데이터가 있는 폴더를 실수로 홀라당 날려먹으면 버전 관리고 뭐고 끝이 난다. 

git에서는 이러한 문제를 원격 저장소, remote repository라는 것을 사용해서 해결할 수 있는데, 말 그대로 로컬에 있는 데이터를 local이 아닌 다른 컴퓨터 (주로 클라우드 서버)에 저장하여서 데이터를 백업해둘 수 있다. 

 

하지만 이를 단순히 "백업"이라고 말하기에는 마음이 편하지 않다. 심지어 GitHub의 Help page에 들어가면 "Git is not adequately designed to serve as a backup tool."이라고 언급을 하고 있다. 물론 원격 저장소를 사용하면 로컬에 있는 데이터를 백업해두고, 로컬에 문제가 있을 때 다시 복구할 수 있지만, 다른 사용자와 코드를 공유하거나 완성된 프로그램을 배포하는 등 훨씬 다양한 기능을 수행할 수 있다.

 

굳이 백업이라는 단어를 써서 원격 저장소를 설명하자면, "소스코드에 특화된 강화된 기능을 가지는 공개용 백업"?

 

몇 가지 GitHub의 기능을 나열하면 아래와 같다.

  • 원격 저장소 기능
  • Issues : 버그 신고 혹은 기능 추가 요청. "이 기능 좀 넣어주세요~", "이거 안 되는데요?"
  • Pull requests : 다른 사용자가 직접 코드를 수정해서 원격 저장소 오너에게 이 코드를 사용해달라고 제안하는 기능.
  • Wiki : 원격 저장소에 있는 프로그램에 대한 위키 페이지 운영 기능.
  • Releases : 배포용 프로그램 생성 기능.

이 모든 것을 무료로 제공 가능한 이유는 단순한 텍스트 파일인 소스코드의 크기가 크지 않기 때문이다. 

개발자가 한평생 작성하는 소스코드는 CD 한장을 채우지 못한다.

때문에 GitHub에 올리는 파일의 크기는 아래와 같은 제약을 받는다.

각 파일별 최대 크기 100MB (인터넷 브라우저로 업로드시 25MB)
권장 원격 저장소 크기 1GB 미만
최대 원격 저장소 크기 100GB*
단 1GB가 넘어가면 지속적으로 저장소 크기를 줄이라고 연락이 옴.

한마디로 소스코드 외에 다른 것들은 가능하면 올리지 말라는 것이다. 

 

예전에는 사전에 지정한 사람만 들어올 수 있는 비공개 원격 저장소를 무료 계정에서는 5개로 제한했었는데 이 제한은 없어진 모양이다. 월 USD7을 내면 Pro 계정으로 업그레이드가 가능한데 이마저도 학생들에게는 무료로 제공하고 있다. 

아래 링크를 참고할 것.

https://education.github.com/pack

 

GitHub Student Developer Pack

The best developer tools, free for students. Get your GitHub Student Developer Pack now.

education.github.com

 

물론 Github가 git을 위한 유일한 원격 저장소 서비스 제공자는 아니다.

 

GitLab, Bitbucket 등 다양한 업체가 있으나 둘러본 적은 없다.

 

따라서 앞으로의 글도 GitHub에 초점을 맞춰서 작성할 예정이다. 

 

잘못된 정보는 댓글로 지적해주시면 정말 감사하겠습니다!
Posted by Admin Knowblesse
0 Comments

취미/Programming | 2019. 11. 11. 20:00 | /21?category=733209
어디까지나 프로그래밍은 취미이다.

 

라고 스스로에게 계속 되뇌고 있지만 이제는 슬슬 인정할 때가 되지 않았나 싶다. 

내게 있어서 프로그래밍은 이미 생활의 일부라고.

 

각설하고 연구를 위해서도 그렇고, 진정한 취미 프로젝트를 위해서도 그렇고 버전 관리는 필수다. 

 

심지어 이제 막 프로그래밍을 배우기 시작하는 사람도 git 사용법을 같이 배워야 한다고 생각한다.

 

과학에서 연구를 할 때 실험을 배우기 전에 연구노트 작성법에 대해서 알려주듯이 프로그래밍을 하는 사람들도 코딩을 제대로 배우기 전에 git 사용법에 대해서 알아야 한다. 원하든 원하지 않든 한번 짠 프로그램은 가능한 기록을 해두는 것이 좋고, 이 기록을 체계적으로 남기기 위해서는 Github 만한 플랫폼이 없다. 객체 지향이나 multi threading 같은걸 알려주기 전에 학습하면서 짜둔 코드를 효율적으로 기록하는 법을 알려주는 게 옳지 않을까. 

 

또한 프로그래밍 초반이야 말로 다른 사람의 코드를 자주 보게 되는데 "그거 내 깃헙에 올려뒀어요~" 라던가 Github 뭐시기 링크만 달랑 첨부되어 있는 경우 코드를 어떻게 받아야 할지도 모르기 때문이다. 내가 비전공자라 그런지 나름 주변에서 프로그래밍을 배웠거나, 지금도 코딩을 하고 있는 사람들에게 코드 전달 목적으로 깃헙을 알려주면 답답한 일들이 자주 발생한다. 거의 대부분은 내가 업데이트를 할 때마다 전체 파일을 zip으로 다운로드하여서 필요한 코드를 골라가기만 하고 제대로 사용할 줄을 모른다. 최소한 raw 버튼의 사용법만 알아도 바로 필요한 코드만 긁어갈 수 있을 텐데.

 

 

 

나도 한동안 git을 쓰지 않았다. Cloud에 코드를 죄다 올려두고 자체 backup 기능이나 파일 버전 관리 기능을 사용해서 오랫동안 작업을 했었다. 그러다가 조금 내용이 많이 바뀐 것 같으면 프로젝트 파일을 통째로 새로 저장하고, 다른 목적을 위해서 프로그램을 수정하게 되어도 또 새로 저장하고... 그러한 결과 아래와 같은 일이 벌어진다.

 

전부 같은 "출석 부르기" 프로그램인데 사용목적과 내용에 따라서, 그리고 개발 상태에 따라서 폴더를 새로 만드니 뭐가 뭔지 알 수 없게 되었고, 각각 업데이트한 내용이 달라서 서로 호환도 안된다. 

 

정말로 코드 짜는 건 20% 밖에 안되고, 의외로 유지보수가 80%나 된다. 주석 잘 달아두자.

 

CUI가 익숙하지 않아서 이것저것 알아보다가 Sourcetree를 계기로 git에 입문했다. 

대략 다섯 권의 git 혹은 Github 관련 책을 읽었으나 생각보다 내용이 중구난방으로 작성되어 있었고 알파벳순으로 정렬된 매뉴얼처럼 정신없었다. 그래도 꾸역꾸역 읽어서 이제는 별문제 없이 사용하지만, conflict error가 나거나 이전 commit으로 돌릴 때, Github 특화된 기능을 사용할 때는 머리가 터질 뿐이다. 

 

'아씨 내가 차라리 책 한 권을 쓰면서 배우는 게 빠르겠다!'라는 생각에 이 글을 시작한다. 

 

우선순위를 고려한 목적은 아래와 같다. 

1. 내가 git의 모든 커멘드에 익숙해질 수 있도록.

2. 이후에 사용법이 궁금할 때 이 글들을 보고 refresh 할 수 있도록. 

3. git 혹은 github 관련 궁금증이 있을 때 제일 먼저 이 블로그로 사람들이 찾아오도록 하기 위해.

 

시간을 최대한 내서 끝까지 포스팅 할 예정이다. 

 

PS 출판을 원하시면 언제든 연락주세요

Posted by Admin Knowblesse
0 Comments

취미/Programming | 2019. 7. 26. 15:10 | /20?category=733209

옆방 연구실에 스탠드형 에어컨이 설치되어있는데 냉각수 배수구가 없어서 수조에 받아서 물이 차면 버리면서 쓰는 중.

 

하지만 적절한 시기를 놓쳐서 맨날 넘친다고...

 

안타까워하면서 간단한 장치를 만들어주었다. 

 

이거에 굳이 아두이노를 쓴 걸 전기공학 하는 사람이 알았다가는 뒤통수를 맞을꺼 같지만 트렌지스터로 회로 설계하기에는 귀찮았기에.

 

Analog input 받아다가 물 안에서 합선되고 5초 뒤에도 합선되어 있으면 경보가 울리는 방식이다. 

 

처음 테스트 환경에서는 물 안에서 합선이 되면 0.3V가 잡히길래 200mV를 기준으로 잡고 이걸 넘으면 합선으로 봤는데 

 

실제 환경에서 작동을 안하더라. 

 

냉각수라고 온도가 낮으면 더 전도가 잘 되어야 하는거 아닌가?

 

아니면 테스트 환경은 머그컵이라 두 도선간의 거리가 짧아서 그랬나.

 

여튼 15mV로 기준을 잡았더니 이젠 너무 자주 울린다. RF noise가 껴서 그런듯. 

 

5초동안 합선되게 잡았더니 문제가 없더라.

 

20분 정도 걸린 프로젝트라 굳이 올려도 아무도 쓸 사람이 없을듯 하지만 그냥 버리긴 아깝기에 코드와 스케메틱을 올려둔다.

 

 

boolean sensorOn;
void setup() {
  pinMode(5,OUTPUT);
  pinMode(LED_BUILTIN,OUTPUT);
  sensorOn = false;
}

void loop() {
  if(analogRead(5) > 15){ // short detected
    digitalWrite(LED_BUILTIN,HIGH);
    if(sensorOn){ // short detected and this was sustained for 5 sec
      // alert
      tone(5,800,1000);
      delay(3000);
      tone(5,800, 1000);
      delay(3000);
      sensorOn = false; // reset
    }
    else { // short detected but this was the first detection
      sensorOn = true; // toggle on
      delay(5000); // wait 5 sec and check the sensor state again
    }
  }
  else { // reset toggle
    sensorOn = false;
    digitalWrite(LED_BUILTIN,LOW);
  }
  delay(500);
}
Posted by Admin Knowblesse
0 Comments

취미/Technology | 2018. 9. 9. 01:42 | /18?category=733208

IoT를 이용하는 (솔직히 이 단어 매우 싫어한다. V=IR도 모르는 저기 정치-경영쪽 사람들이 맨날 떠드는게 볼썽사나워서) 전등 스위치를 동생 생일 선물 대신 만들어주기로 하였다. 


기존에 파는 제품들도 있으나 가격도 비싸고 기능도 별로 없는듯 하여 직접 제작에 들어갔다.


컨트롤러야 아두이노 나노를 쓰면 되고, 전등은 100V 이상의 고압을 사용하니 릴레이로 컨트롤, 

문제는 무선 방식을 택했기에 Wifi든 Bluetooth든 지그비 통신이든 통신 모듈을 아두이노와 연결해야했다.


통신거리가 길어봐야 수m 이고 Bluetooth라면 시리얼 통신 앱이 어떤 OS든 하나는 있을 것 같았기에 Bluetooth 로 개발을 하기로 결정.


전기회로를 설계할 때 가능하면 중국제 제품을 안쓰려고 하는데, 품질이 의심되기 보다는 주로 datasheet를 찾기 어렵거나, 있다고 해도 중국어로만 되어 있는 경우가 간간히 있어서 그렇다.


가격을 생각해서 Devicemart에서 중국제 HC-08 Bluetooth 모듈을 일단 구매 했으나, 다양한 제품들을 만드는 회사라 검색어 오염이 있고, 다른 제품군에 대한 설명은 많으나 HC-08 제품에 대한 설명은 거의 전무했다. 


다른 제품들과 중국어로된 회사 홈페이지를 뒤져서 결국 통신에 성공했다. 


Bluetooth 모듈 사용은 이번이 처음이기에 연결을 시키면서 다양한 것을 배웠다.






1. Arduino와 HC-08의 연결


일단 부품은 잘 모르면 무조건 모듈로 된 제품을 사야한다. 


그냥 덜렁 센서만 툭 샀다가 어떻게 연결하는지도 모르고 고생하기 쉽다.


생으로된 HC-08 모듈을 구매하고 길을 찾고자 여기로 오신 분은 얼른 가서 모듈로된 부품을 구매하기 바란다.


하지만 안타깝게도 부품을 구매한 Devicemart에도 제대로된 모듈 연결방법 설명이 없었다. 


연결방법은 간단하다. 핀은 총 6개가 나와있는데 실질적으로 4개만 사용하면 된다.



* Serial 통신


거의 대부분의 Serial 통신, 직렬 통신은 핀이 네개 필요하다.


VCC, GND, TX, RX


VCC와 GND는 말 그대로 전극의 +와 -. 장치에 전력을 공급해주는 핀이다.


나머지 둘이 통신을 위해서 필요한 핀인데, TX는 데이터 전송용, RX는 데이터 수신용으로 필요하다. 


중요한 것은 두 장치를 서로 연결할때 VCC와 GND는 극성 잘 보고 꼽으면 되지만 RX와 TX는 정 반대로 연결을 해주어야 한다는 것이다.


VCC핀은 보드의 5V 핀에 그대로 연결. GND 핀도 보드의 GND 핀에 그대로 연결을 하면 되지만, 


통신 모듈의 RX핀은 보드의 TX 핀에,

통신 모듈의 TX핀은 보드의 RX 핀에 연결을 해주어야 한다.


Arduino 보드에도 Digital 0번, 1번 핀이 이러한 기능을 수행해 주는데, 이경우 아두이노인지 블루투스 모듈인지 둘중에 하나와 통신이 안되었던 것으로 기억한다.


아, 아마 아두이노의 Serial Monitor 창에서 입력하는 값이 TX가 안되었던 것 같은데...


여튼 아두이노의 D0 D1핀은 앵간하면 건드리지 않는 것이 좋다는게 경험이다.



문제는 그럼 어떻게 Serial 통신을 하느냐, 아두이노 자체적으로 있는 라이브러리인 <SoftwareSerial.h>를 사용하면 된다.


이 라이브러리를 사용하면 지정한 디지털 핀을 TX와 RX 핀으로 설정해서 Serial 통신을 가능하게 해준다.


최종적으로 연결은 이런식으로 하면 됩니다.



VCC와 GND는 알아서들 잘 연결하실꺼고, 


위의 사진에서 모듈의 RX는 아두이노의 D10에, TX는 D11에 연결을 했다.


2. AT(필드) 코드


이번에 처음 배운 것이다. 


왜 어디에도 AT 코드를 설정하는 방법에 대해서 나와있지 않는가....


either 너무 기본적인것이거나 다들 불친절한 것이거나.



AT 코드는 Serial 통신을 사용해서 모듈의 칩의 설정을 바꾸어 주는 코드이다.


이 블루투스 모듈에선는 아래의 AT 코드들이 있다.



펌웨어 버전 확인부터, 블루투스 이름 변경, 연결가능성 설정 등의 메뉴가 있다.


문제는.... 이 코드를 그래서 어디에 어떻게 입력하는지 몰랐다.


설마 그냥 Serial 통신을 연결해두고 "AT"라고 정말 입력하면 돼??



사전 준비가 조금 필요하지만 일단은 진짜 문자 그대로(= ASCII 코드로 ) 저 코멘드를 입력하면 되더라.



일단 HC-08 모듈은 조금 특수적으로 AT Mode에 들어가야 저 명령어가 먹는다.



HC-08아닌 다른 모듈의 경우 KEY를 누르거나 5V 전압을 인가하면 된다고 하던데 그냥 전원을 넣은 상태로 다른 기기와 Pairing이 안된 상태면 무조건 AT 모드에 있는 것 같다.


참고로 이때 이 모듈의 경우 LED가 깜박거린다. 



AT 모드에 진입한후 저 명령어를 입력하기 위해서는 아래의 코드가 필요하다. 


3. 소프트웨어 제작


#include <SoftwareSerial.h> // 가상 Serial 통신을 위해 헤더파일 불러오기


byte rxPin = 11; // 모듈에서의 RX는 D10번, TX는 D11에 넣었다.

byte txPin = 10; // 그렇기에 모듈의 RX와 연결된 D10번 핀은 TX핀으로 설정해야한다.

// 참고로 사용하는 아두이노 기종에 따라서 SoftwareSerial.h를 사용할 수 없는 핀들이 존재한다.

// 꼭 홈페이지에서 document를 읽고 오자. 

// Uno 기준으로는 10번, 11번 모두 해당이 없다.


SoftwareSerial BT(rxPin, txPin); // BT 라는 이름으로 설정.

char c = ' ';


void setup() { // 두 시리얼 포트를 모두 시작.

  Serial.begin(9600); // 시리얼 모니터용

  BT.begin(9600); // 블루투스 모듈용

}


void loop() {

  if(BT.available()){ // BT 모듈에서 응답을 받는 경우이다. BT의 TX에서 전송이 들어올 때.

    while(BT.available()){ // while문을 넣지 않으면 한줄에 한글자씩 출력된다.

      delay(10);

      c = BT.read();

      Serial.print(c);

    }

    Serial.println("");

  }

  

  if(Serial.available()){ // Serial 모니터에서 직접 값을 입력한 경우.

    c = Serial.read();

    BT.write(c); // 블루투스 모듈의 RX 핀으로 쏴준다.

  }

}


char 형식이 아니라 16진수 그대로 출력하게 해두고 가지고 놀다가 재미있는 사실을 발견했는데 값이 입력될때 내가 입력한 문자의 아스키 코드 뿐만 아니라 10진수로 10, 13 이 같이 입력이 되는 현상을 발견했다.


찾아보니 각각 Line Feed와 Carriage Return.


아무래도 시리얼 모니터에 값을 입력하고 엔터를 눌러 전송을 하면 엔터 값 자체도 전송이 되는 듯 하다. (이것도 기본적인 거겠지만 이번에 처음 배웠다.)





참고로 해당 설정은 시리얼 모니터의 아래에서 바꿀 수 있다.


4. 연결


아두이노 연결과 모듈 연결을 성공적으로 끝냈으면 위의 코드를 올리고 시리얼 모니터에 

AT 

라고 입력을 하면 

OK 

라고 뜨는 것을 확인할 수 있다.

(참고로 엔터를 눌러서 값을 전달하는 것과 전송 버튼을 눌러 값을 전달하는 것은 값이 다르다.)


두 HC-08 모듈을 연결하기 위해서는 하나는 마스터 모드, 하나는 슬레이브 모드여야 가능하다.


지그비 통신에서도 비슷한 것을 본 적이 있는데 여기서도 그렇게 작동하나 보다.


둘다 AT 모드에서 설정을 바꾸지 않았다면 둘다 Slave 로 되어 있을 것이다. 


AT+ROLE=M


커멘드를 입력하고


AT+RX 커멘드를 통해서 위의 시리얼 모니터처럼 값이 나오는지 확인한다.


Role : Master


라고 나올 것이다.


자... 이제 두 모듈을 어떻게 서로 연결해주지....


했는데 그냥 연결이 알아서 되더라.


여러 모듈이 동시에 존재하는 경우에는 어떻게 해야하는지는 모르겠으나, 같은 공간에 마스터 하나와 슬레이브 하나만 존재하고, 거리가 멀지 않으면(10미터 이하) 즉각 둘이 페어링이 되는 듯 하다.


일단 목적은 두 기기를 연결시키는 것이라 여러 모듈을 서로 연결시키는 것은 시도해보지 않았다.


나와 같이 HC-08을 사고 힘들어하는 누군가에게 도움이 되었기를 바라며...





Posted by Admin Knowblesse
1 Comments
  1. 심여진 2019.11.15 19:21  댓글주소  수정/삭제  댓글쓰기

    안녕하세요 hc-05 06으로 4시간 헤매다가 덕분에 해결했습니다
    감사해요ㅠ

취미/Technology | 2018. 8. 24. 17:47 | /17?category=733208

서지 관리 프로그램으로 EndNote를 써봤지만 왜인지 모르게 입맛에 맞지 않았고 Mendeley로 갈아탄지 2년.


본인은 데이터를 전부 개인 NAS에 올려서 보관을 하고 있기에 찾은 논문들도 클라우드에 올라가 있다. 


Mendeley에 있는 유용한 기능 셋을 나열하자면, 

- 클라우드 기능. 찾은 PDF를 자체 cloud에 업로드/다운로드 할 수 있다

- watched folder 기능. 폴더 하나를 지정하면 해당 폴더에 들어오는 새로운 pdf 파일을 인식해서 자동으로 등록해준다.

- organize 기능. 찾은 pdf를 하나의 폴더에 넣어준다.


목적은 단순했다.

기존의 PDF 파일들을 동기화 하던 방식(자체 NAS)을 유지하면서 Mendeley를 쓰고 싶었다.


개중에는 비슷한 연구자가 또 있을거라 생각한다. 

원래 드랍박스나 OneDrive로 논문을 관리하다가 Mendeley를 쓰게 되는 경우처럼.


Mendeley의 클라우드를 쓰기 싫은 이유는 

1. 내 NAS가 더 빠르다.

2. 거지같은 아이패드에서 쓰는 pdf 앱은 Mendeley의 cloud에는 접근하지 못한다. 

물론 iOS용 Mendeley 앱이 있으나 자기네 클라우드에서 파일을 받는 것만 가능한 것으로 앎. 

왜냐하면 Mendeley 앱에서 pdf를 받고 그걸 내가 쓰는 pdf 리더 앱으로 열고 수정한 다음에 닫으면 그게 Mendeley로 넘어가지 않아서 서버로 올려주지 못하거든.

물론 Mendeley 앱 내의 주석기능으로 수정하면 반영이 된 상태로 다시 업로드가 되지만.

3. 안에서 폴더를 나눠도 실제 파일 시스템에서는 폴더가 나뉘지 않는다.


결론적으로 

"내 PDF는 알아서 내가 관리할테니 Mendeley 너는 목차나 잘 만들고 비슷한 논문 뜨면 찾아줘" 


문제는....


Mendeley 자체적으로 cloud 기능이 있기에 

1. 새로운 장치에 mendeley를 설치한다.

2. 폴더를 자체적으로 만들고 Mendeley 클라우드에서 pdf 파일들을 다 내려받는다.

(이 pdf 파일들은 사실 이미 내 클라우드의 논문 폴더에 다 들어가 있다.)


Case A. Mendeley에서 pdf를 열고 수정할 경우 자체 폴더에 있는 pdf가 수정되고 내 클라우드에 있는 친구들은 수정이 안된다.


Case B. Mendeley에서 pdf를 열지 않고 클라우드에서 열어서 수정할 경우 Mendeley 앱에서 열었을 때 수정이 안된 버전이 보여진다.


온갖짓을 다 해봤는데 결국 안되는듯 하다. 

누가 멋대로 pdf 파일 가져가래.. PDF 동기화를 끄는 버튼도 없다. 


물론 한 컴퓨터를 정해서 지속적으로 Cloud 논문 파일을 Mendeley에 업로드 해주면서 다른 모든 기기에선 Mendeley 클라우드를 이용하는 방법도 있긴 하다. 귀찮아서 그렇지... 마치 pull이 한 컴퓨터에서만 되는 git의 느낌이려나.






Posted by Admin Knowblesse
0 Comments

취미/Technology | 2018. 8. 5. 15:36 | /16?category=733208

때는 작년 여름, 모종의 이유로 MMORPG를 본의아니게 시작하게 되었다.


같은 모종의 이유로 길드에 가입하게 되었는데 같이 던전을 돌거나 잡담을 하기 위해서는 디스코드를 필수로 사용해야했고, 마이크가 달린 헤드셋의 필요성이 생겼다.


이전에는 마이크가 달린 이어폰을 사용했었으나 핸드폰으로 계속 디스코드를 틀어놓기에는 한계가 있었기에..


처음으로 특정 품목의 상품을 구입하면, 특히 전자기기인 경우, 가장 비싸고 좋은 제품부터 시작해서 필요 없는 기능을 뺴면서 하위 기종으로 내려오는 경향이 있는데 이번에도 같은 방법으로 헤드셋을 알아보았다.


로지텍 제품을 벌써 4개나 구입하고 주변 사람들에게 3개를 더 판 로지텍 빠이기에 로지텍 게이밍 기어를 둘러보다가 마음에 드는 제품으로 G633 기종을 골랐다.


<https://www.logitechg.com/>

(그때는 G933이 없었던것 같은데.. )


구입 당시로부터 거의 1년이 지났는데 아직도 G633이 가장 최신 기종 라인으로 나와있다.

G933과의 차이점은 무선이냐 아니냐의 여부인 것으로 보인다.


그때도 G933이 있었는지는 기억이 나질 않는데 아마 있었다면 무선이 편하기는 하는데 선 정리만 잘하면 굳이 무선 기능을 쓸 이유가 없을듯 해서 + 괜한 딜레이 걱정 때문에 G633을 구입하지 않았을까 생각한다.


개봉기가 아니라 구입후 1년동안 쓴 후기, 제대로 된 리뷰를 시작합니다.



1. 사운드 : 하상 (가격에는 못미침)

안타깝게도 필자는 소위 '막귀'인 사람인지라 가격차이가 4~50만원씩 차이가 나지 않는 이상 오디오 제품의 성능을 구별하지 못한다. 해봐야 상중하로 구분할 수 있으려나.


하지만 G633은 18만원이라는 가격의 오디오 제품에 기대하는 성능 이하의 사운드를 보여주었다. 마이크와 기타 기능들이 달려있는 제품이기에 18만원이라는 가격이 나왔는지는 모르겠지만 음악 감상용의 18만원대 헤드폰에 비해서는 확실히 낮은 품질이었다.


어쩌면 게이밍 헤드셋과 음악 감상용 헤드폰을 1:1로 비교하는 것은 반칙인것 같지만 로지텍사에서 가장 비싼 라인으로 나와있는 헤드폰인데 가격을 더 높이더라도 사운드에 신경을 더 쓸 수 있지는 않았을까.


2. 기능 : 최상

가장 마음에 드는 기능은 접이식 마이크이다. 

마이크 부품에 스위치가 있어서 마이크를 올리고 내리는 동작으로 시스템적으로 마이크를 껐다 켰다 할 수 있다. 또한 멀티 플레이 게임중에 다른 사람들이 말해준 바로는 내 마이크에서 다른 잡음이 상대적으로 덜 들린다고 하더라. 


좌측 스피커 옆에 붙어있는 볼륨조절 버튼이나 기타 기능들도 유용하게 쓸 수 있을 것 같다.


<https://www.logitechg.com/>


눌러서 말하기 기능으로 쓰기에는 매번 헤드셋으로 손을 올리기 어려워서 사용하기 어려웠다.

하지만 직관적으로 사운드를 조절하거나 뮤트 버튼 등을 배정시켜서 편리하게 사용하고 있다.


로지텍 게이밍 기어 제품을 하나 이상 가지고 있다면 같은 프로그램으로 키 변경이나 EQ 등 잡다한 설정들을 변경할 수 있다.


참고로 난 제발 게이밍 기어에 색 좀 넣지 말았으면.. 컬러 LED 왜 넣는 거임...

커스터마이즈를 통해 뭔가 돋보이고 싶어하는건 알겠는데 이런거 커스터마이즈 할 시간에 얼굴을 커스터마이즈 해라


사진 맨 위에 보면 03 버튼 위에 파란색이 살짝 보이는 토글 버튼이 보인다. 


헤드폰에 USB 선, AUX 선을 두개를 꼽을 수 있는데 USB 선으로는 컴퓨터와 다이렉트하게 연결이 되고 AUX 선을 사용하면 핸드폰이나 다른 음향기기와 직접적으로 연결할 수 있다. 


믹싱 기능은 당연히 없고 저 토클 버튼을 사용해서 어디로부터 입력을 받을까를 결정할 수 있다. 


컴퓨터와 피아노에 연결해두고 음악 제작 작업을 해본적이 있는데 Ground 선이 서로 붙어있는지 AUX로 설정해두고 피아노를 치니 노이즈가 끼더라. 꺼진 컴퓨터에 연결되어있던 USB 선을 뽑았더니 노이즈가 사라지는 것을 확인했다.  이 부분에 있어서는 살짝 디테일이 부족한 것은 아닐까 싶다.



3. 내구도 : 최악

이 글을 쓴 이유이기도 하다. 내구도가 엉망이다.


이어폰을 사용하는 사람들이 단선을 가장 걱정한다면, 헤드셋을 사용하는 사람들은 헤드셋의 목이 잘리는 현상을 가장 걱정한다. 


이 빨간 부분이 끊어지는 현상. 헤드폰 부품중에서 가장 큰 압력이 걸리는 부분이기에 단단하게 만들어야 한다. <http://mofi.co.kr/>


이어폰 단선이나 헤드셋 목잘림이 그렇게 자주 있는 일은 아니지만, 가장 취약한 부분이기에 한번 크게 사고가 나거나 3년 이상 오래 쓰면 아무리 조심히 써도 신경을 쓰게 되는 부분이라고 생각한다.


필자도 젠하이저 접이식 헤드폰을 선물받아서 매일 사용하다가 1년을 못견디고 저 부분이 부러지는 사건이 두번이나 있었다. 


이후에 출시된 후속작에서는 해당 부분을 메탈 재질로 바꾸어서 출시했다.


그럼 G633 제품은?


금속 부품 하나 없이 전부 플라스틱 재질이다.


헤드셋의 아치 부분 안에는 메탈이 들어가 있지만 나사를 제외하곤 모두 플라스틱으로 만들어졌다.


그래서 무슨 일이 벌어졌느냐...



처음에 제품을 사서 착용할 때부터 플라스틱이 서로 부딪혀서 끼이익 거리는 소리가 나는 것이 내구도의 허접함을 소리치고 있었는데 결국 이런 일이 벌어졌다. 


저 부품 하나가 헤드셋 한쪽에 가해지는 압력을 모조리 받고 있는데 끊어진 부분 두께가 1.5mm 이다. 


세상에 이쑤시개 여러개를 동그랗게 말아서 쓰는 것이 더 튼튼하겠다


로지텍사에 연락을 했으나 타 블로그에서 외국인 리뷰어가 심하게 까는 것 처럼 서비스를 안해준다더라.


순간접착제로 부품을 붙여보거나 글루건으로 떨어진 부분을 통쨰로 접합하거나 했지만 역시나 압력이 크게 가해져서 1시간만에 떨어져나갔다. 


여기서 부터 수리기.


결국 일을 크게 벌렸다.


망할놈들이 안고쳐준다면 내가 부품을 하나 만들고 말지...


부서진 부품을 역설계 해서 3d 모델을 만들고 단선 없이도 부품을 선에 결착할 수 있도록 디자인을 수정했다.


처음에는 위파트 아래파트 만들어 선 위에서 붙이려 했으나 어려웠다.


결국 저렇게 단일 부품 구조로 엇갈린 형태의 홈을 만들어 선을 저 사이에 억지로 끼워넣도록 했다.





기어이 완성.


중간에 원래 붙어있던 부품을 빼낼때 니퍼로 조금씩 부수며 빼다가 선을 끊어먹을 뻔 했다...


다행히 기능에는 지장이 없는 것으로 봐서 선 겉의 피복만 끊어버린 것 같다.


이번 리뷰 및 수리기의 결론


1. 헤드셋을 살 때 가격 이전에 저 연결부가 충분히 두꺼운지, 혹은 플라스틱이 아니라 금속을 사용했는지를 꼭 확인하자.


2. 로지텍 개쓰레기(하지만 계속 쓰긴 할 것 같다. A/S 제대로 해주는 업체가 삼성 엘지 말고 어디있어. 대신 비싼 제품은 이제는 못살듯 싶다.)



Posted by Admin Knowblesse
11 Comments
  1. 붉은노을2 2018.08.05 20:36 신고  댓글주소  수정/삭제  댓글쓰기

    보증 기간 지나면 유료 수리 거부 & 배째라 행태가 욕먹기는 하는데

    보증 기간 중인데도 AS 거부상황이 벌어진건가요?

  2. Admin Knowblesse 2018.08.05 21:24 신고  댓글주소  수정/삭제  댓글쓰기

    보증 기간 중인데도 기계 결함이 아니라 사용자 부주의로 인한 파손으로 봐서 거절당한 것 같습니다.
    어쩌면 온라인으로 문의를 해서 그런 것 같기도 하고요. 이전에 용산 센터로 직접 찾아갔을 때는 정말 친절하게 해주시던데 말이죠.

    다음은 관련 문의로 받은 메일의 일부입니다.
    """
    제 이름은 Y Cheon 입니다. 귀하는 G633 Artemis Spectrum RGB 7.1 Surround Gaming Headset 제품에 대한 지원을 원하는 것으로 알고 있습니다.

    문의해 주셔서 감사합니다.
    저희 로지텍 코리아 A/S 정책 상, 파손된 제품에 대해서는 제공해 드리는 서비스가 준비되어 있지 않습니다.
    보증 기간 내에서 제품에 기계적인 결함이 있을 시에만 새 제품으로 교환해 드리고 있습니다. 도움을 드리지 못해서 죄송합니다.
    """

  3. 무쁘 2018.10.18 03:07  댓글주소  수정/삭제  댓글쓰기

    헐 저도 똑같은 부품이 부려저셔 순간접착제로 붙여서 조심조심 쓰는중
    부품을 만들다니 대단하세요

    • Admin Knowblesse 2018.11.09 15:46 신고  댓글주소  수정/삭제

      이 부품 부러지신분들 한두분이 아닐것 같아요 으으...
      그나저나 순간접착제로 붙던가요? 저 순간접착제, 글루건 다 써봤는데 1시간도 못가서 다시 부러지길래 이렇게 한건데

  4. 2018.10.31 00:51  댓글주소  수정/삭제  댓글쓰기

    판매는 안하시나요 ㅠㅠ 대단하세요

    • Admin Knowblesse 2018.11.14 10:20 신고  댓글주소  수정/삭제

      판매할만한 퀄리티가 아닙니다 ㅋㅋ
      3D 프린터 인쇄물 특성상 내구도가 썩 좋지는 않아요 3개월 정도 쓰다가 다시 부러졌나 그랬습니다.
      여분이 몇개 있는데 필요하시면 보내드릴까요?

  5. 오리모리 2019.06.02 11:06  댓글주소  수정/삭제  댓글쓰기

    안녕하세요 다름이 아니라 저도 933을 사용중인데 똑같은 부분이 고장이 나서 질문드릴게 있는데 보시면 꼭 답장 부탁드립니다 ㅠㅠ

  6. DK66 2019.06.09 19:57 신고  댓글주소  수정/삭제  댓글쓰기

    부품 직접 만드신건 진짜 대단하세요ㅠㅠ판매하셔도 되겠어요!

  7. 2020.05.25 22:34  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

  8. 2020.06.29 18:01  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

취미/Technology | 2018. 6. 3. 13:23 | /15?category=733208

- 크레마 카르타


근 2년? 3년 전에 신논현역 Yes24 코너에서 반쯤 충동적으로 구입한 크레마 카르타.

킨들과 비교해서 허벌나게 까였던 국내 이북 리더 치고는 만족할만한 성능을 보여주었다.


교보문고의 SAM 은 자취를 감춘지 오래인듯 하고, 리디북스 리더는 플랫폼이 걱정되어서 선택한 크레마 였는데 전자 잉크 패널의 자체적인 단점(깜박임, 잔상)을 뺴고는 베터리, 속도 전부 훌륭한 제품이었다.


한번 충전하면 적어도 일주일 이상은(물론 킨들은 거의 한달을 가는 것 같다만..) 가고 잔상이나 깜박임 등은 살짝 인쇄 질이 나쁜 책을 본다고 생각을 하면 별 문제가 되지 않는다. 책을 읽는 이유가 텍스트로부터의 정보 습득이 아니라 글자 자체를 음미하는 별종이라면 모르겠지만 대부분의 사람에게는 크레마 카르타 수준의 스펙으로는 책을 읽는데 전혀 어려움이 없을 듯 하다. 


또한 물리적인 책의 보관 공간 문제나 휴대성이 낮다는 것을 같이 고려하면 한달에 3권 이상 책을 읽는 사람은 꼭 사야하는 물건이 아닐까 싶다.



- 크레마 카르타 플러스


같은 경험을 선물해 주고 싶어서 여자친구 선물로 크레마 카르타를 구입하려 했으나 단종되고 대신 크레마 카르타 "플러스"가 등장했다.


더 커진 베터리에 빠른 프로세서 등을 내세워서 크레마 카르타가 나온지 얼마 되지 않았는데 제품이 전격 교체되어 버렸다. 


플러스니까 더 좋은 거겠지 하고 구입을 했으나 이건 뭔 물건인지.


다른건 그렇다 쳐도 하루 놔두면 자연방전이 되고 책을 읽으면 5시간은 채 가지 못하는 소위 말하는 조루 베터리를 달고 있었다.


나무위키에서는 "락칩"이라는 프로세서를 사용해서 이같은 문제가 생긴다 했는데 베터리가 핸드폰만도 못한 수준이면 전자 잉크 패널의 가치가 절감되는 것은 아닌지.


A/S를 보내려고 전화를 했는데 상담원은 원래 크레마 카르타 플러스가 베터리 용량이 작아졌다는 말과 아마 문제가 없는 제품일 것이라고. 


나중에 확인을 해보니 오히려 베터리 용량이 2배가 되었던데?


결국 메인보드 문제로 판정이 나서 메인보드 교체를 해주었는데 이번에는 배송 사고로 패널이 망가져 근 2주동안 손에서 떠나있었다.


문제는 A/S를 받은지 2어달 뒤 또 베터리가 말썽이다. 꺼두고 가만히 놔둬도 하룻밤 자고 나면 베터리가 50%는 떨어져 있으니 쓰레기가 따로 없다.


크레마 카르타는 최고의 국내 ebook 리더였으나 카르타 플러스는 열심히 소문 내고 있다. 


"그거 절대 사지 마요."



- 크레마 카르타의 마지막 인사


이미 단종된 카르타의 애정이 깊어갈 무렵 결국 일을 저질렀다. 


워낙 충격에 약하다는 전자 잉크 패널이었지만 케이스를 씌워 두고도 이렇게 까지 약할 줄은 몰랐다.


허리 높이에서 떨어뜨리는 것 뿐인데 패널 한 가운데 선이 생기는 현상이 나타났다.


이전에 핸드폰이 침수되었을 떄도 비슷한 현상이 생겨서 따로 분해한뒤 디스플레이와 메인보드를 연결해주는 선을 뽑아 세척해서 문제를 해결한 경험이 있었기에 같은 짓을 하기 위해 분해를 했으나 이게 마지막 크레마의 인사일줄은 몰랐다.




내부는 비교적 단순 했다. 메인 보드 사이에 베터리가 내장되고 패널과 LED 등은 FPC로 연결이 되어 있었고 작업 해야할 부분도 명료했다.




조심히 케이블을 분리하고 접촉부를 청소한뒤 재조립을 했는데.... 이런 전원은 들어오는데 화면이 바뀌지 않는다. 하드웨어는 멀쩡하고 소프트웨어가 나간건가?


하나 의심이 되는 부분이라면 케이스 뒷면에 구리 판이 붙어있고 접촉 단자 두개가 이 구리판을 통해 연결이 된다. (구리판에 생긴 작은 홈은 이 접촉단자가 붙어있으면서 생긴 자국이다.) 


분해를 위해서 뒷 판을 떼어내면 접촉 단자의 연결이 끊어진다. 


뒷판은 원래 분리가 안되는 파츠고, 고압이나 고열이 발생하는 장치가 아닌 것을 생각하면 굳이 이런 장치를 해놓은 것은 분해를 막기 위해서 해둔 것이 아닐까 추측된다.


공정이 하나가 더 추가 되어서 단가가 올라갈텐데 왜 굳이.. 라는 생각이 들긴 하지만 글쎄 다른 해석이 떠오르지 않는다.


구리판이 매우 얇기에 혹시 손상된 것은 아닐까 하고 추가로 구리 테이프를 붙여서 보강을 해봤지만 전원이 안들어 오는 것은 똑같았다.


아니나 다를까 크레마 카르타의 분해 영상이나 분해 후기는 단 한건도 찾을 수 없었다.


결국 이게 마지막 모습이 되었다. 



- 새로운 크레마


결국 이것을 빌미로 다시 이북리더를 알아보게 되었다. 


카르타 플러스는 재차 강조하지만 쓰레기고, 그랑데나 사운드, 그리고 요 몇주전에 발매된 크레마 엑스퍼트를 보고 있다.


가능하면 크레마 엑스퍼트를 구입하고 싶지만 50만원이나 하는 가격 떄문에 망설여진다. 


손 필기를 그다지 하지 않기에 펜은 필요 없을 것 같고(밑줄은 자주 친다만)  차라리 돈을 좀 더 보태서 앞자리 선배군이 쓰는 소니 디지털 페이퍼를 사자니 이북리더 본 목적에 부합하지 않고...


크레마 엑스퍼트가 출시된지 얼마 되지 않아서 새로운 이북리더는 나올 것 같지는 않기에 역시 그랑데로 결정이 날 것 같다. 


크레마 들도 다 onyx 라는 외국계 기종을 개조해서 파는 것 같던데 국내 자체 개발한 이북리더가 나와서 제품군이 다양해지고 성능이 개선되기를 바라지만 그런 일은 생기지 않을 것 같다.


얼마전 Yes24에서 감사하게도 "우리가 함께한 이야기" 이라는 이벤트를 진행했었는데 8년간 "고작" 185권의 책을 샀는데 (한달에 두권 꼴) 20대 회원 상위 1% 란다.



산 책이라고 해봐야 절반은 만화나 라이트 노벨, 소설 등의 책일꺼라 쪽팔린데 이런 내가 상위 1%라니.


"책을 사는 사람보다 빌려 읽는 사람이 많을 것이다." 

"어디 불법 다운 받아서 읽나보지"

"Yes24가 아니라 다른 데서 살 수도 있지. 교보문고라던가."

"회원 가입만 해두고 활동을 안하는 사람들이 대다수인 것 아니야?"


아무리 변명을 해도 내가 1%인 것은 좀 아닌것 같다. 


20대 회원 대체 얼마나 책을 안읽는 거냐.


책을 읽는다 => 교양이 생긴다. 책을 읽지 않는 사람은 교양이 없다. 라는 두 명제에 대해서는 나도 터무니 없다고 생각하지만 좀 걱정이 된다. 


점점 사람들이 멍청해지는 것은 아닌지....



Posted by Admin Knowblesse
1 Comments
  1. 호향기 2020.02.08 14:27  댓글주소  수정/삭제  댓글쓰기

    이 기기는 톨리노비젼2와 같은 기기입니다.
    뒤판 구리판은 손을 대면 한페이지 넘기기 기능 때문에 있는 것인데
    이 기능을 이 기기에서는 필요 없지만, 따로 설계하는 것은 돈이 더 들어서 ㅠㅠ 이렇게 그냥 제작한듯해요.
    지금 타 블로그분께서 4.4로 업해서 새로운 런처로 가동되니 참 좋은 기기가 다시 되었답니다.

취미/Programming | 2017. 10. 13. 02:48 | /14?category=733209

1년전 처음 접한 이후로 너무 많이 깠지만 아직도 1년은 더 깔 수 있을 것 같은 파이썬.


파이썬의 최대의 단점 중 하나는 Python 3과 2, 두 가지 버전이 존재하며, 이 둘이 서로 호환이 안된다는 것이다.


가장 대표적인 차이점으로 왜인지 모르게 print 함수의 사용 방식을 이야기 하던데 두 언어가 콘솔이 "Python_Sucks"라는 문구를 표시하게 하는 방식은 아래와 같다.


<Python 2.X>

print Python_Sucks

<Python 3.X>

print("Python_Sucks")


간혹 파이썬을 사용하는 프로그램을 돌리다보면 print 문이 들어가있는 구문에서 오류가 발생했다는 메시지를 볼 수 있는데 99%의 확률로 해당 프로그램이 잘못된(제작자가 원치 않았던) 버전의 파이썬으로 프로그램을 돌리고 있는 것이다.


글지기는 fMRI 분석 프로그램을 돌리다가 해당 문제를 경험했는데 default python을 바꾸어줘도 해결이 안되고 프로그램 내부에 어떤 Python을 쓰라고 명령을 할 수 있는 부분도 없고 해서 엄청 빡쳤다.당혹스러웠다. 


잘 아시는 분은 이미 아시겠지만... 


아나콘다를 설치한 유저라면 간단히 문제를 해결 할 수 있다. 


자세한 내용은 아래 사이트를 참고하고, 필요한 부분만 보려면 아래 글지기가 요약해둔 부분을 보면 된다.


https://conda.io/docs/user-guide/tasks/manage-environments.html#creating-an-environment-with-commands




0. 선행조건 : 아나콘다가 깔려있어야 한다.


1. 먼저 콘솔을 실행한다. 우분투에서는 터미널을...


2. 아래의 커멘드를 사용해서 가상 파이썬 환경을 만든다.


>>conda create -n 환경의_이름_(잘외워두자) python=파이썬 버전

예) conda create -n pytEnv27 python=2.7

=> pytEnv27 이라는 이름으로 파이썬 2.7 환경을 만든다.


만드려는 가상환경에 해당하는 파이썬 버전이 없으면 자기가 알아서 깔아준다. (좀 걸리니 커피한잔 마시고 오자.)


3. 해당 환경을 활성화 시켜준다.


<Window>

>>activate 환경의_이름


<Linux>

>>source activate 환경의_이름


환경의 이름을 매번 까먹는 글지기를 포함하는 안타까운 프렌즈라면 아래의 커멘드만 기억하면 된다.


conda info --envs


이것도 기억을 못하는 안타까운 글지기는 아래의 방법을 쓴다.


<Linux>

>>source activate asdfojaeoifjoewjaofi

궁시렁궁시렁

 conda info --envs 를 쓰면 니가 만든 환경을 볼 수 있다는 설명

궁시렁궁시렁


그렇게 하면, 우분투의 경우 터미널 앞에 해당 환경의 이름이 붙어서 나온다!


이 상태에서 프로그램을 실행하면 해당 파이썬 환경에서 프로그램을 돌려볼 수 있다.


부디 이 글이 파이썬 버전에 분노하며 밤 잠을 설치고 있는 불쌍한 대학(원)생을 구원할 수 있기를....

Posted by Admin Knowblesse
0 Comments