머신러닝 엔지니어 실무-Section2-1
인프런 Chris Song님 강의 정리
Section2: 코드 품질, 데이터 검증, 모델 분석
리서치 코드 품질 관리
코드 품질 문제 유형
- 각자 개인 컴퓨터에 저장되어 있음
- 복사 붙여넣기로 개발된 코드로 인한 중복이 많다
- 연구 결과 재연이 불가능
- 너무 많은 전역 변수 (side-effect)
--> 최대한 파라미터를 전달하고 받아오는 방식으로 고쳐야함..
- 너무 긴 코드 (디버깅 불편, 함수와 클래스 구분이 명확하지 않음)
--> python의 경우 500 line 미만으로 개발!
- 상대 참조 (나중에 폴더 구조가 바뀌면, 디버깅이 어려워짐)
--> PYTHONPATH 환경변수를 활용해서 시작 지점을 명확하게 하고, absolute import를 사용해야함
- 명확하지 않은 변수명
깨진 유리창의 법칙
- 만일 한 건물의 유리창이 깨어진 채로 방치되어 있다면, 곧 다른 유리창들도 깨어질 것
- 코드 품질 문제도 좋지 않으면, 다른 사람들의 코드 품질도 안 좋아 질 것이다.
린트와 유닛테스트
린트란? (강좌에 없는 내용)
개념
- 문법 오류, 코드 컨벤션 등을 잡아주는 검사기
- 의심스럽거나, 에러를 발생하기 쉬운 코드에 표시(flag)를 달아 놓음
- 매번 코드 리뷰를 통해 코드 컨벤션을 체크할 수 있지만,
모든 코드를 매번 체크하면서 컨벤션을 유지하는 것은 어려움
- 각 언어 별로 이를 위한 도구가 존재하는데, 이를 Lint한다고 하는 것 같음
flake8
- Python의 Lint 도구
- PEP8을 기반으로 코드 컨벤션을 검사함
- Flake8 Rules
- 예시
# main.py
import os
def helloworld(s):
return f"Hello World! {s}"
if __name__ == '__main__':
print(helloworld('Caleb'))
flake8 main.py
1) F401 --> os 라이브러리를 impor 해놓고 사용하지 않았다.
2) E302 --> 라이브러리를 import 했으면 두 줄은 띄워라
3) E271 --> helloworld 함수 명칭에 공백 여러개가 있다
4) E305 --> 함수나 클래스를 정의한 이후에 비어있는 2줄을 넣어라
5) W292 --> 파일의 마지막에는 공백 line을 삽입해라
- 예시 수정
def helloworld(s):
return f"Hello World! {s}"
if __name__ == '__main__':
print(helloworld('Caleb'))
black
- 코드의 가독성을 높여줌
- 자동으로 re-format을 해줌
# Before
def helloworld(a):
print("Hello world! {a}!")#asdasd
if __name__ == "__main__":
helloworld("Yang")
--> 최대한 파라미터를 전달하고 받아오는 방식으로 고쳐야함..
--> python의 경우 500 line 미만으로 개발!
--> PYTHONPATH 환경변수를 활용해서 시작 지점을 명확하게 하고, absolute import를 사용해야함
모든 코드를 매번 체크하면서 컨벤션을 유지하는 것은 어려움
# main.py
import os
def helloworld(s):
return f"Hello World! {s}"
if __name__ == '__main__':
print(helloworld('Caleb'))
flake8 main.py
1) F401 --> os 라이브러리를 impor 해놓고 사용하지 않았다.
2) E302 --> 라이브러리를 import 했으면 두 줄은 띄워라
3) E271 --> helloworld 함수 명칭에 공백 여러개가 있다
4) E305 --> 함수나 클래스를 정의한 이후에 비어있는 2줄을 넣어라
5) W292 --> 파일의 마지막에는 공백 line을 삽입해라
def helloworld(s):
return f"Hello World! {s}"
if __name__ == '__main__':
print(helloworld('Caleb'))
# Before
def helloworld(a):
print("Hello world! {a}!")#asdasd
if __name__ == "__main__":
helloworld("Yang")
# After
# black main.py
def helloworld(a):
print("Hello world! {a}!") # asdasd
if __name__ == "__main__":
helloworld("Yang")
타입 어노테이션/타입 체크란? (강좌에 없는 내용)
- 파이썬의 동적(dynamic) 타입 처리는 일회성 script or 소규모 application을 개발할 때는 큰 장점으로 작용함
- 하지만 application 규모가 커지게 되면, 다이나믹함이 치명적인 버그로 이어질 확률이 높음
--> 이는 안정성에 위험 요소로 작용함 - 타입 어노테이션(type annotation)은 파이썬 코드에 타입을 명시하기 위한 표준을 정립하기 위한 것
- python 3.5부터 추가됨
- 변수나 함수에 타입이 명시된 파이썬 코드는 정적 타입 검사기를 통해 코드를 실행하지 않고도 타입 에러를 찾아낼 수 있음
타입 검사
- gi라는 변수의 타입을 int로 명시하기 위해 타입 어노테이션을 추가했다.
- 아래 코드를 python으로 실행하면 문제 없이 돌아간다.
- 타입 어노테이션은 언어 레벨에서는 코드 실행에 아무 영향이나 제약을 주지 않기 때문
- 아래와 같이 타입 어노테이션을 사용하는 것을
타입 힌팅(type hinting)
이라고 한다.- 주로 코드를 읽기 쉽게 하거나, 코드 편집기(IDE), 린터(linter)에서 활용됨
# test.py
# python test.py
gi: int="4"
print(gi)
- 하지만 위 코드를 mypy로 실행해보면 에러가 발생한다.
- 변수의 타입과 저장된 값의 타입이 다른 type error 발생
# test.py
# mypy test.py
gi: int="4"
print(gi)
- mypy를 사용하면 python interpreter가 잡지 못하는 타입 버그를 찾아낼 수 있음
오류 검사
- mypy를 사용하면 타입 자체의 버그 뿐만 아니라 실제 런타임에 발생할 수 있는 오류를 미리 알아낼 수도 있음
- 아래 코드를 실행하면 gi 함수 두 번째 인자에 str타입이 넘어가기에 오류가 발생함
# test.py
# python test.py
def gi(msg: str, times: int=1) -> list:
return [msg] * times
gi("Hi", "4")
- 위 코드를 mypy로 돌려보면 미리 오류가 발생할 것임을 알려준다.
# test.py
# mypy test.py
def gi(msg: str, times: int=1) -> list:
return [msg] * times
gi("Hi", "4")
지속적 통합 (CI)
- Continuous integration
- 소프트웨어의 질적 향상을 채크하고 배포 시간을 줄일 수 있음
- Ex. Github Actions, Jenkins
CI란? (강좌에 없는 내용)
- 팀의 구성원들이 작업한 내용을 정기적으로 통합하는 것
- 각각의 팀멤버들로부터 Submit된 소스코드를 정기적으로 통합하는 것
- CI tool: 위 내용을 시행해주는 프로그램
CI 시스템 구축
- CI 시스템이 구축되지 않은 경우:
- 개발자들이 각자 개발한 소스코드를 형상관리 서버에 커밋하면 별도의 품질관리를 거치지 않고, 대부분 개발이 끝난 막바지에 통합을 하여 테스트를 진행함
- 이 경우, 잘못된 소스코드를 형상관리 시스템에 반영하였을 경우에 발생되는 문제가 개발 후반에 장애로 발견됨
- CI 시스템이 구축된 경우:
- CI서버는 형상관리 서버에 Commit된 소스코드를 주기적으로 폴링하여 컴파일, 단위테스트, 코드 인스펙션 등의 과정을 수행
- 폴링:
- 일정한 주기를 가지고 서버와 응답을 주고 받는 방식
- 충돌 회피 또는 동기화 처리의 목적으로 다른 장치의 상태를 주기적으로 검사하여 일정한 조건을 만족할 떄 송수신 등의 자료처리를 함
- 컴파일: 사람의 언어를 컴퓨터가 이해할 수 있는 언어로 바꿔주는 과정
- 코드 인스펙션: 정의된 룰을 기반으로 소스 코드를 검사하여 오류 및 위험요인을 식별하여 알려주는 기능
- 폴링:
- 신규 or 수정된 소스코드가 결함이 있는지 여부를 지속적으로 검증함
- 검증 결과는 이메일, RSS등의 피드백 매커니즘을 통해 개발자에게 전달
- RSS: 블로그, 뉴스, 칼럼 등 업데이트가 잦은 콘텐츠들을 사용자가 편하게 볼 수 있도록 만들어진 규약
- 조기 결함을 발견하여 해결 가능
- CI서버는 형상관리 서버에 Commit된 소스코드를 주기적으로 폴링하여 컴파일, 단위테스트, 코드 인스펙션 등의 과정을 수행
Github Actions (강좌에 없는 내용)
개요
- Github에서 제공하는 워크플로우(workflow)를 자동화하도록 도와주는 도구
- 테스트, 빌드, 배포 등의 다양한 작업들을 자동화하여 처리
- public 저장소의 경우 무료로 사용 가능하며 private 저장소는 월마다 제공되는 무료 사용량 초과 시에 요금이 부과
- 무료 계정 기준 500MB의 스토리지와 월마다 2,000분 제공
- Github 저장소에서 등록하거나
.github/workflows
폴더 내에.yml
파일을 추가하여 등록할 수 있음- Github 저장소 등록
- yml파일 --> 강의 내용
- Github 저장소 등록
Github Actions의 구성
- 워크 플로우(workflows)
- 저장소에 추가하는 자동화된 프로세스
- 하나 이상의 job으로 이루어져 있으며, 이벤트에 의해 실행됨
- 이벤트(Events)
- 워크플로우를 실행하는 특정 활동이나 규칙
- 커밋의 push, pull request가 생성되었을 때, 저장소 dispath event를 통해 Github 외부에서 발생하는 활동으로도 이벤트를 발생시킬 수 있음
- schedule에 POSIX cron 문법으로 스케줄 이벤트를 발생시킬 수 있음
- 러너(runners)
- Github 액션 러너 애플리케이션이 설치된 서버
- Github에서 호스팅하는 러너를 사용할 수도 있고 직접 호스팅 할 수도 있음
- 작업(jobs)
- 워크플로우의 기본 단위
- 스텝으로 이루어져 있음
- 워크플로우는 여러 작업을 병렬적으로 실행하며 순차적으로 실행하도록 설정 할 수 있음
- 빌드와 테스트 코드 수행 작업을 순차적으로 실행 (빌드 실패 시, 테스트는 진행 실행되지 않음)
- 스텝(steps)
- 작업에서 커맨드를 실행하는 독립적인 단위
- 한 작업의 각 스텝들은 동일한 러너에서 실행되므로 해당 작업의 액션들은 서로 데이터를 공유함
- 액션(actions)
- 워크플로우의 가장 작은 요소
- 직접 만들어 사용할 수도 있고, 마켓에 등록된 만들어진 것을 가져와 사용할 수도 있음
워크 플로우 관리
- 민감한 정보 저장
- 비밀번호, 인증서 같은 정보는 Github에 secret으로 저장하여 환경변수로 사용이 가능함
- 의존적인 작업 구성
- 작업은 병렬적으로 수행됨
- 다른 작업이 완전히 끝난 후에 작업을 실행시키고 싶다면 needs 키워드를 통해 작업이 의존성을 갖도록 지정하면 됨
- 빌드 매트릭스 활용
- 워크플로우가 다양한 OS, 플랫폼, 언어의 여러 조합에서 테스트를 실행하려는 경우 빌드 매트릭스를 활용하면 됨
- 빌드 옵션을 배열로 받는 strategy 키워드를 사용하면 됨
- 종속성 캐싱
- GIthub의 러너는 각 작업에서 새로운 환경으로 실행됨
- 작업들이 종속성을 재사용하는 경우 파일들을 캐싱하여 성능을 높이면 됨
- 캐시를 생성하면 해당 저장소의 모든 워크플로우에서 사용 가능
Github Actions 적용사례
- Github에서 Pull Request를 생성했을 때, 자동으로 Github이 다음과 같이 3가지 작업을 자동으로 수행시킴
- 테스트 자동화: 유닛테스트를 돌린 후 결과를 Code Climate에 전송
- 코드 Lint 체크: black & flake8
코딩 컨벤션 체크 자동화 Workflow
- 코딩 컨벤션을 따라야하는 이유
- 코드 가독성을 높여서 함께하는 팀원들에 대한 배려
- 코드의 품질 및 코딩 속도 향상
- 모든 팀원들이 동일한 스타일의 코드를 유지
- Github repository에서
.github/workflows/lint.yml
파일을 생성- 아래와 같이 workflow를 설정해두면, 앞으로 코딩 컨벤션을 맞추지 못하면 Github가 PR merge를 차단함
- main 브랜치에 본인의 코드를 머지하려면 코딩 컨벤션을 맞춰야만 함
name: Lint Code Base
on: push
jobs:
# Set the job key. The key is displayed as the job name
# when a job name is not provided
super-lint:
# Name the Job
name: Lint Code Base
# Set the type of machine to run on
runs-on: ubuntu-latest
env:
OS: ${{ matrix.os }}
PYTHON: '3.7'
steps:
# Checks out a copy of your repository on the ubuntu-latest machine
- name: Checkout code
uses: actions/checkout@v2
# Runs the Super-Linter action
- name: Lint Code Base
uses: github/super-linter@v3
env:
DEFAULT_BRANCH: master
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VALIDATE_PYTHON_BLACK: true
VALIDATE_PYTHON_FLAKE8: true
테스트 자동화 Workflow
-
테스트 자동화 시스템 구축 이유
- 설계 수정 시간의 단축
- 설계 수정은 시간이 지날 수록 그 비용이 급격하게 증가함
- 테스트를 먼저 설계하고 개발을 진행하게 되면, 각 함수의 구조와 기능 정의를 명확하게 하므로, 설계의 구조적 문제를 빠르게 찾아낼 수 있게됨
- 객체지향적인 코드 개발
- 본격적인 개발에 앞서 테스트 코드를 먼저 작성한다면 좀 더 명확한 기능과 구조를 설계할 수 있음
- 디버깅 시간 단축
- 모델의 인퍼런스 결과가 이상한 경우엔 그 원인이 어디로부터 왔는지 명확하게 이해하기 어려움
- 데이터 전/후 처리에 테스트 코드를 작성하면, 모델의 인퍼런스 결과를 좀 더 신뢰할 수 있음
- 유지보수 용이성
- 테스트 코드들을 작성하게 되면, 한 모듈의 기능 변화가 다른 모듈에 어떤 영향을 미치는 지 테스트 코드를 돌려봄으로써 바로 추적할 수 있게됨
- 기능을 추가하더라도 사이드 이펙트에 대한 염려로부터 자유로워짐
- 설계 수정 시간의 단축
-
Code Climate: 코드 품질 관리를 모니터링하도록 해주는 유료 솔루션 (오픈소스의 경우에는 무료)
- 코드 품질 모니터링 대시보드 생성 가능
- 코드의 결함이나 안좋은 패턴들을 감지하고 자동으로 코드 리뷰가 달림 --> 코드 리뷰 자동화 (생산성 향상)
참고
- Flake8로 Python Code를 Lint 해보자
- 파이썬 타입 체크 - Mypy
- CI란?
- 폴링이란
- 폴링개념
- 인터럽트(interupt)와 폴링(polling)의 차이와 개념
- 컴파일이란
- 정적 테스트와 코드 리뷰 - 코드 인스펙션
- RSS 란 무엇인가
- Github Actions이란?
- 리서치 코드의 지속적 통합(CI) 튜토리얼(상편)
- 리서치 코드의 지속적 통합(CI) 튜토리얼(하편)
Author And Source
이 문제에 관하여(머신러닝 엔지니어 실무-Section2-1), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@gjtang/머신러닝-엔지니어-실무-Section2-1
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Author And Source
이 문제에 관하여(머신러닝 엔지니어 실무-Section2-1), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@gjtang/머신러닝-엔지니어-실무-Section2-1저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)