다중 선형 회귀 (Multi Variable Linear Regression)
단순 선형 회귀 분석 (Single Variable Linear Regression) 은 독립변수 1개, 종속변수 1개였지만, Multi Variable Linear Regression 은 다수의 독립변수와 1개의 종속변수를 가진다.
import tensorflow as tf import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from matplotlib import cm trainDataNumber = 100 learningRate = 0.01 totalStep = 1001 np.random.seed(321) x1TrainData = list() x2TrainData = list() yTrainData = list() x1TrainData = np.random.normal(0.0, 1.0, size=trainDataNumber) x2TrainData = np.random.normal(0.0, 1.0, size=trainDataNumber) for i in range(0, trainDataNumber): x1 = x2TrainData[i] x2 = x2TrainData[i] y = 10 * x1 + 5.5 * x2 + np.random.normal(0.0, 3) yTrainData .append(y) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.plot(x1TrainData, x2TrainData, yTrainData, linestyle="none", marker="o", mfc="none", markeredgecolor="red") plt.show()
다중 선형 회귀를 세팅하는 것은 x 데이터가 x1, x2로 추가되어 그래프에 적용되었다는 점 빼고는 단순 선형 회귀와 크게 다를 바 없다. 이를 3차원 공간에서 출력하면 아래와 같다.
직접 작성해서 실행시켜보면 알겠지만, 그래프를 이리저리 돌려볼 수 있다! |
y = 10 * x1 + 5.5 * x2 + 3 + np.random.normal(0.03) 에서 x1, x2, y가 x축, y축, z축의 역할을 한다고 볼 수 있으며 이렇게 3차원 공간이 만들어지게 된다. 그런데 여기서 np.random.normal(0.03), 즉 난수를 생성해서 더해주지 않으면 어떻게 될까?
위의 3차원은 이리저리 돌려봐도 한 직선을 이루는 형태가 나오지 않지만, 난수를 제거하면 위와같이 직선 형태가 나오는 구간이 있다. 직선이 나온다는 것은 결국 한 평면에서만 데이터가 세팅 되어 있다는 것이며, 난수를 생성해서 더해주게 되면 데이터가 한 평면 위에서만 나타나지 않고 여러 평면에 걸쳐서 퍼지게 된다.
다음 코드를 보자.
import tensorflow as tf import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from matplotlib import cm # <step 1> trainDataNumber = 100 learningRate = 0.01 totalStep = 1001 np.random.seed(321) x1TrainData = list() x2TrainData = list() yTrainData = list() x1TrainData = np.random.normal(0.0, 1.0, size=trainDataNumber) x2TrainData = np.random.normal(0.0, 1.0, size=trainDataNumber) for i in range(0, trainDataNumber): x1 = x2TrainData[i] x2 = x2TrainData[i] y = 10 * x1 + 5.5 * x2 yTrainData .append(y) # <step 2> W1 = tf.Variable(tf.random_uniform([1])) W2 = tf.Variable(tf.random_uniform([1])) b = tf.Variable(tf.random_uniform([1])) X1 = tf.placeholder(tf.float32) X2 = tf.placeholder(tf.float32) Y = tf.placeholder(tf.float32) # <step 3> hypothesis = W1 * X1 + W2 * X2 + b costfunction = tf.reduce_mean(tf.square(hypothesis - Y)) optimizer = tf.train.GradientDescentOptimizer(learning_rate=learningRate) train = optimizer.minimize(costfunction) # fig = plt.figure() # ax = fig.add_subplot(111, projection='3d') # ax.plot(x1TrainData, x2TrainData, yTrainData, linestyle="none", marker="o", mfc="none", markeredgecolor="red") # plt.show()
역시 단순 선형 회귀와 별 차이 없다. 생각해 볼 만한 부분은 가설함수인데, 가설함수는 W1, W2, b를 각각 세팅해놓고 X1TrainData, X2TrainData, YTrainData가 들어갈 플레이스홀더 X1, X2, Y와 곱연산을 적용해서 만들어진다. 즉 X1TrainData의 모든 원소들과 W1의 모든 원소들을 곱한 것과 X2TrainData와 W2의 모든 원소들의 곱과 Y를 더하는 수식인데, X1 * W1 + X2 * W2의 경우 아래와 같은 식이 나온다.
tensorflow에선 tf.matmul()이라는 함수로 행렬 곱의 연산을 할 수 있다.
import tensorflow as tf import numpy as np matrix1 = tf.constant([[1, 2, 3, 4], [3, 4, 5, 6]]) # 2 * 4 행렬 (shape(2, 4)) matrix2 = tf.constant([[1, 2], [3, 4], [5, 6], [7, 8]]) # 4 * 2 행렬 (shape(4, 2)) res = tf.matmul(matrix1, matrix2).eval(session=tf.Session()) print(res)
output :
[[ 50 60] [ 82 100]]
이 때, 행렬의 연산은 차원이 맞아야 학습이 가능한데, 위의 경우 2 * 4 행렬과 4 * 2 행렬의 연산이기 때문에 가능했지만, 가령 1 * 3 행렬과 1 * 3 행렬은 계산이 불가능하다.
따라서 Broadcasting 이라는 기능으로 행렬을 늘려 차원을 강제로 맞춰준다.
broadcasting은 곱 연산에만 적용되는 것이 아닌 모든 연산에 적용되는데, 예를 들어 아래와 같은 연산을 한다고 생각해보자.
broadcasting으로 1차원 행렬인 b를 강제로 늘려주면 아래와 같이 모든 원소가 b인 2 * 2 행렬이 만들어지면서 연산이 가능하게 된다.
행렬 곱셈 (Matrix Mutilplication)과 Broadcasting을 적절하게 이용하면 일일이 다 적을 필요 없이 가설함수를 쉽게 만들어줄 수 있다.
그래프 생성이 끝났으면 이제 학습 결과를 확인해보자.
import tensorflow as tf import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from matplotlib import cm # <step 1> trainDataNumber = 200 learningRate = 0.01 totalStep = 1001 np.random.seed(321) x1TrainData = list() x2TrainData = list() yTrainData = list() x1TrainData = np.random.normal(0.0, 1.0, size=trainDataNumber) x2TrainData = np.random.normal(0.0, 1.0, size=trainDataNumber) for i in range(0, trainDataNumber): x1 = x1TrainData[i] x2 = x2TrainData[i] y = 10 * x1 + 5.5 * x2 + 3 + np.random.normal(0.0, 3) yTrainData.append(y) # <step 2> W1 = tf.Variable(tf.random_uniform([1])) W2 = tf.Variable(tf.random_uniform([1])) b = tf.Variable(tf.random_uniform([1])) X1 = tf.placeholder(tf.float32) X2 = tf.placeholder(tf.float32) Y = tf.placeholder(tf.float32) # <step 3> hypothesis = W1 * X1 + W2 * X2 + b costfunction = tf.reduce_mean(tf.square(hypothesis - Y)) optimizer = tf.train.GradientDescentOptimizer(learning_rate=learningRate) train = optimizer.minimize(costfunction) # <step 4> sess = tf.Session() sess.run(tf.global_variables_initializer()) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.plot(x1TrainData, x2TrainData, yTrainData, linestyle="none", marker="o", mfc="none", markeredgecolor="red") Xs = np.arange(min(x1TrainData), max(x1TrainData), 0.05) Ys = np.arange(min(x2TrainData), max(x2TrainData), 0.05) Xs, Ys = np.meshgrid(Xs, Ys) print("------------------------------------------------------------------------------------") print("Train(Optimization Start") for step in range(totalStep): cost_val, W1_val, W2_val, b_val, _ = sess.run([costfunction, W1, W2, b, train], feed_dict={X1 : x1TrainData, X2 : x2TrainData, Y : yTrainData}) if step % 50 == 0: print("Step : {}, cost : {}, W1 : {}, W2 : {}, b : {}".format(step, cost_val, W1_val, W2_val, b_val)) if step % 100 == 0: ax.plot_surface(Xs, Ys, W1_val * Xs + W2_val * Ys + b_val, rstride=4, cstride=4, alpha=0.2, cmap=cm.jet) print("Train Finished") print("------------------------------------------------------------------------------------") plt.show() sess.close()
학습 결과 |
학습 결과 3차원 그래프 (1) |
학습 결과 3차원 그래프 (2) |
댓글
댓글 쓰기