Open GY-jung opened 7 years ago
1-12 directory에 프로그램이 돌아가는데 필요한 데이터와 파이썬 파일을 업로드했습니다. preprocessing.py 는 돌아가는데 필요한 데이터가 너무 커서 업로드하지 못했고, regression.py와 predict.py는 데이터가 잘 있어서 제대로 작동합니다.
Goood!
나중에 이건 서버에 이식해서 서비스에 활용해도 좋을 것 같습니다.
실제 서비스에 이식할때 library의존성 문제가 항상 있는데요, 이기회에 Docker 공부해보는것도 좋을 것 같네요. Docker 는 OS를 포함해서 하나의 배포용 패키지를 만들어주는 툴입니다. 실제 서비스 제작에 관심있다면 반드시 알아야함!
Docker이용해 배포 및 실서버 이식은 다른 인턴분들하고 같이 해보면 좋을것 같네요. 어차피 실제 개발하게 되면 배워야 하는거라서...
utils.py
import csv
import numpy as np
def csvreader(filename, delimiter = ' '):
fever = []
with open(filename, 'r') as csvfile:
feverreader = csv.reader(csvfile, delimiter = delimiter)
for row in feverreader:
fever.append(row)
return fever
def is_number(s):
try:
float(s)
return True
except ValueError:
return False
def tonumpy(fever) :
fever = np.asarray(fever)
return fever
def normalize(row):
avg = np.mean(row)
row -= avg
var = np.var(row) + 1e-8
row /= np.sqrt(var)
return row, avg, var
def printmax(data):
print ("max")
print (np.amax(data, axis = 0))
def printmin(data):
print ("min")
print (np.amin(data, axis = 0))
preprocessing.py
#coding=utf-8
# 데이터셋을 합치고 가공하는 과정. 비정상적인 값들을 제거하고, 필요한 feature들을 더 넣어줌.
# 디렉토리에 있는 "total.csv" 파일을 받아 "final%d.csv (% datanum)", "avg.csv", "var.csv" 파일을 저장함.
import csv
import numpy as np
import time
from utils import *
scalable = [0, 1, 16, 18] # 해열제 섭취량, 초기 온도, 체중, 나이의 경우 평균 0, variance 1로 scale 해주는 것이 도움될 것으로 추정됨. scale 가능한 변수들의 index임.
datanum = 10 # 사용할 data 개수. 전체 데이터는 백 이십만개이지만 컴퓨터 계산 사양의 한계로 오만 개 정도가 최대로 사용할 수 있는 data 개수인 것 같음.
def regvalue(data): # dataset에서 regression에 쓸 value만 남김
total__ = data[:,[3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23]]
return total__
def nanfilter(data,p) : # dataset에서 missing value 지움
nan= data[:, p]
nan_mask = np.zeros_like(nan, dtype = "bool")
for i in np.arange(len(nan)):
if ( is_number(nan[i]) ) :
nan_mask[i] = True
data = (data[nan_mask])
return data
def elimoutlier(data): # 체중, 해열제 섭취량이 정상 범위에서 벗어난 것 지움.
weight = data[:,16]
weight_mask = np.zeros_like(weight, dtype = "bool")
for i in np.arange(len(weight)):
if is_number(weight[i]) and ( float(weight[i]) >=2 ) and (float(weight[i])<=40):
weight_mask[i] = True
data = data[weight_mask]
volume = data[:,1]
volume_mask = np.zeros_like(volume, dtype = "bool")
for i in np.arange(len(volume)):
if is_number(volume[i]) and ( float(volume[i]) >=0.1 ) and (float(volume[i])<=30):
volume_mask[i] = True
data = (data[volume_mask])
return data
def tempdownfilter(data): # 온도가 떨어지는 것을 예측하는 것이므로 초기 온도가 너무 낮은 것(35도 미만) 지움
temp = data[:, 0]
temp_mask = np.zeros_like(temp, dtype = "bool")
for i in np.arange(len(temp)):
if ( float(temp[i]) >= 35.0 ) :
temp_mask[i] = True
data = (data[temp_mask])
return data
def timezerofilter(data): # 해열제를 먹은 직후 체온 데이터는 쓰지 않을 것이므로 지움
tpass = data[:,2]
tpass_mask = np.zeros_like(tpass, dtype = "bool")
for i in np.arange(len(tpass)):
if ( float(tpass[i]) > 600 ) :
tpass_mask[i] = True
data = (data[tpass_mask])
return data
def filterwrapper(data): # 위의 5개 filter wrap함
data1 = data[:datanum]
data2 = regvalue(data1)
for cnt in np.arange(data2.shape[1]):
data3 = nanfilter(data2, cnt)
data4 = np.array(data3, dtype = "float")
data5 = elimoutlier(data4)
data6 = tempdownfilter(data5)
data7 = timezerofilter(data6)
return data7
def dummyhour(fever): #해열제 섭취 후 다시 체온을 젤 때까지 걸리는 시간 (정수 단위) 을 dummy 변수화하여 regression에 사용하면 좋을 것이라고 생각함. 해열제 섭취 후 3시간 - 4시간 구간에 잰 체온인 경우 hour3 변수가 1이고, hour1 hour2 hour4 hour5 hour6은 모두 0.
dummyarray = np.zeros((len(fever[:,2]),6))
for i in range(5):
j = i+1
for t in range(len(fever[:,2])):
if (fever[t,2] == j):
dummyarray[t,j] = 1
if (fever[t,2] >= 6):
dummyarray[t,5] = 1
fever = np.concatenate((fever, dummyarray), axis = 1)
return fever
def addinv(data, scalable): # scale 가능한 변수에 한해 역수 취한 값을 feature로 추가함.
inv = np.zeros((len(data), len(scalable)))
for cnt in np.arange(len(scalable)):
inv[:, cnt] = 1 / (data[:, scalable[cnt]] + 1e-2)
datainv = np.concatenate((data, inv), axis = 1)
return datainv
def normalizescalable(data, scalable) : # scale 가능한 변수와 그것의 역수들을 normalize함. 나중에 평균과 분산을 predict.py에서 사용할 것이기 때문에 csv로 저장.
avg = np.zeros(2 * len(scalable))
var = np.zeros(2 * len(scalable))
for cnt in np.arange(len(scalable)):
data[:, scalable[cnt]], avg[cnt], var[cnt] = normalize(data[:, scalable[cnt]])
data[:, data.shape[1] - len(scalable) + cnt], avg[cnt+len(scalable)], var[cnt+len(scalable)] = normalize(data[:, data.shape[1] - len(scalable) + cnt])
return data, avg, var
def timescale(data) : # 해열제 섭취 후 체온 잰 시간을 3600으로 나눠 시간 단위로 변환함. 초 단위로 하면 해열제 섭취 후 시간만 scale이 너무 커 training에 문제 있음.
data[:, 2] = data[:, 2] / 3600
return data
def featureaddwrapper(data) : # 위의 4개 feature 변환 및 추가하는 함수들 wrap함
data1 = dummyhour(data)
data2 = timescale(data1)
data3 = addinv(data2,scalable)
data4, avg, var = normalizescalable(data3, scalable)
with open("avg.csv", 'wb') as writer :
np.savetxt("avg.csv", avg, fmt = '%s', delimiter = ' ')
with open("var.csv", 'wb') as writer :
np.savetxt("var.csv", var, fmt = '%s', delimiter = ' ' )
return data4
def generate_data(datanum, now = False): # 실제로 사용할 data 만들어서 csv로 저장
if now :
data = tonumpy(csvreader("total.csv"))
data1 = data[:datanum]
data2 = filterwrapper(data1)
data3 = featureaddwrapper(data2)
with open("final%d .csv" %datanum, 'wb') as writer:
np.savetxt("final%d.csv" %datanum, data3, fmt = '%s', delimiter = ' ')
generate_data(datanum, now = True)
regression.py
# coding=utf-8
# 아이의 정보 (체중, 성별, 나이) 와 섭취한 해열제 종류 및 양, 해열제 먹인 순간의 측정 초기 온도, 해열제 먹인 후 경과 시간을 바탕으로, 초기에 비해 온도 감소량이 얼마나 될지 예측할 수 있는 모델을 설계함.
# 모델은 hidden layer가 2개인 neural net이고, 모델에 의해 예측된 체온감소와 실제 체온감소의 차의 제곱을 최소화하도록 설계함
# 대략 100번정도의 iteration이 진행되면 validation set에서 모델에 의해 예측된 체온감소와 실제 체온감소의 차의 제곱의 평균이 0.65 ~ 0.7 정도 나옴. 즉 체온 감소량을 평균적으로 0.8도 범위 정도로 예측함.
# 디렉토리에 "final%d.csv" %datanum 을 필요로 함
import numpy as np
import csv
import time
import tensorflow as tf
from preprocessing import *
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
# 모델 hyperparameter
eps = 1e-1
lr = 0.001
decay = 0.9
scalable = [0,1,16,18]
hidden1 = 100
hidden2 = 50
datanum = 10
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
#데이터 로딩
data = tonumpy(csvreader("final%d.csv" %datanum))
data = np.array(data, dtype = "float")
np.random.shuffle(data)
printmax(data)
printmin(data)
data = np.transpose(data)
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
#dataset 분할
train_set = data[:, 0:int(data.shape[1] * 0.6)]
dev_set = data[:, int(data.shape[1]* 0.6) : int(data.shape[1]* 0.8)]
test_set = data[:, int(data.shape[1]* 0.8):] # 6 : 2 : 2 로 training / validation / test 을 분할함
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
# 체온 감소량을 예측할 것이므로 체온 감소량을 제외한 값들을 training에 사용
temp_mask = np.ones(data.shape[0], dtype = "bool")
temp_mask[3] = False
X_train = np.array(train_set[temp_mask], dtype = "float")
temp_train = np.array(train_set[3], dtype = "float")
X_dev = np.array(dev_set[temp_mask], dtype = "float32")
temp_dev = np.array(dev_set[3], dtype = "float32")
X_test = np.array(test_set[temp_mask], dtype = "float32")
temp_test = np.array(test_set[3], dtype = "float32")
X_train = np.transpose(X_train)
X_dev = np.transpose(X_dev)
X_test = np.transpose(X_test)
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
#some tensorflow...
#placeholder
inputs_placeholder = tf.placeholder(tf.float32, (None, X_train.shape[1]), name = "inputs")
temps_placeholder = tf.placeholder(tf.float32, (None,), name = "temps")
#affine layers
W1 = tf.Variable(tf.random_uniform((X_train.shape[1],hidden1), minval = -np.sqrt(6.0/(X_train.shape[1] + hidden1) ), maxval = np.sqrt(6.0/(X_train.shape[1] + hidden1))), dtype = tf.float32)
b1 = tf.Variable(tf.zeros((1,hidden1)) , dtype = tf.float32)
W2 = tf.Variable(tf.random_uniform((hidden1,hidden2), minval = -np.sqrt(6.0/(hidden1 + hidden2)), maxval = np.sqrt(6.0/(hidden1 + hidden2))), dtype = tf.float32)
b2 = tf.Variable(tf.zeros((1,hidden2)), dtype = tf.float32)
W3 = tf.Variable(tf.random_uniform((hidden2,1), minval = -np.sqrt(6.0/hidden2), maxval = np.sqrt(6.0/hidden2)), dtype = tf.float32)
b3 = tf.Variable(tf.zeros((1,1)), dtype = tf.float32)
#activation : tanh
z1 = tf.matmul(inputs_placeholder, W1) + b1
h1 = tf.nn.tanh(z1)
z2 = tf.matmul(h1, W2) + b2
h2 = tf.nn.tanh(z2)
z3 = tf.add(tf.matmul(h2, W3) , b3, name = "op_to_restore") # 예상 체온
y1 = tf.matmul(X_dev, W1) + b1
g1 = tf.nn.tanh(y1)
y2 = tf.matmul(g1, W2) + b2
g2 = tf.tanh(y2)
y3 = tf.matmul(g2,W3) + b3
#L2 loss
loss = tf.reduce_mean((z3 - temps_placeholder)**2)
dev_loss = tf.reduce_mean((y3 - temp_dev)**2)
#model 재사용을 위한 saver
saver = tf.train.Saver()
#Adamoptimizer
optimizer = tf.train.AdamOptimizer(lr)
train_op = optimizer.minimize(loss)
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
#Training. 5번의 step마다 loss 확인. devset에서 loss가 늘어난 경우에 learning rate를 0.9배로 decay
best_dev = 10
for step in range(101):
sess.run(train_op, feed_dict = {inputs_placeholder : X_train, temps_placeholder : temp_train})
if step%5 == 0: # 매 스텝마다 예상 감소 체온과 실제 감소 체온 3개, train_loss, dev_loss 출력
print(step, sess.run(loss, feed_dict = {inputs_placeholder : X_train, temps_placeholder : temp_train}), sess.run(loss, feed_dict = {inputs_placeholder : X_dev, temps_placeholder : temp_dev}))
print(sess.run((z3[0],z3[1], z3[2]), feed_dict = {inputs_placeholder : X_train, temps_placeholder : temp_train}))
print (temp_train[0], temp_train[1], temp_train[2])
if best_dev < sess.run(loss, feed_dict = {inputs_placeholder : X_dev, temps_placeholder : temp_dev}) :
lr *= decay
print ("decay")
print (lr)
else :
best_dev = sess.run(dev_loss, feed_dict = {inputs_placeholder : X_train, temps_placeholder : temp_train})
print ("test set loss")
print (sess.run(loss, feed_dict = {inputs_placeholder : X_test, temps_placeholder : temp_test}))
#save model. predict에서 사용함
save_path = saver.save(sess, 'C:\\Users\\MobileDoctor\\1-12\\model')
predict.py
# coding=utf-8
# regression.py 에서 만든 모델을 바탕으로 예상 감소 체온을 예측해주는 프로그램. example_info에 차례로 체온, 해열제 양, 해열제 섭취 후 경과 시간, 해열제 종류, 체중, 성별, 나이( 단위 : day) 를 입력하면, 예상 감소 체온을 알려주는 프로그램.
import tensorflow as tf
from preprocessing import *
from utils import *
from merge12 import *
scalable = [0,1,16,18]
example_info = (38.0, 5.0, 3600, 1, 15.0, 0, 1140) # 예시 데이터.
def predict_temp(info):
temp, volume, time_pass, kind, weight, gender, born_date = info[:]
final_data = np.zeros((19,1))
final_data[0] = temp
final_data[1] = volume
final_data[2] = time_pass
final_data[3] = 0.0 # dummy
final_data[3+kind] = 1.0
final_data[16] = weight
final_data[17] = gender
final_data[18] = born_date
final_data = np.transpose(final_data)
final_data = dummyhour(final_data)
processed_data = addinv(final_data, scalable)
processed_data = timescale(processed_data)
processed_data = np.transpose(processed_data)
return processed_data
def pseudonormalize(data):
avg = tonumpy(csvreader("avg.csv", delimiter = ' '))
var = tonumpy(csvreader("var.csv", delimiter = ' '))
for cnt in np.arange(len(scalable)):
data[scalable[cnt]] -= float(np.asscalar(avg[cnt]))
data[scalable[cnt]] /= np.sqrt(float(np.asscalar(var[cnt])))
for cnt in np.arange(len(scalable)):
data[len(data) - len(scalable) + cnt] -= float(np.asscalar(avg[cnt + len(scalable)]))
data[len(data) - len(scalable) + cnt] /= np.sqrt(float(np.asscalar(var[cnt + len(scalable)])))
return data
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
# example_info를 모델에 들어갈 수 있게 변환
test = pseudonormalize(predict_temp(example_info))
time_mask = np.ones(len(test), dtype = "bool")
time_mask[3] = False
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
#model loading
sess = tf.Session()
saver = tf.train.import_meta_graph("C:\\Users\\MobileDoctor\\1-12\\model.meta")
saver.restore(sess, "C:\\Users\\MobileDoctor\\1-12\\model")
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
#모델에 예측 체온 넣어 계산
X_test = np.array(test[time_mask], dtype = "float32")
temp_test = np.array(test[3], dtype = "float32")
X_test = np.transpose(X_test)
temp_test = np.transpose(temp_test)
graph = tf.get_default_graph()
temps_placeholder = graph.get_tensor_by_name("temps:0")
inputs_placeholder = graph.get_tensor_by_name("inputs:0")
feed_dict = { inputs_placeholder : X_test, temps_placeholder : temp_test }
op_to_restore = graph.get_tensor_by_name("op_to_restore:0")
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
#체온 출력
print ("estimated temp")
print (sess.run(op_to_restore, feed_dict = feed_dict))
실제 train에 쓰지 않은 데이터에 test 해보고 결과좀 알려주세요~ 그냥 서비스를 만드는 것보다 이게 맞는지 아닌지 검증 할 수 있는 방법을 아는게 더 중요합니다.
아이의 신상정보 (체중, 성별, 나이) 해열제 섭취정보(섭취한 해열제 종류, 섭취 용량, 해열제 먹은 후 경과 시간, 해열제 섭취 당시 체온) 을 predict.py의 example_info에 입력하면 에상 체온 감소량을 출력하는 프로그램을 만들었습니다. hidden layer가 2개인 neural net을 사용했으며, 모델이 예상한 체온 감소량과 실제 체온 감소량의 차의 제곱을 minimize하도록 network를 train했습니다. 컴퓨터 계산 성능의 문제로 데이터 120만개 중 5만개만 사용해서 모델을 만들었습니다.
dependencies : python 3.6 , python library( tensorflow, numpy ) 디렉토리를 통째로 업로드하겠습니다.