diff --git a/README.md b/README.md index cf2a236..4ce2ad6 100644 --- a/README.md +++ b/README.md @@ -18,51 +18,20 @@ ## Table of Contents +### [Data System](./data-system/README.md) + ### [Data Sampling](./data-sampling/README.md) ### [Data Management](./data-management/README.md) -- ML개발을 하다보면 Raw data를 조금씩 변경시켜 가면서 즉, feature engineering을 해보면서 - Data 의 version이 생겨나게 된다. -- Data version마다 '최종', '최종최종', '이게 진짜 좋음' 이렇게 파일명으로 개발할 것인가?! - software engineering에서 Git을 사용하는 이유는 분명 있다. -- Tool: [DVC](https://dvc.org/), PyTorch, Pandas, ... - ### [Model Training](./model-training/README.md) ### [Model Management](./model-management/README.md) -- model 개발 과정을 보면 - Data Processing -> Train & Evaluate -> Raw Data -> 다시 Data Processing....과정의 반복이다. - -- 그리고 Production level로 AI model이 serving되고 그 이후에 성능 개선이 되어서 version up 된 model이 serving되기도 한다. - 아니면 아직 serving되기 전에도 여러 성능비교를 하며 model version이 update되기도 한다. -- Model 결정시 어떤 data 저장이 필요한가 - - model 소스 코드 - - Evaluation Metric 결과 - - 사용한 parameters - - model.pkl 파일 - - 학습에 사용한 data - - 데이터 전처리용 코드 - - 전처리된 data - ... 등 - 이런 정보들이 함께 저장되어야 추후에 '해당 모델의 성능을 **재현** 할 수 있다.' -- Tool: [MLflow](https://mlflow.org/), PyTorch, Pandas, ... - ### [Model Validation/Evaluation/Testing](./model-validation/README.md) -- Tool: [Scikit-learn](https://scikit-learn.org/) - ### [Model Packaging and Serving](./model-packaging-serving/README.md) -- 이 이전의 단계까지 Model 학습과 평가... 이런 과정들을 거쳐서 최종 모델 학습의 산물인 `Check Point`가 나온다. -- 모델 배포란, 학습한 모델의 체크포인트와 모델이 사용하는 정적 파일(아티팩트)를 패키지로 묶어서 -- 그 모델을 `Model Registry`에 보관하고 거기에 보관된 모델을 -- 서버에 배포하는 과정이다. - 배포된 모델은 서버에서 서비스되어 사용자에게 모델 결과를 제공해 줄 수 있다. - -- Tool: [BentoML](https://www.bentoml.com/), [NVIDIA Triton](https://developer.nvidia.com/ko-kr/nvidia-triton-inference-server), GCP VertexAI, AWS Sagemaker - ### [Model, ML pipeline, Model serving Monitoring](./all-monitoring/README.md) - [Model 성능 측정/수집](./all-monitoring/offline-monitoring/README.md) @@ -72,8 +41,6 @@ - 모델 online(실제 서비스가 나가있는 상태에서의) 모니터링 - 시계열 대시보드 구성 -### [Feature Store] - # MLOps Pipeline 데이터 흐름, 모델 학습, 서빙, 모니터링 등의 전체적인 아키텍쳐. @@ -115,6 +82,7 @@ Related Engineering: +- [Data System](#data-system) - [Data Sampling](#data-sampling) - [Labeling](#labeling) - [Class Imbalance](#class-imbalance) diff --git a/data-system/README.md b/data-system/README.md new file mode 100644 index 0000000..c7c24df --- /dev/null +++ b/data-system/README.md @@ -0,0 +1,259 @@ +# 데이터 시스템 (데이터 웨어하우스, 데이터 레이크, 빅쿼리, Airflow, 데이터셋 관리, 데이터 품질 모니터링, 데이터 워크플로 구성) + +학습한 날짜: 240519 + +## 데이터 웨어하우스 + +![Untitled](./assets/Untitled.png) + +데이터 웨어하우스란 다양한 데이터 소스를 수집, 통합, 적재, 관리하는 시스템이고, + +이 수집, 통합, 적재, 관리를 위해서 ETL 같은 파이프라인으로 시스템을 구성한다. + +빠르게 대용량 데이터를 분석하는데 특화되어있는 시스템이라고 생각하면 된다. 이 때 분석은 데이터 웨어하우스의 OLAP 쿼리를 사용해서 분석한다. + +### OLTP 란? OLAP 란? + +![Untitled](./assets/Untitled%201.png) + +OLAP: 복잡한 쿼리를 통해 다차원으로 데이터를 분석하는 기술. + +이 기술은 거대 데이터를 효율적으로 분석하는데 필요한 기술이기 때문에 제품 데이터 또는 로그 데이터 분석에 적합하다. + +### 그러면 데이터 베이스와 데이터 웨어하우스의 차이가 뭐냐? + +로그를 데이터 베이스에 저장하고, 이를 분석해서 사용하면 안되냐? 데이터 베이스는 200만개의 데이터(로그 데이터)라고 하자. 이 데이터에 쿼리도 버거워하고, 이걸 join한다고 하면 거의 불가하거나 지연이 발생해서 적절하지 않다. + +![Untitled](./assets/Untitled%202.png) + +에드혹 쿼리: 즉각적인 응답을 요구하는 쿼리 + +### 그러면 데이터 레이크와 데이터 웨어하우스의 차이가 뭐냐? + +1. 데이터 레이크 + - 비정형 데이터, 반정형 데이터, 정형 데이터 드으이 다양한 형태의 대량 데이터를 보관하기 위한 목적의 저장소. + - 저장소의 특성상 원시 데이터와 비가공 데이터 모두를 수집받을 수 있어서 수집을 위한 형태 제약이 없다. 그냥 아뭍따 저장해놓고 보자 느낌이네.. + - 이런 특성으로 가급적 원본 데이터를 세부적으로 분석해야할 때, 이로부터 인사이트를 얻을 수 있다. + +![Untitled](./assets/Untitled%2019.png) +![Untitled](./assets/Untitled%2020.png) + +### 데이터 웨어하우스의 장/단점 + +장점 + +1. 거대 데티어 분석에 특화된 구조와 다차원 분석 및 칼럼 특화 조회를 지원해서 복잡 쿼리 도 빠른 응답 시간으로 조회 가능. +2. 데이터 ETL, 파이프라인, BI 도구 등 다양한 생태계에 호환되는 구조로 연동이 쉽다. +3. SQL기반으로 정형 데이터를 분석하므로 쉬운 사용성 + +단점 + +1. 높은 비용 +2. 구축 난이도 +3. ETL 구성 비용이 높다. +4. 비정형 데이터를 미지원 <- 우리 같은 의료 이미지 데이터에서는 ㅠㅠ 데이터 레이크의 구성이 필요. + +### 데이터 웨어하우스의 종류 + +1. Google BigQuery +2. AWS Redshift +3. Databricks +4. Snowflake + +## Google BigQuery 사용해보기 + +![Untitled](./assets/Untitled%203.png) + +### 특징 + +1. 콘솔에 들어가면 빅쿼리 바로 볼 수 있는 거처럼. Fully-managed 서버리스 구조로 서버 스펙이나 서버 상태를 관리할 필요 없이 쿼리에 집중 가능 +2. 사용한 만큼의 금액만큼만 지불하며 사용의기준은 스캔된 데이터의 용량이다. +3. 정형, 반정형 데이터 적재 및 조회에 적합하다. +4. **스트리밍 데이터 수집 기능을 제공하기 때문에 데이터 적재 및 분석이 가능하다. ⭐️** + + ![Untitled](./assets/Untitled%204.png) + + ![Untitled](./assets/Untitled%205.png) + +5. **Vertex AI 및 BQML 기능을 통한 쿼리를 통해 ML 기능으로 확장이 가능하다. ⭐️⭐️** + +→ 4, 5번 이 Google BigQuery의 가장 큰 특징이다! **⭐️⭐️⭐️** + +### Big Query 데이터 계층 + +![Untitled](./assets/Untitled%206.png) + +### 사용해보기 + +순서 + +1. GCP 프로젝트 설정 +2. BigQuery 초기 구성 +3. 위키피디아 데이터를 적재 해 볼 것임 (huggingface 에 이 데이터 있음) +4. 적재한 위키피디아 데이터에 쿼리를 날려서 다차원 분석을 해보자 +5. Big Query에서 실시간 데이터를 처리하고 분석해보자. + +--- + +### 1. GCP 프로젝트 설정 + +Go https://cloud.google.com + +![Untitled](./assets/Untitled%207.png) + +그 다음 Run a query in BigQuery 클릭하면 빅쿼리 웹 으로 이동함. + +### 2. BigQuery 초기 구성 - Create Project + +![Untitled](./assets/Untitled%208.png) + +![Untitled](./assets/Untitled%209.png) + +### 3. 위키피디아 데이터를 BigQuery에 적재 + +이 때 웹 환경이 아니라 SDK를 사용해서 코드 상에서 해볼 것임 + +→ 그렇기 때문에 GCP Service Account Key 발급 필요. + +**1) GCP Service Account Key 발급** + +![Untitled](./assets/Untitled%2010.png) + +![Untitled](./assets/Untitled%2011.png) + +![Untitled](./assets/Untitled%2012.png) + +![Untitled](./assets/Untitled%2013.png) + +**2) BigQuery를 사용할 수 있는 라이브러리 설치** + +```python + pip install pandas-gbq # 빅쿼리에 있는 데이터를 pandas의 데이터셋과 호환시켜주는 라이브러리임. +``` + +**3) 위키피디아 데이터를 BigQuery에 적재** + +[https://huggingface.co/datasets/wikipedia](https://huggingface.co/datasets/wikipedia) 여기 가보면 + +[https://huggingface.co/datasets/wikipedia#dataset-card-for-wikipedia](https://huggingface.co/datasets/wikipedia#dataset-card-for-wikipedia) 여기에 어떻게 데이터를 불러오는지 적혀있고, + +그걸 참고해서 적재해보면, 아래와 같은 코드가 된다. + +```python +from datasets import load_dataset +from google.oauth2 import service_account +import pandas_gbq +import pandas as pd + +credentials = service_account.Credentials.from_service_account_file( + # 여기 1) 단계에서 생성한 credentials json file 위치를 넣는다. +) + +dataset = load_dataset("wikipedia", language="en", data="20220301") +df = pd.DataFrame(dataset["train"][:100000]) +pandas_gbq.to_gbq( + df, + "introduction.wikipedia", + project_id="hjchung-machine-learning", #2. BigQuery 초기 구성 - Create Project 단계에서 만든 프로젝트 이름 + credentials=credentials +) +``` + +그리고 이게 실행되는 동안 BigQuery에서 Create dataset을 눌러서 introduction을 생성해준다. + +![Untitled](./assets/Untitled%2014.png) + +### 4. 적재한 위키피디아 데이터에 쿼리를 날려서 다차원 분석 + +![Untitled](./assets/Untitled%2015.png) + +```sql +WITH KoreaTexts AS ( + SELECT + text, + REGEXP_CONTAINS(LOWER(text), LOWER('Korea')) AS ContainsKorea, + REGEXP_CONTAINS(text, '[가-힣]+') AS ContainsHangul + FROM + 'hjchung-machine-learning.introduction.wikipedia' +) + +SELECT + CONCAT( + ROUNT((SUM(CASE WHEN ContainsHangul THEN 1 ELSE 0 END) / COUNT(*)) * 100, 2), + '%' + ) AS PercentageOfHangulInKoreaTexts +FROM + KoreaTexts +WHERE + ContainsKorea +``` + +![Untitled](./assets/Untitled%2016.png) + +### BigQuery에서 실시간 데이터를 처리하고 분석 + +```python +from google.cloud import bigquery +import uuid +import time +import random +import string + + +def generate_random_text(length: int = 10) -> str: + letters = string.ascii_letters + string.digit + return "".join(random.choice(letters) for i in range(length)) + + +credentials = service_account.Credentials.from_service_account_json( + # 여기 1) 단계에서 생성한 credentials json file 위치를 넣는다. +) +table_id = "hjchung-machine-learning.introduction.streaming" + +try: + credentials.get_table(table_id) + print("Table {} already exits.".format(table_id)) +except: + schema = [ + bigquery.SchemaField(name="log_id", field_type="STRING"), + bigquery.SchemaField(name="text", field_type="STRING"), + bigquery.SchemaField(name="date", field_type="STRING"), + ] + table = bigquery.Table(table_id, schema=schema) + table = credentials.create_table(table) + print( + "Create table {}.{}.{}".format( + table.project, table.dataset_id, table.table_id) + ) + + +# 랜덤하게 계속 line을 빅쿼리에 추가해보자. +def insert_new_line() -> None: + rows_to_insert = ( + { + "log_id": str(uuid.uuid4()), + "text": generate_random_text(50), + "date": int(time.time()) + } + ) + + +for _ in range(100000): + insert_new_line() + + +``` + +![Untitled](./assets/Untitled%2017.png) + +실시간으로 추가된 걸 확인할 수 있다. + +### BigQuery에서 실시간 데이터를 처리는 어디에 활용할 수 있을까?⭐️ + +모델 서빙에서 발생한 로그 데이터를 BigQuery 스트리밍 적재하여 + +⭐️⭐️⭐️model drift 방지를 위한 지속적 학습(Continuous Training; CT) 마련 가능. ⭐️⭐️⭐️ + +![Untitled](./assets/Untitled%2018.png) + +여기에 스트리밍 API를 바로 쏘기보단 kafka같은 메세지 브로커를 쓰긴 함. diff --git a/data-system/assets/Untitled 1.png b/data-system/assets/Untitled 1.png new file mode 100644 index 0000000..47412f1 Binary files /dev/null and b/data-system/assets/Untitled 1.png differ diff --git a/data-system/assets/Untitled 10.png b/data-system/assets/Untitled 10.png new file mode 100644 index 0000000..e168861 Binary files /dev/null and b/data-system/assets/Untitled 10.png differ diff --git a/data-system/assets/Untitled 11.png b/data-system/assets/Untitled 11.png new file mode 100644 index 0000000..ba1202c Binary files /dev/null and b/data-system/assets/Untitled 11.png differ diff --git a/data-system/assets/Untitled 12.png b/data-system/assets/Untitled 12.png new file mode 100644 index 0000000..c5c00a4 Binary files /dev/null and b/data-system/assets/Untitled 12.png differ diff --git a/data-system/assets/Untitled 13.png b/data-system/assets/Untitled 13.png new file mode 100644 index 0000000..d7e5c90 Binary files /dev/null and b/data-system/assets/Untitled 13.png differ diff --git a/data-system/assets/Untitled 14.png b/data-system/assets/Untitled 14.png new file mode 100644 index 0000000..b9da3b0 Binary files /dev/null and b/data-system/assets/Untitled 14.png differ diff --git a/data-system/assets/Untitled 15.png b/data-system/assets/Untitled 15.png new file mode 100644 index 0000000..e773c49 Binary files /dev/null and b/data-system/assets/Untitled 15.png differ diff --git a/data-system/assets/Untitled 16.png b/data-system/assets/Untitled 16.png new file mode 100644 index 0000000..0b1e82e Binary files /dev/null and b/data-system/assets/Untitled 16.png differ diff --git a/data-system/assets/Untitled 17.png b/data-system/assets/Untitled 17.png new file mode 100644 index 0000000..e1f3151 Binary files /dev/null and b/data-system/assets/Untitled 17.png differ diff --git a/data-system/assets/Untitled 18.png b/data-system/assets/Untitled 18.png new file mode 100644 index 0000000..badea4c Binary files /dev/null and b/data-system/assets/Untitled 18.png differ diff --git a/data-system/assets/Untitled 19.png b/data-system/assets/Untitled 19.png new file mode 100644 index 0000000..93b706f Binary files /dev/null and b/data-system/assets/Untitled 19.png differ diff --git a/data-system/assets/Untitled 2.png b/data-system/assets/Untitled 2.png new file mode 100644 index 0000000..89aa8dd Binary files /dev/null and b/data-system/assets/Untitled 2.png differ diff --git a/data-system/assets/Untitled 20.png b/data-system/assets/Untitled 20.png new file mode 100644 index 0000000..17c5762 Binary files /dev/null and b/data-system/assets/Untitled 20.png differ diff --git a/data-system/assets/Untitled 3.png b/data-system/assets/Untitled 3.png new file mode 100644 index 0000000..3055790 Binary files /dev/null and b/data-system/assets/Untitled 3.png differ diff --git a/data-system/assets/Untitled 4.png b/data-system/assets/Untitled 4.png new file mode 100644 index 0000000..5d95346 Binary files /dev/null and b/data-system/assets/Untitled 4.png differ diff --git a/data-system/assets/Untitled 5.png b/data-system/assets/Untitled 5.png new file mode 100644 index 0000000..966c0dc Binary files /dev/null and b/data-system/assets/Untitled 5.png differ diff --git a/data-system/assets/Untitled 6.png b/data-system/assets/Untitled 6.png new file mode 100644 index 0000000..2c4f09d Binary files /dev/null and b/data-system/assets/Untitled 6.png differ diff --git a/data-system/assets/Untitled 7.png b/data-system/assets/Untitled 7.png new file mode 100644 index 0000000..246d342 Binary files /dev/null and b/data-system/assets/Untitled 7.png differ diff --git a/data-system/assets/Untitled 8.png b/data-system/assets/Untitled 8.png new file mode 100644 index 0000000..87a5dff Binary files /dev/null and b/data-system/assets/Untitled 8.png differ diff --git a/data-system/assets/Untitled 9.png b/data-system/assets/Untitled 9.png new file mode 100644 index 0000000..5ec3571 Binary files /dev/null and b/data-system/assets/Untitled 9.png differ diff --git a/data-system/assets/Untitled.png b/data-system/assets/Untitled.png new file mode 100644 index 0000000..545a94a Binary files /dev/null and b/data-system/assets/Untitled.png differ diff --git a/data-system/bigquery/batch_dataset_store_and_query.py b/data-system/bigquery/batch_dataset_store_and_query.py new file mode 100644 index 0000000..c0eb94a --- /dev/null +++ b/data-system/bigquery/batch_dataset_store_and_query.py @@ -0,0 +1,48 @@ +""" +위키피디아 데이터를 BigQuery에 적재 + +https://huggingface.co/datasets/wikipedia 여기 가보면 + +https://huggingface.co/datasets/wikipedia#dataset-card-for-wikipedia 여기에 어떻게 데이터를 불러오는지 적혀있고, + +그걸 참고해서 적재해보면, 아래와 같은 코드가 된다. +""" +from datasets import load_dataset +from google.oauth2 import service_account +import pandas_gbq +import pandas as pd + +credentials = service_account.Credentials.from_service_account_file( + # 여기 1) 단계에서 생성한 credentials json file 위치를 넣는다. +) + +dataset = load_dataset("wikipedia", language="en", data="20220301") +df = pd.DataFrame(dataset["train"][:100000]) +pandas_gbq.to_gbq( + df, + "introduction.wikipedia", + # 2. BigQuery 초기 구성 - Create Project 단계에서 만든 프로젝트 이름 + project_id="hjchung-machine-learning", + credentials=credentials +) + + +# In BigQuery, run the following query to check if the data is loaded correctly +# WITH KoreaTexts AS( +# SELECT +# text, +# REGEXP_CONTAINS(LOWER(text), LOWER('Korea')) AS ContainsKorea, +# REGEXP_CONTAINS(text, '[가-힣]+') AS ContainsHangul +# FROM +# 'hjchung-machine-learning.introduction.wikipedia' +# ) + +# SELECT +# CONCAT( +# ROUNT((SUM(CASE WHEN ContainsHangul THEN 1 ELSE 0 END) / COUNT(*)) * 100, 2), +# '%' +# ) AS PercentageOfHangulInKoreaTexts +# FROM +# KoreaTexts +# WHERE +# ContainsKorea diff --git a/data-system/bigquery/stream_dataset_store_and_query.py b/data-system/bigquery/stream_dataset_store_and_query.py new file mode 100644 index 0000000..e257328 --- /dev/null +++ b/data-system/bigquery/stream_dataset_store_and_query.py @@ -0,0 +1,57 @@ +from google.cloud import bigquery +import uuid +import time +import random +import string + + +def generate_random_text(length: int = 10) -> str: + letters = string.ascii_letters + string.digit + return "".join(random.choice(letters) for i in range(length)) + + +credentials = service_account.Credentials.from_service_account_json( + # 여기 1) 단계에서 생성한 credentials json file 위치를 넣는다. +) +table_id = "hjchung-machine-learning.introduction.streaming" + +try: + credentials.get_table(table_id) + print("Table {} already exits.".format(table_id)) +except: + schema = [ + bigquery.SchemaField(name="log_id", field_type="STRING"), + bigquery.SchemaField(name="text", field_type="STRING"), + bigquery.SchemaField(name="date", field_type="STRING"), + ] + table = bigquery.Table(table_id, schema=schema) + table = credentials.create_table(table) + print( + "Create table {}.{}.{}".format( + table.project, table.dataset_id, table.table_id) + ) + + +# 랜덤하게 계속 line을 빅쿼리에 추가해보자. +def insert_new_line() -> None: + rows_to_insert = ( + { + "log_id": str(uuid.uuid4()), + "text": generate_random_text(50), + "date": int(time.time()) + } + ) + + +for _ in range(100000): + insert_new_line() + + +# In BigQuery, run the following query to check if the data is loaded correctly +# SELECT +# COUNT(*) +# FROM +# 'hjchung-machine-learning.introduction.streaming' +# WHERE +# date > 1648849200 +# AND date < 1648849300