Skip to content

Commit

Permalink
Add Docstring
Browse files Browse the repository at this point in the history
ν•¨μˆ˜μ™€ 클래슀의 λ…μŠ€νŠΈλ§μ„ μž‘μ„±ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
  • Loading branch information
chl8469 committed Sep 15, 2021
1 parent eced4d4 commit 8c34395
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 29 deletions.
35 changes: 22 additions & 13 deletions app/api/router/predict.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,18 @@
@router.put("/insurance")
async def predict_insurance(info: ModelCorePrediction, model_name: str):
"""
Get information and predict insurance fee
param:
info:
# μž„μ‹œλ‘œ intν˜•νƒœλ₯Ό 받도둝 μ œμž‘
# preprocess 단계λ₯Ό κ±°μΉ˜λ„λ‘ λ§Œλ“€ μ˜ˆμ •
age: int
sex: int
bmi: float
children: int
smoker: int
region: int
return:
insurance_fee: float
정보λ₯Ό μž…λ ₯λ°›μ•„ λ³΄ν—˜λ£Œλ₯Ό μ˜ˆμΈ‘ν•˜μ—¬ λ°˜ν™˜ν•©λ‹ˆλ‹€.
Args:
info(dict): λ‹€μŒμ˜ 값듀을 μž…λ ₯λ°›μŠ΅λ‹ˆλ‹€. age(int), sex(int), bmi(float), children(int), smoker(int), region(int)
Returns:
insurance_fee(float): λ³΄ν—˜λ£Œ μ˜ˆμΈ‘κ°’μž…λ‹ˆλ‹€.
"""
def sync_call(info, model_name):
"""
none sync ν•¨μˆ˜λ₯Ό sync둜 λ§Œλ“€μ–΄ μ£ΌκΈ° μœ„ν•œ ν•¨μˆ˜μ΄λ©° μž…μΆœλ ₯은 λΆ€λͺ¨ ν•¨μˆ˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.
"""
model = ScikitLearnModel(model_name)
model.load_model()

Expand All @@ -61,11 +58,23 @@ def sync_call(info, model_name):

@router.put("/atmos")
async def predict_temperature(time_series: List[float]):
"""
μ˜¨λ„ 1μ‹œκ°„ 간격 μ‹œκ³„μ—΄μ„ μž…λ ₯λ°›μ•„ 이후 24μ‹œκ°„ λ™μ•ˆμ˜ μ˜¨λ„λ₯Ό 1μ‹œκ°„ κ°„κ²©μ˜ μ‹œκ³„μ—΄λ‘œ μ˜ˆμΈ‘ν•©λ‹ˆλ‹€.
Args:
time_series(List): 72μ‹œκ°„ λ™μ•ˆμ˜ 1μ‹œκ°„ 간격 μ˜¨λ„ μ‹œκ³„μ—΄ μž…λ‹ˆλ‹€. 72개의 μ›μ†Œλ₯Ό κ°€μ Έμ•Ό ν•©λ‹ˆλ‹€.
Returns:
List[float]: μž…λ ₯받은 μ‹œκ°„ 이후 24μ‹œκ°„ λ™μ•ˆμ˜ 1μ‹œκ°„ 간격 μ˜¨λ„ 예츑 μ‹œκ³„μ—΄ μž…λ‹ˆλ‹€.
"""
if len(time_series) != 72:
L.error(f'input time_series: {time_series} is not valid')
return "time series must have 72 values"

def sync_pred_ts(time_series):
"""
none sync ν•¨μˆ˜λ₯Ό sync둜 λ§Œλ“€μ–΄ μ£ΌκΈ° μœ„ν•œ ν•¨μˆ˜μ΄λ©° μž…μΆœλ ₯은 λΆ€λͺ¨ ν•¨μˆ˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.
"""
tf_model = my_model.model
time_series = np.array(time_series).reshape(1, -1, 1)
result = tf_model.predict(time_series)
Expand Down
27 changes: 19 additions & 8 deletions app/api/router/train.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,18 @@ def train_insurance(
version: float = 0.1
):
"""
insurance와 κ΄€λ ¨λœ ν•™μŠ΅μ„ μ‹€ν–‰ν•˜κΈ° μœ„ν•œ APIμž…λ‹ˆλ‹€.
Args:
PORT (int): PORT to run NNi. Defaults to 8080
experiment_sec (int): Express the experiment time in seconds Defaults to 20
experiment_name (str): experiment name Defaults to exp1
experimeter (str): experimenter (author) Defaults to DongUk
model_name (str): model name Defaults to insurance_fee_model
version (float): version of experiment Defaults to 0.1
PORT (int): NNIκ°€ 싀행될 포트번호. κΈ°λ³Έ κ°’: 8080
experiment_sec (int): μ΅œλŒ€ μ‹€ν—˜μ‹œκ°„(μ΄ˆλ‹¨μœ„). κΈ°λ³Έ κ°’: 20
experiment_name (str): μ‹€ν—˜μ΄λ¦„. κΈ°λ³Έ κ°’: exp1
experimeter (str): μ‹€ν—˜μžμ˜ 이름. κΈ°λ³Έ κ°’: DongUk
model_name (str): λͺ¨λΈμ˜ 이름. κΈ°λ³Έ κ°’: insurance_fee_model
version (float): μ‹€ν—˜μ˜ 버전. κΈ°λ³Έ κ°’: 0.1
Returns:
msg: Regardless of success or not, return address values including PORT.
msg: μ‹€ν—˜ μ‹€ν–‰μ˜ 성곡과 상관없이 포트번호λ₯Ό ν¬ν•¨ν•œ NNI Dashboard의 μ£Όμ†Œλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. μ‹€ν—˜μ˜ μ΅œμ’… κ²°κ³Όλ₯Ό λ°˜ν™˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
"""
L.info(
f"Train Args info\n\texperiment_sec: {experiment_sec}\n\texperiment_name: {experiment_name}\n\texperimenter: {experimenter}\n\tmodel_name: {model_name}\n\tversion: {version}")
Expand Down Expand Up @@ -64,10 +67,18 @@ def train_insurance(

@router.put("/atmos")
def train_atmos(expr_name: str):
"""
μ˜¨λ„ μ‹œκ³„μ—΄κ³Ό κ΄€λ ¨λœ ν•™μŠ΅μ„ μ‹€ν–‰ν•˜κΈ° μœ„ν•œ APIμž…λ‹ˆλ‹€.
Args:
expr_name(str): NNIκ°€ μ‹€ν–‰ν•  μ‹€ν—˜μ˜ 이름 μž…λ‹ˆλ‹€. 이 νŒŒλΌλ―Έν„°λ₯Ό 기반으둜 project_dir/experiments/[expr_name] 경둜둜 μ°Ύμ•„κ°€ config.yml을 μ΄μš©ν•˜μ—¬ NNIλ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.
Returns:
str: NNIμ‹€ν—˜μ΄ μ‹€ν–‰λœ 결과값을 λ°˜ν™˜ν•˜κ±°λ‚˜ μ‹€ν–‰κ³Όμ •μ—μ„œ λ°œμƒν•œ μ—λŸ¬ 메세지λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. μ‹€ν—˜μ˜ μ΅œμ’… κ²°κ³Όλ₯Ό λ°˜ν™˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
"""
nni_port = get_free_port()
expr_path = os.path.join(base_dir, 'experiments', expr_name)

# subprocess둜 nniμ‹€ν–‰
try:
nni_create_result = subprocess.getoutput(
"nnictl create --port {} --config {}/config.yml".format(
Expand Down
11 changes: 11 additions & 0 deletions app/api/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ class ModelCoreBase(BaseModel):


class ModelCorePrediction(BaseModel):
"""
predict_insurance API의 μž…λ ₯ κ°’ 검증을 μœ„ν•œ pydantic ν΄λž˜μŠ€μž…λ‹ˆλ‹€.
Attributes:
age(int)
sex(int)
bmi(float)
children(int)
smoker(int)
region(int)
"""
age: int
sex: int
bmi: float
Expand Down
9 changes: 9 additions & 0 deletions app/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
load_dotenv(verbose=True)

def connect(db):
"""
databaseμ™€μ˜ 연결을 μœ„ν•œ ν•¨μˆ˜ μž…λ‹ˆλ‹€.
Args:
db(str): μ‚¬μš©ν•  λ°μ΄ν„°λ² μ΄μŠ€μ˜ 이름을 μ „λ‹¬λ°›μŠ΅λ‹ˆλ‹€.
Returns:
created database engine: λ°μ΄ν„°λ² μ΄μŠ€μ— μ—°κ²°λœ 객체λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
"""

This comment has been minimized.

Copy link
@Ilevk

Ilevk Sep 15, 2021

Example λΆ€λΆ„ μΆ”κ°€ν•΄μ£Όμ‹œλ©΄ 쒋을 것 κ°™μ•„μš”

print(db)

POSTGRES_USER = os.getenv("POSTGRES_USER")
Expand Down
91 changes: 83 additions & 8 deletions app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@


class CoreModel:

"""
predict API ν˜ΈμΆœμ„ λ°›μ•˜μ„ λ•Œ μ‚¬μš©λ  ML λͺ¨λΈμ„ λ‘œλ“œν•˜λŠ” ν΄λž˜μŠ€μž…λ‹ˆλ‹€.
Attributes:
model_name(str): μ˜ˆμΈ‘μ„ μ‹€ν–‰ν•  λͺ¨λΈμ˜ 이름
model(obj): λͺ¨λΈμ΄ μ €μž₯될 μΈμŠ€ν„΄μŠ€ λ³€μˆ˜
query(str): μž…λ ₯받은 λͺ¨λΈμ΄λ¦„을 기반으둜 λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ λͺ¨λΈμ„ λΆˆλŸ¬μ˜€λŠ” SQL queryμž…λ‹ˆλ‹€.
"""
def __init__(self, model_name):
self.model_name = model_name
self.model = None
Expand All @@ -35,17 +42,35 @@ def __init__(self, model_name):
""".format(self.model_name)

def load_model(self):
"""
λ³Έ 클래슀λ₯Ό μƒμ†λ°›μ•˜μ„ λ•Œ 이 ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•˜μ§€ μ•ŠμœΌλ©΄ μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œν‚΅λ‹ˆλ‹€.
"""
raise Exception

def predict_target(self, target_data):
"""
λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ λΆˆλŸ¬μ™€ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜μ— μ €μž₯된 λͺ¨λΈμ„ 기반으둜 μ˜ˆμΈ‘μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€.
Args:
target_data: predict API 호좜 μ‹œ μž…λ ₯받은 κ°’μž…λ‹ˆλ‹€. μžλ£Œν˜•μ€ λͺ¨λΈμ— 따라 λ‹€λ¦…λ‹ˆλ‹€.
Returns:
예츑된 값을 λ°˜ν™˜ ν•©λ‹ˆλ‹€. μžλ£Œν˜•μ€ λͺ¨λΈμ— 따라 λ‹€λ¦…λ‹ˆλ‹€.
"""
return self.model.predict(target_data)


class ScikitLearnModel(CoreModel):
"""
Scikit learn 라이브러리 기반의 λͺ¨λΈμ„ 뢈러였기 μœ„ν•œ ν΄λž˜μŠ€μž…λ‹ˆλ‹€.
"""
def __init__(self, *args):
super().__init__(*args)

def load_model(self):
"""
λͺ¨λΈμ„ λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ λΆˆλŸ¬μ™€ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜μ— μ €μž₯ν•˜λŠ” ν•¨μˆ˜ μž…λ‹ˆλ‹€. 상속받은 λΆ€λͺ¨ν΄λž˜μŠ€μ˜ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λ₯Ό μ΄μš©ν•˜λ©°, λ°˜ν™˜ 값은 μ—†μŠ΅λ‹ˆλ‹€.
"""
_model = engine.execute(self.query).fetchone()
if _model is None:
raise ValueError('Model Not Found!')
Expand All @@ -56,10 +81,16 @@ def load_model(self):


class TensorFlowModel(CoreModel):
"""
Tensorflow 라이브러리 기반의 λͺ¨λΈμ„ 뢈러였기 μœ„ν•œ ν΄λž˜μŠ€μž…λ‹ˆλ‹€.
"""
def __init__(self, *args):
super().__init__(*args)

def load_model(self):
"""
λͺ¨λΈμ„ λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ λΆˆλŸ¬μ™€ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜μ— μ €μž₯ν•˜λŠ” ν•¨μˆ˜ μž…λ‹ˆλ‹€. 상속받은 λΆ€λͺ¨ν΄λž˜μŠ€μ˜ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λ₯Ό μ΄μš©ν•˜λ©°, λ°˜ν™˜ 값은 μ—†μŠ΅λ‹ˆλ‹€.
"""
_model = engine.execute(self.query).fetchone()
if _model is None:
raise ValueError('Model Not Found!')
Expand All @@ -82,6 +113,19 @@ def write_yml(
model_name,
version
):
"""
NNI μ‹€ν—˜μ„ μ‹œμž‘ν•˜κΈ° μœ„ν•œ config.ymlνŒŒμΌμ„ μž‘μ„±ν•˜λŠ” ν•¨μˆ˜ μž…λ‹ˆλ‹€.
Args:
path(str): μ‹€ν—˜μ˜ 경둜
experiment_name(str): μ‹€ν—˜μ˜ 이름
experimenter(str): μ‹€ν—˜μžμ˜ 이름
model_name(str): λͺ¨λΈμ˜ 이름
version(float): 버전
Returns:
λ°˜ν™˜ 값은 μ—†μœΌλ©° μž…λ ₯받은 경둜둜 yml파일이 μž‘μ„±λ©λ‹ˆλ‹€.
"""
with open('{}/{}.yml'.format(path, model_name), 'w') as yml_config_file:
yaml.dump({
'authorName': f'{experimenter}',
Expand Down Expand Up @@ -111,7 +155,20 @@ def write_yml(

return


def zip_model(model_path):
"""
μž…λ ₯받은 λͺ¨λΈμ˜ 경둜λ₯Ό μ°Ύμ•„κ°€ λͺ¨λΈμ„ μ••μΆ•ν•˜μ—¬ λ©”λͺ¨λ¦¬ 버퍼λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
Args:
model_path(str): λͺ¨λΈμ΄ μžˆλŠ” κ²½λ‘œμž…λ‹ˆλ‹€.
Returns:
memory buffer: λͺ¨λΈμ„ μ••μΆ•ν•œ λ©”λͺ¨λ¦¬ 버퍼λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
Note:
λͺ¨λΈμ„ 보쑰기얡μž₯μΉ˜μ— 파일둜 μ €μž₯ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
"""
model_buffer = io.BytesIO()

basedir = os.path.basename(model_path)
Expand All @@ -128,18 +185,36 @@ def zip_model(model_path):

return model_buffer


def get_free_port():
"""
호좜 μ¦‰μ‹œ μ‚¬μš©κ°€λŠ₯ν•œ 포트번호λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
Returns:
ν˜„μž¬ μ‚¬μš©κ°€λŠ₯ν•œ 포트번호
"""
with socketserver.TCPServer(("localhost", 0), None) as s:
free_port = s.server_address[1]
return free_port


def check_expr_over(experiment_id, experiment_name, experiment_path):
"""
train APIμ—μ„œ μ‚¬μš©λ˜κΈ° μœ„ν•˜μ—¬ λ§Œλ“€μ–΄ μ‘ŒμŠ΅λ‹ˆλ‹€. experiment_idλ₯Ό μž…λ ₯λ°›μ•„ ν•΄λ‹Ή idλ₯Ό 가진 nni μ‹€ν—˜μ„ λͺ¨λ‹ˆν„°λ§ ν•©λ‹ˆλ‹€. ν˜„μž¬ μΆ”μƒν™”λ˜μ–΄μžˆμ§€ μ•Šμ•„ μ½”λ“œ μž¬μ‚¬μš©μ„±μ΄ λΆ€μ‘±ν•˜λ©° κ°œμ„ μ΄ ν•„μš”ν•©λ‹ˆλ‹€.
* 파일둜 μƒμ„±λ˜λŠ” λͺ¨λΈμ΄ λ„ˆλ¬΄ λ§Žμ•„μ§€μ§€ μ•Šλ„λ‘ μœ μ§€ν•©λ‹ˆλ‹€.(3개 이상 λͺ¨λΈμ΄ μƒμ„±λ˜λ©΄ μ„±λŠ₯순으둜 3μœ„ λ―Έλ§Œμ€ μ‚­μ œ)
* nnictl experiment list(shell command)λ₯Ό 주기적으둜 ν˜ΈμΆœν•˜μ—¬ μ‹€ν—˜μ΄ ν˜„μ œ 진행쀑인지 νŒŒμ•…ν•©λ‹ˆλ‹€.
* μ‹€ν—˜μ˜ μƒνƒœκ°€ DONE으둜 λ³€κ²½λ˜λ©΄ 졜고점수 λͺ¨λΈμ„ λ°μ΄ν„°λ² μ΄μŠ€μ— μ €μž₯ν•˜κ³  nnictl stop experiment_idλ₯Ό μ‹€ν–‰ν•˜μ—¬ μ‹€ν—˜μ„ μ’…λ£Œν•œ ν›„ ν”„λ‘œμ„ΈμŠ€κ°€ μ’…λ£Œλ©λ‹ˆλ‹€.
Args:
experiment_id(str)
experiment_name(str)
experiment_path(str)
"""
minute = 60

while True:
time.sleep(1*minute)

# μ‹€ν—˜μ΄ λλ‚¬λŠ”μ§€ 확인
expr_list = subprocess.getoutput("nnictl experiment list")

running_expr = [expr for expr in expr_list.split('\n') if experiment_id in expr]
Expand All @@ -148,32 +223,32 @@ def check_expr_over(experiment_id, experiment_name, experiment_path):
stop_expr = subprocess.getoutput("nnictl stop {}".format(
experiment_id))
L.info(stop_expr)
break # μ‹€ν—˜μ΄ λλ‚˜λ©΄ λ¬΄ν•œλ£¨ν”„ μ’…λ£Œ
break

elif experiment_id not in expr_list:
L.info(expr_list)
break # κ°‘μžκΈ° λˆ„κ΅°κ°€κ°€ nnictl stop으둜 λ‹€ 꺼버렸을 상황에 λŒ€λΉ„
break

else:
model_path = os.path.join(experiment_path,
"temp",
"*_{}*".format(experiment_name))
exprs = glob.glob(model_path)
if len(exprs) > 3: # λͺ¨λΈνŒŒμΌμ΄ λ„ˆλ¬΄ λ§Žμ•„μ§€μ§€ μ•Šκ²Œ 3개 λ„˜μœΌλ©΄ μ‚­μ œ
if len(exprs) > 3:
exprs.sort()
[shutil.rmtree(_) for _ in exprs[3:]]

# λͺ¨λΈμ €μž₯

model_path = os.path.join(experiment_path,
"temp",
"*_{}*".format(experiment_name))
exprs = glob.glob(model_path)
if not exprs: # λͺ¨λΈνŒŒμΌμ΄ ν•˜λ‚˜λ„ 없을 경우 κ·Έλƒ₯ μ’…λ£Œ
if not exprs:
return 0

exprs.sort()
exprs = exprs[0]
metrics = os.path.basename(exprs).split("_")[:2] # metric 개수
metrics = os.path.basename(exprs).split("_")[:2]
metrics = [float(metric) for metric in metrics]

score_sql = """SELECT mae
Expand Down

0 comments on commit 8c34395

Please sign in to comment.