AI/DeepLearning

회귀 모델 정리 - 앙상블 및 기타 모델

soccerda 2020. 7. 13. 02:25
반응형

앙상블은 여러 모델을 합치는 모델로, 1:1 모델은 없다

 

2개의 모델이 합쳐서 2개의 모델로 출력되는 다:다 모델을 만들자

 

다:다 1 모델

#1. 데이터
import numpy as np

x1 = np.array([range(1, 101), range(101, 201)])
y1 = np.array([range(1, 101), range(101, 201)])
x2 = np.array([range(501, 601), range(601, 701)])
y2 = np.array([range(501, 601), range(601, 701)])

print(x1.shape)
print(y1.shape)
print(x2.shape)
print(y2.shape)


(2, 100)

(2, 100)

(2, 100)

(2, 100)

 

x1데이터가 들어간 모델과 x2 데이터가 들어간 모델을 구성한 다음 y1 데이터와 y2데이터가 가각 출력되는 모델을 만들었다.

 

1에서 100까지의 데어터와 101에서 200까지의 데이터를 가진 모델 1과, 501에서 601까지 100개와 601에서 700까지의 데이터를 100개를 가진 모델 2를 앙상블 하였다. 

결과로는 마찬가지로 1에서 100까지 와 101에서 201까지의 모델과 501에서 600, 601에서 700까지의 모델 두 가지로 출력되게 하고 이를 훈련시키도록 하였다.

 

(2,100) 결과를 입력이 (2,)가 될 수 있도록 transpose 하자.

x1 = np.transpose(x1)
y1 = np.transpose(y1)
x2 = np.transpose(x2)
y2 = np.transpose(y2)

print(x1.shape)
print(y1.shape)
print(x2.shape)
print(y2.shape)

(100, 2)

(100, 2)

(100, 2)

(100, 2)

모델의 shape에 맞도록 변환이 되었다.

 

train, test, validation을 나누자. train_test_split를 사용하여 8:1:1로 나누겠다. validation까지 구성하므로 두 번 사용하자.

shuffle = False는 데이터를 섞지 않겠다는 의미이다. 나중에 test 값으로 predict를 하게 되는데 이때 보기 편하게 하기 위해서이다.

 

from sklearn.model_selection import train_test_split
x1_train, x1_test, y1_train, y1_test = train_test_split(
    x1, y1, random_state=66, test_size=0.2, shuffle = False
)
x1_val, x1_test, y1_val, y1_test = train_test_split(
    x1_test, y1_test, random_state=66, test_size=0.5, shuffle = False
)

x2_train, x2_test, y2_train, y2_test = train_test_split(
    x2, y2, random_state=66, test_size=0.2, shuffle = False
)
x2_val, y2_val, x2_test, y2_test = train_test_split(
    x2_test, y2_test, random_state=66, test_size=0.5, shuffle = False
)

print('x2_train.shape : ', x2_train.shape)
print('x2_val.shape : ', x2_val.shape)
print('x2_test.shape : ', x2_test.shape)

('x2_train.shape : ', (80, 2))

('x2_val.shape : ', (10, 2))

('x2_test.shape : ', (10, 2)

 

모델 구성은 input1과 input2를 구성한다. 각각 (10,2)의 모델이다. 따라서 input의 shape=(2,)가 된다.

#2. 모델 구성
from keras.models import Sequential, Model
from keras.layers import Dense, Input
# model =  Sequential()

input1 = Input(shape=(2,))
dense1 = Dense(100, activation='relu')(input1)
dense1 = Dense(30)(dense1)
dense1 = Dense(7)(dense1)

input2 = Input(shape=(2,))
dense2 = Dense(50, activation='relu')(input2)
dense2 = Dense(30)(dense2)
dense2 = Dense(7)(dense2)

input1은 2, 100, 30, 7의 노두의 개수 구성하고 input2는 2, 50, 30, 7의 노드의 개수 구성을 한다. 

히든 레이어 부분의 노드의 개수 구성은 어떤 값을 넣어도 상관없다. 반복해서 실습하다 보면 어느 정도의 노드를 구성하는 것이 좋을지 자연스럽게 익힐 수 있다. 레이어의 기핑 ㅣ역시 마찬가지다. 마지막 아웃풋 노드 역시 7인 것은 크게 상관없다. 앙상블에서 다시 연결되므로 이 역시도 히든 레이어이기 때문이다. 이제 모델을 앙상블 하자.

 

concatenate로 dense1과 dense2를 merge 했고, 이어서 히든 레이어 3개를 더 추가했다. 각각 노드 10개, 5개, 50개로 구성했다. 

from keras.layers.merge import concatenate
merge1 = concatenate([dense1, dense2])

middle1 = Dense(10)(merge1)
middle2 = Dense(5)(middle1)
middle3 = Dense(30)(middle2)

 

이제 각 모델로 분기될 아웃풋 모델을 만들자.

output1 = Dense(30)(middle3)
output1 = Dense(7)(output1)
output1 = Dense(2)(output1)

output2 = Dense(20)(middle3)
output2 = Dense(70)(output2)
output2 = Dense(2)(output2)

첫 번째 아웃풋 모델은 middle3으로부터 분기되어 30, 7의 히든 레이어를 거쳐 2개의 최종 아웃풋 노드를 출력한다.

두 번째 아웃풋 모델은 middle3으로부터 분기되어 20, 70의 히든 레이어를 거쳐 2개의 최종 아웃풋 모델로 출력한다.

 

model = Model(inputs = [input1, input2],
              outputs = [output1, output2]
)
model.summary()
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_11 (InputLayer)           (None, 2)            0                                            
__________________________________________________________________________________________________
input_12 (InputLayer)           (None, 2)            0                                            
__________________________________________________________________________________________________
dense_67 (Dense)                (None, 100)          300         input_11[0][0]                   
__________________________________________________________________________________________________
dense_70 (Dense)                (None, 50)           150         input_12[0][0]                   
__________________________________________________________________________________________________
dense_68 (Dense)                (None, 30)           3030        dense_67[0][0]                   
__________________________________________________________________________________________________
dense_71 (Dense)                (None, 30)           1530        dense_70[0][0]                   
__________________________________________________________________________________________________
dense_69 (Dense)                (None, 7)            217         dense_68[0][0]                   
__________________________________________________________________________________________________
dense_72 (Dense)                (None, 7)            217         dense_71[0][0]                   
__________________________________________________________________________________________________
concatenate_5 (Concatenate)     (None, 14)           0           dense_69[0][0]                   
                                                                 dense_72[0][0]                   
__________________________________________________________________________________________________
dense_73 (Dense)                (None, 10)           150         concatenate_5[0][0]              
__________________________________________________________________________________________________
dense_74 (Dense)                (None, 5)            55          dense_73[0][0]                   
__________________________________________________________________________________________________
dense_75 (Dense)                (None, 30)           180         dense_74[0][0]                   
__________________________________________________________________________________________________
dense_76 (Dense)                (None, 30)           930         dense_75[0][0]                   
__________________________________________________________________________________________________
dense_79 (Dense)                (None, 20)           620         dense_75[0][0]                   
__________________________________________________________________________________________________
dense_77 (Dense)                (None, 7)            217         dense_76[0][0]                   
__________________________________________________________________________________________________
dense_80 (Dense)                (None, 70)           1470        dense_79[0][0]                   
__________________________________________________________________________________________________
dense_78 (Dense)                (None, 2)            16          dense_77[0][0]                   
__________________________________________________________________________________________________
dense_81 (Dense)                (None, 2)            142         dense_80[0][0]                   
==================================================================================================
Total params: 9,224
Trainable params: 9,224
Non-trainable params: 0

 

input_7과 input_8에 각각 (None,2)이 확인되는 것과 concatenate_1에 (None, 14)이 출력되는 것을 확인하면 된다.

특히 concatenate_3 이 14가 되는 것은 모델 1과 모델 2의 아웃풋인 dense_39과 dense_42의 아웃풋이 각각( None, 7)이고 이를 합하면 (None, 14)이기 때문이다. 최종 아웃풋은 각각(None,2)이다.

 

#3. 훈련
model.compile(loss='mse', optimizer='adam', metrics=['mse'])

model.fit([x1_train, x2_train], [y1_train, y2_train],
          epochs=50, batch_size=1,
          validation_data=([x1_val, x2_val], [y1_val, y2_val]))

 2개 이상의 x값과 y값이 입력되므로 , 훈련을 위해 fit 함수에 x값 자리에 x1_train과 x2_train을 리스트로 묶어서 입력하고, y값 자리 역시 y1_train, y2_train을 리스트로 묶어서 입력한다. validation 역시 동일하게 리스트로 입력한다.

 

#4. 평가 예측
mse = model.evaluate([x1_test, x2_test],
                     [y1_test, y2_test], batch_size=1)
print("mse : ", mse)

y1_predict, y2_predict = model.predict([x1_test, x2_test])
print("y1 예측값 : \n", y1_predict, "\n y2 예측값 : \n", y2_predict)

 

전체 소스

#1. 데이터
import numpy as np

x1 = np.array([range(1, 101), range(101, 201)])
y1 = np.array([range(1, 101), range(101, 201)])
x2 = np.array([range(501, 601), range(601, 701)])
y2 = np.array([range(501, 601), range(601, 701)])

print(x1.shape)
print(y1.shape)
print(x2.shape)
print(y2.shape)

x1 = np.transpose(x1)
y1 = np.transpose(y1)
x2 = np.transpose(x2)
y2 = np.transpose(y2)

print(x1.shape)
print(y1.shape)
print(x2.shape)
print(y2.shape)

from sklearn.model_selection import train_test_split
x1_train, x1_test, y1_train, y1_test = train_test_split(
    x1, y1, random_state=66, test_size=0.2, shuffle = False
)
x1_val, x1_test, y1_val, y1_test = train_test_split(
    x1_test, y1_test, random_state=66, test_size=0.5, shuffle = False
)

x2_train, x2_test, y2_train, y2_test = train_test_split(
    x2, y2, random_state=66, test_size=0.2, shuffle = False
)
x2_val, y2_val, x2_test, y2_test = train_test_split(
    x2_test, y2_test, random_state=66, test_size=0.5, shuffle = False
)

print('x2_train.shape : ', x2_train.shape)
print('x2_val.shape : ', x2_val.shape)
print('x2_test.shape : ', x2_test.shape)

#2. 모델 구성
from keras.models import Sequential, Model
from keras.layers import Dense, Input
# model =  Sequential()

input1 = Input(shape=(2,))
dense1 = Dense(100, activation='relu')(input1)
dense1 = Dense(30)(dense1)
dense1 = Dense(7)(dense1)

input2 = Input(shape=(2,))
dense2 = Dense(50, activation='relu')(input2)
dense2 = Dense(30)(dense2)
dense2 = Dense(7)(dense2)

from keras.layers.merge import concatenate
merge1 = concatenate([dense1, dense2])

middle1 = Dense(10)(merge1)
middle2 = Dense(5)(middle1)
middle3 = Dense(30)(middle2)

output1 = Dense(30)(middle3)
output1 = Dense(7)(output1)
output1 = Dense(2)(output1)

output2 = Dense(20)(middle3)
output2 = Dense(70)(output2)
output2 = Dense(2)(output2)

model = Model(inputs = [input1, input2],
              outputs = [output1, output2]
)
model.summary()

#3. 훈련
model.compile(loss='mse', optimizer='adam', metrics=['mse'])

model.fit([x1_train, x2_train], [y1_train, y2_train],
          epochs=50, batch_size=1,
          validation_data=([x1_val, x2_val], [y1_val, y2_val]))

#4. 평가 예측
mse = model.evaluate([x1_test, x2_test],
                     [y1_test, y2_test], batch_size=1)
print("mse : ", mse)

y1_predict, y2_predict = model.predict([x1_test, x2_test])
print("y1 예측값 : \n", y1_predict, "\n y2 예측값 : \n", y2_predict)

('mse : ', [10.36696479320526, 0.8444129228591919, 9.522551536560059, 0.8444129228591919, 9.522551536560059]) ('y1 \xec\x98\x88\xec\xb8\xa1\xea\xb0\x92 : \n',

array([[ 91.85174 , 190.10536 ], [ 92.75377 , 191.04071 ], [ 93.65572 , 191.97594 ], [ 94.55768 , 192.91115 ], [ 95.45966 , 193.84645 ], [ 96.36169 , 194.78171 ], [ 97.26367 , 195.717 ], [ 98.165634, 196.65227 ], [ 99.06761 , 197.58755 ], [ 99.969604, 198.52289 ]], dtype=float32), '\n

y2 \xec\x98\x88\xec\xb8\xa1\xea\xb0\x92 : \n', array([[586.49603, 686.1932 ], [587.8375 , 687.65076], [589.179 , 689.1083 ], [590.52045, 690.56573], [591.862 , 692.02344], [593.2034 , 693.4808 ], [594.545 , 694.93835], [595.8863 , 696.39557], [597.22784, 697.8534 ], [598.5693 , 699.3108 ]], dtype=float32))

 

원래 y1_test 값은 91에서 100, 191에서 200, y2_test 값은 591에서 600, 691에서 700인데 예측된 y1_predict는 91.85~99.96, 190.10~198.52, y2_predict는 586.49~598.56, 686.19~699.31로 상당히 근접하게 맞추었다. epochs가 100번이고 노드와 레이어가 적은 모델임을 감안하면 괜찮은 결과이다. test 값으로 predict 해서 값만 잘 나온 것일 수도 있다. 물론 결과가 잘 나왔다는 표현이 적절치 않을 수도 있고, predict와 평가가 상당히 주관적일 수도 있다. 튜닝을 조금 더하여 더 좋은 값으로 만들자.

 


다:다 2 모델

2개의 모델이 입력되어 3개의 모델을 출력하는 앙상블 2:2 모델을 만들자

# 앙상블 다:다 모델2
#1. 데이터
import numpy as np

x1 = np.array([range(1, 101), range(101, 201)])
y1 = np.array([range(1, 101), range(101, 201)])
x2 = np.array([range(501, 601), range(601, 701)])
y2 = np.array([range(501, 601), range(601, 701)])
y3 = np.array([range(701, 801), range(801, 901)])

print(x1.shape)
print(x2.shape)
print(y1.shape)
print(y2.shape)
print(y3.shape)

x1, x2 가 두 개의 모델로 인풋 되어 y1, y2, y3가 아웃풋으로 나오는 모델이다.

훈련시켜 최적의 가중치와 초소의 loss 값을 구한다. 이 결과를 predict 값으로 확인 가능하게 하자.

 

데이터의 행과 열을 모델이 입력될 수 있게 transpose 하자

x1 = np.transpose(x1)
x2 = np.transpose(x2)
y1 = np.transpose(y1)
y2 = np.transpose(y2)
y3 = np.transpose(y3)

print(x1.shape)
print(x2.shape)
print(y1.shape)
print(y2.shape)
print(y3.shape)

실행 결과 데이터의 입력과 출력 shape가 정삭적으로 잘 배치되었다.

(100, 2)

(100, 2)

(100, 2)

(100, 2)

(100, 2)

 

 

train_test_split로 데이터를 8:1:1로 자르자. 

y값이 하나가 더 늘었으므로 train_test_split도 늘어난 y3 데이터만을 단독으로 잘라야 한다.

 

from sklearn.model_selection import train_test_split
x1_train, x1_test, y1_train, y1_test = train_test_split(
    x1, y1, random_state=66, test_size=0.2, shuffle = False
)
x1_val, x1_test, y1_val, y1_test = train_test_split(
    x1_test, y1_test, random_state=66, test_size=0.5, shuffle = False
)
x2_train, x2_test, y2_train, y2_test = train_test_split(
    x2, y2, random_state=66, test_size=0.2, shuffle = False
)
x2_val, y2_val, x2_test, y2_test = train_test_split(
    x2_test, y2_test, random_state=66, test_size=0.5, shuffle = False
)

# y3 데이터의 분리
y3_train, y3_test = train_test_split(
    y3, random_state=66, test_size=0.2, shuffle=False
)
y3_val, y3_test = train_test_split(
    y3_test, random_state=66, test_size=0.5, shuffle=False
)

print('y3_train.shape : ', y3_train.shape)
print('y3_val.shape : ', y3_val.shape)
print('y3_test.shape : ', y3_test.shape)

train_test_split는 x와 y 꼭 1쌍이 아닌 1개의 파라미터만 넣어도 데이터를 분리할 수 있다.

('y3_train.shape : ', (80, 2))

('y3_val.shape : ', (10, 2))

('y3_test.shape : ', (10, 2))

8:1:1 정상이다.

 

이전 다:다 1 모델에서 사용했던 모델은 2:2였다. 이번에는 2:3이므로 2:2를 수정해서 사용하겠다.

input은 그대로 2개이고 2개의 모델을 concatenate로 merge 하는 것 까지 동일하다.

#2. 모델 구성
from keras.models import Sequential, Model
from keras.layers import Dense, Input
# model = Sequential()

input1 = Input(shape=(2,))
dense1 = Dense(100, activation='relu')(input1)
dense1 = Dense(30)(dense1)
dense1 = Dense(7)(dense1)

input2 = Input(shape=(2,))
dense2 = Dense(50, activation='relu')(input2)
dense2 = Dense(30)(dense2)
dense2 = Dense(7)(dense2)

from keras.layers.merge import concatenate
merge1 = concatenate([dense1, dense2])

middle1 = Dense(10)(merge1)
middle2 = Dense(50)(middle1)
middle3 = Dense(30)(middle2)

output1 = Dense(30)(middle3)
output1 = Dense(7)(output1)
output1 = Dense(2)(output1)

output2 = Dense(20)(middle3)
output2 = Dense(70)(output2)
output2 = Dense(2)(output2)

output3 = Dense(25)(middle3)
output3 = Dense(5)(output3)
output3 = Dense(2)(output3)

3개의 모델로 분기해서 3개의 아웃풋 모델을 만들었다.

model = Model(inputs = [input1, input2],
              outputs = [output1, output2, output3]
)

output 레이어가 총 3개를 명시했다. 그래서 2:3 모델이 구현되었다.

 

#3. 훈련
model.compile(loss='mse', optimizer='adam', metrics=['mse'])

model.fit([x1_train, x2_train], [y1_train, y2_train, y3_train],
          epochs=50, batch_size=1,
          validation_data=([x1_val, x2_val], [y1_val, y2_val, y3_val])
)

 훈련 때도 y3_train까지 3개의 아웃풋에 들어간다는 것과 validation 할 때 역시 y3_val까지 3개의 리스트 형태로 들어간다.

 

#4. 평가 예측
mse = model.evaluate([x1_test, x2_test],
                     [y1_test, y2_test, y3_test], batch_size=1)
print("mse : ", mse)

y1_predict, y2_predict, y3_predict = model.predict([x1_test, x2_test])
print("y1 예측값 : \n", y1_predict,
      "\n y2 예측값 : \n", y2_predict, "\n y3 예측값 : \n", y3_predict)

y3_test가 평가에 추가되는 것과 x1_test와 x2_test 2개의 데이터로 예측해서, y1_predict, y2_predict, y3_predict 총 3개의 아웃풋이 예측값으로 나온다.

 

전체 소스

# 앙상블 다:다 모델2
#1. 데이터
import numpy as np

x1 = np.array([range(1, 101), range(101, 201)])
y1 = np.array([range(1, 101), range(101, 201)])
x2 = np.array([range(501, 601), range(601, 701)])
y2 = np.array([range(501, 601), range(601, 701)])
y3 = np.array([range(701, 801), range(801, 901)])

print(x1.shape)
print(x2.shape)
print(y1.shape)
print(y2.shape)
print(y3.shape)

x1 = np.transpose(x1)
x2 = np.transpose(x2)
y1 = np.transpose(y1)
y2 = np.transpose(y2)
y3 = np.transpose(y3)

print(x1.shape)
print(x2.shape)
print(y1.shape)
print(y2.shape)
print(y3.shape)

from sklearn.model_selection import train_test_split
x1_train, x1_test, y1_train, y1_test = train_test_split(
    x1, y1, random_state=66, test_size=0.2, shuffle = False
)
x1_val, x1_test, y1_val, y1_test = train_test_split(
    x1_test, y1_test, random_state=66, test_size=0.5, shuffle = False
)
x2_train, x2_test, y2_train, y2_test = train_test_split(
    x2, y2, random_state=66, test_size=0.2, shuffle = False
)
x2_val, y2_val, x2_test, y2_test = train_test_split(
    x2_test, y2_test, random_state=66, test_size=0.5, shuffle = False
)

# y3 데이터의 분리
y3_train, y3_test = train_test_split(
    y3, random_state=66, test_size=0.2, shuffle=False
)
y3_val, y3_test = train_test_split(
    y3_test, random_state=66, test_size=0.5, shuffle=False
)

print('y3_train.shape : ', y3_train.shape)
print('y3_val.shape : ', y3_val.shape)
print('y3_test.shape : ', y3_test.shape)

#2. 모델 구성
from keras.models import Sequential, Model
from keras.layers import Dense, Input
# model = Sequential()

input1 = Input(shape=(2,))
dense1 = Dense(100, activation='relu')(input1)
dense1 = Dense(30)(dense1)
dense1 = Dense(7)(dense1)

input2 = Input(shape=(2,))
dense2 = Dense(50, activation='relu')(input2)
dense2 = Dense(30)(dense2)
dense2 = Dense(7)(dense2)

from keras.layers.merge import concatenate
merge1 = concatenate([dense1, dense2])

middle1 = Dense(10)(merge1)
middle2 = Dense(50)(middle1)
middle3 = Dense(30)(middle2)

output1 = Dense(30)(middle3)
output1 = Dense(7)(output1)
output1 = Dense(2)(output1)

output2 = Dense(20)(middle3)
output2 = Dense(70)(output2)
output2 = Dense(2)(output2)

output3 = Dense(25)(middle3)
output3 = Dense(5)(output3)
output3 = Dense(2)(output3)

model = Model(inputs = [input1, input2],
              outputs = [output1, output2, output3]
)

#3. 훈련
model.compile(loss='mse', optimizer='adam', metrics=['mse'])

model.fit([x1_train, x2_train], [y1_train, y2_train, y3_train],
          epochs=50, batch_size=1,
          validation_data=([x1_val, x2_val], [y1_val, y2_val, y3_val])
)

#4. 평가 예측
mse = model.evaluate([x1_test, x2_test],
                     [y1_test, y2_test, y3_test], batch_size=1)
print("mse : ", mse)

y1_predict, y2_predict, y3_predict = model.predict([x1_test, x2_test])
print("y1 예측값 : \n", y1_predict,
      "\n y2 예측값 : \n", y2_predict, "\n y3 예측값 : \n", y3_predict)
('mse : ', [197.90591583251953, 5.409859657287598, 72.54960632324219, 119.9464340209961, 5.409859657287598, 72.54960632324219, 119.9464340209961])
('y1 \xec\x98\x88\xec\xb8\xa1\xea\xb0\x92 : \n', array([[ 90.29159 , 188.77376 ],
       [ 91.1051  , 189.64316 ],
       [ 91.91859 , 190.51245 ],
       [ 92.732   , 191.38179 ],
       [ 93.54552 , 192.25114 ],
       [ 94.35905 , 193.12053 ],
       [ 95.17251 , 193.98984 ],
       [ 95.97662 , 194.85376 ],
       [ 96.769264, 195.71106 ],
       [ 97.56188 , 196.56837 ]], dtype=float32), '\n y2 \xec\x98\x88\xec\xb8\xa1\xea\xb0\x92 : \n', array([[582.7431 , 681.3667 ],
       [583.8239 , 682.4863 ],
       [584.9046 , 683.6061 ],
       [585.98517, 684.72546],
       [587.0661 , 685.8451 ],
       [588.1468 , 686.96484],
       [589.2275 , 688.08435],
       [590.311  , 689.20776],
       [591.3976 , 690.3353 ],
       [592.48444, 691.463  ]], dtype=float32), '\n y3 \xec\x98\x88\xec\xb8\xa1\xea\xb0\x92 : \n', array([[779.5717 , 878.82355],
       [780.71515, 880.0633 ],
       [781.85834, 881.3029 ],
       [783.00134, 882.54254],
       [784.1448 , 883.7822 ],
       [785.28796, 885.022  ],
       [786.4311 , 886.2615 ],
       [787.5758 , 887.5102 ],
       [788.72186, 888.7694 ],
       [789.8681 , 890.0289 ]], dtype=float32))

y1값이 91에서 100, 191에서 200인데 예측값은 91.1에서 97.5 사이, 189,6에서 196.5이며 

y2값은 591에서 600, 691에서 700인데 예측값은 583.8~592.4,  682.4~691.4로 분포 범위는 많이 근사하다.

y3값 역시 790~800, 890~900인데 예측값은 780.7~789.8, 880.0~890.0으로 분포 범위는 많이 근사하다.

 

이런 모델을 많이 만들지 않지만 이 역시도  사용할 수 있는 가능성이 있는 모델이고, 지금까지는 정확도를 높이는 것보다는 모델을 구성하는 여러 가지 방법을 배우는 것으로 이런 모델이 있다는 것을 이해하고 숙지하자.

 

 

앙상블 다:1 모델

2개의 모델이 입력되어 1개의 모델로 출력되는 다:1 모델을 구현하자. 앙상블 모델 중에서 도 가장 많이 나올 수 있는 모델이다.

 

#1. 데이터
import numpy as np

x1 = np.array([range(1, 101), range(101, 201)])
x2 = np.array([range(501, 601), range(601, 701)])
y = np.array([range(1, 101), range(101, 201)])

print(x1.shape)
print(x2.shape)
print(y.shape)

x1 = np.transpose(x1)
x2 = np.transpose(x2)
y = np.transpose(y)

print(x1.shape)
print(x2.shape)
print(y.shape)

(2, 100)

(2, 100)

(2, 100)

(100, 2)

(100, 2)

(100, 2)

x1이 1에서 100, 101에서 200, x2 가 501에서 601, 601에서 701의 데이터가 준비되어 있고, y는 1에서 100, 101에서 200의 데이터이다.

shape를 맞추자.

 

from sklearn.model_selection import train_test_split
x1_train, x1_test, y_train, y_test = train_test_split(
    x1, y, random_state=66, test_size=0.2, shuffle = False
)
x1_val, x1_test, y_val, y_test = train_test_split(
    x1_test, y_test, random_state=66, test_size=0.5, shuffle = False
)
x2_train, x2_test = train_test_split(
    x2, random_state=66, test_size=0.2, shuffle = False
)
x2_val, x2_test = train_test_split(
    x2_test, random_state=66, test_size=0.5, shuffle = False
)

 

train_test_split로 x1, x2, y를 각각 8:1:1로 분리하자. y는 1개뿐이므로 x1과 같이 train_test_split로 분리해주고 , x2 만 따로 분리하자.

print('x2_train.shape : ', x2_train.shape)
print('x2_val.shape : ', x2_val.shape)
print('x2_test.shape : ', x2_test.shape)

('x2_train.shape : ', (80, 2))

('x2_val.shape : ', (10, 2))

('x2_test.shape : ', (10, 2))

8:1:1의 비율로 잘 분리가 되었다. 모델을 구성하자. 인풋 모델이 2개, 아웃풋 모델이 1개이므로 우선 인풋 모델 2개를 구성하겠다. concatenate 전까지는 이전 다:다 모델과 동일하게 구성하면 된다.

#2. 모델 구성
from keras.models import Sequential, Model
from keras.layers import Dense, Input
# model = Sequential()

input1 = Input(shape=(2,))
dense1 = Dense(100, activation='relu')(input1)
dense1 = Dense(30)(dense1)
dense1 = Dense(7)(dense1)

input2 = Input(shape=(2,))
dense2 = Dense(50, activation='relu')(input2)
dense2 = Dense(30)(dense2)
dense2 = Dense(7)(dense2)

from keras.layers.merge import concatenate
merge1 = concatenate([dense1, dense2])

2개의 모델을 concatenate로 단순 merge를 했다. 이제 출력이 1개의 모델이므로 여기서는 분기할 필요 없이 바로 모델을 이어주면 된다. 아웃풋 모델을 만들자.

model = Model(inputs = [input1, input2],
              outputs = output1
)

merge1과 output1을 연결했다. 물론 그 사이에 히든 레이어를 더 추가해도 된다. 

 

#3. 훈련
model.compile(loss='mse', optimizer='adam', metrics=['mse'])

model.fit([x1_train, x2_train], y_train,
          epochs=50, batch_size=1,
          validation_data=([x1_val, x2_val], y_val))

inputs는 input1과 input2가 리스트 형태로 들어가지만, outputs는 output1 하나여서 리스트 형태가 아닌 레이어 이름으로 들어간다.

x1_train과 x2_train은 리스트 형태로, y_train은 변수명만으로 fit 했다. 

#4. 평가 예측
mse = model.evaluate([x1_test, x2_test], y_test, batch_size=1)
print("mse : ", mse)

y_predict = model.predict([x1_test, x2_test])
print("y1 예측값 : \n", y_predict)

평가와 예측을 둘 다 x1_test와 x2_test로 했다.

 

 

전체 소스

#1. 데이터
import numpy as np

x1 = np.array([range(1, 101), range(101, 201)])
x2 = np.array([range(501, 601), range(601, 701)])
y = np.array([range(1, 101), range(101, 201)])

print(x1.shape)
print(x2.shape)
print(y.shape)

x1 = np.transpose(x1)
x2 = np.transpose(x2)
y = np.transpose(y)

print(x1.shape)
print(x2.shape)
print(y.shape)

from sklearn.model_selection import train_test_split
x1_train, x1_test, y_train, y_test = train_test_split(
    x1, y, random_state=66, test_size=0.2, shuffle = False
)
x1_val, x1_test, y_val, y_test = train_test_split(
    x1_test, y_test, random_state=66, test_size=0.5, shuffle = False
)
x2_train, x2_test = train_test_split(
    x2, random_state=66, test_size=0.2, shuffle = False
)
x2_val, x2_test = train_test_split(
    x2_test, random_state=66, test_size=0.5, shuffle = False
)

print('x2_train.shape : ', x2_train.shape)
print('x2_val.shape : ', x2_val.shape)
print('x2_test.shape : ', x2_test.shape)

#2. 모델 구성
from keras.models import Sequential, Model
from keras.layers import Dense, Input
# model = Sequential()

input1 = Input(shape=(2,))
dense1 = Dense(100, activation='relu')(input1)
dense1 = Dense(30)(dense1)
dense1 = Dense(7)(dense1)

input2 = Input(shape=(2,))
dense2 = Dense(50, activation='relu')(input2)
dense2 = Dense(30)(dense2)
dense2 = Dense(7)(dense2)

from keras.layers.merge import concatenate
merge1 = concatenate([dense1, dense2])

middle1 = Dense(10)(merge1)
middle2 = Dense(50)(middle1)
middle3 = Dense(30)(middle2)

output1 = Dense(30)(middle3)
output1 = Dense(7)(output1)
output1 = Dense(2)(output1)



model = Model(inputs = [input1, input2],
              outputs = output1
)

#3. 훈련
model.compile(loss='mse', optimizer='adam', metrics=['mse'])

model.fit([x1_train, x2_train], y_train,
          epochs=50, batch_size=1,
          validation_data=([x1_val, x2_val], y_val))

#4. 평가 예측
mse = model.evaluate([x1_test, x2_test], y_test, batch_size=1)
print("mse : ", mse)

y_predict = model.predict([x1_test, x2_test])
print("y1 예측값 : \n", y_predict)

('mse : ', [7.80609769821167, 7.806097507476807]) ('y1 \xec\x98\x88\xec\xb8\xa1\xea\xb0\x92 : \n',

array([

[ 88.722466, 189.37909 ],

[ 89.52292 , 190.24033 ],

[ 90.32337 , 191.10156 ],

[ 91.12381 , 191.96277 ],

[ 91.924255, 192.82397 ],

[ 92.72471 , 193.68524 ],

[ 93.525154, 194.54645 ],

[ 94.32563 , 195.4077 ],

[ 95.126274, 196.26909 ],

[ 95.92697 , 197.13051 ]

], dtype=float32))

 

원래 y1_test의 값은 91~100, 191~200인데 우리가 예측한 y_predict 값은 88.7~95.9, 189.3~197.1로 오차가 일부 있다.

그래도 대략 범위 부분에 모여 있다.

 

1:다 모델

엄밀히 말하면 앙상블 모델이 아니다. 1개의 모델이 입력되어 여러 개의 모델로 나눠지는 분기 모델이다. 그래서 concatenate도 사용하지 않고 분기만 사용하면 된다.

#1. 데이터
import numpy as np

x = np.array([range(1, 101), range(101, 201)])
y1 = np.array([range(501, 601), range(601, 701)])
y2 = np.array([range(1, 101), range(101, 201)])

print(x.shape)
print(y1.shape)
print(y2.shape)

x = np.transpose(x)
y1 = np.transpose(y1)
y2 = np.transpose(y2)

print(x.shape)
print(y1.shape)
print(y2.shape)

(2, 100)

(2, 100)

(2, 100)

(100, 2)

(100, 2)

(100, 2)

입력 x는 1개, 출력 y는 y1, y2로 2개 실행하여 shape를 확인

from sklearn.model_selection import train_test_split
x_train, x_test, y1_train, y1_test = train_test_split(
    x, y1, random_state=66, test_size=0.2, shuffle = False
)
x_val, x_test, y1_val, y1_test = train_test_split(
    x_test, y1_test, random_state=66, test_size=0.5, shuffle = False
)
y2_train, y2_test = train_test_split(
    y2, random_state=66, test_size=0.2, shuffle = False
)
y2_val, y2_test = train_test_split(
    y2_test, random_state=66, test_size=0.5, shuffle = False
)

print('y2_train.shape : ', y2_train.shape)
print('y2_val.shape : ', y2_val.shape)
print('y2_test.shape : ', y2_test.shape)

x와 y1을 train_test_split로 같이 분리하고 , y2는 따로 train_test_split 했다.

결과

('y2_train.shape : ', (80, 2))

('y2_val.shape : ', (10, 2))

('y2_test.shape : ', (10, 2))

잘 분리되었다.

#2. 모델 구성
from keras.models import Sequential, Model
from keras.layers import Dense, Input
# model = Sequential()

input1 = Input(shape=(2,))
dense1 = Dense(100, activation='relu')(input1)
dense1 = Dense(30)(dense1)
dense1 = Dense(7)(dense1)


output1 = Dense(30)(dense1)
output1 = Dense(7)(output1)
output1 = Dense(2)(output1)

output2 = Dense(30)(dense1)
output2 = Dense(7)(output2)
output2 = Dense(2)(output2)

model = Model(inputs = input1,
              outputs = [output1, output2]
)
model.summary()

1:다 모델의 경우 단순 분기 모델이므로 분기 지점만 잡아주면 된다. concatenate가 필요 없고 input이 1개 output을 2개로 했다.. dense1 레이어에서 바로 output1, output2 레이어로 분기해주고 Model에 inputs는 1개, outputs는 2개의 변수를 리스트로 입력했다.

#3. 훈련
model.compile(loss='mse', optimizer='adam', metrics=['mse'])

model.fit(x_train, [y1_train, y2_train],
          epochs=50, batch_size=1,
          validation_data=(x_val, [y1_val, y2_val]))

#4. 평가 예측
mse = model.evaluate(x_test, [y1_test, y2_test], batch_size=1)
print("mse : ", mse)

y1_predict, y2_predict = model.predict(x_test)
print("y1 예측값 : \n", y1_predict, "\n y2 예측값 : \n", y2_predict)

 

 

전체 소스

#1. 데이터
import numpy as np

x = np.array([range(1, 101), range(101, 201)])
y1 = np.array([range(501, 601), range(601, 701)])
y2 = np.array([range(1, 101), range(101, 201)])

print(x.shape)
print(y1.shape)
print(y2.shape)

x = np.transpose(x)
y1 = np.transpose(y1)
y2 = np.transpose(y2)

print(x.shape)
print(y1.shape)
print(y2.shape)

from sklearn.model_selection import train_test_split
x_train, x_test, y1_train, y1_test = train_test_split(
    x, y1, random_state=66, test_size=0.2, shuffle = False
)
x_val, x_test, y1_val, y1_test = train_test_split(
    x_test, y1_test, random_state=66, test_size=0.5, shuffle = False
)
y2_train, y2_test = train_test_split(
    y2, random_state=66, test_size=0.2, shuffle = False
)
y2_val, y2_test = train_test_split(
    y2_test, random_state=66, test_size=0.5, shuffle = False
)

print('y2_train.shape : ', y2_train.shape)
print('y2_val.shape : ', y2_val.shape)
print('y2_test.shape : ', y2_test.shape)

#2. 모델 구성
from keras.models import Sequential, Model
from keras.layers import Dense, Input
# model = Sequential()

input1 = Input(shape=(2,))
dense1 = Dense(100, activation='relu')(input1)
dense1 = Dense(30)(dense1)
dense1 = Dense(7)(dense1)


output1 = Dense(30)(dense1)
output1 = Dense(7)(output1)
output1 = Dense(2)(output1)

output2 = Dense(30)(dense1)
output2 = Dense(7)(output2)
output2 = Dense(2)(output2)

model = Model(inputs = input1,
              outputs = [output1, output2]
)
model.summary()

#3. 훈련
model.compile(loss='mse', optimizer='adam', metrics=['mse'])

model.fit(x_train, [y1_train, y2_train],
          epochs=50, batch_size=1,
          validation_data=(x_val, [y1_val, y2_val]))

#4. 평가 예측
mse = model.evaluate(x_test, [y1_test, y2_test], batch_size=1)
print("mse : ", mse)

y1_predict, y2_predict = model.predict(x_test)
print("y1 예측값 : \n", y1_predict, "\n y2 예측값 : \n", y2_predict)

('mse : ', [45.780569839477536, 44.77642822265625, 1.0041377544403076, 44.77642822265625, 1.0041377544403076]) (

'y1 \xec\x98\x88\xec\xb8\xa1\xea\xb0\x92 : \n',array([

[595.20605, 695.6682 ],

[596.57294, 697.07367],

[597.9693 , 698.51575],

[599.4414 , 700.052 ],

[600.91345, 701.5883 ],

[602.3855 , 703.1245 ],

[603.8576 , 704.6607 ],

[605.3296 , 706.197 ],

[606.80164, 707.7332 ],

[608.2738 , 709.2694 ]], dtype=float32),

'\n y2 \xec\x98\x88\xec\xb8\xa1\xea\xb0\x92 : \n', array([

[ 90.03383 , 190.96425 ],

[ 90.96403 , 191.97758 ],

[ 91.884285, 192.99042 ],

[ 92.779305, 194.00209 ],

[ 93.674324, 195.01369 ],

[ 94.56934 , 196.02533 ],

[ 95.46437 , 197.03696 ],

[ 96.35937 , 198.04858 ],

[ 97.2544 , 199.0602 ],

[ 98.1494 , 200.07182 ]

], dtype=float32))

 

원래 y1과 y2의 test 값은 가각 [91~100, 191~200],[591~600,691~700]

하지만 예측값은 좋지 않다. 이건 데이터가 적고, 학습을 적게 시키느라 파라미터 튜닝이 잘 안된 이유도 있지만, 사실 이 모델은 잘 사용하지 않는다. 이런 모델도 가능하다는 것만 알아두자.

 

 

실무에서 모델링이 차지하는 비율은 10% 정도밖에 되지 않는다. 데이터 전처리가 더욱 중요하다는 의미이다. 얼마나 잘 정제된 데이터를 보유하느냐가 그 모델의 훈련 능력을 향상시키는 데 있어 가장 중요하다.

반응형