TIL/2023.5월

TIL 머신러닝, 선형회귀

황소탄 2023. 5. 16. 22:42

2023.05.16 화

 

문제

강의를 따라가며 실습 중 발생한 문제입니다.

import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import Adam, SGD

x_data = np.array([[1], [2], [3]])
y_data = np.array([[10], [20], [30]])

model = Sequential([
  Dense(1)
])

model.compile(loss='mean_squared_error', optimizer=SGD(lr=0.1))

model.fit(x_data, y_data, epochs=100) # epochs 복수형으로 쓰기!

다음 코드는 텐서플로우에서 케라스를 사용하여 작성한 것입니다.

코드를 작성시켰을 때, 100번의 반복을 통해 loss를 기록하고 loss가 작게 생기는 것을 목표로 하는 코드입니다.

강의에서는 코드를 작동시키면 그 결과가 출력되었지만, 사본으로 저장한 강의 자료를 이용하여 코드를 동작시켰을 때 에러가 발생하였습니다.

WARNING:absl:`lr` is deprecated in Keras optimizer, please use `learning_rate` or use the legacy optimizer, e.g.,tf.keras.optimizers.legacy.SGD.
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-52-b916cb00e6f5> in <cell line: 15>()
     13 model.compile(loss='mean_squared_error', optimizer=SGD(lr=0.1))
     14 
---> 15 model.fit(x_data, y_data, epochs=100) # epochs 복수형으로 쓰기!

5 frames
/usr/local/lib/python3.10/dist-packages/keras/engine/training_v1.py in _make_train_function(self)
   2282                 with backend.name_scope("training"):
   2283                     # Training updates
-> 2284                     updates = self.optimizer.get_updates(
   2285                         params=self._collected_trainable_weights,
   2286                         loss=self.total_loss,

AttributeError: 'SGD' object has no attribute 'get_updates'

시도

에러를 먼저 파악해보았습니다.

1.

WARNING에러는 버전이 업그레이드 되면서 Ir을 사용하는 방법은 더 이상 추천하지 않기에 learning_rate를 사용하거나 legacy optimizer, e.g.,tf.keras.optimizers.legacy.SGD.를 사용하라는 말이였습니다.

->하지만 WARNING이기 코드가 동작하는 것에는 문제가 되지 않아 일단 무시하기로 했습니다.

2.

다음 에러는 AttributeError: 'SGD' object has no attribute 'get_updates' 즉 SGD에 get_updates 메서드를 찾지 못하여 발생한 에러입니다.

실제 검색을 통해 알아보니 텐서플로우 2.7.0부터 get_updates메서드가 삭제되었다는 것을 발견하였습니다

->하지만 pip list를 사용하여 텐서플로우의 버전을 확인하였을 때 2.12.0가 적용되었기에 실질적으로 문제가 없어야 합니다.

3.

다시 코드를 찬찬히 살피는 중 다음과 같은 부분을 발견하였습니다.

모듈이 적용되지 않거나 인식하지 못했을 때 저런 표시를 보았습니다.

import tensorflow.keras.models as models
import tensorflow.keras.layers as layers
import tensorflow.keras.optimizers as optimizers

print(models)
print(layers)
print(optimizers)

as를 사용하여 모듈에 별칭을 만들고 print를 통해 적용되었는지 확인해보았습니다.

 

<module 'tensorflow.keras.models' from '/usr/local/lib/python3.10/dist-packages/keras/api/_v2/keras/models/__init__.py'>
<module 'tensorflow.keras.layers' from '/usr/local/lib/python3.10/dist-packages/keras/api/_v2/keras/layers/__init__.py'>
<module 'tensorflow.keras.optimizers' from '/usr/local/lib/python3.10/dist-packages/keras/api/_v2/keras/optimizers/__init__.py'>

위치가 나오는 것을 보면 저장되었다는 것을 확인할 수 있기에 이것도 문제가 아니였습니다.

 

해결

일단 문제는 해결되었습니다.

새로운 사본을 만들고 블록의 코드를 작동시키지 않고 바로 문제가 발생한 블록의 코드를 작동시켜보았습니다.

신기하게도 작동이 됩니다.

물론 WARNING코드가 출력되지만 어떤 부분에서 차이가 발생하였는지 정말 모르겠습니다.

정말 혹시나 코드가 수정되어 작동이 되지 않는 것일 수 있으니 코드를 그대로 복사하여 붙여넣기하고 문제의 사본에서 실행했지만, 같은 오류가 발생합니다.

pip list를 사용하여 텐서플로우 버전을 확인하여도 같은 버전이며 에러의 원인이다 생각했던 노란 물결표시도 동작하는 코드에서 발생합니다.

 

그렇다면 다른 점은 위의 예제 코드를 실행하였나 그렇지 않았나 차이인데, 출력되는 에러메시지

AttributeError: 'SGD' object has no attribute 'get_updates'

이것을 생각하면 그것이 정말 문제일까 생각됩니다. 일단 문제는 해결하였지만 원인을 결국 찾지 못했습니다.

 

텐서플로우와 케라스

텐서플로우

import tensorflow as tf

tf.compat.v1.disable_eager_execution()

x_data = [[1, 1], [2, 2], [3, 3]]
y_data = [[10], [20], [30]]

X = tf.compat.v1.placeholder(tf.float32, shape=[None, 2])
Y = tf.compat.v1.placeholder(tf.float32, shape=[None, 1])

W = tf.Variable(tf.random.normal(shape=(2, 1)), name='W')
b = tf.Variable(tf.random.normal(shape=(1,)), name='b')

케라스를 사용하고 않하고의 차이가 꽤 큽니다 무엇보다 이제는 텐서플로우 v2부터는 이러한 구현 방식을 권장하지 않고 있다고 합니다.

x_data는 input값, y_data는 output 값입니다. [1,1]의 값은 10이 출력되어야 합니다.

 

x, y는 값을 넣어줄 공간을 정의합니다, 텐서플로우에서는 placeholder라고 표현합니다.

소수형태로 출력되고 shape(형태)는 x는 2개, y는 1개의 값이 들어갑니다.

(이부분은 이후 딥러닝에서 자세히 다룬다고 했습니다)

 

W(Weight)는 가중치(곱하기) b(Bias)는 편향(더하기)을 표현합니다.(f(x)=wx+b 형태)

Variable을 사용하여 초기값과 데이터 타입을 지정하며

random을 사용하여 랜덤한 값을 받습니다.

hypothesis = tf.matmul(X, W) + b
cost = tf.reduce_mean(tf.square(hypothesis - Y))
optimizer = tf.compat.v1.train.GradientDescentOptimizer(learning_rate=0.01).minimize(cost)

hypothesis는 가설을 의미하며 WX + b 식은 선형회귀를 의미합니다.

선형회귀에 대하여 간단히 설명하면 정답 포인트에 가설의 선을 가깝게 위치시키는 것을 목표로 합니다.

[1,1]의 위치에서 10이 정답이고 w,b의 값을 변경하면서 [1,1]위치에서 10이라는 값에 가장 근접할 수록 cost가 줄어듭니다.

cost는 가설에서 정답값을 빼고 제곱하여 평균을 구합니다.

optimizer는 동작거리를 지정하고 cost 값을 적게 만드는 것을 목표로 지정합니다.

with tf.compat.v1.Session() as sess:
  sess.run(tf.compat.v1.global_variables_initializer())

  for step in range(50):
    c, W_, b_, _ = sess.run([cost, W, b, optimizer], feed_dict={X: x_data, Y: y_data})
    print('Step: %2d\t loss: %.2f\t' % (step, c))

  print(sess.run(hypothesis, feed_dict={X: [[4, 4]]}))

세션은 동작하는 모든 그래프나 값을 저장하는 곳입니다.

sess.run(tf.compat.v1.global_variables_initializer())코드는 코드를 다시 작동시켰을 때 이전에 작동한 그래프를 초기화시켜주는 역할을 합니다.

이후 50번 반복문을 돌면서 위에서 정의한 값을 사용하여 동작 후 step에는 몇번째인지, loss에는 cost를 출력하게 됩니다.

학습이 잘되었는지 파악하기 위해 아래의 print문을 사용합니다 input값을 [4,4]를 넣고 output값을 확인하는 것인데,

학습이 잘 되었다면 최대한 cost를 적게 발생시키기 위해 40에 가까운 값을 출력해야 합니다.

 

이것을 케라스에서 구현하면 코드가 훨씬 간단해집니다.

import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import Adam, SGD

x_data = np.array([[1], [2], [3]])
y_data = np.array([[10], [20], [30]])

model = Sequential([
  Dense(1)
])

model.compile(loss='mean_squared_error', optimizer=SGD(lr=0.1))

model.fit(x_data, y_data, epochs=100) # epochs 복수형으로 쓰기!

텐서플로우의 케라스라는 클래스를 사용합니다.

Sequential는 모델을 정의할 때 사용합니다. Dense는 가설을 구현할 때 사용합니다, 

마찬가지로 정답을 넣어주고 

Sequential을 이용하여 순차적으로 모델을 쌓을 수 있는 형태로 만들어줍니다,선형구조에서는 레이어가 하나이기 때문에 Dense(1)를 사용하여 출력이 하나라고 표현합니다.

mean_squared_error을 사용하여 cost를 따로 표현하지 않습니다.

동작범위는 0.1로 정하고(업데이트 이전 자료라 Ir보다는lerning_rate를 사용해 줍니다.

학습을 100번 반복해주도록 설정해주면 위의 텐서플로우만 사용했을 때보다 훨씬 쉽게 구현이 가능합니다.

 

느낀점

머신러닝은 인과를 생각하는 영역인 줄 알았지만, 통계를 사용해야 하니 수학적인 부분이 많습니다, 이전에 모 회사에서 딥러닝을 위해 데이터를 만드는 아르바이트를 잠시했었습니다.

특정 글이 있으면 주어진 카테고리에 들어갈 문장을 찾고 그 문장이나 단어에 적당한 카테고리가 무엇인지 분류하는 아르바이트였습니다.

한 주에 1400~2000개 가량의 데이터를 한 달 정도 작성하였고, 저 말고도 많은 사람들이 했을 것이니 모인 데이터의 수는 어마어마 했겠네요.

이런 반복작업을 통한 데이터를 만들고 ai가 이것을 바탕으로 판단하는 것이라 생각하였는데 뭔가 비슷하지만 조금 다른 느낌입니다.