펌 : https://eagle705.github.io/cslog/2018/06/14/PyTorch_0.4/

 

PyTorch 0.4 version up 정리

14 Jun 2018 in ComputerScience on DeepLearning



본 문서는 PyTorch v0.4에서 변경된 APIs를 기술하기 위한 문서입니다. 공식 Migration guide를 참조했습니다.

A. 소개

B. Migration Guide

  • Tensors와 Variables가 합쳐짐
  • 0-dimensional (scalar) Tensors를 지원함
  • Backprop을 위한 값들을 저장하지 않게 했던 volatileflag가 Depreciation됨
  • dtypes, devices그리고 Numpy-style Tensor 생성 함수가 추가됨 (테스트 필요)
  • Writing device-agnostic code (무슨뜻이지)
  • 새로운 edge-case constraints가 nn.Module안에서 submodules, parameters, buffers 이름등으로 생김

Tensors와 Variables가 합쳐짐

torch.Tensor와 torch.autograd.Variable이 이젠 같은 클래스가 되었습니다. 

torch.Tensor 클래스는 old Variable 처럼 히스토리 추적이 가능하게 되었습니다.

예전엔 딱 자료구조용인 Tensor를 선언하고 그걸 Variable로 랩핑해줬다면, 지금은 마치 TensorFlow의 Tensor처럼 안에 기능이 다 통합 된 것 같습니다.

 

지금도 Variable랩핑이 전 처럼 가능하지만, 리턴값은 전과 다르게 torch.Tensor로 나올 것 입니다.

 

즉, 예전코드와 호환은 잘 된다는 것이겠지요. 다만 예전 코드에서의 Variable은 의미상으론 읽기 편해지나, 기능상으론 redundant해졌다고도 볼 수 있을 것 같습니다.

 

 

 

Tensor의 type() 함수가 변경됨

예전엔 type()함수가 데이터의 타입을 리턴했습니다만,

지금은 torch.Tensor를 리턴합니다.(Variable도 그렇겠죠??) 에전처럼 데이터타입을 보고싶으면, 
type() 대신 x.type() 또는 isinstance() 를 사용해야합니다.

 

일반적인 Python의 쓰임과 달라서 저도 많이 당황했습니다.

 

>>> x = torch.DoubleTensor([1, 1, 1]) >>> print(type(x)) # was torch.DoubleTensor "<class 'torch.Tensor'>" >>>

 

print(x.type()) # OK: 'torch.DoubleTensor' 'torch.DoubleTensor' >>> print(isinstance(x, torch.DoubleTensor)) # OK: True True

 

 

autograd가 tracking history를 하는 시점?

autograd는 Tensor의 gradient를 계산하기 위해 computational graph를 고려하기 위해 고안되었었습니다. autograd의 핵심 flag인 requires_grad는 이제 Tensors의 attribute가 되었습니다. 그렇다면 이제 Tensors는 과연 언제부터 computational graph를 고려하게 될까요? 아래 예제를 통해 보시면 직접 requires_grad flag를 True로 지정해줘야함을 알 수 있습니다.

 

>>> x = torch.ones(1) # create a tensor with requires_grad=False (default) >>> x.requires_grad False >>> y = torch.ones(1) # another tensor with requires_grad=False >>> z = x + y >>> # both inputs have requires_grad=False. so does the output >>> z.requires_grad False >>> # then autograd won't track this computation. let's verify! >>> z.backward() RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn >>> >>> # now create a tensor with requires_grad=True >>> w = torch.ones(1, requires_grad=True) >>> w.requires_grad True >>> # add to the previous result that has require_grad=False >>> total = w + z >>> # the total sum now requires grad! >>> total.requires_grad True >>> # autograd can compute the gradients as well >>> total.backward() >>> w.grad tensor([ 1.]) >>> # and no computation is wasted to compute gradients for x, y and z, which don't require grad >>> z.grad == x.grad == y.grad == None True

 

requires_grad flag 조작하기

 

 

default 값은 False로 되어있습니다. 아래와 같이 변경할 수 있습니다. 함수 뒤에가 _ 이면 in-place(새로 대입할 필요가 없는, 그 자리에서 교체되는)로 보시면 됩니다

>>> existing_tensor.requires_grad_() >>> existing_tensor.requires_grad True >>> my_tensor = torch.zeros(3, 4, requires_grad=True) >>> my_tensor.requires_grad True

Tensor와 Variables가 합쳐졌다면, 그럼 .data은 어떻게 된거죠?

.data는 원래 Variables로 부터 Tensor를 추출해내는데 사용되었었습니다. y = x.data는 이제 다음과 같은 의미를 갖는데, y는 Tensor가 되고 x와 같은 데이터를 share(복사가 아니라 share라는게 매우 중요)합니다. 하지만 x의 computational history와 분리되고 requires_grad=False 처리가 됩니다. 

하지만 .data는 다소 unsafe할때가 있습니다. x.data의 변화가 autograd에 의해서 추적이 안되기 때문에, gradient를 계산할 때 값이 잘못될 수 있습니다. (.data는 값을 복사하는게 아니라 share하기 때문에 값이 바뀌면 당연히 gradient에 영향을 줘야하는데 require_grad=False니 못주는 상황입니다.) 
그러므로 추천하기로는 x.detach()사용을 권합니다. 얘는 .data와 비슷한 역할(share data, require_grad=False)을 하지만 값이 바뀌면 autograd가 바뀐걸 알 수 있습니다. 기억할건, 왠만하면 .detach()를 사용하면 된다는 것입니다. 아래 예제를 보시죠.

Tensor.detach() 사용할 때 (권장),

>>> a = torch.tensor([1,2,3.], requires_grad = True) >>> out = a.sigmoid() >>> c = out.detach() >>> c.zero_() tensor([ 0., 0., 0.]) >>> out # modified by c.zero_() !! tensor([ 0., 0., 0.]) >>> out.sum().backward() # Requires the original value of out, but that was overwritten by c.zero_() RuntimeError: one of the variables needed for gradient computation has been modified by an

Tensor.data 사용할 때 (비추),

>>> a = torch.tensor([1,2,3.], requires_grad = True) >>> out = a.sigmoid() >>> c = out.data >>> c.zero_() tensor([ 0., 0., 0.]) >>> out # out was modified by c.zero_() tensor([ 0., 0., 0.]) >>> out.sum().backward() >>> a.grad # The result is very, very wrong because `out` changed! tensor([ 0., 0., 0.])

Scalar Tensors지원 (0-dimensional Tensors)

이전 버전에서는 Tensor vector에서 인덱싱하면 Python number를 줬지만 Variablevector에서는 Tensor vector와는 다르게(inconsistently!) vector of size (1,)을 리턴했습니다. sum함수도 마찬가지였습니다. 이제는 numpy.array 스타일처럼 Scalar Tensor를 지원합니다. (.item() 을 주목해서보자. 나중에 사용할 수도)

>>> torch.tensor(3.1416) # create a scalar directly tensor(3.1416) >>> torch.tensor(3.1416).size() # scalar is 0-dimensional torch.Size([]) >>> torch.tensor([3]).size() # compare to a vector of size 1 torch.Size([1]) >>> >>> vector = torch.arange(2, 6) # this is a vector >>> vector tensor([ 2., 3., 4., 5.]) >>> vector.size() torch.Size([4]) >>> vector[3] # indexing into a vector gives a scalar tensor(5.) >>> vector[3].item() # .item() gives the value as a Python number 5.0 >>> mysum = torch.tensor([2, 3]).sum() >>> mysum tensor(5) >>> mysum.size() torch.Size([])

losses 계산

기존 패턴은 total_loss += loss.data[0] 방식이었습니다. 0.4.0 전에는 loss도 Variable에 랩핑된 텐서로써 (1,) size를 가졌었습니다. 하지만 0.4.0에서는 loss는 이제 0 dimension을 갖는 scalar입니다. loss.item() 을 사용하세요. scalar에서부터 Python number를 얻을 땐 앞으로 .item()을 사용해야합니다. 
Note that if you don’t convert to a Python number when accumulating losses, you may find increased memory usage in your program. This is because the right-hand-side of the above expression used to be a Python float, while it is now a zero-dim Tensor. The total loss is thus accumulating Tensors and their gradient history, which may keep around large autograd graphs for much longer than necessary.

Deprecation of volatile flag

volatile는 이전 버전에서는 주로 inference할때 많이 사용되었었습니다. volatile flag는 이제 deprecated 되었고, 효과가 없습니다. 전에는 Variable에서 volatile=True 조건이면 autograd가 추적하지 않았지만 이젠 torch.no_grad(), torch.set_grad_enabled(grad_mode) 외에 다른 것들로 대체 되었습니다.

>>> x = torch.zeros(1, requires_grad=True) >>> with torch.no_grad(): ... y = x * 2 >>> y.requires_grad False >>> >>> is_train = False >>> with torch.set_grad_enabled(is_train): ... y = x * 2 >>> y.requires_grad False >>> torch.set_grad_enabled(True) # this can also be used as a function >>> y = x * 2 >>> y.requires_grad True >>> torch.set_grad_enabled(False) >>> y = x * 2 >>> y.requires_grad False

 

 

조금 더 이해하고 포스팅을 수정해야겠습니다.

ToDo

  • new data types
  • gpu device allocation 
    (문법이 조금 바뀜, .cuda() -> .to(torch.device("cuda:0" if torch.cuda.is_available() else "cpu")) )

Tensor Flow의 기본 변수및 함수 설명입니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 텐서플로우의 기본적인 구성을 익힙니다.
import tensorflow as tf
 
# tf.constant: 말 그대로 상수입니다.
hello = tf.constant('Hello, TensorFlow!')
print(hello)
 
= tf.constant(10)
= tf.constant(32)
= tf.add(a, b)  # a + b 로도 쓸 수 있음
print(c)
 
# 위에서 변수와 수식들을 정의했지만, 실행이 정의한 시점에서 실행되는 것은 아닙니다.
# 다음처럼 Session 객제와 run 메소드를 사용할 때 계산이 됩니다.
# 따라서 모델을 구성하는 것과, 실행하는 것을 분리하여 프로그램을 깔끔하게 작성할 수 있습니다.
# 그래프를 실행할 세션을 구성합니다.
sess = tf.Session()
# sess.run: 설정한 텐서 그래프(변수나 수식 등등)를 실행합니다.
print(sess.run(hello))
print(sess.run([a, b, c]))
 
# 세션을 닫습니다.
sess.close()
 
cs


'Deep Learning > Tensor Flow' 카테고리의 다른 글

Tensor Flow Code 분석 - Neural Network  (0) 2017.08.28
Tensor Flow 기반의 Code 분석 코드는 git hub에 잘 정리된 Code를 퍼왔습니다.
출처 : https://github.com/golbin/TensorFlow-Tutorials


주석도 잘 달려 있었으나 제가 초보적인 관점에서 공부를 하는 마음으로 조금 더 추가 했습니다.
 
정리하다 보니 one-hot encode와 reduce_mean의 개념을 추가로 추가로 정리해야 겠네요. ^^
모두 열심히 공부합시다다



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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# 털과 날개가 있는지 없는지에 따라, 포유류인지 조류인지 분류하는 신경망 모델을 만들어봅니다.
import tensorflow as tf
import numpy as np
 
# [털, 날개] 라고 가정한다 
# 2가지 데이터 . 즉, input Node는 2개
# x_data 는 2가지 데이터를 가진 데이터 Set이 6개
x_data = np.array(
    [[00], [10], [11], [00], [00], [01]])
 
# [기타, 포유류, 조류] 라고 가정한다. 
# 3가지 분류  Output Node는 3개
 
# 다음과 같은 형식을 one-hot 형식의 데이터라고 합니다. ( 하나만 1, 나머지 0 )
 
# 정답(Label)을 의미하는 y_data이 one-hot 형식을 하는 이유는 ? 
# 예측 시 확률 적으로 가장 큰 값을 그것!? 으로 분류하는데 
# 만약 예측 값이 [ 0.8 , 0.1 , 0.1 ] 일 경우 
# 정답[1, 0, 0] 과의 차이를 줄여 나가는 방식으로 # W와 b를 정교화하는데 
# 이 때, ont-hot 형식이어야 차이 값 비교하는 연산을 하기 쉽기 때문이다.
# 만약 데이터가 y_data = np.array([[0],[1],[2],[0],[0],[2]))라면
# 데이터를 비교하기 어렵다. 
# 이럴 경우는 .one_hot이라는 함수를 통해 one-hot형식으로 변경 할 수 있다.
 
y_data = np.array([
    [100],  # 기타
    [010],  # 포유류
    [001],  # 조류
    [100],
    [100],
    [001]
])
 
#########
# 신경망 모델 구성
######
= tf.placeholder(tf.float32)
= tf.placeholder(tf.float32)
 
# 신경망은 2차원으로 [입력층(특성), 출력층(레이블)] -> [2, 3] 으로 정합니다.
= tf.Variable(tf.random_uniform([23], -1.1.))
 
# 편향을 각각 각 레이어의 아웃풋 갯수로 설정합니다.
# 편향은 아웃풋의 갯수, 즉 최종 결과값의 분류 갯수인 3으로 설정합니다.
= tf.Variable(tf.zeros([3]))
 
# 신경망에 가중치 W과 바이어스 b을 적용합니다
# Y' = XW + b
= tf.add(tf.matmul(X, W), b)
# 가중치와 편향을 이용해 계산한 결과 값에
# 텐서플로우에서 기본적으로 제공하는 활성화 함수인 ReLU 함수를 적용합니다.
# Activation 함수 종류는 많은 종류가 있으나, ReLU는 미분하면 0과 1의 값이 나오기 때문에 
# Deep Learning에서 계산을 줄여 성능을 높일 수 있기 때문에 많이 사용한다.
= tf.nn.relu(L)
 
# 마지막으로 softmax 함수를 이용하여 출력값을 사용하기 쉽게 만듭니다
# softmax 함수는 다음처럼 결과값을 전체합이 1인 확률로 만들어주는 함수입니다.
# 예) [8.04, 2.76, -6.52] -> [0.53 0.24 0.23]
# softmax 함수는 확률을 1로 만들어 Label 값 , 
# 즉 , one-hot encoding된 정답 값과 차이를 비교하기 쉽게 하기 위해서 사용한다.
# 참고로 ,one-hot 된 값도 모두 더하면 1, softmax 된 값도 모두 더하면 1이기 때문에 비교가 쉽다.
model = tf.nn.softmax(L)
 
# 신경망을 최적화하기 위한 비용 함수를 작성합니다.
# 각 개별 결과에 대한 합을 구한 뒤 평균을 내는 방식을 사용합니다.
# 전체 합이 아닌, 개별 결과를 구한 뒤 평균을 내는 방식을 사용하기 위해 axis 옵션을 사용합니다.
# axis 옵션이 없으면 -1.09 처럼 총합인 스칼라값으로 출력됩니다.
#        Y         model         Y * tf.log(model)   reduce_sum(axis=1)
# 예) [[1 0 0]  [[0.1 0.7 0.2]  -> [[-1.0  0    0]  -> [-1.0, -0.09]
#     [0 1 0]]  [0.2 0.8 0.0]]     [ 0   -0.09 0]]
# 즉, 이것은 예측값과 실제값 사이의 확률 분포의 차이를 비용으로 계산한 것이며,
# 이것을 Cross-Entropy 라고 합니다.
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(model), axis=1))
 
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train_op = optimizer.minimize(cost)
 
 
#########
# 신경망 모델 학습
######
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
 
for step in range(100):
    sess.run(train_op, feed_dict={X: x_data, Y: y_data})
 
    if (step + 1) % 10 == 0:
        print(step + 1, sess.run(cost, feed_dict={X: x_data, Y: y_data}))
 
 
#########
# 결과 확인
# 0: 기타 1: 포유류, 2: 조류
######
# tf.argmax: 예측값과 실제값의 행렬에서 tf.argmax 를 이용해 가장 큰 값을 가져옵니다.
# 예)  [ [ 0 1 0] [ 1 0 0 ] ] -> [1 0] :
# index가 0 1 0 일 때 가장 큰 값의 index는 1 , 1 0 0 index 0 이므로 [ 1 0 ]
#     [[0.2 0.7 0.1] [0.9 0.1 0.0]] -> [1 0]
prediction = tf.argmax(model, 1)
target = tf.argmax(Y, 1)
print('예측값:', sess.run(prediction, feed_dict={X: x_data}))
print('실제값:', sess.run(target, feed_dict={Y: y_data}))
 
is_correct = tf.equal(prediction, target)
accuracy = tf.reduce_mean(tf.cast(is_correct, tf.float32))
print('정확도: %.2f' % sess.run(accuracy * 100, feed_dict={X: x_data, Y: y_data}))
 
 
cs




딥러닝 학습 기술들

 | 

이번 글은 딥러닝 관련 다양한 학습기술들을 살펴보고자 합니다. 이번 글은 미국 스탠포드 대학의 CS231n과 역시 같은 대학의 CS224d 강좌를 정리했음을 먼저 밝힙니다. 따로 정리할 예정인 배치정규화(batch-regularization)를 제외하고 전반적인 내용을 요약하였습니다. 그럼 시작하겠습니다.

딥러닝 학습의 일반적 절차

딥러닝의 일반적 절차는 다음과 같습니다.

  1. 적절한 네트워크 선택

    1) 구조(structure) : Single words vs Bag of Words, etc.

    2) 비선형성(nonlinearity) 획득 방법 : ReLu vs tanh, etc.

  2. 그래디언트 체크 : 네트워크를 구축했는데 그래디언트 계산이 혹시 잘못될 염려가 있으므로 잘됐는지 체크해봅니다

  3. 학습 파라메터 초기화 : 초기화 방법에도 여러가지가 있으므로 적절히 선택합니다

  4. 학습 파라메터 최적화 : Stochastic Gradient vs Adam, etc.

  5. 과적합 방지 : dropout vs regularize, etc.

비선형성 획득 : 활성함수

뉴럴네트워크의 개별 뉴런에 들어오는 입력신호의 총합을 출력신호로 변환하는 함수를 활성화함수(activation function)라고 합니다. 활성화함수 유무는 초창기 모델인 퍼셉트론(perceptron)과 뉴럴네트워크의 유일한 차이점이기도 하죠. 활성화함수는 대개 비선형함수(non-linear function)를 씁니다. 활성화함수로 왜 선형함수를 쓰면 안되는 걸까요? ‘밑바닥부터 시작하는 딥러닝’의 한 글귀를 인용해보겠습니다.

선형함수인 h(x)=cx를 활성화함수로 사용한 3층 네트워크를 떠올려 보세요. 이를 식으로 나타내면 y(x)=h(h(h(x)))가 됩니다. 이는 실은 y(x)=ax와 똑같은 식입니다. a=c3이라고만 하면 끝이죠. 즉, 은닉층이 없는 네트워크로 표현할 수 있습니다. 뉴럴네트워크에서 층을 쌓는 혜택을 얻고 싶다면 활성화함수로는 반드시 비선형 함수를 사용해야 합니다.

그러면 뉴럴네트워크 활성화함수 몇 가지 살펴보겠습니다.

시그모이드

로지스틱 함수로도 불립니다. 원래 수식 및 미분식은 아래와 같습니다.

σ(x)=11+exσ(x)=σ(x)(1σ(x))

시그모이드 함수의 범위는 [0,1]이고요, 그래프의 모양은 아래와 같습니다.

시그모이드 함수를 1차 미분한 그래프는 아래와 같습니다.

시그모이드 함수는 개별 뉴런이 내뱉어 주는 값을 S자 커브 형태로 자연스럽게 활성화를 해주기 때문에 예전부터 인기가 좀 있었습니다. 다만 입력값이 -5보다 작거나 5보다 클 경우에는 그래디언트 값이 지나치게 작아지고(=이렇게 되면 학습이 잘 안되죠), exp 연산이 다소 무겁다(=학습이 느려지죠)는 단점이 있습니다.

아울러 σ(x)의 범위는 [0,1]로서 모두 0 이상의 값을 지닌다는 문제가 있습니다. 이게 단점이 되는 이유는 바로 학습 속도와 관련이 있는데요. 예컨대 아래와 같은 뉴런이 있고 활성화함수 f가 시그모이드라고 가정해봅시다.

x0x1x2는 모두 0 이상의 값을 갖습니다. 이들은 직전 층에서 시그모이드 함수에 의해 그 값이 양수로 활성화됐기 때문입니다. 여기에서 역전파시 최종 Loss에서 출발해 시그모이드 적용 직전의 wixi+b 각각에 들어오는 그래디언트를 δ라고 두겠습니다. 그렇다면 wi의 그래디언트는 아래와 같습니다.

Lwi=xi×δ

앞서 말씀드렸듯 x0x1x2는 모두 0 이상이기 때문에 δ가 양수라면 wi의 그래디언트가 항상 양수, 반대라면 모두 음수 값을 갖게 될 것입니다. δ가 양수인 상황에서 wi를 업데이트해보겠습니다.

이상적인 wi는 아래 그림처럼 파란색 화살표이지만, 실제 학습시 wi는 빨간색 화살표처럼 지그재그로 움직여야 한다는 걸 확인할 수 있습니다. wi의 그래디언트(기울기)가 항상 양수여서 학습시 허용되는 방향이 초록색 영역뿐이기 때문입니다. 이 때문에 활성화함수가 zero-centered 모양이 아니면 학습시 수렴속도가 늦거나 수렴이 어려운 경향이 있다고 합니다.

하이퍼볼릭탄젠트

하이퍼볼릭탄젠트는 시그모이드 함수의 크기와 위치를 조절(rescale and shift)한 함수입니다. 시그모이드 함수와의 관계식과 미분식은 각각 아래와 같습니다.

tanh(x)=2σ(2x)1=exexex+extanh(x)=1tanh2(x)

하이퍼볼릭탄젠트의 범위는 [1,1]입니다. 그래프의 모양은 시그모이드 함수와는 달리 0을 기준으로 대칭인 점을 확인할 수 있습니다. 이 때문에 하이퍼볼릭탄젠트는 시그모이드를 활성화함수로 썼을 때보다 학습 수렴 속도가 빠르다고 합니다.

하이퍼볼릭탄젠트를 1차 미분한 그래프는 아래와 같습니다. 시그모이드함수와 마찬가지로 x가 -5보다 작거나 5보다 크면 그래디언트가 0으로 작아지는 점을 볼 수 있습니다. 이것이 하이퍼볼릭탄젠트의 단점입니다.

Rectified Linear Unit (ReLU)

ReLU는 아래와 같이 정의됩니다.

f(x)=max(0,x)

그래프의 모양은 아래와 같습니다. x가 양수이기만 하면 그래디언트가 1로 일정하므로 그래디언트가 죽는 현상을 피할 수 있고, 미분하기도 편리해 계산복잡성이 낮습니다. 실제로 시그모이드나 하이퍼볼릭탄젠트 함수 대비 학습수렴 속도가 6배나 빠르다고 합니다.

다만 위 그림에서 확인할 수 있듯 0을 기준으로 대칭인 모양은 아닙니다. 아울러 x가 음수이면 그래디언트가 무조건 0이 된다는 단점이 있습니다. 이를 극복하기 위해 Leaky ReLU가 고안되었습니다.

Leaky ReLU

Leaky ReLU의 식은 아래와 같습니다.

f(x)=max(0.01x,x)

그래프의 모양은 다음과 같습니다. x가 음수일 때 그래디언트가 0.01이라는 점을 제외하고는 ReLU와 같은 특성을 지닙니다.

Exponential Linear Units (ELU)

ELU는 ReLU의 특성을 공유하고요, 그래디언트가 죽지 않는다는 장점이 있다고 합니다. 다음 수식과 같습니다.

f(x)=xifx>0f(x)=α(ex1)ifx0

Maxout Neurons

MN은 다음과 같습니다. 연결된 두 개의 뉴런 값 중 큰 값을 취해 비선형성을 확보합니다. 다만 활성화함수를 적용하기 위해 필요한 연산량이 많다는 단점이 있습니다.

f(x)=max(w1Tx+b1,w2Tx+b2)

학습 파라메터 초기화

각 층의 가중치(weights)와 편향(bias) 등 학습 파라메터는 초기값 설정이 매우 중요하다고 합니다. 뉴럴네트워크가 풀려는 문제 자체가 non-convex optimization이기 때문에 시작점에 따라 최적지점을 찾지 못하게 될 수도 있습니다.

또한 학습 파라메터의 초기값을 적절하게 설정할 경우 그래디언트 조절에도 유의미한 효과를 낸다고 합니다. 이와 관련해 시그모이드 함수의 1차 미분 그래프를 다시 보도록 하겠습니다.

입력값 x에 가중치 w를 곱하고 편향 b를 더한 식을 t라고 둡시다. 여기에서 w가 100, b가 50이라면 x가 0.01로 매우 작더라도 t는 51이 됩니다. 역전파시 시그모이드 함수를 통과시키면 σ(51)가 반환이 될텐데요, 위 그래프를 보시다시피 t가 5만 넘어도 σ(t)는 0에 수렴하기 때문에 그래디언트가 죽어버리는 결과를 초래하게 됩니다. 그래디언트가 지나치게 작아지기 때문에 이후 학습이 사실상 불가능해지는 것이지요.

이와 별개로 뉴럴네트워크 입력층의 가중치 W를 모두 0으로 초기화한다면 어떻게 될까요? 순전파 때는 W가 0이기 때문에 두번째 층의 뉴런에 모두 같은 값이 전달됩니다. 미분의 연쇄법칙(chain-rule)을 떠올려보면 두번째 층의 모든 뉴런에 같은 값이 입력된다는 것은 역전파 때 두번째 층의 가중치가 모두 똑같이 갱신된다는 말이 됩니다. 다시 말해 뉴런이 100개가 됐든 1000개가 됐든 거의 같은 값을 출력하게 돼 네트워크의 표현력을 제한하게 된다는 얘기입니다.

따라서 학습파라메터의 초기값을 잘 설정해주어야 합니다. 이와 관련해 다양한 파라메터 초기화 방법론이 제시되었습니다. 일부를 소개하면 다음과 같습니다. 여기에서 nin은 직전 레이어의 차원수, nout은 다음 레이어의 차원수입니다. 아래 초기화식은 각 층의 가중치 W에 관한 식이고요, 은닉층과 출력층의 편향 b는 대개 0으로 설정한다고 합니다.

LeCun Initialization (Xavier Initialization)

WUniform(nin,nout)Var(W)=1nin

Glorot Initialization

WUniform(nin,nout)Var(W)=2nin+nout

He Initialization

WUniform(nin,nout)Var(W)=2nin

학습 파라메터 최적화 (1)

학습 파라메터 최적화 기법으로 널리 쓰이는 그래디언트 디센트(Gradient Descent)는 기본적으로 아래와 같은 구조를 지닙니다. 여기에서 θ는 갱신 대상 학습 파라메터, dL/dθ는 Loss에 대한 θ의 그래디언트, η는 학습률(leaning rate)을 의미합니다. 즉 아래 식은 Loss에 대한 θ의 그래디언트 반대 방향으로 η만큼 조금씩 θ를 업데이트하라는 뜻입니다.

θθηLθ

그래디언트 디센트 방법론에도 여러 변형이 존재합니다. 세 가지 살펴보겠습니다. 아래 제시된 코드는 파이썬 기준입니다.

Batch Gradient Descent

이 방법은 전체 학습데이터 Loss에 대한 각 파라메터의 그래디언트를 한꺼번에 구한 뒤 1 epoch동안 모든 파라메터 업데이트를 단 한번 수행하는 방식입니다. 매우 느리고 메모리 요구량이 많다는 단점이 있지만 최적해를 찾을 수 있다는 장점이 있다고 합니다. (It’s guaranteed to converge to the global minimum for convex error surfaces and to a local minimum for non-convex surfaces)

for i in range(nb_epochs):
    params_grad = evaluate_gradient(loss_function, data, params)
    params = params - learning_rate * params_grad

Stochastic Gradient Descent

학습데이터의 순서를 랜덤으로 섞은 뒤 개별 레코드(위 코드에서 example) 단위로 Loss와 그래디언트를 구한 뒤 학습 파라메터를 조금씩 업데이트하는 방식입니다. 1 epoch동안 학습데이터 개수만큼의 업데이트가 수행됩니다. BGD보다 훨씬 빠르면서도 수렴 결과가 BGD와 일치(학습률을 줄였을 때)한다고 합니다.

for i in range(nb_epochs):
    np.random.shuffle(data)
    for example in data:
    	params_grad = evaluate_gradient(loss_function, example, params)
    	params = params - learning_rate * params_grad

Mini-batch Gradient Descent

이 방식은 개별 레코드가 아니라 batch_size(아래 코드에서 50) 단위로 학습한다는 점을 제외하고는 SGD와 같습니다. SGD에 비해 안정적으로 학습하는 경향이 있다고 합니다. 게다가 데이터가 배치 단위로 들어가게 되면 사실상 행렬 연산이 되기 때문에 시중에 공개돼 있는 강력한 라이브러리를 사용할 수 있다는 장점 또한 있습니다.

for i in range(nb_epochs):
    np.random.shuffle(data)
    for batch in get_batches(data, batch_size=50):
    	params_grad = evaluate_gradient(loss_function, batch, params)
    	params = params - learning_rate * params_grad

학습 파라메터 최적화 (2)

그래디언트 디센트 계열 외에 다양한 최적화 기법을 소개합니다. 최근 각광받고 있는 기법들입니다.

Momentum

모멘텀은 운동량을 뜻하는 단어로 물리 현상과 관계가 있습니다. 예컨대 아래 그림처럼 공이 한번 움직이기 시작하면 기울기 방향으로 힘을 받아 가속하게 되죠. 모멘텀 기법은 바로 이 점에 착안했습니다.

모멘텀 기법은 수식으로는 다음과 같이 쓸 수 있습니다. 여기에서 μv는 물체가 아무런 힘을 받지 않을 때 서서히 하강시키는 역할을 합니다(μ는 0.9 등의 값으로 설정합니다). 물리에서는 지면 마찰이나 공기 저항에 해당합니다. 나머지는 그래디언트 디센트 기법과 동일합니다.

vμvηLθθθ+v

모멘텀 기법의 최적화 효과를 직관적으로 나타낸 그림은 아래와 같습니다. 하단 좌측 그림을 보시면 현재의 그래디언트가 모멘텀과 같은 방향이라면 업데이트가 더 크게 이뤄지게 됩니다. 하단 우측 그림에서 최적화 지점이 원 내부 중앙이라고 했을 때 모멘텀 기법이 조금 더 효율적인 업데이트 경로를 거치고 있는 점을 확인할 수 있습니다.

코드로는 아래와 같습니다. 여기에서 μ는 사용자가 지정하는 하이퍼파라메터입니다.

param_grad = evaluate_gradient(loss_function, data, params)
v = mu * v - learning_rate * param_grad
param = v + param

Nesterov Accelerated Gradient

이 기법은 모멘텀 기법을 업그레이드한 버전입니다. 현재 학습 파라메터(붉은색 원 : 아래 코드에서 params)를 직전까지 축적된 그래디언트 방향(녹색선)으로 이동시킵니다. 이 벡터(paramsahead)를 기준으로 그래디언트(붉은색 선 : paramsgradahead)를 계산합니다. 실제 업데이트는 둘을 모두 반영해 이뤄집니다.

모멘텀과의 차이 : 모멘텀은 현재 점(붉은색 원)에서 그래디언트를 구합니다. NAG는 녹색선과 빨간선이 이루는 꼭지점에서 그래디언트를 구합니다.

이 기법을 코드로 나타내면 아래와 같습니다. 여기에서도 μ는 역시 사용자가 지정하는 하이퍼파라메터입니다.

params_ahead = params + mu * v
params_grad_ahead = evaluate_gradient(loss_function, data, params_ahead)
v = mu * v - learning_rate * params_grad_ahead
params = v + params

AdaGrad

학습률 감소와 연관된 기법입니다. AdaGrad는 각각의 학습 파라메터에 맞춤형으로 학습률을 조정하면서 학습을 진행합니다. 수식은 아래와 같습니다. 여기에서 는 행렬의 원소별 곱셈을 의미합니다. 식을 보시면 학습 파라메터의 원소 가운데 많이 움직인(크게 갱신된) 원소는 학습률이 낮아지게 돼 있습니다. 다시 말해 학습률이 학습 파라메터의 원소마다 다르게 적용된다는 뜻입니다.

hh+LθLθθθηhLθ

이를 코드로 나타면 아래와 같습니다. 아래 코드에서 eps는 분모가 너무 0에 가깝지 않도록 안정화하는 역할을 합니다. 보통 104에서 108의 값을 쓴다고 합니다.

params_grad = evaluate_gradient(loss_function, data, params)
h = h + params_grad**2
params = params - learning_rate / (np.sqrt(h) + eps) * params_grad

RMSProp

AdaGrad는 학습률 η를, 과거의 기울기를 제곱한 값을 계속 더해나간 h로 나눠줍니다. 학습을 진행할 수록 η가 지속적으로 작아진다는 뜻입니다. 계속 학습하면 η가 0이 돼서 학습이 불가능해지는 시점이 옵니다. RMSProp은 이를 개선하기 위한 기법입니다. 즉 과거의 모든 기울기를 다 더해 균일하게 반영하는 것이 아니라, 먼 과거의 기울기는 서서히 잊고 새로운 기울기 정보를 크게 반영하기 위해 h를 계산할 때 지수이동평균(Exponential Moving Average)을 적용합니다.

코드는 아래와 같습니다. 여기에서 decay_rate는 사용자 지정 하이퍼파라메터이고 보통 [0.9,0.99,0.999] 가운데 하나를 쓴다고 합니다.

params_grad = evaluate_gradient(loss_function, data, params)
h = decay_rate * h + (1 - decay_rate) * params_grad**2
params = params - learning_rate / (np.sqrt(h) + eps) * params_grad

Adam

모멘텀은 공이 구르듯 하는 물리 법칙에 착안해 만들어진 기법입니다. AdaGrad과 RMSProp은 학습 파라메터의 개별 원소마다 학습률을 달리 적용합니다. 두 기법을 합친 것이 바로 Adam입니다. 퍼포먼스가 좋아서 최근 많은 관심을 받고 있는 기법인데요. 코드는 다음과 같습니다.

params_grad = evaluate_gradient(loss_function, data, params)
m = beta1 * m + (1 - beta1) * params_grad
v = beta2 * v + (1 - beta2) * params_grad**2
params = params - learining_rate * m / (np.sqrt(v) + eps)

여기에서 beta1beta2eps는 사용자가 지정하는 하이퍼파라메터입니다. 논문에 따르면 각각 0.9, 0.999, 108이 좋다고 합니다.

각 기법 비교

너무나도 유명한 그림이라 설명은 생략하겠습니다. 저 역시 정리 용도로 올려 둡니다.

과적합 방지

과적합(overfitting)이란 모델이 학습데이터에만 지나치게 적응해서 일반화 성능이 떨어지는 경우를 말합니다. 기계학습은 범용 성능을 지향하기 때문에 학습데이터 외에 처음 보는 데이터가 주어지더라도 올바르게 판단할 수 있는 능력을 가져야 합니다. 뉴럴네트워크 학습시 과적합을 방지하는 몇 가지 기법에 대해 살펴보도록 하겠습니다.

모델 크기 줄이기

가장 간단한 방법입니다. 레이어나 뉴런 등 학습해야할 파라메터의 개수를 줄여서 과적합을 방지합니다.

early stopping

학습을 일찍 중단하는 방식으로 과적합을 방지합니다.

가중치 감소

과적합은 학습 파라메터의 값이 커서 발생하는 경우가 많다고 합니다. 가중치 감소(weight decay)는 이를 방지하기 위해 학습 파라메터의 값이 크면 그에 상응하는 큰 패널티를 부여하는 기법입니다.

1) L2 Regularization : 가장 일반적인 regulization 기법입니다. 기존 손실함수(Lold)에 모든 학습파라메터의 제곱을 더한 식을 새로운 손실함수로 씁니다. 아래 식과 같습니다. 여기에서 1/2이 붙은 것은 미분 편의성을 고려한 것이고, λ는 패널티의 세기를 결정하는 사용자 지정 하이퍼파라메터입니다. 이 기법은 큰 값이 많이 존재하는 가중치에 제약을 주고, 가중치 값을 가능한 널리 퍼지도록 하는 효과를 냅니다.

W=[w1w2...wn]Lnew=Lold+λ2(w12+w22+...+wn2)

2) L1 Regulazation : 기존 손실함수에 학습파라메터의 절대값을 더해 적용합니다. 이 기법은 학습파라메터를 sparse하게(거의 0에 가깝게) 만드는 특성이 있습니다.

Lnew=Lold+λ(|w1|+|w2|+...+|wn|)

**3) L1 + L2 **: 물론 두 기법을 동시에 사용할 수도 있습니다.

Lnew=Lold+λ12WTW+λ2(|w1|+|w2|+...+|wn|)

Dropout

드롭아웃은 일부 뉴런을 꺼서 학습하는 방법입니다. 일종의 앙상블(ensemble) 효과를 낸다고 합니다. 학습시에는 삭제할 뉴런을 무작위로 끄고, 테스트할 때 모든 뉴런을 씁니다.

기타 학습 기법들

기타 기법들을 소개합니다.

학습률 감소

학습률(learining rate)은 아래 그림처럼 학습 과정에 중요한 역할을 차지합니다. 지나치게 크면 발산하여 올바른 학습을 할 수 없고, 작으면 학습시간이 너무 길어집니다.

학습 시작부터 종료시까지 학습률을 고정한 채로 학습을 시킬 수도 있지만 학습이 거듭될 수록 해당 모델이 최적 지점에 수렴하게 될 것이므로 막바지에는 학습률을 작게 해 파라메터를 미세 조정하는 것이 좋을 것입니다. 학습률 감소 기법은 이 때문에 제안됐는데요, 각각 아래와 같습니다. 여기에서 η는 학습률, t는 스텝 수이며 k는 사용자가 지정하는 하이퍼파라메터입니다.

step decay : 스텝마다 일정한 양만큼 학습률을 줄이는 기법입니다. 5epoch마다 반으로 줄이거나 20epoch마다 1/10씩 줄이는 방법이 많이 쓰이지만, 데이터나 네트워크 구조에 따라 일률적으로 적용하기는 어렵습니다.

exponential decay : η=η0ekt

1/t decay : η=η0/(1+kt)

하이퍼파라메터 최적화

하이퍼파라메터는 사용자가 지정해줘야 하는 값으로 어떤 값이 최적인지는 미리 알기 어렵습니다. 데이터나 모델 구조마다 달라지기도 하고요. 최적의 하이퍼파라메터를 찾기 위한 일반적인 절차는 아래와 같습니다.

  • 1단계 : 하이퍼파라메터 값의 범위를 설정한다 (보통 로그스케일로 작게 지정)
  • 2단계 : 설정된 범위에서 하이퍼파라메터의 값을 무작위로 추출한다
  • 3단계 : 샘플링한 하이퍼파라메터 값을 사용해 학습하고, 검증 데이터로 정확도를 평가한다 (단, 에폭은 작게 설정)
  • 2단계와 3단계를 반복하고, 그 결과를 보고 하이퍼파라메터 탐색 범위를 좁힌다

Multi-Task Learning

Multi-Task Learing이란 여러 학습 과제를 동시에 해결하는 기계학습의 한 종류입니다. 예컨대 같은 학습말뭉치로 개체명인식(Named Entity Recognition)과 품사분류(Part-Of-Speech Tagging)를 동시에 수행하는 뉴럴네트워크를 만들 수 있습니다. 아래 그림을 먼저 볼까요?

위 그림의 두 네트워크는 마지막에 붙어있는 소프트맥스 계층(Softmax layer)만 제외하면 완전히 동일합니다. 다만 S1의 소프트맥스 확률값은 NER, S2는 포스태깅 과제를 수행하면서 나오는 스코어라는 점에 유의할 필요가 있습니다. 위와 같은 Multi-Task Learining 네트워크에서는 아래 수식처럼 역전파시 S1의 그래디언트와 S2의 그래디언트가 동일한 네트워크에 함께 전달되면서 학습이 이뤄지게 됩니다.


이제 MySQL WorkBench  를 설치하고, 작업을 시작하려는데,


접속이 되지 않는다.


왜냐면,, root 권한은 로컬 접속만 허용되기 때문이다.


계정을 하나 생성하던가 root 권한의 원격 접속을 허용해주면 된다.


명령어는 간단하다.


먼저 mysql에 접속한다.


mysql -u root -p



root 권한의 원격접속 권한을 추가한다.



INSERT INTO mysql.user (host,user,password) VALUES ('%','root',password('설정할 Password 입력'));



위의 명령 시  아래의 에러가 나는 경우는,  Mysql Version Upgrade로 인해 명령어가 변경된 경우, 아래의 명령어를 사용해야 한다.

ERROR 1364 (HY000): Field 'ssl_cipher' doesn't have a default value




INSERT INTO mysql.user (host,user,password,ssl_cipher, x509_issuer, x509_subject, authentication_string) VALUES ('%','root',password('설정할 Password 입력'),'','','','');

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';

FLUSH PRIVILEGES;



접속을 시도해 본다. 될꺼야..!!  안되면 댓글 좀 남겨주세요 .... 제가 찾아보고 알려드릴께요.



앞에 포스팅한 것과 같은 문제다.


/etc/mysql/my.conf  의 datadir 에 write 할 수 없는 권한이기 때문이다. 



기본 datadir 은  my.conf에 설정되어 있고,   /var/lib/mysql 이다.

먼저, 해당하는 권한 폴더를 chown -R mysql:mysql [datadir] 을 통해 해결 가능하다. 

chmod -R 755  [datadir] 도 같이 해주자. 
      
또 !!! 이건 정말 삽질로 알아낸건데, 권한을 변경해도 정상동작하지 않는다  크크크 권한은 사실 가장 쉬운 해법이 었드랬다.

그럼  왜냐 !!? 
비밀이다. 

사실은....비밀은 아니고, 
조금 귀찮겠지만,  문제를 해결하려면 로그를 봐야 한다. 
    
로그 위치는  var/log/mysql/error.log 이다.   내가 겪은 에러의 유형은 3가지다.



1. InnoDB: Operating system error number 13 in a file operation    -->  권한이 없는 문제.

2. datadir을 재설정하고 재시작하는 방법을 몰랐기 때문...

3. 재부팅...



1번의 권한 문제야 위의 방법으로 해결하면 되고, 

재시작 문제는 아래와 같은 명령어를 때려 준다. ( 그냥 때려 , 계속 때려 ~~ )



새롭게 저장할 폴더의 권한을 mysql:mysql로 변경을 합니다.$ chown -R mysql:mysql /media/hdd/mysql

기존의 mysql폴더를 backup을 한 뒤에 생성한 mysql의 폴더를 기존의 mysql로 연결을 해줍니다.


sudo mv /var/lib/mysql /var/lib/mysql-old

ln -s [datadir] /var/lib/mysql


AppArmor에 datadir을 등록한 뒤에, apparmor profiles을 다시 로딩

sudo echo "alias /var/lib/mysql/ -> /your/new/datadir/," >> /etc/apparmor.d/tunables/alias

--> 이때 sudo 명령으로 동작하지 않으면 su 로 하면된다.  
근데 또 우분투 초짜들은 su를 하고 어려움을 겪지 ... 왜안되지??ㅋㅋ

안되는게 아니야 ... root의 비밀번호를 설정하지 않은 거지 ㅋㅋ


sudo passwd root 명령을 통해 비밀번호를 설정하고 다시 su를 통해 들어가서 sudo를 빼고 명령어를 때린다.

echo "alias /var/lib/mysql/ -> /your/new/datadir/," >> /etc/apparmor.d/tunables/alias


sudo /etc/init.d/apparmor reload

를 통해 변경된 datadir을 알려준다.


마지막으로 mysql서버를 재시작해준다. 


sudo /etc/init.d/mysql restart


그래도 안되면, 재부팅을 해보자.... 이건 운에 맡긴다 제바알 ....




InnoDB: Operating system error number 13 in a file operation


이 에러의 정체!!!!!!  권한이다 권한..


무슨 권한...??   mysql 을 사용하려는 데 database 를 만들 폴더에 권한이 없는 것이다.



/etc/mysql/my.conf  의 datadir 에 write 할 수 없는 권한이기 때문이다. 



기본 datadir 은  my.conf에 설정되어 있고,   /var/lib/mysql 이다.

먼저, 해당하는 권한 폴더를 chown -R mysql:mysql [datadir] 을 통해 해결 가능하다. 

chmod -R 755  [datadir] 도 같이 해주자. 
      
또 !!! 이건 정말 삽질로 알아낸건데, 권한을 변경해도 정상동작하지 않는다  크크크 권한은 사실 가장 쉬운 해법이 었드랬다.

그럼  왜냐 !!? 
비밀이다. 

사실은....비밀은 아니고, 
조금 귀찮겠지만,  문제를 해결하려면 로그를 봐야 한다. 
    
로그 위치는  var/log/mysql/error.log 이다.   내가 겪은 에러의 유형은 3가지다.



1. InnoDB: Operating system error number 13 in a file operation    -->  권한이 없는 문제.

2. datadir을 재설정하고 재시작하는 방법을 몰랐기 때문...

3. 재부팅...



1번의 권한 문제야 위의 방법으로 해결하면 되고, 

재시작 문제는 아래와 같은 명령어를 때려 준다. ( 그냥 때려 , 계속 때려 ~~ )



새롭게 저장할 폴더의 권한을 mysql:mysql로 변경을 합니다.$ chown -R mysql:mysql /media/hdd/mysql

기존의 mysql폴더를 backup을 한 뒤에 생성한 mysql의 폴더를 기존의 mysql로 연결을 해줍니다.


sudo mv /var/lib/mysql /var/lib/mysql-old

ln -s [datadir] /var/lib/mysql


AppArmor에 datadir을 등록한 뒤에, apparmor profiles을 다시 로딩

sudo echo "alias /var/lib/mysql/ -> /your/new/datadir/," >> /etc/apparmor.d/tunables/alias

--> 이때 sudo 명령으로 동작하지 않으면 su 로 하면된다.  
근데 또 우분투 초짜들은 su를 하고 어려움을 겪지 ... 왜안되지??ㅋㅋ

안되는게 아니야 ... root의 비밀번호를 설정하지 않은 거지 ㅋㅋ


sudo passwd root 명령을 통해 비밀번호를 설정하고 다시 su를 통해 들어가서 sudo를 빼고 명령어를 때린다.

echo "alias /var/lib/mysql/ -> /your/new/datadir/," >> /etc/apparmor.d/tunables/alias


sudo /etc/init.d/apparmor reload

를 통해 변경된 datadir을 알려준다.


마지막으로 mysql서버를 재시작해준다. 


sudo /etc/init.d/mysql restart


그래도 안되면, 재부팅을 해보자.... 이건 운에 맡긴다 제바알 ....


'Data > Mysql' 카테고리의 다른 글

WorkBench 접속 Fail  (1) 2016.09.26
Unbuntu mysql datadir 변경  (0) 2016.09.05
MySql: Access denied for user 'root'@'localhost'  (0) 2016.09.05
Ubuntu MySQL 재설치 문제 , 동작 문제  (0) 2016.09.05

이제 막 첫 서버 접속을 시작하려는데~~~

이놈의 망할 denied 가 뜬다.  스트레스!!!


MySql: Access denied for user 'root'@'localhost' 

MySql: Access denied for user 'root'@'localhost' 

MySql: Access denied for user 'root'@'localhost' 

MySql: Access denied for user 'root'@'localhost' 

MySql: Access denied for user 'root'@'localhost' 





Mysql 패스워드가 초기화 되지 않아서 생기는 문제다.



로그인시 권한 정보를 확인하는 테이블을 일시적으로 skip 하여  

로그인할수 있게 한후에 디비정보 변경을 하고 다시 서비스를 재시작하는 것이 필요하다.



1. mysql 서비스 종료


sudo /etc/init.d/mysql stop


2. mysql 데몬 직접 실행( --skip-grant-table 옵션) 

 - 권한 정보 skip (설정후 보안을 위해 반드시 재시작 해야한다)


sudo /usr/sbin/mysqld --skip-grant-tables --skip-networking &


3. mysql 접속 

mysql -u root mysql

In mysql>



4. 패드워드 초기화


use mysql;

UPDATE user SET authentication_string=PASSWORD('당신의 비밀번호') where USER='root';
FLUSH PRIVILEGES;

exit



5. mysql 서비스 재시작


$sudo /etc/init.d/mysql stop $sudo /etc/init.d/mysql start



mysql을 재 설치시 설치가 안되는 문제가 여러번 발생했다.

삽질을 얼마나 한지 모르겠다.


mysql-server-5.5 버전기준이니 다른 버전이면 안 맞을 수 있다. 다른걸 찾아봐야지모 @''@ 데헷.




Web Search 결과,  단순 apt-get purge mysql-server 가 아니라,
기존의 폴더마저 삭제하는 용의 주도함이 필요했던 것 이었다.  ( 내가 이게 부족했던 거야 ... 후....하... )


그것도 모르고 ,,, 얼마나 많이 재설치를 많이 했는지 ...  소요 삽질 30분 가량  ... 슬펐다.


이 때, 아래와 같은 명령어  set 을 활용하면,  재설치에 성공한다.



sudo apt-get purge mysql-server

sudo apt-get purge mysql-common



sudo rm -rf /var/log/mysql

sudo rm -rf /var/log/mysql.*

sudo rm -rf /var/lib/mysql

sudo rm -rf /etc/mysql



sudo apt-get install mysql-server --fix-missing --fix-broken 




하지만!!!!!


재설치에 성공했다고 끝이 아니다. ( 니가 알던 MySQL이 아니야 )


쉽게 되는게 없는 건 필자도 지금 보는 사람도 알 것이다.


또 망할 문제들이 수두룩 하게 있다.


망할망할... 퉤퉤퉤 왜  IT는 삽질을 해야 지식을 얻고 그 지식을 곧바로 까먹고를 반복할까 
기록하자니 귀찮고 다시 찾는데 또 한참걸리고, 
그래서 내가! 정리해본다 >_<



내가 겪은 문제를 나열해 본다.


mysql daemon이 시작되지 않는 문제


ps -aux | grep mysql  을 통해 daemon이 살아있는지 확인 할 수 있다.  존재하지 않는다면 100% 설정을 잘못한 것이다.


가장 쉬운 첫 번째 해결방법은  권한 이다. 



/etc/mysql/my.conf  의 datadir 에 write 할 수 없는 권한이기 때문이다. 



기본 datadir 은  my.conf에 설정되어 있고,   /var/lib/mysql 이다.

먼저, 해당하는 권한 폴더를 chown -R mysql:mysql [datadir] 을 통해 해결 가능하다. 

chmod -R 755  [datadir] 도 같이 해주자. 
      
또 !!! 이건 정말 삽질로 알아낸건데, 권한을 변경해도 정상동작하지 않는다  크크크 권한은 사실 가장 쉬운 해법이 었드랬다.

그럼  왜냐 !!? 
비밀이다. 

사실은....비밀은 아니고, 
조금 귀찮겠지만,  문제를 해결하려면 로그를 봐야 한다. 
    
로그 위치는  var/log/mysql/error.log 이다.   내가 겪은 에러의 유형은 3가지다.



1. 권한이 없는 문제.

2. datadir을 재설정하고 재시작하는 방법을 몰랐기 때문...

3. 재부팅...



1번의 권한 문제야 위의 방법으로 해결하면 되고, 

재시작 문제는 아래와 같은 명령어를 때려 준다. ( 그냥 때려 , 계속 때려 ~~ )



새롭게 저장할 폴더의 권한을 mysql:mysql로 변경을 합니다.$ chown -R mysql:mysql /media/hdd/mysql

기존의 mysql폴더를 backup을 한 뒤에 생성한 mysql의 폴더를 기존의 mysql로 연결을 해줍니다.


sudo mv /var/lib/mysql /var/lib/mysql-old

ln -s [datadir] /var/lib/mysql


AppArmor에 datadir을 등록한 뒤에, apparmor profiles을 다시 로딩

sudo echo "alias /var/lib/mysql/ -> /your/new/datadir/," >> /etc/apparmor.d/tunables/alias

--> 이때 sudo 명령으로 동작하지 않으면 su 로 하면된다.  
근데 또 우분투 초짜들은 su를 하고 어려움을 겪지 ... 왜안되지??ㅋㅋ

안되는게 아니야 ... root의 비밀번호를 설정하지 않은 거지 ㅋㅋ


sudo passwd root 명령을 통해 비밀번호를 설정하고 다시 su를 통해 들어가서 sudo를 빼고 명령어를 때린다.

echo "alias /var/lib/mysql/ -> /your/new/datadir/," >> /etc/apparmor.d/tunables/alias


sudo /etc/init.d/apparmor reload

를 통해 변경된 datadir을 알려준다.


마지막으로 mysql서버를 재시작해준다. 


sudo /etc/init.d/mysql restart


자 이제 되야 해 ....이건 되야해 하면서

mysql -u root -p  엔터!!돻.


 Access denied for user 'root'@'localhost' 뙇.
뿌왉
뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉뿌왉


이건 다음 포스팅에 계속 해보자.  빡침의 연속이네 이거 개빡...


아참 뭔가 잘안된다 싶으면 

sudo 




2016.08.29 시작

나도 블로그 라는 것을 시작해본다 음트트...

+ Recent posts