ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Tensorflow Keras 기초 - 1
    Machine Learning/Tensorflow 2021. 3. 14. 22:35
    반응형

    Tensorflow를 처음 접한건 2년전에 2버전이 처음 나왔을때, 1버전으로 공부했을때 입니다.

    1버전때 당시 공부했던 자료를 올리려고 했으나, Tensorflow도 편해지는 쪽으로 변화했고,

    저도 더이상은 1버전을 사용하지 않으니 올려도 의미가 없을듯 하네요.

    그래서 1버전때 공부했던 tensorflow로 placeholder, constant, varivariable등은 제외하고,

    모델 구성 및 Tensorflow로 GridSearchCV를 이용하는 방법을 적으려고 합니다.

     

     

    keras가 tensorflow의 라이브러리에 추가되었습니다.

    2버전이 나올때부터.. 그래서 마음편하게 사용이 가능해졌습니다.

    from tensorflow.keras.models import Sequential
    from tensorflow.keras.layers import Dense # layers -> 모델구성
    from sklearn.datasets import make_regression
    # 신경망에서는 정규화가 우선임
    from sklearn.preprocessing import MinMaxScaler
    X,y = make_regression(n_samples=100, n_features=2,noise=0.1,random_state=1)
    scalarX, scalarY = MinMaxScaler(), MinMaxScaler()
    X = scalarX.fit_transform(X)
    y = scalarY.fit_transform(y.reshape(100,1))

    실제 데이터를 이용하여 작업하지 않고, sklearn에서 임의적으로 샘플데이터를 생성해주면 그걸 이용해서,

    keras에 적용하려고 합니다.

     

    # keras 모델
    model = Sequential()
    # 100*2 출력차수지정, 2*4 -> 100*4
    # layer depth
    # Dense는 FFNN망을 구성할때 씀
    model.add(Dense(4, input_dim=2, activation='relu'))
    # 100*4 / 4*4 / 100*4
    model.add(Dense(4, activation='relu'))
    # 100*4 / 4*1 / 100*1 예측
    model.add(Dense(1, activation='linear'))
    # backend = tensorflow
    # loss 에 mse, cross enthropy, KL-divergence : 분포를 비교
    model.compile(loss='mse', optimizer='adam') # tensorflow 모델을변환
    model.fit(X,y, epochs=1000, verbose=0)

    일반적으로 Layer들을 차례대로 쌓을때 사용되는 Sequential() 함수입니다.

    현재는 보기 쉽게 model 이라는 변수에 담아서 add 라는 메소드를 이용해서

    차곡차곡 쌓아도 되지만, 실제로는 리스트로 쌓고 나중에 return하는 방식을 많이 사용합니다.

     

    Dense는 일반적인 회귀식을 도출합니다.

    y = x*w + b

    이런식으로 말이죠

     

    레이어를 총 3개를 쌓았습니다.

     

    그리고 나서 compile 메소드를 호출합니다.

    여기서 loss(손실함수)는 mse로 사용합니다.

    회귀식을 검증하는 방법을 mse로 사용한다고 보면 됩니다.

     

    2021.03.13 - [Machine Learning/데이터과학을 위한 통계] - 데이터과학을 위한 통계 - 13일차 (회귀와 예측)

     

    데이터과학을 위한 통계 - 13일차 (회귀와 예측)

    4. 회귀와 예측 단순선형회귀란? 한 변수와 또 다른 변수의 크기 사이의 어떤 관계가 있는 지 보여주는 것 아들의 키와 아버지 키의 점그래프(scatter plot) 두개의 데이터는 선형관계를 알 수 있습

    datacook.tistory.com

    optimizer(최적화)는 adam을 사용합니다.

    사실 optimizer는 상당히 많습니다.

    처음으로 배우는 건 경사하강법이라고 배웁니다.

    사실 경사하강법에서 현재까지 많이 진보된 기술이 adam입니다.

    AdaGrad + RMSProp 의 장점만을 가진 계산 방법입니다.

     

    그 다음 fit 메소드를 이용해서 학습을 진행합니다.

     

    Xnew, a = make_regression(n_samples=3, n_features=2, noise=0.1,random_state=1)
    Xnew = scalarX.transform(Xnew)
    ynew = model.predict(Xnew)
    for i in range(len(Xnew)):
        print("입력데이터=%s, 예측결과=%s"%(Xnew[i], ynew[i]))

    입력데이터=[0.29466096 0.30317302], 예측결과=[0.17507902]
    입력데이터=[0.39445118 0.79390858], 예측결과=[0.7437372]
    입력데이터=[0.02884127 0.6208843 ], 예측결과=[0.38996625]

     

    새롭게 데이터를 생성해서 모델의 test set으로 학습이 잘 되었는지 확인을 해봅니다.

     

    대부분 이런식으로 학습과 결과를 확인하는 방식으로 진행됩니다.

    최근들어서는 이미지(다차원의 벡터)를 생성을 한다던지, 음성을 생성한다던지, 점점 더 복잡하게 사용이 되고 있습니다.

     



    실제 데이터를 이용한 학습

    pima.data
    0.02MB

     

     

    from tensorflow.keras.models import Sequential
    from tensorflow.keras.layers import Dense
    import numpy
    numpy.random.seed(7)
    dataset = numpy.loadtxt("pima.data", delimiter=",")
    
    X = dataset[:,0:8] # 8개 독립변수
    Y = dataset[:,8] # 종속변수
    model = Sequential()
    # ? * 8 / 8*12 => ? * 12
    model.add(Dense(12, input_dim=8,kernel_initializer='uniform', activation='relu'))
    # ? * 12 / 12 * 8 -> ? * 8
    model.add(Dense(8,kernel_initializer='uniform', activation='relu'))
    # ? * 8 / 8 * 1 -> ? * 1 분류
    model.add(Dense(1,kernel_initializer='uniform', activation='sigmoid')) # 0.5
    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
    
    # 데이터 분리입력 (train, test) :과적합 되는상황이나옴
    # train, validation, test
    
    history = model.fit(X,Y,validation_split=0.33 ,epochs=150, batch_size=10)
    scores = model.evaluate(X,Y)
    print("\n%s: %.2f%%"%(model.metrics_names[1], scores[1]*100))

    위에랑 별다를게 없는 진행구조입니다.

     

    단 달라진게 있다면, kernel_initializer을 사용했다는 점이네요.

    간단하게 설명하자면 kernel을 uniform으로 초기화 해서 진행하는 겁니다.

    통계학에서는 균일분포라고 합니다.

    들어오는 데이터의 값을 정규화하는 과정이라고 보시면 편합니다.

     

    결과확인

    import matplotlib.pyplot as plt
    print(history.history.keys())
    # loss, accuracy
    plt.plot(history.history['accuracy'])
    plt.plot(history.history['loss'])
    plt.show()

    dict_keys(['val_loss', 'val_accuracy', 'loss', 'accuracy'])

    plt.plot(history.history['val_accuracy'])
    plt.plot(history.history['val_loss'])
    plt.show()

    plt.plot(history.history['accuracy'])
    plt.plot(history.history['val_accuracy'])
    plt.title('accuracy')
    plt.ylabel('accuracy')
    plt.xlabel('epoch')
    plt.legend(['train','test'], loc='upper left')
    plt.show()

    plt.plot(history.history['loss'])
    plt.plot(history.history['val_loss'])
    plt.title('loss')
    plt.ylabel('loss')
    plt.xlabel('epoch')
    plt.legend(['train','test'], loc='upper left')
    plt.show()

    결과를 보고있으면, 등락이 조금 심하긴 하지만 상당히 잘 만들어지고 있습니다.

     


    다른 데이터로 학습하기

    from sklearn.preprocessing import scale
    from sklearn.model_selection import train_test_split
    from sklearn.datasets import make_moons
    import matplotlib.pyplot as plt
    X,Y = make_moons(noise=0.2, random_state=0, n_samples=1000)
    X = scale(X)
    X_train,X_test, Y_train,Y_test = train_test_split(X,Y,test_size=.3)
    fig, ax = plt.subplots()
    ax.scatter(X[Y==0,0], X[Y==0,1], label='Class 0')
    ax.scatter(X[Y==1,0], X[Y==1,1], color='r', label='Class 1')
    ax.legend()
    ax.set(xlabel='X', ylabel='Y', title='binary classification')

    [Text(0, 0.5, 'Y'), Text(0.5, 0, 'X'), Text(0.5, 1.0, 'binary classification')]

    from tensorflow import keras
    from tensorflow.keras.models import Sequential
    from tensorflow.keras.layers import Dense
    import numpy
    # 비선형 모델 - 신경망
    model = Sequential()
    model.add(Dense(32, input_dim=2, activation='relu')) # 차원확대
    model.add(Dense(1, activation='sigmoid'))
    model.compile(optimizer='AdaDelta',loss='binary_crossentropy', metrics=['accuracy'])
    # callback 함수는 window 자동으로 호출되는 함수 / 이미지 출력할 준비를해라
    tb_callback = keras.callbacks.TensorBoard(log_dir='./Graph/model_1/',histogram_freq=100,write_graph=True,write_images=False)
    tb_callback.set_model(model) # 콜백을 모델에 등록

    여기서 나오는 callback 함수는 굉장히 유용하게 사용하는 함수입니다.

    learning rate를 epoch이 진행하는 만큼 줄일수도 있고,

    어느정도 학습이 되면 진행이 안될때가 있습니다.

    그럴때 중지해주는 역할을 해줄수도 있습니다.

    지금은 tensorboard에 저장해서 나중에 그래프 형식으로

    시각화해서 볼수도 있습니다.

    model.summary()

    Model: "sequential_5"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    dense_14 (Dense)             (None, 32)                96        
    _________________________________________________________________
    dense_15 (Dense)             (None, 1)                 33        
    =================================================================
    Total params: 129
    Trainable params: 129
    Non-trainable params: 0
    _________________________________________________________________

    hist = model.fit(X_train,Y_train,batch_size=32, epochs=200,verbose=0,callbacks=[tb_callback] ,validation_data =(X_test,Y_test))

    여기서 batch_size는 한번에 모든 데이터를 학습하면 정확한 학습을 할수가 없기 때문에

    나누어서 학습을 진행합니다.

    컴퓨터는 2진법을 사용하기 때문에 2의 배수를 추천합니다.

    가장 많이 사용하는 배치사이즈는 32, 64입니다.

    적용하는 데이터에 변화해서 적용하는게 관례입니다.

     

    verbose는 현재 학습이 진행되고 있는 모습을 print 할건지 안할건지를 묻는 파라미터입니다.

     

    score = model.evaluate(X_test,Y_test, verbose=0)
    print("Test loss :", score[0])
    print("Test accuracy : ", score[1])

    Test loss : 0.6808927655220032
    Test accuracy :  0.49000000953674316

    score = model.evaluate(X_test, Y_test, verbose=0)
    print("Test loss:",score[0])
    print("Test accuracy :", score[1])

    Test loss: 0.6808927655220032
    Test accuracy : 0.49000000953674316

     


    Custum callback 생성

    # Callback class
    # Custum callback 함수 제작
    # 함수에 의해서 호출되는 객체
    class CustomHistory(keras.callbacks.Callback): # 상속
        def init(self):
            self.train_loss = []
            self.val_loss = []
            self.train_acc = []
            self.val_acc = []
        def on_epoch_end(self,batch, logs={}): # 오버라이딩
            self.train_loss.append(logs.get('loss'))
            self.val_loss.append(logs.get('val_loss'))
            self.train_acc.append(logs.get('accuracy'))
            self.val_acc.append(logs.get('val_accuracy'))
    from tensorflow.keras.datasets import mnist
    import matplotlib.pylab as plt
    from tensorflow.keras.models import Sequential
    from tensorflow.keras.layers import Dense
    (X_train0, y_train0), (X_test0, y_test0) = mnist.load_data()
    print(X_train0.shape, X_train0.dtype)
    print(y_train0.shape, y_train0.dtype)
    print(X_test0.shape, X_test0.dtype)
    print(y_test0.shape, y_test0.dtype)

    (60000, 28, 28) uint8
    (60000,) uint8
    (10000, 28, 28) uint8
    (10000,) uint8

    plt.imshow(X_train0[0])
    plt.grid(False)
    plt.show

    X_train = X_train0.reshape(60000,784).astype('float32')/255.0
    X_test = X_test0.reshape(10000,784).astype('float32')/255.0
    print(X_train.shape, X_train.dtype) # 60000 * 784

    (60000, 784) float32

    y_train0[:5]
    # one hot encoding 여부 : multi - label-> softmax
    # 경우에 수에 대한 확률값

    array([5, 0, 4, 1, 9], dtype=uint8)

     

    이런식으로 숫자로 카테고리로 되어있으면, 원핫인코딩을 통해서 변경해줘야 합니다.

    from tensorflow.keras.utils import to_categorical
    Y_train = to_categorical(y_train0,10)
    Y_test = to_categorical(y_test0,10)
    Y_train[:5]

    array([[0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],
           [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
           [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],
           [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
           [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]], dtype=float32)

    from tensorflow.keras.optimizers import SGD
    import numpy as np
    np.random.seed(0)
    model = Sequential()
    # 60000 * 784
    model.add(Dense(512, input_dim=784, activation='sigmoid'))
    # 60000 * 15 / 15 *10 -> 60000*10
    model.add(Dense(15))
    model.add(Dense(10, activation='sigmoid'))
    # lr : learning rate
    # stochastic gradient descent
    model.compile(optimizer=SGD(lr=0.2), loss='mse', metrics=['accuracy'])
    model.layers

    [<tensorflow.python.keras.layers.core.Dense at 0x1a3235c95e0>,

    <tensorflow.python.keras.layers.core.Dense at 0x1a33a18ff70>,

    <tensorflow.python.keras.layers.core.Dense at 0x1a336cdd6a0>]

    l1 = model.layers[0]
    l2 = model.layers[1]
    # 레이어 속성으로 정보확인
    print(l1.name)
    print(l1.input_shape)
    print(l1.output_shape)
    print(l1.activation)

     

     

    dense_2
    (None, 784)
    (None, 512)
    <function sigmoid at 0x000001A329CBCA60>

    custom_hist = CustomHistory()
    custom_hist.init()
    hist = model.fit(X_train,Y_train, epochs=10, batch_size=32,validation_data=(X_test, Y_test),callbacks = [custom_hist], verbose=2)

     

    Epoch 1/10
    1875/1875 - 3s - loss: 0.0335 - accuracy: 0.8309 - val_loss: 0.0283 - val_accuracy: 0.8728
    Epoch 2/10
    1875/1875 - 3s - loss: 0.0265 - accuracy: 0.8734 - val_loss: 0.0236 - val_accuracy: 0.8854
    Epoch 3/10
    1875/1875 - 3s - loss: 0.0230 - accuracy: 0.8846 - val_loss: 0.0207 - val_accuracy: 0.8974
    Epoch 4/10
    1875/1875 - 3s - loss: 0.0212 - accuracy: 0.8913 - val_loss: 0.0194 - val_accuracy: 0.8988
    Epoch 5/10
    1875/1875 - 3s - loss: 0.0201 - accuracy: 0.8955 - val_loss: 0.0189 - val_accuracy: 0.9034
    Epoch 6/10
    1875/1875 - 4s - loss: 0.0193 - accuracy: 0.8983 - val_loss: 0.0182 - val_accuracy: 0.9060
    Epoch 7/10
    1875/1875 - 3s - loss: 0.0188 - accuracy: 0.9008 - val_loss: 0.0175 - val_accuracy: 0.9072
    Epoch 8/10
    1875/1875 - 3s - loss: 0.0183 - accuracy: 0.9035 - val_loss: 0.0174 - val_accuracy: 0.9071
    Epoch 9/10
    1875/1875 - 3s - loss: 0.0179 - accuracy: 0.9048 - val_loss: 0.0167 - val_accuracy: 0.9122
    Epoch 10/10

     

    plt.plot(hist.history['loss'])
    plt.show()
    hist.history

    plt.plot(hist.history['accuracy'], 'b-', label='Training')
    plt.plot(hist.history['val_accuracy'], 'r:', label='test')
    plt.legend()
    plt.show()
    
    print(hist.model)
    print(hist.params)
    print(hist.history['accuracy'])
    print(hist.history['val_accuracy'][9])
    plt.show()
    plt.plot(custom_hist.train_loss, 'y', label='train loss')
    plt.show()

     

    # 문제 X_test의 이미지 한장의 label을 예측해보시오
    model.predict(X_test[:1,:])

    array([[6.2109232e-03, 5.4900710e-07, 1.4565855e-02, 3.5887808e-02,
            4.1352403e-05, 1.1081398e-03, 4.5354878e-07, 9.9730408e-01,
            1.1727006e-04, 6.7159534e-04]], dtype=float32)


    보스턴 집값 예측

    # 보스턴집값예측
    from tensorflow.keras.datasets import boston_housing
    (x_train, y_train), (x_test, y_test) = boston_housing.load_data()
    num_faetures=13
    model = Sequential()
    model.add(Dense(1, input_dim=num_faetures, activation='linear'))
    model.summary()
    model.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])
    model.fit(x_train, y_train, batch_size=1, epochs=10, verbose=1)

    Model: "sequential_2" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_5 (Dense) (None, 1) 14 ================================================================= Total params: 14 Trainable params: 14 Non-trainable params: 0 _________________________________________________________________ Epoch 1/10 404/404 [==============================] - 0s 462us/step - loss: 46348.9062 - mae: 192.8823 Epoch 2/10 404/404 [==============================] - 0s 365us/step - loss: 306.5411 - mae: 13.7649 Epoch 3/10 404/404 [==============================] - 0s 397us/step - loss: 141.6203 - mae: 9.5426 Epoch 4/10 404/404 [==============================] - 0s 588us/step - loss: 113.8913 - mae: 8.2782 Epoch 5/10 404/404 [==============================] - 0s 463us/step - loss: 95.0634 - mae: 7.5620 Epoch 6/10 404/404 [==============================] - 0s 513us/step - loss: 79.1631 - mae: 6.9111 Epoch 7/10 404/404 [==============================] - 0s 597us/step - loss: 71.5609 - mae: 6.4469 Epoch 8/10 404/404 [==============================] - 0s 701us/step - loss: 64.2840 - mae: 6.0288 Epoch 9/10 404/404 [==============================] - 0s 625us/step - loss: 60.5084 - mae: 5.9006 Epoch 10/10 404/404 [==============================] - 0s 454us/step - loss: 57.9359 - mae: 5.6564

    [38]:

    <tensorflow.python.keras.callbacks.History at 0x1a33b99a520>

     

    # mae
    mse, mae = model.evaluate(x_test,y_test,verbose=False)
    rmse= np.sqrt(mse)
    print(mse,rmse,mae)

    71.7118148803711 8.468282876733104 6.279849052429199

    # 문제 : x_test의 3집을 예상하시오.
    model.evaluate(x_test,y_test,verbose=False)
    pred = model.predict(x_test[:3,:])
    real = y_test[:3]
    print(model.predict(x_test[:3,:]))
    print('실제집값 :', y_test[:3])

    [[ 8.539891]
     [19.76989 ]
     [27.80211 ]]
    실제집값 : [ 7.2 18.8 19. ]


    Keras에서 GridSearchCV 이용하기

    import numpy as np
    from sklearn.model_selection import GridSearchCV
    from tensorflow.keras.models import Sequential
    from tensorflow.keras.layers import Dense
    from tensorflow.keras.wrappers.scikit_learn import KerasClassifier
    # 케라스랑 사이킷 연결해주는거  KerasClassifier , regressor
    def create_model():
        model = Sequential()
        model.add(Dense(12, input_dim=8, activation='relu'))
        model.add(Dense(1,activation='sigmoid'))
        model.compile(loss='binary_crossentropy', optimizer='adam',metrics=['accuracy'])
        return model
    seed=7
    np.random.seed(seed)
    dataset = np.loadtxt('pima.data',delimiter=',')
    #dataset = dataset.dropna()
    X = dataset[:,0:8]
    Y = dataset[:,8]
    model = KerasClassifier(build_fn=create_model, verbose=1)
    batch_size = [16,32,64,128,256]
    epochs=[10,50,100]
    # 매개변수 입력 형태는 dict
    param_grid = dict(batch_size=batch_size, epochs=epochs)
    grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1) # -1은 CPU 전체다 사용해라
    grid_result = grid.fit(X, Y)
    print("최적스코어 : %f      사용한 파라미터조합 : %s"%(grid_result.best_score_, grid_result.best_params_))
    means = grid_result.cv_results_['mean_test_score']
    stds = grid_result.cv_results_['std_test_score']
    params = grid_result.cv_results_['params']
    for mean, stdev, param in zip(means, stds, params):
        print("%f (%f) with : %r" %(mean,stdev,param))

     

    최적스코어 : 0.700543      사용한 파라미터조합 : {'batch_size': 16, 'epochs': 100}
    0.585935 (0.022451) with : {'batch_size': 16, 'epochs': 10}
    0.678440 (0.026824) with : {'batch_size': 16, 'epochs': 50}
    0.700543 (0.054053) with : {'batch_size': 16, 'epochs': 100}
    0.578321 (0.090383) with : {'batch_size': 32, 'epochs': 10}
    0.647186 (0.041309) with : {'batch_size': 32, 'epochs': 50}
    0.699262 (0.028545) with : {'batch_size': 32, 'epochs': 100}
    0.527383 (0.054202) with : {'batch_size': 64, 'epochs': 10}
    0.662889 (0.048762) with : {'batch_size': 64, 'epochs': 50}
    0.656362 (0.047308) with : {'batch_size': 64, 'epochs': 100}
    0.548375 (0.115079) with : {'batch_size': 128, 'epochs': 10}
    0.614608 (0.064973) with : {'batch_size': 128, 'epochs': 50}
    0.652449 (0.038027) with : {'batch_size': 128, 'epochs': 100}
    0.398217 (0.099459) with : {'batch_size': 256, 'epochs': 10}
    0.584840 (0.088266) with : {'batch_size': 256, 'epochs': 50}
    0.615873 (0.053336) with : {'batch_size': 256, 'epochs': 100}

     

     

    가장 좋은건

    0.527383 (0.054202) with : {'batch_size': 64, 'epochs': 10} 입니다.

    반응형
Designed by Tistory.