개발자 '쑥말고인절미'
[TENSORFLOW] 자동차 연비 예측하기: 회귀 예제 리뷰 본문
https://www.tensorflow.org/tutorials/keras/regression?hl=ko
자동차 연비 예측하기: 회귀 | TensorFlow Core
자동차 연비 예측하기: 회귀 Note: 이 문서는 텐서플로 커뮤니티에서 번역했습니다. 커뮤니티 번역 활동의 특성상 정확한 번역과 최신 내용을 반영하기 위해 노력함에도 불구하고 공식 영문 문서
www.tensorflow.org
상단의 링크의 예제를 리뷰해본다.
이 예제는 회귀와 분류를 해보는데, 회귀(regression)의 사전적 정의는 '한 바퀴 돌아서 본디의 자리나 상태로 돌아오는 것'이다. 회귀는 여러 개의 독립 변수와 한 개의 종속 변수 간의 상관관계를 모델링하는 기법을 의미하는데 회귀의 목적은 가격이나 확률 같이 연속된 출력 값을 예측하는 것이다. 예를 들면 아파트의 방 개수, 화장실 크기 등의 독립 변수에 따라서 아파트 가격인 종속변수가 어떤 관계를 가지는지를 모델링하고 예측하는 것이다.
이와 달리 분류(classification)는 말 그대로 분류를 하는건데 여러 개의 클래스 중 하나의 클래스를 선택하는 것이 목적이다. 예를 들어, 사진에 사과 또는 오렌지가 포함되어 있을 때 어떤 과일인지 인식하는 것이다.
해당 예제는 Auto MPG 데이터셋을 사용하여 1970년대 후반과 1980년대 초반의 자동차 연비를 예측하는 모델을 만든다. 70년대 후반과 80년대 초반에 출시된 자동차 정보를 모델에 제공하겠다.
이 정보에는 다음과 같은 속성이 포함되어 있다.
- MPG(연비)
- cylinders(실린더)
- displacement(변위)
- horsepower(마력)
- weight(중량)
- acceleration(가속)
- model year(연식)
- Origin(무슨 속성인지 모르겠음)
이 외에 차량이름도 포함되어 있지만 예제에서는 사용하지 않는다.
이 예제는 tf.keras API를 사용한다. tf.keras가 무엇인지는 아래 쪽에 작성해놨다.
(아래 링크를 한번 읽어보는 것도 나쁘지 않아보인다.)
https://89douner.tistory.com/279
3. Tensorflow와 Keras와의 관계
안녕하세요. 이번 글에서는 tensorflow와 keras의 관계에 대해서 알아보도록 하겠습니다. 1. Keras and Multi-Backend Keras는 기본적으로 high level API 입니다. 아래 링크에서 언급하고 있듯이 딥러닝의 아주..
89douner.tistory.com
우선 Tensorflow(텐서플로우)와 Keras(케라스)가 무엇인지 알면 좋을거 같은데,
텐서플로우는 구글에서 개발하고 오픈소스로 공개한 머신러닝 프레임워크이고 케라스는 텐서플로우 위에서 동작하는 라이브러리이다. 텐서플로우는 훌륭한 프레임워크이지만 처음 머신러닝을 접하는 사람(나)이라면 아직 사용하기에는 어려운 부분이 많다고 한다. 반면에 케라스는 사용자 친화적으로 개발되었기 때문에 사용이 매우 편한데 정말 간단한 신경망의 경우, 겨우 몇 줄 만으로 만들 수가 있다고 한다.
만약, 머신러닝을 처음 시작하고, 비교적 단순한 신경망을 구성하거나, 기존의 갖추어진 기능만을 사용해 빠른 시간 내에 프로토타이핑을 하고자 한다면 케라스만으로 충분할 수 있다. 하지만 텐서플로우는 훨씬 더 디테일한 조작이 가능하여 신경망을 유심히 관찰하고, 연구 및 개발을 해야하는 경우라면 텐서플로우를 사용하는 것이 좋을 수 있다.
tf.keras로 주요 틀을 구현하고, 순수한 텐서플로우로 내용을 채워넣는 방법이 가장 좋은 옵션이 될 수 있다고 한다.
tf.keras는 딥 러닝 모델을 빌드하고 학습시키기 위한 텐서플로우의 상위 수준 API이다. 또한, 신속한 프로토 타입 제작, 최첨단 연구 및 프로덕션에 사용되며 다음과 같은 세 가지 주요 이점이 있다.
- 사용자 친화적 : 일반적인 사용 사례에 맞춰 최적화된 케라스의 인터페이스는 간단하고 일관성이 있다. 케라스는 사용자 오류에 대해 명확하고 실행 가능한 피드백을 제공한다.
- 모듈식 및 구성 가능 : 케라스 모델은 거의 제한 없이 구성 가능한 빌딩 블록을 함께 연결하는 방식으로 만들어진다.
- 쉽게 확장 가능 : 연구를 위한 새로운 아이디어를 표현하는 맞춤 빌딩 블록을 작성할 수 있다. 새로운 레이어, 츨정항목, 손실 함수를 만들고 최첨단 모델을 개발한다.
참고하여 읽으면 좋은 링크는 중간중간 넣어놓겠다.
[ML] Tensorflow 와 Keras 간단 비교
들어가기 앞서, 인공지능 분야를 공부하게 되면, 자연스럽게 접하게 되는 프레임워크가 있습니다. 바로 구글에서 개발한, 텐서플로우 입니다. 그 다음으로 많이 듣게 되는 용어는 케라스 입니다
wooono.tistory.com
Keras | TensorFlow Core
Keras tf.keras는 딥 러닝 모델을 빌드하고 학습시키기 위한 TensorFlow의 상위 수준 API입니다. 또한 신속한 프로토타입 제작, 최첨단 연구 및 프로덕션에 사용되며 다음과 같은 세 가지 주요 이점이 있
www.tensorflow.org
자, 이제 예제를 시작해보겠다.
1. 아래 링크를 통해 예제를 전부 구현해보았다는 가정을 두고 리뷰를 시작하겠다.
[TENSORFLOW] 자동차 연비 예측하기: 회귀 예제 구현
회사에 입사하고 받은 과제 중 하나가 아래 링크의 예제를 돌리는 것이었고, 이 과제를 통해서 텐서플로우라는 것을 처음 다뤄보았다. 자동차 연비 예측하기: 회귀 | TensorFlow Core 자동차 연비
tobeabettercoder.tistory.com
2. 산점도 행렬이 무엇인가?
# 산점도 행렬을 그리기 위해 seaborn 패키지를 설치합니다
pip install -q seaborn
예제 시작부터 산점도 행렬을 그리기 위해 seaborn 패키지를 설치한다고 나와있다.
산점도 행렬이 무엇일까?
우선 산점도는 두 변수 간의 영향력(관계)을 보여주기 위해 가로 축과 세로 축에 데이터 포인트(점)를 그리는데 사용된다.
산점도 행렬이라는 것은 말 그대로 산점도를 배열한 것인데, 산점도 행렬을 사용하여 여러 변수 쌍의 관계를 동시에 평가할 수 있다.
3. 데이터 구하기
먼저 데이터셋을 다운로드한다.
dataset_path = keras.utils.get_file("auto-mpg.data",
"http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data")
tf.keras.utils.get_file()은 URL에서 파일을 다운로드해 오는 메소드이다.
get_file(fname, origin)의 형태로 되어 있다.
첫 번째 파라미터 fname은 파일의 이름인데 절대경로가 지정되면 파일이 해당 위치에 저장된다.
두 번째 파라미터 origin은 파일의 원본 URL이다.
C:\Users\dbs5421\.keras\datasets 경로에 파일이 저장되어 있는것을 확인할 수 있었다.
그 다음 판다를 사용하여 데이터를 읽는다.
column_names = ['MPG','Cylinders','Displacement','Horsepower','Weight',
'Acceleration', 'Model Year', 'Origin']
raw_dataset = pd.read_csv(dataset_path, names=column_names, na_values = "?",
comment='\t', sep=" ", skipinitialspace=True)
pandas.read_csv()를 통해 csv 파일을 읽는 것인데 쉼표로 구분된 값(csv) 파일을 DataFrame으로 읽어온다. pandas.read_csv(filepath_or_buffer, names=NoDefault.no_default, na_values=None, comment=None, sep=NoDefault.no_default, skipinitialspace=False)의 형태로 되어 있다.
첫 번째 파라미터 filepath_or_buffer는 읽어올 파일 형식이나 경로이다.
두 번째 파라미터 names=NoDefault.no_default는 배열 형식이 들어가야하고, 사용할 열 이름의 목록이다. 소스를 보면 column_names로 배열형태의 열 이름을 저장해주었다.
세 번째 파라미터 na_values=None는 NA/NaN으로 인식할 추가 문자열이라고 한다. NA는 Not Available의 줄임말로 사용할 수 없는 모든 유형의 데이터를 의미하고, NaN은 Not a Number의 줄임말로 사용할 수 없는 숫자 데이터를 의미한다. (NA/NaN은 R언어에서 사용되는 특수 값들이다.) 소스를 보면 "?"로 입력 되어 있으므로 데이터에 "?" 값이 들어가 있으면 "?" 또한 사용할 수 없는 데이터로 인식하게 하는 것이다.
네 번째 파라미터 comment=None는 None자리에 입력된 문자가 포함된 줄은 분석하지 않고 완전히 무시해야한다는 의미이다. 만약, 줄의 시작 부분에 해당 문자가 있으면 그 줄이 통채로 무시된다.(매개 변수는 단일문자여야 한다.) 예를 들어, comment='#'인 경우 #empty\na,b,c\n1,2,3을 header=0으로 구문 분석하면 'a,b,c'가 헤더로 처리 된다.
소스에서는 '\t'가 입력된 줄을 무시하고 분석한다고 작성되어 있는 것이다.
다섯 번째 파라미터 sep=NoDefault.no_default는 사용할 구분 기호이다. 소스에서는 공백 한 칸을 기준으로 데이터를 나누겠다는 의미로 쓰였다. 만약 " "를 ""로 수정해서 공백이 없게 하면 에러가 발생한다.
여섯 번째 파라미터 skipinitialspace=False는 구분 기호 뒤에 공백을 건너뛸지 말지를 결정하는 부분이다. True로 작성하면 공백을 건너뛸 것이고 False로 작성하면 건너뛰지 않을 것이다.
자, 위의 과정을 통해서 데이터를 가공하여 raw_dataset에 저장을 해줬다.
가공 전 데이터를 보면 열 이름도 없고 차 이름도 다 저장이 되어있다.
가공 후 데이터를 보면 목록(열)이 생겼고 차 이름 부분도 잘 지워져있다.
그 다음 가공된 데이터를 카피해서 dataset에 저장해준다.
dataset = raw_dataset.copy()
+ 소스에 dataset.tail()도 있는데 이건 그냥 데이터가 잘 들어갔는지 확인해보려고 작성한 것 같아서 위 소스에선 뺐다. pandas.DataFrame.tail(int n)은 마지막 n행을 반환하는 메소드이다. 예제소스에서 dataset.tail()을 출력해보면 아래와 같이 출력된다.
n이 양수일 경우 전체 행에서 밑에서 n개의 행을 출력한다. n이 음수일 경우엔 n개의 행을 제외하고 전부 출력한다. 아래의 예시를 확인하면 이해가 더 쉬울 것이다.
4. 데이터 정제하기
아래 소스를 출력해보면 일부 데이터가 누락되어 있는 것을 확인할 수 있다.
dataset.isna().sum()
pandas.DataFrame.isna() 메소드는 NaN만 True로 반환하고 나머지는 False로 반환하는 메소드인데 단순하게 null값을 찾아 True로 반환한다고 생각하면 된다. 아래부분에 예시를 넣었으니 읽어보자.
아래 캡쳐 화면은 dataset에서 isna()메소드로 null값을 찾아서 sum()메소드로 True의 합계를 낸 것이다. 결과를 보면 Horsepower부분에 데이터가 누락되어 있는 것(결측값)을 확인할 수 있다.
우리는 데이터를 단순하게 만들기 위해 데이터가 누락된 행은 pandas.DataFrame.dropna()메소드를 이용해 삭제하겠다.
dataset = dataset.dropna()
아래 출력화면을 보면 dropna() 이전의 데이터는 398개의 행으로 이루어져 있었는데 dropna()를 실행하고 난 뒤 6개의 결측값이 포함된 6개의 행이 삭제되어 392개의 행으로 줄어든 것을 확인할 수 있었다.
그 다음 데이터에서 Origin열은 수치형이 아니고 범주형이어서 원-핫 인코딩으로 변환할 것이다.
여기서 원-핫 인코딩이란 아래 참고한 링크를 보면 무엇인지 이해하기 쉬울 것이다. 설명하기엔 글이 길어질 거 같아 생략하지만 이해하긴 쉬우니 참고한 링크를 읽어보자.
08) 원-핫 인코딩(One-Hot Encoding)
컴퓨터 또는 기계는 문자보다는 숫자를 더 잘 처리 할 수 있습니다. 이를 위해 자연어 처리에서는 문자를 숫자로 바꾸는 여러가지 기법들이 있습니다. 원-핫 인코딩(One-Ho ...
wikidocs.net
아래 소스를 보면 pop()메소드로 dataset에 있는 Origin이라는 열만 뽑아서 origin에 저장하고 dataset에서 해당 열을 삭제해줬다.
origin = dataset.pop('Origin')
그런 다음 아래 소스를 보면origin이 1이면 USA 열을 만들어 1을 저장, origin이 2이면 Europe 열을 만들어 2를 저장, origin이 3이면 Japan 열을 만들어 1을 저장하도록 했다.
dataset['USA'] = (origin == 1)*1.0
dataset['Europe'] = (origin == 2)*1.0
dataset['Japan'] = (origin == 3)*1.0
이렇게 예제에서 사용할 데이터 가공을 끝마쳤다.
5. 데이터셋을 훈련 세트와 테스트 세트로 분할하기
이제 아래 소스로 데이터를 훈련 세트와 테스트 세트로 분할 할 것인데, 테스트 세트는 모델을 최종적으로 평가할 때 사용한다.
train_dataset = dataset.sample(frac=0.8,random_state=0)
test_dataset = dataset.drop(train_dataset.index)
pandas.DataFrame.sample()를 이용하여 랜덤으로 dataset에 있는 데이터의 80퍼센트를 추출하여 train_dataset에 저장을 해주었다. sample(frac=None, random_state=None)의 형태로 되어 있는데
첫 번째 인자인 frac는 얼마만큼 데이터를 추출해 낼것인지에 대한 값을 입력해주면 된다. 위 소스처럼 0~1사이의 값인 0.8로 입력했을 땐 80퍼센트가 추출되고, 1을 입력했을 때는 전체 데이터를 랜덤으로 재배열한다.
두 번째 인자인 random_state는 랜덤으로 뽑아진 데이터가 한번 설정되면 고정되는 것을 의미하는데 0이든 100이든 아무 숫자나 넣으면 몇 번을 실행해도 동일하게 추출된다. random_state가 아예 없다면 데이터를 추출할 때마다 랜덤한 데이터들이 추출된다.
그 다음 pandas.DataFrame.drop()을 이용하여 dataset에서 train_dataset에 저장된 행의 index를 전부 삭제하여 test_dataset에 저장해준다.
train_dataset은 훈련세트가 된 것이고, test_dataset은 테스트 세트가 되었다.
6. 데이터 조사하기
이제 훈련 세트에서 몇 개의 열을 선택해 산점도 행렬을 만들어 살펴보겠다.
아래 소스를 보면 MPG, Cylinders, Displacement, Weight 열을 선택해 kde 그래프로 그렸다.
sns.pairplot(train_dataset[["MPG", "Cylinders", "Displacement", "Weight"]], diag_kind="kde")
diag_kind는 표현할 그래프 방식을 입력하는 란이다. diag_kind가 뭔지 궁금해서 auto로도 변경해보았는데 그래프의 유형이 달라졌다. 그래프를 볼 땐 위 소스에 아래 소스 한줄만 추가 작성해서 보면 된다.
plt.show()
이제 전반적인 통계를 확인해보겠다.
train_stats = train_dataset.describe()
train_stats.pop("MPG")
train_stats = train_stats.transpose()
pandas.DataFrame.describe()메소드를 이용하여 train_dataset의 통계 데이터를 train_stats에 저장해준다. 그런 다음 데이터 train_stats에서 MPG 열은 삭제해준다. (사실 통계 데이터가 뭔지 모르겠다...^^)
그 다음 pandas.DataFrame.transpose() 메소드를 이용해 데이터 train_stats의 행과 열의 위치를 바꿔줬다.
7. 특성과 레이블 분리하기
이제 특성에서 타깃 값 또는 레이블을 분리할건데, 이 레이블을 예측하기 위해 모델을 훈련시킬 것이다. 아래 소스를 보자. pop메소드를 이용하여 데이터 train_dataset의 MPG 열을 train_labels에 저장하고, 데이터 test_dataset의 MPG 열을 test_labels에 저장해준다.
train_labels = train_dataset.pop('MPG')
test_labels = test_dataset.pop('MPG')
8. 데이터 정규화
이제 위에서 확인한 train_stats 통계를 다시 살펴보고 각 특성의 범위가 얼마나 다른지 아래 소스를 통해 확인해보자. 특성의 스케일과 범위가 다르면 정규화(normalization)하는 것이 권장된다. 특성을 정규화하지 않아도 모델이 수렴할 수 있지만, 훈련시키기 어렵고 입력 단위에 의존적인 모델이 만들어진다.
의도적으로 훈련 세트만 사용하여 통계치를 생성했다. 이 통계는 테스트 세트를 정규화 할 때에도 사용된다. 이는 테스트 세트를 모델이 훈련에 사용했던 것과 동일한 분포로 투영하기 위해서이다.
def norm(x):
return (x - train_stats['mean']) / train_stats['std']
normed_train_data = norm(train_dataset)
normed_test_data = norm(test_dataset)
이제 정규화된 데이터를 사용하여 모델을 훈련할 것인데 주의할 점이 있다. 여기에서 입력 데이터를 정규화하기 위해 사용한 통계치(평균과 표준편차)는 원-핫 인코딩과 마찬가지로 모델에 주입되는 모든 데이터에 적용되어야 한다. 여기에는 테스트 세트는 물론 모델이 실전에 투입되어 얻은 라이브 데이터도 포함된다.
9. 모델 만들기
모델을 구성해보자. 여기에서는 두 개의 완전 연결(densely connected) 은닉층으로 Sequential 모델을 만들겠다. 출력 층은 하나의 연속적인 값을 반환한다. 나중에 두 번째 모델을 만들기 쉽도록 build_model 함수로 구성 단계를 감싸겠다. 아래의 소스를 보면 모델을 반환하는 build_model 함수를 만들었다.
def build_model():
model = keras.Sequential([
layers.Dense(64, activation='relu', input_shape=[len(train_dataset.keys())]),
layers.Dense(64, activation='relu'),
layers.Dense(1)
])
optimizer = tf.keras.optimizers.RMSprop(0.001)
model.compile(loss='mse',
optimizer=optimizer,
metrics=['mae', 'mse'])
return model
이제 아래 소스로 모델을 만들고 keras의 summary() 메소드로 만들어진 모델의 정보를 간단하게 출력한다.
model = build_model()
model.summary()
위에서 keras의 Sequential 모델을 만들었는데 Sequential 모델은 각 레이어에 정확히 하나의 입력 텐서와 하나의 출력 텐서가 있는 일반 레이어 스택에 적합하다고 한다. 자세한 내용은 아래 링크를 읽어보자.
Sequential 모델 | TensorFlow Core
Sequential 모델 설정 import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers Sequential 모델을 사용하는 경우 Sequential 모델은 각 레이어에 정확히 하나의 입력 텐서와 하나의 출력 텐서가
www.tensorflow.org
이제 모델을 한번 실행해 보겠다. 훈련 세트에서 샘플 10개를 1개의 배치로 만들어 model.predict 메서드를 호출해 보겠다.
example_batch = normed_train_data[:10]
example_result = model.predict(example_batch)
keras의 predict() 메소드는 입력 샘플에 대한 출력 예측을 생성하는 메소드이다.
예제를 보면 predict 메소드로 제대로 작동하는 것을 확인했다는데 어... 사실 나는 뭐가 뭔지 모르겠어서 그냥 잘 된건가보다 하고 넘어갔다.
10. 모델 훈련
이제 위에서 생성한 모델을 1000번의 에포크(epoch) 동안 훈련한다. history 객체에는 훈련 정확도와 검증 정확도가 기록된다. 여기서 에포크(epoch)란 사전적 의미로 "(중요한 사건, 변화들이 일어난)시대"라는 의미인데 훈련 데이터셋에 포함된 모든 데이터들이 한 번씩 모델을 통과한 횟수로, 모든 학습 데이터셋을 학습하는 횟수를 의미한다.
class PrintDot(keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs):
if epoch % 100 == 0: print('')
print('.', end='')
EPOCHS = 1000
history = model.fit(
normed_train_data, train_labels,
epochs=EPOCHS, validation_split = 0.2, verbose=0,
callbacks=[PrintDot()])
위에서 보면 PrintDot 클래스로 에포크가 끝날 때마다 점(.)을 출력해 훈련 진행 과정을 표시하도록 되어있다.
그리고 keras의 fit()메소드는 정해진 수의 세대에 걸쳐 모델을 학습시키는 메소드인데(데이터셋에 대해 반복) 반환형은 History 객체이다. fit메소드에 epochs=EPOCHS라고 적힌 부분이 내가 정해준 수이다. EPOCHS만큼 모델을 학습시키는데 위에서 1000이라고 정의해주었으니 1000번 모델을 학습시키는 것이다.
자 이제 아래 소스를 이용해 history 객체에 저장된 통계치를 사용해 모델의 훈련 과정을 시각화 해보자.
hist = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
아래 캡쳐 화면을 보면 epoch가 0부터 999까지 총 1000개 학습된 것이 보인다. 학습이 잘 됐다.
그 다음 아래 소스를 추가하여 생성한 history객체를 그래프로 보겠다.
def plot_history(history):
hist = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
plt.figure(figsize=(8,12))
plt.subplot(2,1,1)
plt.xlabel('Epoch')
plt.ylabel('Mean Abs Error [MPG]')
plt.plot(hist['epoch'], hist['mae'],
label='Train Error')
plt.plot(hist['epoch'], hist['val_mae'],
label = 'Val Error')
plt.ylim([0,5])
plt.legend()
plt.subplot(2,1,2)
plt.xlabel('Epoch')
plt.ylabel('Mean Square Error [$MPG^2$]')
plt.plot(hist['epoch'], hist['mse'],
label='Train Error')
plt.plot(hist['epoch'], hist['val_mse'],
label = 'Val Error')
plt.ylim([0,20])
plt.legend()
plt.show()
plot_history(history)
plt.show()를 하면 위 쪽 6. 데이터 조사하기에서 그린 kde 그래프도 같이 뜨는데 그건 끄고 다음 캡쳐 화면만 보면 된다.
위 그래프를 보면 수 백번 에포크를 진행한 이후에는 모델이 거의 향상되지 않는 것 같다. model.fit() 메서드를 수정하여 검증 점수가 향상되지 않으면 자동으로 훈련을 멈추도록 만들어 보겠다. 에코프마다 훈련 상태를 점검하기 위해 EarlyStopping 콜백(callback)을 사용하겠다. 지정된 에포크 횟수 동안 성능 향상이 없으면 자동으로 훈련이 멈춘다.
아래 소스와 그래프를 보자.
model = build_model()
early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)
history = model.fit(normed_train_data, train_labels, epochs=EPOCHS,
validation_split = 0.2, verbose=0, callbacks=[early_stop, PrintDot()])
plot_history(history)
위 소스에서 patience=10 은 성능 향상을 체크할 에포크 횟수이다. 아래 출력된 점을 보면 1000개의 점 밑에 반 줄 정도 더 찍힌게 보이는가? model.fit() 메서드를 수정하면서 점이 추가적으로 찍힌 것이다.
위 그래프를 보면 검증 세트의 평균 오차가 +/-2 MPG이다. 좋은 결과인지 아닌지는 내가 알아서 판단하자.(어.. 사실 모르겠다. 판단불가다.)
아래 소스로 모델을 훈련할 때 사용하지 않았던 테스트 세트에서 모델의 성능을 확인해보자. 이를 통해 모델이 실전에 투입되었을 때 모델의 성능을 짐작할 수 있다.
loss, mae, mse = model.evaluate(normed_test_data, test_labels, verbose=2)
print("테스트 세트의 평균 절대 오차: {:5.2f} MPG".format(mae))
위에서 사용한 evaluate()메소드는 테스트 모드에서 모델의 손실 값과 측정항목 값을 반환하는 메소드이다.
11. 예측
마지막으로 아래 소스로 테스트 세트에 있는 샘플을 사용해 MPG 값을 예측해 보겠다.
test_predictions = model.predict(normed_test_data).flatten()
plt.scatter(test_labels, test_predictions)
plt.xlabel('True Values [MPG]')
plt.ylabel('Predictions [MPG]')
plt.axis('equal')
plt.axis('square')
plt.xlim([0,plt.xlim()[1]])
plt.ylim([0,plt.ylim()[1]])
_ = plt.plot([-100, 100], [-100, 100])
위 그래프를 보니 모델이 꽤 잘 예측한 것 같다.
이제 아래의 소스를 통해 오차의 분포를 살펴보자.
error = test_predictions - test_labels
plt.hist(error, bins = 25)
plt.xlabel("Prediction Error [MPG]")
_ = plt.ylabel("Count")
아래 결과 그래프를 보면 가우시안 분포가 아니지만 아마도 훈련 샘플의 수가 매우 작기 때문일 것이다.
결론
이 예제는 회귀 문제를 위한 기법을 소개했다.
- 평균 제곱 오차(MSE)는 회귀 문제에서 자주 사용하는 손실 함수이다.(분류 문제에서 사용하는 손실 함수와 다르다.)
- 비슷하게 회귀에서 사용되는 평가 지표도 분류와 다르다. 많이 사용하는 회귀 지표는 평균 절대값 오차(MAE)이다.
- 수치 입력 데이터의 특성이 여러 가지 범위를 가질 때 동일한 범위가 되도록 각 특성의 스케일을 독립적으로 조정해야 한다.
- 훈련 데이터가 많지 않다면 과대적합을 피하기 위해 은닉층의 개수가 적은 소규모 네트워크를 선택하는 방법이 좋다.
- 조기 종료(Early stopping)는 과대적합을 방지하기 위한 좋은 방법이다.
나만의 결론
어우 너무 어렵다. 소스가 돌아가게만 하는데 3일이 걸렸고, 리뷰작성만 이틀이 걸렸다. 사실 중간 쯤 부터는 상세히 리뷰하는걸 포기했다... 그리고 대강 흐름은 알겠는데 뭐가 뭐고 어떻게 돌아가서 어떠한 결과가 나왔을 때 그 결과 값을 어떤식으로 봐야하는지, 그 결과 값이 좋은 것인지 나쁜 것인지 잘못나온것인지 등등 점점 미궁속으로 빠져버렸다. 이번 예제를 돌리고 리뷰해보면서 텐서플로우를 찍먹해봤는데 달콤하다가 쓰다가 시다가 난리도 아니었다. 아마 이 예제를 내가 제대로 받아들이려면 이 게시글을 앞으로 여러 번 들락거리면서 수정하고 읽어야할 것 같다.
아 그리고 어떤건 데이터들은 print()로 출력할 수 있었는데 그래프들은 plt.show()를 해야지만 출력이 됐다. plt.show()가 뭐길래?
참고링크
https://www.tensorflow.org/guide/keras?hl=ko
https://ko.wikipedia.org/wiki/%EC%82%B0%EC%A0%90%EB%8F%84
https://rfriend.tistory.com/416
https://www.tensorflow.org/api_docs/python/tf/keras/utils/get_file
https://pandas.pydata.org/docs/reference/frame.html
https://steadiness-193.tistory.com/252
https://seaborn.pydata.org/generated/seaborn.pairplot.html
https://www.delftstack.com/ko/api/python-pandas/
https://keras.io/ko/models/model/
https://matplotlib.org/3.5.0/api/_as_gen/matplotlib.pyplot.html