한동안 기초적인 코드부터 논문 속 코드를 일부 재현하면서 공부를 해왔다. 아마 이제는 좀 더 실질적으로 모델을 만들어보고 제품을 만들어보는 작업을 하게 될텐데 지금까지 배운 기초적인 부분들도 체계화하고 학습을 위한 코드와 실무에서의 코드가 어떻게 다른지 이책을 통해
체험해보고자 선택하게 되었다. 실제로 이 책의 저자는 GCP(구글 클라우드 플랫폼)에서 일한 덕분에 다양한 케이스들을 다룰 수 있었다.
디자인 패턴과 문제
1. 디자인 패턴이란?
실제 개발 환경에서 반복적으로 발생하는 문제들이 있는데 이 원인을 사전적으로 예방할 수 있는 프로그래밍 패턴을 디자인 패턴이라고 한다. 머신러닝에서의 디자인 패턴이라 함은, 결국 머신러닝 시스템을 구축하는 프로세스에서 발생하는 문제를 예방할 수 있는 패턴들을 의미한다.
2. 머신러닝의 문제
1) 데이터 품질
- 데이터 라벨의 정확도
- 데이터 완전성 : 우리가 학습시킨 데이터가 그 세계관이고, 이 데이터가 실제 서빙되는 서비스의 목적을 달성할만큼 완전해야한다.
- 데이터 일관성 : 데이터 셋 전체의 일관성을 유지하기 위해서 데이터 구축에 있어서 표준이 마련되어야 한다.
- 데이터 적시성 : 데이터 사건이 발생한 시점과 데이터 베이스에 추가된 시점 사이의 지연시간을 의미하는데 이 차이가 클 때 모델 구성에 어려움이 있는 경우도 있어서 확인해야한다.
2) 재현성
프로그래밍은 일반적으로 재현가능하지만, 머신러닝 모델은 무작위성이 내재되어 있다. 특히 Gradient Descent 방식은 훈련 과정에서 똑같은 결과값을 내지는 않기 때문에 똑같은 모델, 똑같은 코드로 학습을 해도 약간 다른 결과를 생성할 수 있다.
따라서 이를 보장하기 위해 tf.ramdom.set_seed(value) 등을 통해서 random하게 나오는 결과들에 대해서 동일한 무작위성을 적용하도록 설정한다. 또한 라이브러리 버전도 통일하는 것을 권장한다
3) 데이터 드리프트
머신러닝 모델은 일반적으로 입력과 출력간의 정적인 관계를 나타내지만 실제 프로덕션에서는 시간이 지남에 따라서 데이터가 달라질 수 있다. 갑자기 유저의 특성이 달라질수도 있고, 기상 예측의 경우에는 오늘날과 50년전의 데이터는 다를 수 있다. 또한 오늘날은 기술이 발달해서 파악할 수 있는 특징이 더 많아진다. 이에 대해서는 별도의 처리방법이 있고 6.3절에서 볼 수 있다.
4) 확장
리서쳐가 추론하거나 예측을 가져오는 인프라와 매시간 수백만건의 예측 요청을 받는 프로덕션 모델을 위한 인프라는 완전히 다르다. 따라서 모델 -> 서빙으로 가는 확장성 문제를 해결하는 것이 중요하다.
5) 다양한 목표
제품이 어떤 목표냐에 따라서 1종 오류를 줄일지 2종 오류를 줄일지가 달라진다. 따라서 이런 부분에 대해서도 잘 싱크되어야 한다.
이번 블로그 글에서는 모델의 Input으로 들어가는 데이터들을 어떻게 처리해서 모델에 전달할지에 대한 패턴들을 정리한 글이다.
데이터 표현 디자인 패턴
머신러닝 모델은 여러 변수들의 수학적 함수 처리를 모아두었다고 보면 되며, 이러한 함수는 특히 명확하게 정해진 데이터 표현으로 처리되어야만 잘 작동한다. 예를 들어 아이의 병 판단을 예측하는 의사결정 나무 모델에서 아이의 키가 100cm 이상인가?와 같은 Boolean 형으로 되어 있어야 모델이 처리하는데 Input으로 아이의 키 128cm만 들어가면 모델이 동작할 수 없다.
이처럼 학습가능한 데이터 표현을 잘 담았는지 데이터 표현 디자인 패턴을 정리해보았다.
1. 스케일링 : 손실 함수의 곡률이 크면 비정상적인 가중치 업데이트가 일어날 수 있기 때문에 -1과 1사이에서 보통 수치를 조정한다.
- min-max scaling = (x-min(x1) - (x - max(x1)) / max(x1) - min(x1)
- 클리핑 : 합리적인 최소, 최대값을 설정하고 이를 기준으로 Min-max를 취한다음 이것보다 크거나 작은 아웃라이어 값은 1, -1로 처리한다.
- z점수 정규화 : 평균과 표준편차를 사용하여 Z정규화 처리를 하는 것
- 윈저라이징 : 데이터 값의 10번째 및 90번째 백분위수를 각각 클리핑한다.
- bucketize : 변수를 동일한 간격으로 나누는 것
- ML.BUCKETIZE(num_views, [1,6,10]) as bin : 이렇게 하면, 1이하, 1초과 6미만, 6이상부터 10미만, 10이상으로 4개의 버킷이 배정된다.
- 박스콕스 변환 : 정규성을 가지지 않은 분포들을 정규성을 가질 수 있도록 처리하는 작업
- 이에 대한 상세한 설명은 https://zephyrus1111.tistory.com/190 에서 잘 정리되어 있다.
- 코드는 아래와 같이 처리할 수 있다.
traindf['boxcox'], est_lambda = (scipy.stats.boxcox(traindf[num_views]))
- 텍스트 데이터의 경우에는 가변적인 길이를 처리해야하는데 이는 상황에 따라 다르게 처리할 필요가 있다.
- 주로 원핫 인코딩을 처리하는 편인데 가변적인 길이인 경우에는 각 어휘 항목의 발생횟수를 카운팅해서 배열로 처리할 수도 있고, 상대 빈도를 사용할 수도 있다.
디자인 패턴 1 : 해시 패턴
가장 많이 사용되는 원핫인코딩이 가지고 있는 문제는 3가지 정도가 있다.
1. [큰 카디널리티] 만일 카테고리가 수백가지인 경우, 카디널리티가 너무 커진다. 즉 학습하려는 모델을 저장하기 위한 공간이 너무 커진다.
2. [콜드 스타트] 모델 개발 이후에도 카테고리가 더 생긴 경우에는 모델은 이에 대해 예측할 수 없으므로 처리해야한다.
3. [불완전한 어휘] 데이터가 커질 경우, 학습 데이터에서 무작위 샘플링으로 특정 카테고리에서 학습하기에 데이터가 덜 뽑힐 수도 있다.
이를 해결하기 위해 해시패턴이 있는데 문제를 예시로 들어서 해결 방식을 정해보려고 한다.
비행기의 도착 지연을 예측하는 문제에서, 입력 중 하나로 출발하는 공항이 있는데 데이터셋 수집 당시 미국에는 347개의 공항이 있었다. 이를 어떻게 구현해야할까?
1. 카테고리 입력을 고유한 문자열로 변환한다.
2. 문자열을 숫자로 변환해주는 해시 알고리즘을 사용한다.(빅쿼리에서는 FARM_FINGERPRINT)
3. 해시 결과를 원하는 버킷수로 나누고 나머지를 취한다.
- 경험상 각 버킷당 5개의 항목을 혼합하는 정도로 버킷의 수를 선택하는 것이 좋다.
4.나머지를 특성으로 활용한다.
1. 불완전한 어휘 : 버킷안의 여러개의 카테고리가 혼재되어 있어서 적어도 정보가 매우 부족한 문제를 일부 해결할 수 있다.
2. 콜드 스타트 : 새 공항이 추가되면 나머지가 동일한 버킷에 추가되어서 예측되어서 문제를 해결할 수 있다.
3. 큰 카디널리티 : 버킷을 조정하면 적은 공간에 효율적으로 정보를 저장할 수 있다.(물론 손실이 존재하기는 한다.)
*이 때 해시 나머지가 같아서 발생하는 버킷 충돌 문제는 각 카테고리의 집계, 통계량을 특징으로 넣어서 해소하는 방법도 있다.
디자인 패턴 2 : 임베딩
최대한 정보가 보존되는 방식으로 높은 카디널리티 데이터를 저차원 공간에 매핑하는 작업으로 원핫 인코딩과 다르게 카테고리간의 관계성이 있는 경우에 적합한 방식이다.
텍스트의 경우
1. 토큰화 : 어휘의 각 단어를 색인에 매핑하는 조회 테이블
2. 임베딩 : 토큰을 정해진 차원 형태로 변경
이미지의 경우
1. 임베딩 : 이미지 차원 -> 줄이려는 차원으로 변경
임베딩 차원을 어떻게 정해야할지에 대한 고민이 있는데 딥러닝 계층의 뉴런 수를 선택할 때와 유사하다. 책에서 제공하는 팁은 2개 정도 있는데 이 두개를 범위로 해서, hyperparameter 튜닝을 해봐도 좋을 것 같다. 물론 이 역시 경험에 따른 공식이다.
1. unique한 원소의 네제곱근을 활용한다.
2. embedding차원이 약 0.625배여야한다.
관련 출처 : https://developers.googleblog.com/2017/11/introducing-tensorflow-feature-columns.html
#텐서플로우 허브에서 빅쿼리로 스위블과 같은 사전 학습된 모델 로드
CREATE OR REPLACE MODEL advdata.swivel_text_embed
OPTIONS(model_type = 'tensorflow', model_path = 'gs://BUCKET/swivel/*')
#모델을 사용하여 자연어 텍스트 열을 임베딩 배열로 변환하고 임베딩 조회 테이블을 새테이블로 저장
CREATE OR REPLACE TABLE advdata.comments_embedding as
SELECT
output_0 as comments_embedding,
comments
FROM
ML.PREDICT(MODEL advdata.swivel_text_embed,
(SELECT comments, LOWER(comments) AS sentences
FROM `bigquery-public-data.noaa_preliminary_severe_storms.wind_reports`)
)
디자인 패턴 3: 특징 교차
택시 요금을 예측하는 모델에서 요일 데이터와 시간(Hour) 데이터가 있을 때 요일별 시간을 하나의 Feature로 정의해서 모델에 적용할 수 있다. 혹은 성별, 연령과 같이 교차해서 봤을 때 인사이트가 있는 경우를 말한다.
ML.FEATURE_CROSS(STRUCT(day_of_week, hour_of_week)) as day_X_hour
*듣다보니 이걸 그냥 다 넣으면 딥러닝에서는 알아서 학습하지 않나? 생각이 들었는데 이렇게 교차해서 넣어주면 학습시간 단축의 효과가 있다는 점이 특징이다. 하지만 두 변수간의 관계를 잘 파악하기가 어려운 경우에는 신경망에 더 넣는게 효과적일 수는 있다.
특징 교차의 문제 : 단순히 n개의 특징 A와 m개의 특징 B를 교차하면 A+B였던 특징 갯수가 AB가 되고 sparse vector가 될 수밖에 없다. 그래서 이렇게 한 이후에 임베딩 계층으로 해결하는 접근법도 있다.
디자인 패턴 4: 멀티모달 입력
위에서 특징 교차를 활용했는데, 이 때는 동일한 유형(이미지, 텍스트, 카테고리 등)끼리만 교차를 시켰다면 모델을 만드는데 필요한 구성 요소들을 잘 표현하는 input data 중에서 유형이 다르더라도 이를 합쳐서 처리하는 방식이다.
우선 텍스트, 이미지의 경우에는 CNN -> Flatten하고, 합치려는 데이터를 concat하듯이 붙여주고 학습시키면 된다.
'Machine Learning > 유튜브, 책, 아티클 정리' 카테고리의 다른 글
만들면서 배우는 생성 AI 13장 - 멀티모달 모델 (1) | 2024.01.03 |
---|---|
만들면서 배우는 생성 AI 12장 - 월드 모델 (1) | 2023.12.15 |
만들면서 배우는 생성 AI 11장 - 음악생성 (1) | 2023.12.15 |
만들면서 배우는 생성AI 10장 : 고급 GAN (0) | 2023.12.14 |
만들면서 배우는 생성AI 9장 : 트랜스포머 모델 (0) | 2023.12.12 |