날씨에 따른 배추가격을 예상해 보는 서비스를 작성해 보도록 하겠습니다.
1강 : 프로젝트 아이디어 선정 및 학습데이터 수집하기
지금 예시는 단순 참고용으로 여러분들만의 상황에 맞는 다양한 예측 서비스를 고민해 보면 좋을거 같습니다. 날씨에 따른 교통사고 수 예측, 인구 밀집도에 따른 코로나 환자 확진자 수 예측 과 같은 다양한 서비스들을 구현해 내도록 고안해 볼 수 있겠죠?

날씨관련 정보를 찾기 위해 기상청에서 제공하는 기상재료개방 포털로 이동합니다.
https://data.kma.go.kr/cmmn/main.do
기후통계분석 -> 다중지점통계에서 기온, 강수량과 같은 다양한 정보를 조회할 수 있습니다.
농산물유통정보 사이트에서 배추가격에 대한 정보를 가져와야 겠죠?
동향/전망 -> 일일동향에서 하단과 같이 조회를 한 후 엑셀이나 CSV파일로 다운로드를 합니다.
다만 이렇게 수집한 데이터는 인공지능이 제대로 학습하기 쉬운 형태는 아닙니다. 따라서 인공지능이 인식하기 쉬운 데이터로 정제를 해 주어야 합니다. 데이터를 쉽게 적용할 수 있도록 형태를 변경해 줘야 합니다.
기본적으로 날짜에 따라서 기온, 강수량, 가격 정보를 8개월 정도로 가공해 보았습니다.
2강 : 파이썬으로 인공지능모델 개발하기
C드라이브에 특정 경로를 하나 만들어 준 다음 가공한 엑셀 데이터를 폴더 내부로 이동해 주세요.
주피터 노트북을 실행해 파이썬으로 개발을 해 보겠습니다.
기본적으로 다변인 선형회기 모델을 개발하는 것을 목표로 하겠습니다.
엑셀에서 데이터를 읽어 오는 방법에 대해 알아보도록 하겠습니다.
평균온도, 최저온도, 최고온도, 강수량 과 같은 다양한 변인이 가격에 영향을 미친다라고 가정합니다.
※ 다변인 선형회귀 ※
다변인 선형회귀는 모델에 영향을 미치는 변인이 여러 개 일 때 사용하는 모델입니다. 현재 우리의 데이터에서는 변인이 ‘평균 온도’, ‘최저 온도’, ‘최고 온도’, ‘강수량’이므로 이 모든 변인이 ‘가격’에 영향을 미친다고 감안해야 합니다. 따라서 가중치(Weight)을 고려했을 때 다음과 같은 수식을 세울 수 있습니다.
H(x1, x2, x3, x4) = x1w1 + x2w2 + x3w3 + x4w4
이는 행렬의 곱을 이용하면 다음과 같이 간단하게 표현할 수 있습니다.
H(X) = XW
이를 소스코드에 그대로 옮기면 됩니다. 다만 학습의 보폭(Step)을 적절히 선택해야 안정적으로 학습이 가능할 것입니다. 저는 학습률을 0.000005로 설정하여 되도록 짧은 시간에 정확한 결과가 나오도록 구현해보았습니다.
실제로 아래 코드를 활용해 실제로 학습을 실행해 보도록 하겠습니다.
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
import numpy as np
from pandas.io.parsers import read_csv
model = tf.global_variables_initializer();
data = read_csv('price data.csv', sep=',')
xy = np.array(data, dtype=np.float32)
# 4개의 변인을 입력을 받습니다.
x_data = xy[:, 1:-1]
# 가격 값을 입력 받습니다.
y_data = xy[:, [-1]]
# 플레이스 홀더를 설정합니다.
X = tf.placeholder(tf.float32, shape=[None, 4])
Y = tf.placeholder(tf.float32, shape=[None, 1])
W = tf.Variable(tf.random_normal([4, 1]), name="weight")
b = tf.Variable(tf.random_normal([1]), name="bias")
# 가설을 설정합니다.
hypothesis = tf.matmul(X, W) + b
# 비용 함수를 설정합니다.
cost = tf.reduce_mean(tf.square(hypothesis - Y))
# 최적화 함수를 설정합니다.
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.000005)
train = optimizer.minimize(cost)
# 세션을 생성합니다.
sess = tf.Session()
# 글로벌 변수를 초기화합니다.
sess.run(tf.global_variables_initializer())
# 학습을 수행합니다.
for step in range(100001):
cost_, hypo_, _ = sess.run([cost, hypothesis, train], feed_dict={X: x_data, Y: y_data})
if step % 500 == 0:
print("#", step, " 손실 비용: ", cost_)
print("- 배추 가격: ", hypo_[0])
# 학습된 모델을 저장합니다.
saver = tf.train.Saver()
save_path = saver.save(sess, "./saved.cpkt")
print('학습된 모델을 저장했습니다.')
실제로 학습된 모델이 해당 폴더에 저장이 되어 있는걸 확인할 수 있습니다!!!!
3강 : 저장된 학습 모델로 배추 가격 예측하기
※ 학습 모델을 저장하는 이유 ※
학습 모델을 저장하는 이유는 간단합니다. 만약 학습 모델을 저장하지 않고 사용자로부터 배추 가격 예측 요청(Request)이 발생할 때마다 매 번 학습을 해서 결과를 돌려준다면 시간이 오래 걸리고 많은 리소스가 소모 될 것입니다.
따라서 오프라인(Offline)에서 주기적으로 데이터를 이용해 학습을 진행한 뒤에, 그 결과를 저장해서 서버에서는 실시간 요청에 따라 이미 저장된 학습 모델로 배추 가격을 예측하는 것이 효율적입니다.
※ 배추 가격 예측 테스트 소스코드 ※
따라서 실제 웹 서버의 기능을 구현하기 전에 간단히 배추 가격을 예측하는 테스트 코드를 작성해봅시다.
먼저 프로젝트의 기본경로에서 주피터노트북 새로운 파이썬 파일을 생성해 주세요.
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
import numpy as np
# 플레이스 홀더를 설정합니다.
X = tf.placeholder(tf.float32, shape=[None, 4])
Y = tf.placeholder(tf.float32, shape=[None, 1])
W = tf.Variable(tf.random_normal([4, 1]), name="weight")
b = tf.Variable(tf.random_normal([1]), name="bias")
# 가설을 설정합니다.
hypothesis = tf.matmul(X, W) + b
# 저장된 모델을 불러오는 객체를 선언합니다.
saver = tf.train.Saver()
model = tf.global_variables_initializer()
# 4가지 변수를 입력 받습니다.
avg_temp = float(input('평균 온도: '))
min_temp = float(input('최저 온도: '))
max_temp = float(input('최고 온도: '))
rain_fall = float(input('강수량: '))
with tf.Session() as sess:
sess.run(model)
# 저장된 학습 모델을 파일로부터 불러옵니다.
save_path = "./saved.cpkt"
saver.restore(sess, save_path)
# 사용자의 입력 값을 이용해 배열을 만듭니다.
data = ((avg_temp, min_temp, max_temp, rain_fall), )
arr = np.array(data, dtype=np.float32)
# 예측을 수행한 뒤에 그 결과를 출력합니다.
x_data = arr[0:4]
dict = sess.run(hypothesis, feed_dict={X: x_data})
print(dict[0])
실제로 예측을 수행해 보도록 하겠습니다.
이후에 파일을 위와 같이 저장된 학습 모델 파일과 동일한 경로에 두고 실행하시면 됩니다.
위와 같이 임의로 넣어 본 데이터에서 학습 결과를 정상적으로 출력한 것을 알 수 있습니다.
– 평균 온도: 10
– 최저 온도: -5
– 최고 온도: 20
– 강수량: 0.8
예측된 배추 가격: 4515원
4강 : 기초 데이터 시각화 하기
※ 기초 데이터 시각화의 필요성 ※
다양한 데이터를 수집해서 그대로 인공지능으로 학습을 시킨다면 목적성이나 방향성을 제대로 잡지 못할 수 있습니다. 이럴 때 수집된 데이터가 어떤 상관 관계가 있는지를 데이터 시각화를 통해서 상관 관계를 유추하는 방법이 사용될 수도 있습니다.
데이터의 개수가 많을 때는 한 눈에 데이터가 보이지 않을 수 있으므로 유용한 방법이 될 수 있습니다.
※ 엑셀로 시각화 해보기 ※
우리가 학습 데이터로 사용했던 엑셀 파일을 열어 확인해 보도록 하겠습니다. 단순히 숫자만 기록되어 있어서 상관관계를 직관적으로 파악하기 어렵죠?
데이터 정제 과정에서 연도(Year) 정보가 숫자 8자리로 입력되어 있습니다.
엑셀에서 시간에 따른 데이터 시각화를 위해서는 ‘텍스트 나누기’ 과정이 필요합니다.
아래와 같이 설정을 변경해서 따라해 주세요.
위와 같이 ‘날짜’로 서식을 설정해주시면 자동으로 날짜 형태로 데이터가 변환됩니다.
이제 날짜(Year)와 평균 온도(Average Temp)를 설정해서 ‘데이터’ -> ‘꺾은선 그래프’를 만들어 주세요.
그럼 위와 같이 날짜에 따라서 기온이 오르락 내리락 하는것을 확인해 볼 수 있습니다. 이 부분은 굳이 우리가 눈으로 확인하지 않아도 계절적인 영향으로 온도가 오르고 내린다라는걸 알 수 있는데요.
만약 날씨 데이터가 아닌 다른 데이터가 아래와 같은 형태의 패턴을 보인다면 새로운 사실을 발견하는데 매우 유용할 수 있습니다.
이후에 날짜와 가격을 기준으로 시각화를 진행해 봅시다.
그럼 위와 같이 가격 그래프도 날짜에 따라 다양하게 변화하는 걸 확인할 수 있습니다. 또 계절적으로 영향을 받는다는 사실도 알 수 있어요.
아래 그래프는 날짜에 따른 ‘강수량’ 그래프입니다.
그래프의 형태들을 확인했을 때 저는 온도 및 강수량이 배추 가격에 영향을 미치는 요인이 될 수 있다는 직감을 얻을 수 있었습니다. 이와 같이 기초 데이터를 시각화 하는 과정에서 다양한 인사이트를 얻을 수도 있다는 점을 기억해 주세요. 특정한 결과(Result)에 영향을 미치는 변인을 분석하는 과정에서 이러한 시각화는 큰 도움을 줄 수 있습니다.
5강 : 플라스크 웹 서버와 웹 디자인 구현하기
https://mdbootstrap.com/freebies/
템플릿을 다운로드 해 주세요.
다운로드한 템플릿을 C드라이브에 모델 파일이 있는 폴더로 옮겨 복사 붙여넣기를 해 주세요. 폴더명은 Web으로 수정을 해 주시면 훨씬 더 간편하게 작업이 가능합니다.
index.html 파일을 더블클릭하면 mdbootstrap으로 만들어진 웹피이지를 확인할 수 있습니다. 이제 이 템플릿을 우리가 원하는 형태로 수정을 하면 되는데요.
이후에 자신이 원하는 웹 서비스에 맞게 디자인을 자유롭게 꾸며주시면 됩니다. 저는 웹 사이트의 불필요한 부분을 쳐내고 필요한 부분만 넣었습니다.
※ 필요한 부분만 남겨서 간단히 웹 디자인 하기 ※
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>VEGITA</title>
<!-- Font Awesome -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- Material Design Bootstrap -->
<link href="css/mdb.min.css" rel="stylesheet">
<!-- Your custom styles (optional) -->
<link href="css/style.min.css" rel="stylesheet">
<style type="text/css">
html,
body,
header,
.carousel {
height: 100%;
}
@media (min-width: 800px) and (max-width: 850px) {
.navbar:not(.top-nav-collapse) {
background: #1C2331!important;
}
}
</style>
</head>
<body>
<nav class="navbar fixed-top navbar-expand-lg navbar-dark scrolling-navbar">
<div class="container">
<a class="navbar-brand" href="https://mdbootstrap.com/material-design-for-bootstrap/" target="_blank">
<strong>VEGITA</strong>
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">HOME
<span class="sr-only">(current)</span>
</a>
</li>
</ul>
<ul class="navbar-nav nav-flex-icons">
<li class="nav-item">
<a href="#" class="nav-link border border-light rounded"
target="_blank">
<i class="fa fa-github mr-2"></i>GITHUB
</a>
</li>
</ul>
</div>
</div>
</nav>
<div id="carousel-example-1z" class="carousel slide carousel-fade" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carousel-example-1z" data-slide-to="0" class="active"></li>
<li data-target="#carousel-example-1z" data-slide-to="1"></li>
<li data-target="#carousel-example-1z" data-slide-to="2"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="carousel-item active">
<div class="view">
<video class="video-intro" autoplay loop>
<source src="https://mdbootstrap.com/img/video/city.mp4" type="video/mp4" >
</video>
<div class="mask rgba-black-light d-flex justify-content-center align-items-center">
<div class="text-center white-text mx-5 wow fadeIn">
<h1 class="mb-4">
<strong>배추 가격 예측 AI 로봇</strong>
</h1>
<p>
<strong>빠르고 정확하게 향후 배추 가격을 예측합니다.</strong>
</p>
<p class="mb-4 d-none d-md-block">
<strong>기상청 전국 기온 및 강수량 데이터와 전국 월별 배추 가격 빅 데이터를 분석하여 시계열 수치 예측을 수행합니다</strong>
</p>
<a target="_blank" href="#" class="btn btn-outline-white btn-lg">START
<i class="fa fa-graduation-cap ml-2"></i>
</a>
</div>
</div>
</div>
</div>
<div class="carousel-item">
<div class="view">
<video class="video-intro" autoplay loop>
<source src="https://mdbootstrap.com/img/video/forest.mp4" type="video/mp4">
</video>
<div class="mask rgba-black-light d-flex justify-content-center align-items-center">
<div class="text-center white-text mx-5 wow fadeIn">
<h1 class="mb-4">
<strong>배추 가격 예측 AI 로봇</strong>
</h1>
<p>
<strong>빠르고 정확하게 향후 배추 가격을 예측합니다.</strong>
</p>
<p class="mb-4 d-none d-md-block">
<strong>기상청 전국 기온 및 강수량 데이터와 전국 월별 배추 가격 빅 데이터를 분석하여 시계열 수치 예측을 수행합니다</strong>
</p>
<a target="_blank" href="#" class="btn btn-outline-white btn-lg">START
<i class="fa fa-graduation-cap ml-2"></i>
</a>
</div>
</div>
</div>
</div>
<div class="carousel-item">
<div class="view">
<video class="video-intro" autoplay loop>
<source src="https://mdbootstrap.com/img/video/Tropical.mp4" type="video/mp4">
</video>
<div class="mask rgba-black-light d-flex justify-content-center align-items-center">
<div class="text-center white-text mx-5 wow fadeIn">
<h1 class="mb-4">
<strong>배추 가격 예측 AI 로봇</strong>
</h1>
<p>
<strong>빠르고 정확하게 향후 배추 가격을 예측합니다.</strong>
</p>
<p class="mb-4 d-none d-md-block">
<strong>기상청 전국 기온 및 강수량 데이터와 전국 월별 배추 가격 빅 데이터를 분석하여 시계열 수치 예측을 수행합니다</strong>
</p>
<a target="_blank" href="#" class="btn btn-outline-white btn-lg">START
<i class="fa fa-graduation-cap ml-2"></i>
</a>
</div>
</div>
</div>
</div>
</div>
<a class="carousel-control-prev" href="#carousel-example-1z" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#carousel-example-1z" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
<main>
<div class="container">
<section class="mt-5 wow fadeIn">
<div class="row">
<div class="col-md-6 mb-4">
<img src="https://mdbootstrap.com/img/Marketing/mdb-press-pack/mdb-main.jpg" class="img-fluid z-depth-1-half" alt="">
</div>
<div class="col-md-6 mb-4">
<h3 class="h3 mb-3">배추 가격 예측 결과</h3>
<p>머신 러닝 선형 회귀(Linear Regression) 모델을 확장하여 시계열에 따른 배추 가격을 예측하고 학습 결과를 확인했습니다. 미래의 배추 가격을 효과적으로 예측할 수 있습니다.</p>
<hr>
<p>2,900개 이상의 데이터를 활용하여 1.8% 미만의 데이터 오차율을 보이는 배추 가격 예측 모델을 개발했습니다.
</p>
<a target="_blank" href="#" class="btn btn-grey btn-md">Download
<i class="fa fa-download ml-1"></i>
</a>
</div>
</div>
</section>
<hr class="my-5">
<section>
<h3 class="h3 text-center mb-5">배추 가격 예측하기</h3>
<div class="row wow fadeIn">
<div class="col-lg-6 col-md-12 px-4">
평균 기온:
<br>
최저 기온:
<br>
최고 기온:
<br>
강수량:
</div>
<div class="col-lg-6 col-md-12">
결과:
</div>
</div>
</section>
</div>
</main>
<footer class="page-footer text-center font-small mt-4 wow fadeIn">
<div class="footer-copyright py-3">
© 2023 Copyright:
<a href="#" target="_blank"> wade</a>
</div>
</footer>
<!-- SCRIPTS -->
<!-- JQuery -->
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
<!-- Bootstrap tooltips -->
<script type="text/javascript" src="js/popper.min.js"></script>
<!-- Bootstrap core JavaScript -->
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<!-- MDB core JavaScript -->
<script type="text/javascript" src="js/mdb.min.js"></script>
<!-- Initializations -->
<script type="text/javascript">
// Animations initialization
new WOW().init();
</script>
</body>
</html>
templates 폴더를 만들어서 html 파일을 index.html 이라는 이름으로 변경해 넣어주세요.
그리고 static 폴더를 만들어서 나머지 CSS와 관련된 폴더들을 넣어 주시면 됩니다.
이제 이제 다른 사용자들이 우리가 만든 웹 사이트를 볼 수 있도록 하기 위해서 플라스크(Flask) 웹 서버를 만들어 봅시다. 플라스크는 파이썬 기반의 웹 서버 프레임워크입니다. 따라서 server.py 소스코드를 생성해 줍시다.
아래와 같이 설정을 변경후 저장해 주세요.
플라스크 웹서버 코드는 구글링을 조금만 하면 바로 만들 수 있도록 코드가 제공되니 검색에서 활용하면 됩니다. 아래 코드를 첨부해 놓겠습니다.
# -*- coding: utf-8 -*-
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route("/", methods=['GET', 'POST'])
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug = True)
아래와 같이 anaconda prompt를 실행한 후 python server.py를 실행하면
로컬호스트 http://127.0.0.1:5000 이 활성화 되는 걸 확인할 수 있습니다.
7강 _ 플라스크와 텐서플로 연동하기
지난번에 만든 모델파일들을 model 폴더안에 다 넣어 놓도록 하겠습니다. 아래와 같이 4개의 파일을 잘라넣기 해서 이동시켜 주세요.
이제 사용자로부터 배추 가격 예측 요청(Request)이 들어오면 그 결과를 반환하도록 서버 소스코드를 수정합니다.
※ 플라스크 서버 소스코드 ※
# -*- coding: utf-8 -*-
from flask import Flask, render_template, request
import datetime
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
import numpy as np
app = Flask(__name__)
# 플레이스 홀더를 설정합니다.
X = tf.placeholder(tf.float32, shape=[None, 4])
Y = tf.placeholder(tf.float32, shape=[None, 1])
W = tf.Variable(tf.random_normal([4, 1]), name="weight")
b = tf.Variable(tf.random_normal([1]), name="bias")
# 가설을 설정합니다.
hypothesis = tf.matmul(X, W) + b
# 저장된 모델을 불러오는 객체를 선언합니다.
saver = tf.train.Saver()
model = tf.global_variables_initializer()
# 세션 객체를 생성합니다.
sess = tf.Session()
sess.run(model)
# 저장된 모델을 세션에 적용합니다.
save_path = "./model/saved.cpkt"
saver.restore(sess, save_path)
@app.route("/", methods=['GET', 'POST'])
def index():
if request.method == 'GET':
return render_template('index.html')
if request.method == 'POST':
# 파라미터를 전달 받습니다.
avg_temp = float(request.form['avg_temp'])
min_temp = float(request.form['min_temp'])
max_temp = float(request.form['max_temp'])
rain_fall = float(request.form['rain_fall'])
# 배추 가격 변수를 선언합니다.
price = 0
# 입력된 파라미터를 배열 형태로 준비합니다.
data = ((avg_temp, min_temp, max_temp, rain_fall), (0, 0, 0, 0))
arr = np.array(data, dtype=np.float32)
# 입력 값을 토대로 예측 값을 찾아냅니다.
x_data = arr[0:4]
dict = sess.run(hypothesis, feed_dict={X: x_data})
# 결과 배추 가격을 저장합니다.
price = dict[0]
return render_template('index.html', price=price)
if __name__ == '__main__':
app.run(debug = True)
서버를 정지한 후 재시작해 주시고 실행해 주시면 됩니다.