일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- digital geography
- 파이썬
- pandas
- digitalgeography
- 도시계획
- 서울
- QGIS
- 웹크롤링
- Python
- SQL
- postgres
- 그래프색상
- spacesyntax
- connectivity
- graphtheory
- 핫플레이스
- multinomiallogitregression
- 도시공간분석
- 스마트시티
- platformurbanism
- 서울데이터
- 네이버
- 도시인공지능
- naver
- 베이지안뉴럴네트워크
- 공간데이터
- 도시설계
- 베이지안
- 그래프이론
- 공간분석
- Today
- Total
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- digital geography
- 파이썬
- pandas
- digitalgeography
- 도시계획
- 서울
- QGIS
- 웹크롤링
- Python
- SQL
- postgres
- 그래프색상
- spacesyntax
- connectivity
- graphtheory
- 핫플레이스
- multinomiallogitregression
- 도시공간분석
- 스마트시티
- platformurbanism
- 서울데이터
- 네이버
- 도시인공지능
- naver
- 베이지안뉴럴네트워크
- 공간데이터
- 도시설계
- 베이지안
- 그래프이론
- 공간분석
- Today
- Total
이언배 연구노트
[Bayesian Neural Network] 결과 분포의 분산과 Uncertainty의 관계 본문
때는 바야흐로 엊그제 저녁, 교수님께서 논문을 검토해주시고는
"BNN 결과물의 분포로부터 뽑은 샘플의 분산이 uncertainty 라고 해서 시각화한 건 알겠는데, 그 의미를 명확히 하는 게 좋겠다" 는 말씀을 주셨다.
상황은 이렇다,
북촌의 보행량을 예측하는 BNN을 만들었고, 그 결과물은 '분포'로 나온다.
왜냐하면 도시에서 '확실'한 건 없으니까, 불확실성을 포함한 결과물을 낼 수 있는 머신러닝 모델을 만드는 건 도움이 될 거라고 생각했기 때문.
BNN 은 결과물을 확률에 기반한 분포로 주기 때문에, 분포를 알기 위한 샘플의 평균으로 주된 값을 구하고, 그 분포로 결과물의 '불확실성' 을 얻는다.
여기까지가 BNN 을 쓰게 되는 의미있는 사실인데,
세상에마상에나, 보행량은 0~1200이 넘는 수준으로 다양하게 나타나는데
사람이 0명 지나다닌다고 추정하건, 1200명 지나다닌다고 추정하건
결과 분포의 분산은 오직 5~9 사이에서 왔다갔다 한다는 거다.
"이 길에는 5명 정도 다니긴 하는데 뭐 65% 정도 확률로 0명에서 10명 사이도 되겠네요. 그 범위를 넘어가는 경우는 35% 정도? 아무튼 드물어요." 라는 얘기를 하고 싶은건데,
이대로라면
"이 길에는 1200명 정도 다니긴 하는데 뭐 65% 정도 확률로 1195명에서 1205명 사이도 되겠네요. 그 범위를 넘어가는 경우는 35% 정도? 아무튼 드물어요."
라는 결론이 같이 나와버린 셈이다.
처음에는 "도시 데이터로 이동량을 추정하는 거니까 머신러닝 모델이 의도한대로 안돌아갈 수도 있지" 정도로 여기고
논문에는 "아~ 원래 분산으로 불확실성을 수치화하려고 했는데 뭐가 잘 안되네요~~ 다음에 더 잘해볼게요~" 로 썼는데...
문제가 생겼다.
내 잘못이었다.
class BNN(nn.Module):
def __init__(self, input_dim = 20, hidden_dim = 20, output_dim = 1, prior_scale = 100.):
super(BNN, self).__init__()
self.activation = nn.ReLU()
# First layer
self.layer1 = PyroModule[nn.Linear](input_dim, hidden_dim)
self.layer1.weight1 = PyroSample(dist.Normal(0., prior_scale).expand([hidden_dim, input_dim]).to_event(2))
self.layer1.bias1 = PyroSample(dist.Normal(0., prior_scale).expand([hidden_dim]).to_event(1))
# Second layer
self.layer2 = PyroModule[nn.Linear](hidden_dim, 10)
self.layer2.weight2 = PyroSample(dist.Normal(0., prior_scale).expand([10, hidden_dim]).to_event(2))
self.layer2.bias2 = PyroSample(dist.Normal(0., prior_scale).expand([10]).to_event(1))
# Third layer
self.layer3 = PyroModule[nn.Linear](10, output_dim)
self.layer3.weight3 = PyroSample(dist.Normal(0., prior_scale).expand([output_dim, 10]).to_event(2))
self.layer3.bias3 = PyroSample(dist.Normal(0., prior_scale).expand([output_dim]).to_event(1))
def forward(self, x, y = None):
x = self.activation(self.layer1(x))
x = self.activation(self.layer2(x))
mu = self.activation(self.layer3(x)).squeeze(-1)
sigma = pyro.sample("sigma", dist.Gamma(7.5, 1.)) #####################여기에요 여기!!!!
with pyro.plate("data", size = mu.shape[0]):
pyro.sample("coefs", dist.Normal(mu, sigma), obs = y)
중간에 sigma 를 dist.Gamma(7.5,1.0)으로 작성해두었다...
아 그러니까 애당초에 내가 분산을 7.5 언저리에서 나오도록 코드를 짜놓고는
"왜 항상 7 쯤에서 나올까요~~ 신기하네요~~ 잘 모르겠슴다! 헤헿" 했다...
분노가 치밀어 오른다...
GPT said
sigma 의 weight 도 학습하는 모델을 새로 짜줬다.
class BNN(nn.Module):
def __init__(self, input_dim=20, hidden_dim=20, output_dim=1, prior_scale=100.):
super(BNN, self).__init__()
self.activation = nn.ReLU()
# First layer
self.layer1 = PyroModule[nn.Linear](input_dim, hidden_dim)
self.layer1.weight1 = PyroSample(dist.Normal(0., prior_scale).expand([hidden_dim, input_dim]).to_event(2))
self.layer1.bias1 = PyroSample(dist.Normal(0., prior_scale).expand([hidden_dim]).to_event(1))
# Second layer
self.layer2 = PyroModule[nn.Linear](hidden_dim, 10)
self.layer2.weight2 = PyroSample(dist.Normal(0., prior_scale).expand([10, hidden_dim]).to_event(2))
self.layer2.bias2 = PyroSample(dist.Normal(0., prior_scale).expand([10]).to_event(1))
# Third layer for mean (mu)
self.layer3_mu = PyroModule[nn.Linear](10, output_dim)
self.layer3_mu.weight3 = PyroSample(dist.Normal(0., prior_scale).expand([output_dim, 10]).to_event(2))
self.layer3_mu.bias3 = PyroSample(dist.Normal(0., prior_scale).expand([output_dim]).to_event(1))
# Third layer for standard deviation (sigma)
###############################################sigma 를 위한 레이어를 하나 더
self.layer3_sigma = PyroModule[nn.Linear](10, output_dim)
self.layer3_sigma.weight4 = PyroSample(dist.Normal(0., prior_scale).expand([output_dim, 10]).to_event(2))
self.layer3_sigma.bias4 = PyroSample(dist.Normal(0., prior_scale).expand([output_dim]).to_event(1))
def forward(self, x, y=None):
x = self.activation(self.layer1(x))
x = self.activation(self.layer2(x))
# 평균(mu) 예측
mu = self.layer3_mu(x).squeeze(-1)
# 표준편차(sigma) 예측
sigma = self.layer3_sigma(x).squeeze(-1)
sigma = torch.nn.functional.softplus(sigma) # sigma를 항상 양수로 유지
with pyro.plate("data", size=mu.shape[0]):
pyro.sample("coefs", dist.Normal(mu, sigma), obs=y) ##########sigma 마저도 학습하는 BNN을 구축
return mu, sigma
아 그랬더니 이번에는 변수 명이 겹친다고 에러가 난다...
내 추정으로는 dist.Normal(mu, sigma) 부분에서, mu와 sigma 에 weight 변수의 지정이 겹쳐서 그런 것 같기도 하고,
그렇다고 변수명을 다르게 하니 이번에는 AutoMultivatiatedNormalDist 로 guide 함수를 짜는데 초기 세팅이 안된단다...
그럼 다시 기초로 돌아가서,
내가 논문에서 의도했던 대로 쓰려면, sigma 즉, uncertainty 를 나타내는 distribution 의 분산마저도 학습을 통해 얻어져야 하는 게 맞다.
그게 아니고 더 추정치를 가까이 하고 싶다면, 기존 데이터의 분산을 토대로 gamma distribution 을 적절히 잘 골라주고는 "연구자의 사전지식을 활용해서 보다 좋은 추정치를 얻을 수 있었습니다" 도르로 가는 방향을 찾아봐야겠다.
우선, 통행량의 분산은 어느정도인지 파악해보자.
SELECT time, avg(y_hat), stddev(y_hat) FROM buk_y_hat_rev0 group by time order by time;
시간대별로 통행량의 평균과 분산을 보면
얼추 적게는 4, 많게는 150 언저리까지 분산이 나온다. 아무래도 사람이 많이 다닐 때에는 분산이 더 크겠지. 많이 다니는 도로와 적게 다니는 도로의 차이가 크니까.
그런데 이것은 사실이 아닙니다.
우리가 봐야할 건 북촌 전체 기준의 평균과 분산이 아니고, 도로마다의 보행량 분포다.
"그 시간에 그 도로에는 몇 명 정도의 범위 내에서 사람들이 이동할 것인가?" 를 중심으로 짜야 하니까.
종로 CCTV의 raw_data까지 가야하는 거구나...
SELECT 이름, 라인명, time, avg(count), stddev(count) FROM cctv_counting
WHERE dow = 1 AND month <= 6 AND 라인명 LIKE '사람%'
GROUP BY 이름, 라인명, time
ORDER BY avg DESC;
겨우겨우 CCTV raw data까지 찾아내서 주중, 3~6월, 사람 카운팅만 한 데이터를 찾아내어 평균과 분산을 내보았다.
자하문로는 서촌이니까 그렇다치고,
북촌로의 경우 평균 480명 정도가 보행으로 지나갔고, 분산은 150가량까지 간다.
얼추 평균이 줄어들면 분산도 줄어들고.
그럼 분산의 분포는 어떨까.
이런 모양이다... 그러니까 어차피 0이 제일 많고 그 뒤로는 확률이 매우 드물다는 얘기.
서촌도 합쳐진 데이터긴 하지만, 솔직히 뭐 크게 차이는 없을 것 같다.
그럼 이걸 확률분포로 표현해서 gamma distribution 에 넣으면 되지 않을까?
Distribution: Continuous
statpowers.com
Gamma distribution 을 시각화해주는 Site 다.
Gamma distribution 에 집착하는 이유는 뭐냐고? Normal distribution 과 공액 관계이기 때문.
그게 무슨상관이냐고? 몰라 내가 normal distribution 기반이니까 뭔가 연관이 있겠지.
감마분포를 만들어보자.
솔직히 뭐 생긴거로만 치면 이렇게 0이 훨씬 많은 분포로 하는 게 맞겠지...
하지만 이렇게 해서는 절대 100 넘는 분포는 못 만든다.
왜냐하면 새벽시간대는 당연히 분산이 0에 가까울거고 (애당초 사람이 많이 안다니니 데이터의 불확실성도 낮다),
새벽 시간대가 훨씬 많으니까.
내가 테스트해보고 싶은 건, 넓은 범위의 분산 분포에서는 어떻게 나올것인가가 궁금한거다.
이러면 80~100사이의 분산이 나올 확률이 8%정도 나온다.
그럴듯 한가...?
그럴듯 하다고 가정하고, 다시 한 번 돌려보자...
'Bayesian Analysis' 카테고리의 다른 글
[Bayesian Analysis] bayesian neural network 를 실전에 적용해보기 (0) | 2024.09.11 |
---|---|
[다양한 분포] 적재 적소에 분포 쓰기 (0) | 2024.05.22 |
베이지안 계산 (1) | 2024.05.22 |
계층적 모형 (1) | 2024.05.21 |
베이지안 추론 (0) | 2024.05.21 |