Skip to main content
Summary

로봇은 정답이 아니라 믿음을 가진다

로봇이 복도를 달리고 있다고 상상해 봅시다. 바퀴는 조금씩 미끄러지고, 센서는 가끔 엉뚱한 값을 내며, 주변 환경은 완벽하게 구별되지 않습니다. 사람이라면 "아마 이쯤 온 것 같은데?"라고 말할 상황에서 로봇도 비슷한 생각을 해야 합니다.

다만 로봇은 그 생각을 숫자로 표현합니다.

"나는 2번 위치에 있을 가능성이 10%, 3번 위치에 있을 가능성이 60%, 4번 위치에 있을 가능성이 30%다."

이런 식으로 가능한 위치마다 확률을 붙이면, 로봇은 하나의 위치만 고집하지 않고 여러 가능성을 동시에 품을 수 있습니다. 이것이 위치 추정의 출발점입니다.

이전 장에서 우리는 센서값이 하나의 정확한 숫자로 떨어지지 않는다는 것을 배웠습니다. 같은 거리를 여러 번 측정해도 값은 조금씩 흔들립니다. 평균은 대표값을 알려 주고, 분산과 표준편차는 값이 얼마나 퍼져 있는지 알려 줍니다. 이번 장에서는 한 걸음 더 나아갑니다. 센서값이 흔들린다면, 로봇은 그 흔들리는 정보를 어떻게 자기 위치 판단에 반영할까요?

그 답이 바로 베이즈 추정입니다.

베이즈 추정은 어렵게 들리지만, 로봇의 관점에서는 꽤 자연스럽습니다.

"원래 이렇게 믿고 있었는데, 새 센서값을 보니 생각을 이렇게 고치는 게 좋겠다."

이 한 문장에 베이즈 추정의 핵심이 들어 있습니다.

베이즈 추정의 기본 감각

사전 믿음: 관측하기 전의 생각

베이즈 추정에서 가장 먼저 등장하는 말은 사전 믿음, 또는 사전 확률입니다. 영어로는 prior belief 또는 prior probability라고 합니다. 이름이 조금 딱딱하지만 뜻은 간단합니다.

사전 믿음은 새 센서값을 보기 전에 로봇이 이미 가지고 있던 믿음입니다.

예를 들어 로봇이 1차원 복도 위에 있고, 가능한 위치가 5칸이라고 해 봅시다.

위치:   0    1    2    3    4

처음에는 로봇이 자기 위치를 전혀 모를 수 있습니다. 그러면 모든 위치가 똑같이 가능하다고 생각할 수 있습니다.

믿음: 0.2  0.2  0.2  0.2  0.2

각 위치의 확률을 모두 더하면 1이 됩니다. 이것은 "로봇은 어딘가에는 반드시 있다"는 뜻입니다. 단지 어디에 있는지를 모를 뿐입니다.

반대로 이전에 로봇이 움직인 기록이 있다면 믿음은 한쪽으로 몰려 있을 수 있습니다.

위치:   0    1    2    3    4
믿음: 0.05 0.10 0.25 0.45 0.15

이 경우 로봇은 3번 위치에 있을 가능성이 가장 높다고 믿고 있습니다. 하지만 100% 확신하지는 않습니다. 2번이나 4번일 가능성도 남겨 둡니다.

이 태도가 중요합니다. 로봇이 불확실한 세계에서 살아남으려면 "나는 무조건 여기 있다"라고 우기기보다, "여기일 가능성이 가장 높지만 다른 가능성도 있다"라고 생각하는 편이 안전합니다.

이제 센서가 새로운 관측값을 가져오면, 로봇은 이 사전 믿음을 수정합니다.

관측 가능도: 이 위치라면 이런 센서값이 나올까?

두 번째로 필요한 개념은 관측 가능도입니다. 영어로는 likelihood라고 합니다.

관측 가능도는 다음 질문에 답합니다.

"로봇이 정말 이 위치에 있다면, 지금 본 센서값이 나올 가능성은 얼마나 될까?"

예를 들어 복도에 문이 있는 위치와 벽만 있는 위치가 섞여 있다고 해 봅시다. 로봇에는 앞쪽을 보고 "문인지 아닌지"를 판단하는 센서가 있습니다. 실제 환경은 다음과 같습니다.

위치:   0   1   2   3   4
환경:  벽  문  벽  문  벽

센서가 이번에 "문이 보인다"라고 말했습니다. 그렇다면 로봇은 어디에 있을 가능성이 커질까요? 당연히 문이 있는 1번이나 3번 위치일 가능성이 커집니다.

하지만 센서는 완벽하지 않습니다. 문이 있는 곳에서 문이라고 맞힐 확률이 80%이고, 벽이 있는 곳에서도 실수로 문이라고 말할 확률이 20%라고 합시다.

그러면 "문이 보인다"라는 관측에 대한 가능도는 이렇게 쓸 수 있습니다.

위치:             0    1    2    3    4
환경:             벽   문   벽   문   벽
P(문 관측 | 위치): 0.2  0.8  0.2  0.8  0.2

여기서 P(문 관측 | 위치)는 "해당 위치에 있을 때 문이라고 관측할 확률"이라는 뜻입니다. 세로 막대 |는 "조건"을 뜻합니다. 즉, 오른쪽 조건이 주어졌을 때 왼쪽 사건이 일어날 확률입니다.

중요한 점은 관측 가능도가 곧 위치 확률은 아니라는 것입니다.

P(문 관측 | 위치 1)은 "1번 위치에 있을 때 센서가 문이라고 말할 가능성"입니다. 이것은 P(위치 1 | 문 관측), 즉 "문을 봤을 때 로봇이 1번 위치에 있을 가능성"과 다릅니다.

베이즈 추정은 이 둘을 연결해 줍니다.

사후 믿음: 새 정보를 반영한 믿음

베이즈 추정의 목표는 사후 믿음을 구하는 것입니다. 사후 믿음은 새 관측을 반영한 뒤의 믿음입니다.

흐름은 다음과 같습니다.

  • 사전 믿음: 센서값을 보기 전, 로봇이 각 위치에 대해 가지고 있던 확률

  • 관측 가능도: 각 위치에서 지금 같은 센서값이 나올 가능성

  • 사후 믿음: 사전 믿음과 관측 가능도를 결합한 뒤 새로 계산한 확률

수식으로 쓰면 다음과 같습니다.

사후 믿음 ∝ 사전 믿음 × 관측 가능도

여기서 ∝는 "비례한다"는 뜻입니다. 즉, 우선 각 위치마다 사전 믿음과 관측 가능도를 곱합니다. 그러면 아직 전체 합이 1이 아닐 수 있습니다. 마지막에 전체 합으로 나누어 확률의 합이 1이 되도록 맞춥니다. 이 과정을 정규화라고 합니다.

베이즈 추정의 기본 계산은 정말로 이 정도입니다.

1. 위치마다 기존 믿음을 준비한다.
2. 위치마다 관측 가능도를 계산한다.
3. 둘을 곱한다.
4. 전체 합으로 나누어 확률처럼 만든다.

수식의 모양 때문에 겁먹을 필요는 없습니다. 로봇 입장에서 보면 이런 말입니다.

"원래 가능성이 높던 위치이면서, 지금 센서값도 잘 설명하는 위치라면 더 믿자."

반대로 말하면 다음과 같습니다.

"원래 가능성이 낮거나, 지금 센서값과 잘 맞지 않는 위치라면 덜 믿자."

이제 실제 숫자로 계산해 보겠습니다.

1차원 격자 위치 추정 예제

가능한 위치가 5개인 복도가 있습니다.

위치:   0   1   2   3   4
환경:  벽  문  벽  문  벽

처음에는 로봇이 자기 위치를 전혀 모른다고 하겠습니다. 따라서 사전 믿음은 균등합니다.

prior = [0.2, 0.2, 0.2, 0.2, 0.2]

센서가 "문이 보인다"라고 말했습니다. 문이 있는 위치에서 센서가 문이라고 말할 확률은 0.8, 벽이 있는 위치에서 실수로 문이라고 말할 확률은 0.2라고 하겠습니다.

likelihood = [0.2, 0.8, 0.2, 0.8, 0.2]

이제 위치별로 곱합니다.

unnormalized = prior × likelihood
             = [0.04, 0.16, 0.04, 0.16, 0.04]

이 값들의 합은 0.44입니다.

0.04 + 0.16 + 0.04 + 0.16 + 0.04 = 0.44

확률의 합은 1이 되어야 하므로 모든 값을 0.44로 나눕니다.

posterior = [0.04/0.44, 0.16/0.44, 0.04/0.44, 0.16/0.44, 0.04/0.44]
          ≈ [0.091, 0.364, 0.091, 0.364, 0.091]

관측 전에는 모든 위치가 20%였습니다. 그런데 "문이 보인다"라는 센서값을 반영하자, 문이 있는 1번과 3번 위치의 확률이 약 36.4%로 올라갔습니다. 벽이 있는 0번, 2번, 4번 위치의 확률은 약 9.1%로 내려갔습니다.

하지만 1번과 3번 중 어디인지는 아직 구별할 수 없습니다. 둘 다 문이 있는 위치이기 때문입니다. 베이즈 추정은 마법처럼 답을 만들어 내지 않습니다. 현재 정보로 구별할 수 없는 것은 확률로 남겨 둡니다. 이것이 오히려 강점입니다. 모르는 것을 안다고 착각하지 않기 때문입니다.

Python으로 베이즈 갱신 구현하기

이제 같은 계산을 Python으로 구현해 보겠습니다. NumPy 배열을 사용하면 위치별 곱셈과 정규화를 간단하게 처리할 수 있습니다.

import numpy as np

prior = np.array([0.2, 0.2, 0.2, 0.2, 0.2])
likelihood = np.array([0.2, 0.8, 0.2, 0.8, 0.2])

unnormalized = prior * likelihood
posterior = unnormalized / np.sum(unnormalized)

print('unnormalized:', unnormalized)
print('posterior:', posterior)
print('sum:', np.sum(posterior))

실행하면 대략 다음과 같은 결과가 나옵니다.

unnormalized: [0.04 0.16 0.04 0.16 0.04]
posterior: [0.09090909 0.36363636 0.09090909 0.36363636 0.09090909]
sum: 1.0

여기서 prior * likelihood는 행렬 곱이 아닙니다. 같은 위치끼리 곱하는 원소별 곱셈입니다. 0번 위치의 사전 믿음과 0번 위치의 관측 가능도를 곱하고, 1번 위치의 사전 믿음과 1번 위치의 관측 가능도를 곱하는 식입니다.

마지막 줄에서 확률의 합이 1.0이 되는 것을 확인할 수 있습니다. 정규화가 제대로 된 것입니다.

이 과정을 함수로 만들면 더 편합니다.

import numpy as np

def bayes_update(prior, likelihood):
    unnormalized = prior * likelihood
    total = np.sum(unnormalized)

    if total == 0:
        raise ValueError('정규화할 수 없습니다. 가능도의 합을 확인하세요.')

    posterior = unnormalized / total
    return posterior

prior = np.array([0.2, 0.2, 0.2, 0.2, 0.2])
likelihood = np.array([0.2, 0.8, 0.2, 0.8, 0.2])

posterior = bayes_update(prior, likelihood)
print(posterior)

베이즈 갱신은 이 함수 하나로 요약할 수 있습니다. 물론 실제 로봇에서는 위치가 수천 개일 수도 있고, 센서 모델이 훨씬 복잡할 수도 있습니다. 그래도 핵심 구조는 변하지 않습니다.

기존 믿음에 새 관측의 가능도를 곱하고, 다시 확률로 정리합니다.

그림으로 믿음의 변화 보기

확률은 숫자만 보면 감이 잘 오지 않을 때가 많습니다. 로봇의 믿음이 어떻게 바뀌었는지 막대그래프로 그려 보겠습니다.

import numpy as np
import matplotlib.pyplot as plt

positions = np.arange(5)
prior = np.array([0.2, 0.2, 0.2, 0.2, 0.2])
likelihood = np.array([0.2, 0.8, 0.2, 0.8, 0.2])
posterior = bayes_update(prior, likelihood)

width = 0.25

plt.figure(figsize=(8, 4))
plt.bar(positions - width, prior, width=width, label='prior')
plt.bar(positions, likelihood, width=width, label='likelihood')
plt.bar(positions + width, posterior, width=width, label='posterior')

plt.xticks(positions)
plt.ylim(0, 1.0)
plt.xlabel('position')
plt.ylabel('probability')
plt.title('Bayes update in a 1D grid')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

그래프를 보면 세 종류의 막대가 보입니다. prior는 처음 믿음입니다. 모든 위치에서 높이가 같습니다. likelihood는 센서값이 각 위치와 얼마나 잘 맞는지 나타냅니다. 문이 있는 1번과 3번 위치에서 높습니다. posterior는 두 정보를 결합한 결과입니다.

눈여겨볼 점은 사후 믿음이 가능도와 똑같지 않다는 것입니다. 지금 예제에서는 사전 믿음이 균등했기 때문에 사후 믿음이 가능도와 비슷한 모양이 되었습니다. 하지만 사전 믿음이 한쪽으로 치우쳐 있다면 결과는 달라집니다.

사전 믿음이 다르면 결과도 달라진다

이번에는 로봇이 이미 3번 위치 근처에 있을 것 같다고 믿고 있었다고 해 봅시다.

위치:       0     1     2     3     4
사전 믿음: 0.05  0.10  0.20  0.50  0.15

여기서 다시 센서가 "문이 보인다"라고 말합니다. 관측 가능도는 이전과 같습니다.

가능도:    0.2   0.8   0.2   0.8   0.2

이제 둘을 곱해 보겠습니다.

곱한 값:   0.01  0.08  0.04  0.40  0.03

합은 0.56입니다. 정규화하면 다음과 같습니다.

사후 믿음: 0.018 0.143 0.071 0.714 0.054

이번에는 3번 위치의 확률이 매우 높아졌습니다. 왜 그럴까요?

3번 위치는 원래도 가능성이 높았고, 센서값도 잘 설명합니다. 그러니 사후 믿음에서 강하게 살아남습니다. 1번 위치도 문이 있는 곳이므로 센서값과는 잘 맞지만, 사전 믿음이 낮았기 때문에 3번만큼 올라가지는 못합니다.

Python으로 확인해 봅시다.

prior = np.array([0.05, 0.10, 0.20, 0.50, 0.15])
likelihood = np.array([0.2, 0.8, 0.2, 0.8, 0.2])

posterior = bayes_update(prior, likelihood)
print(posterior)

결과는 다음과 비슷합니다.

[0.01785714 0.14285714 0.07142857 0.71428571 0.05357143]

이 예제는 베이즈 추정의 성격을 잘 보여 줍니다. 베이즈 추정은 새 센서값만 믿지 않습니다. 그렇다고 기존 생각만 고집하지도 않습니다. 기존 믿음과 새 정보를 함께 봅니다.

로봇에게 이것은 매우 현실적인 태도입니다. 센서가 한 번 "문!"이라고 외쳤다고 해서 로봇이 갑자기 전혀 엉뚱한 곳으로 순간이동했다고 판단하면 안 됩니다. 반대로 기존 위치 추정만 믿고 센서 관측을 무시해도 안 됩니다. 베이즈 추정은 둘 사이에서 균형을 잡습니다.

센서가 두 번 말하면 믿음은 더 날카로워진다

로봇은 한 번만 관측하고 끝나지 않습니다. 움직이면서 계속 센서값을 받습니다. 베이즈 갱신은 반복할 수 있습니다. 새 관측을 반영해 만든 사후 믿음은 다음 순간의 사전 믿음이 됩니다.

첫 번째 관측 전 사전 믿음 → 첫 번째 사후 믿음
첫 번째 사후 믿음 → 두 번째 관측 전 사전 믿음
두 번째 관측 반영 → 두 번째 사후 믿음

같은 위치에서 센서가 다시 "문이 보인다"라고 말했다고 해 봅시다. 물론 실제 로봇이라면 그 사이 움직였는지도 고려해야 하지만, 여기서는 베이즈 갱신의 감각을 보기 위해 로봇이 움직이지 않았다고 가정하겠습니다.

prior = np.array([0.2, 0.2, 0.2, 0.2, 0.2])
likelihood_door = np.array([0.2, 0.8, 0.2, 0.8, 0.2])

belief = prior

for i in range(3):
    belief = bayes_update(belief, likelihood_door)
    print(f'update {i + 1}:', belief)

결과는 대략 다음과 같습니다.

update 1: [0.09090909 0.36363636 0.09090909 0.36363636 0.09090909]
update 2: [0.02439024 0.39024390 0.02439024 0.39024390 0.02439024]
update 3: [0.00621118 0.39751553 0.00621118 0.39751553 0.00621118]

벽 위치의 확률은 점점 줄어듭니다. 문 위치의 확률은 상대적으로 커집니다. 하지만 1번과 3번은 여전히 구별되지 않습니다. 두 위치 모두 센서 관측을 똑같이 잘 설명하기 때문입니다.

이럴 때 필요한 것은 다른 정보입니다. 로봇이 이동했다는 정보, 다른 종류의 센서값, 또는 주변 지형의 더 자세한 특징이 들어오면 두 가능성 중 하나가 더 강해질 수 있습니다.

베이즈 추정은 정보를 억지로 만들어 내지 않습니다. 대신 들어온 정보를 차곡차곡 반영합니다. 그래서 여러 번의 관측과 움직임이 쌓이면 처음에는 흐릿했던 위치 믿음이 점점 선명해집니다.

움직임도 믿음을 바꾼다

지금까지는 센서 관측만 보았습니다. 하지만 로봇 위치 추정에는 또 하나의 중요한 정보가 있습니다. 바로 로봇의 움직임입니다.

로봇이 오른쪽으로 한 칸 이동하라는 명령을 받았다고 해 봅시다. 그러면 위치 믿음도 오른쪽으로 이동해야 합니다. 예를 들어 로봇이 1번 위치에 있을 가능성이 컸다면, 이동 후에는 2번 위치에 있을 가능성이 커져야 합니다.

하지만 움직임 역시 완벽하지 않습니다. 바퀴가 미끄러지면 한 칸보다 덜 갈 수 있고, 바닥 상태가 좋으면 조금 더 갈 수도 있습니다. 따라서 움직임으로 믿음을 업데이트할 때도 확률이 필요합니다.

이번 장에서는 관측 갱신에 집중하지만, 전체 위치 추정 흐름은 보통 두 단계로 이루어집니다.

  • 예측: 로봇의 움직임 명령과 운동 모델을 이용해 믿음을 앞으로 이동시킨다.

  • 보정: 센서 관측을 이용해 예측된 믿음을 다시 고친다.

  • 반복: 시간이 흐를 때마다 예측과 보정을 반복한다.

이 구조는 다음 장에서 만날 칼만 필터의 핵심이기도 합니다. 칼만 필터도 기본적으로 "움직임으로 예측하고, 센서로 보정한다"는 흐름을 따릅니다. 다만 확률분포를 가우시안 형태로 다루고, 평균과 분산을 더 체계적으로 계산합니다.

관측 가능도를 어떻게 만들까?

앞의 예제에서는 가능도를 손으로 정했습니다.

문이 있는 위치에서 문이라고 말할 확률: 0.8
벽이 있는 위치에서 문이라고 말할 확률: 0.2

그렇다면 실제 로봇에서는 이 숫자를 어떻게 정할까요? 이것을 센서 모델이라고 부릅니다. 센서 모델은 "특정 상태에서 센서가 어떤 값을 낼 가능성이 큰가"를 설명합니다.

거리 센서를 예로 들어 봅시다. 로봇이 벽에서 실제로 2.0m 떨어져 있는데 거리 센서가 2.1m를 측정했다면 꽤 그럴듯합니다. 하지만 8.0m를 측정했다면 이상합니다. 그러면 2.1m에 대한 가능도는 높고, 8.0m에 대한 가능도는 낮아야 합니다.

이전 장에서 배운 가우시안 분포를 사용하면 이런 가능도를 만들 수 있습니다. 예를 들어 실제 예상 거리와 센서 측정값의 차이가 작을수록 가능도를 크게 주고, 차이가 클수록 가능도를 작게 줄 수 있습니다.

아주 단순화하면 이런 식입니다.

import numpy as np

def gaussian_likelihood(measured, expected, sigma):
    error = measured - expected
    return np.exp(-0.5 * (error / sigma) ** 2)

여기서 measured는 실제 센서가 읽은 값이고, expected는 어떤 위치에 있다고 가정했을 때 예상되는 센서값입니다. sigma는 센서 노이즈의 크기입니다. sigma가 작으면 센서를 꽤 믿는다는 뜻이고, sigma가 크면 센서값이 많이 흔들릴 수 있다고 보는 것입니다.

정규분포의 정확한 상수까지 포함하지 않아도, 베이즈 갱신에서는 위치별 가능도의 상대적인 크기가 중요할 때가 많습니다. 어차피 마지막에 정규화하기 때문입니다.

간단한 거리 센서 예제를 보겠습니다. 1차원 위치 0부터 4까지 있고, 오른쪽 끝 4번 위치에 벽이 있다고 합시다. 각 위치에서 오른쪽 벽까지의 예상 거리는 다음과 같습니다.

위치:       0   1   2   3   4
예상 거리: 4   3   2   1   0

센서가 오른쪽 벽까지의 거리를 1.2라고 측정했습니다. 그렇다면 3번 위치가 가장 그럴듯합니다. 3번 위치의 예상 거리는 1이기 때문입니다.

positions = np.arange(5)
expected_distance = 4 - positions
measured_distance = 1.2
sigma = 0.5

likelihood = gaussian_likelihood(
    measured=measured_distance,
    expected=expected_distance,
    sigma=sigma
)

prior = np.ones(5) / 5
posterior = bayes_update(prior, likelihood)

print('expected distance:', expected_distance)
print('likelihood:', likelihood)
print('posterior:', posterior)

이 예제에서는 위치 3 주변의 가능도가 크게 나옵니다. 센서가 "벽까지 약 1.2m"라고 말했기 때문에, 오른쪽 벽에서 약 1m 떨어진 위치가 가장 자연스럽습니다.

이제 센서값을 단순히 "문이다/아니다" 같은 범주로만 보지 않고, 연속적인 숫자로도 베이즈 갱신에 사용할 수 있다는 감이 생깁니다.

베이즈 추정에서 자주 하는 착각

베이즈 추정을 처음 배울 때 자주 헷갈리는 지점이 있습니다. 특히 P(관측 | 위치)와 P(위치 | 관측)을 구분하는 것이 중요합니다.

P(관측 | 위치)는 가능도입니다. 로봇이 특정 위치에 있다고 가정했을 때, 지금 같은 센서값이 나올 확률입니다.

P(위치 | 관측)은 우리가 정말 알고 싶은 값입니다. 지금 센서값을 봤을 때, 로봇이 특정 위치에 있을 확률입니다.

두 값은 같은 것이 아닙니다. 예를 들어 어떤 위치에서 문 센서가 잘 작동한다고 해서, 문을 봤을 때 반드시 그 위치에 있다는 뜻은 아닙니다. 비슷한 문이 여러 곳에 있을 수도 있기 때문입니다.

베이즈 추정은 이 차이를 사전 믿음으로 조정합니다.

P(위치 | 관측) ∝ P(위치) × P(관측 | 위치)

여기서 P(위치)는 사전 믿음입니다. 즉, 관측만 보고 판단하지 않고, 관측 전부터 그 위치가 얼마나 가능했는지도 함께 고려합니다.

또 하나의 착각은 가장 확률이 높은 위치 하나만 중요하다고 생각하는 것입니다. 실제로 로봇 제어에서는 가장 가능성 높은 위치를 대표 위치로 사용할 때도 많습니다. 하지만 분포 전체가 중요할 때가 많습니다.

예를 들어 가장 높은 확률이 0.35이고 나머지 위치에도 확률이 넓게 퍼져 있다면, 로봇은 아직 자기 위치를 꽤 불확실하게 알고 있는 것입니다. 반대로 한 위치의 확률이 0.95라면 훨씬 자신 있게 행동할 수 있습니다.

로봇에게 확률분포는 단순한 계산 결과가 아니라 자기 확신의 모양입니다.

작은 로봇 위치 추정 시뮬레이션

마지막으로 작은 예제를 하나 더 만들어 보겠습니다. 로봇은 1차원 복도에 있고, 복도에는 문과 벽이 섞여 있습니다.

위치:   0   1   2   3   4   5   6
환경:  벽  문  벽  벽  문  벽  문

로봇은 처음에 어디 있는지 모릅니다. 센서는 현재 위치가 문인지 벽인지 알려 주지만 완벽하지 않습니다. 센서가 맞힐 확률은 0.8이라고 하겠습니다.

import numpy as np
import matplotlib.pyplot as plt

def bayes_update(prior, likelihood):
    unnormalized = prior * likelihood
    return unnormalized / np.sum(unnormalized)

def make_likelihood(world, observation, p_correct=0.8):
    likelihood = np.zeros(len(world))

    for i, cell in enumerate(world):
        if cell == observation:
            likelihood[i] = p_correct
        else:
            likelihood[i] = 1.0 - p_correct

    return likelihood

world = np.array(['wall', 'door', 'wall', 'wall', 'door', 'wall', 'door'])
belief = np.ones(len(world)) / len(world)

observations = ['door', 'wall', 'door']

history = [belief.copy()]

for obs in observations:
    likelihood = make_likelihood(world, obs, p_correct=0.8)
    belief = bayes_update(belief, likelihood)
    history.append(belief.copy())

for step, b in enumerate(history):
    print(f'step {step}:', np.round(b, 3))

이 코드는 로봇이 같은 자리에서 세 번 관측했다고 가정합니다. 실제 이동은 아직 넣지 않았습니다. 여기서는 관측이 믿음을 어떻게 바꾸는지만 보려는 목적입니다.

출력은 관측 순서에 따라 달라집니다. 예를 들어 처음에 door를 관측하면 문 위치의 확률이 올라갑니다. 다음에 wall을 관측하면 벽 위치의 확률이 다시 올라갑니다. 다시 door를 관측하면 문 위치 쪽이 강해집니다.

그림으로도 확인해 보겠습니다.

positions = np.arange(len(world))

plt.figure(figsize=(9, 5))

for step, b in enumerate(history):
    plt.plot(positions, b, marker='o', label=f'step {step}')

plt.xticks(positions)
plt.ylim(0, 0.5)
plt.xlabel('position')
plt.ylabel('belief')
plt.title('Belief update with repeated observations')
plt.grid(True, alpha=0.3)
plt.legend()
plt.show()

선을 따라가 보면 로봇의 믿음이 관측에 따라 움직이는 것을 볼 수 있습니다. 확률이 높은 위치는 올라가고, 관측과 잘 맞지 않는 위치는 내려갑니다. 하지만 완전히 0이 되지는 않습니다. 센서가 틀릴 수 있기 때문입니다.

이 작은 예제는 앞으로 배울 더 큰 위치 추정 알고리즘의 씨앗입니다. 지도 위 여러 위치에 확률을 나누어 두고, 움직임과 센서 관측이 들어올 때마다 확률분포를 갱신하는 방식은 로봇 위치 추정에서 매우 중요한 생각입니다.

믿음을 업데이트하는 로봇의 태도

베이즈 추정은 로봇에게 하나의 태도를 가르칩니다.

"나는 지금까지의 정보로 이렇게 믿고 있다. 하지만 새 정보가 들어오면 믿음을 고칠 준비가 되어 있다."

이 태도는 불확실한 세계에서 매우 강력합니다. 센서는 틀릴 수 있고, 바퀴는 미끄러질 수 있으며, 환경은 비슷한 모양을 반복할 수 있습니다. 그럴 때 로봇은 하나의 답에 매달리기보다 여러 가능성을 확률로 관리해야 합니다.

이번 장에서 배운 핵심은 세 가지입니다.

  • 사전 믿음은 관측 전 로봇이 가지고 있던 위치 가능성이다.

  • 관측 가능도는 특정 위치에서 지금 같은 센서값이 나올 가능성이다.

  • 사후 믿음은 사전 믿음과 관측 가능도를 곱하고 정규화한 결과다.

이제 우리는 로봇이 센서값을 단순히 읽는 것이 아니라, 기존 믿음과 결합해 자기 위치에 대한 더 나은 믿음을 만든다는 것을 알게 되었습니다.

다음 장에서는 이 감각을 조금 더 실용적인 형태로 바꿉니다. 로봇의 위치를 하나의 확률분포로 보고, 움직임으로 예측하고 센서값으로 보정하는 칼만 필터의 기본 아이디어를 살펴보겠습니다. 칼만 필터는 이름은 무섭지만, 그 속에는 이미 우리가 배운 베이즈 추정의 흐름이 들어 있습니다.

책 목록

로봇을 위한 수학과 Python: 좌표에서 시뮬레이터까지

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기