11차시의 기계는 아는 것에서 출발해 굴러갔습니다. 오늘은 방향을 뒤집습니다 —
결론을 먼저 정해 놓고 거꾸로 캐물으면, 그 캐묻기의 자취가 그대로 “왜”에 대한 답이 됩니다.
그리고 이 단원의 두 기둥인 탐색과 추론을 한 프로그램으로 잇습니다.
성취기준 12인기01-0512인기01-0112인기01-04
후향 추론설명 트리설명 가능한 AI지식 획득의 병목추론 × 탐색단원 정리
🎯 학습 목표
전향 추론과 후향 추론이 어디서 출발해 어디로 가는지 구별하고, 후향 추론의 재귀가 그대로 설명 트리가 되는 것을 코드에서 짚을 수 있다.
실패한 설명 트리에서 어느 하위 목표가 막혔는지를 읽어 내고, 사실 하나를 더해 실패를 성공으로 뒤집을 수 있다.
규칙 추론이 판정한 위험을 A*의 비용으로 넣어, 같은 걸음 수로 위험 칸을 0으로 만드는 프로그램을 실행하고 결과를 숫자로 설명할 수 있다.
🤔
여는 장면 — “왜죠?”라고 물었을 때
은행 창구입니다. 대출 신청이 거절되었습니다. 담당자가 화면을 들여다보며 말합니다.
“시스템이 그렇게 나왔습니다.” 여러분이 “왜죠?”라고 물으면, 무엇이 돌아와야 할까요.
가능한 답은 크게 셋입니다.
“안 됩니다.” — 판정만 있습니다. 다음에 무엇을 해야 할지 알 수 없습니다.
“점수가 612점인데 기준이 650점입니다.” — 숫자가 생겼습니다.
그런데 왜 612점인지는 여전히 없습니다. 숫자는 판정을 되풀이했을 뿐입니다.
“최근 6개월에 연체가 두 번 있었습니다. 연체가 있으면 등급이 한 단계 내려가고,
내려간 등급에서는 이 상품의 기준을 넘지 못합니다.” —
이제 사슬이 있습니다. 어디를 손보면 결과가 달라지는지도 함께 알려 줍니다.
셋째 답만이 설명입니다. 앞의 둘은 결과의 다른 표현일 뿐이에요.
셋째 답에는 규칙과 사실이 어떤 순서로 맞물렸는지가 들어 있고,
그래서 사람이 반박할 수도 있습니다 — “두 번째 연체는 은행 전산 오류였습니다”처럼요.
요즘은 자동으로 내려진 판정에 대해 이런 설명을 요구할 수 있어야 한다는 목소리가
법과 제도로도 번지고 있습니다.
11차시에서 우리가 만든 기계도 사실 사슬을 만들었습니다.
관찰한 사실 깃털이 있다·헤엄친다에서 출발해
[1] 깃털이 있다 → 새다, [2] 새다 AND 헤엄친다 → 펭귄이다 순서로 두 번 발동하고 멈췄지요.
새로 알아낸 것은 새다·펭귄이다 두 개였습니다.
그 로그는 분명히 사슬이었습니다. 다만 그것은 “굴려 봤더니 이런 것들이 나왔다”의 기록이지,
“이 결론이 왜 나왔는가”에 대한 답으로 지어진 것은 아니었습니다.
💭 오늘의 물음
알고 싶은 결론을 먼저 정해 놓고
거꾸로 캐물으면, 그 캐묻기의 자취가 그대로 “왜”에 대한 답이 되는가?
오늘 우리는 방향을 뒤집는 엔진을 하나 더 만들고, 그 엔진이 실패했을 때
무엇을 말해 주는지를 봅니다. 그리고 마지막 15분에는 이 단원의 두 기둥 —
1~9차시의 탐색과 10~12차시의 추론 — 을
한 프로그램 안에서 잇습니다.
1
방향을 뒤집는다 — 후향 추론
11차시의 전향 추론은 사실에서 출발했습니다.
조건이 갖춰진 규칙을 찾아 결론을 사실 창고에 넣고, 그 새 사실이 또 다른 규칙의 조건이 되고,
더 나올 것이 없어지는 고정점에서 멈췄지요.
오늘의 후향 추론은 정반대입니다. 목표에서 출발합니다.
“이 동물이 펭귄인가?”를 밝히려면 무엇이 필요한가를 묻고, 그 필요한 것을 또 새로운 목표로 삼아
한 단 더 내려갑니다. 바닥에 닿으면 그것은 관찰한 사실이거나, 아무도 알려 주지 않은 것입니다.
후향 추론의 알고리즘은 세 줄이면 끝납니다. 목표 하나를 받아서 이렇게 합니다.
목표가 이미 아는 사실이면 밝혀진 것이다. 여기서 끝낸다.
아니면 그 목표를 결론으로 갖는 규칙을 찾는다. 그 규칙의 조건 하나하나를
새 목표로 삼아 같은 일을 되풀이한다. 조건이 전부 밝혀지면 목표도 밝혀진 것이다.
그런 규칙이 하나도 없거나, 있어도 조건을 못 밝히면 밝힐 방법이 없다.
둘째 줄의 “같은 일을 되풀이한다”가 바로 재귀 호출입니다.
prove(목표) 안에서 prove(조건)을 부르는 거예요.
그리고 재귀가 한 단 내려갈 때마다 들여쓰기를 한 칸 늘려 찍으면,
화면에 그려지는 들여쓰기가 곧 물음의 사슬이 됩니다.
오늘 코드의 pad = " " * depth 한 줄이 그 일을 합니다.
📌 어느 쪽이 유리한가는 상황이 정한다
전향은 아는 것이 많고 결론이 무엇일지 모를 때 좋습니다 —
센서 값이 쏟아지는 공장 설비 감시처럼요. 후향은 확인하고 싶은 결론이 정해져 있을 때 좋습니다 —
“이 환자가 폐렴인가”, “이 신청자가 승인 대상인가”처럼요.
규칙이 여섯 개일 때는 차이가 안 보입니다. 그러나 규칙이 만 개고 아는 사실이 십만 개라면,
전향은 굴릴 수 있는 것을 전부 굴리고, 후향은 물은 것 하나만 캡니다.
여기서 놓치지 말아야 할 것이 하나 있습니다. 두 엔진은 같은 지식 베이스를 씁니다.
10차시에서 적은 규칙 여섯 개는 오늘 한 글자도 바뀌지 않습니다.
11차시 마지막에 확인했던 지식과 엔진의 분리가 여기서 한 번 더 증명되는 셈이에요.
같은 지식을 두 방향으로 읽을 수 있다는 것 — 이것이 지식을 데이터로 적어 둔 값어치입니다.
2
밟은 사슬이 그대로 설명이 된다
아는 사실이 깃털이 있다·헤엄친다 둘일 때
prove("펭귄이다")를 부르면 화면에 이렇게 찍힙니다.
기호는 셋입니다 — ? 는 “이 규칙으로 밝혀 보자”,
O 는 “밝혀졌다”,
X 는 “밝힐 방법이 없다”입니다.
? 펭귄이다 <- 규칙 'IF 새다 AND 헤엄친다' 로 밝혀 보자? 새다 <- 규칙 'IF 깃털이 있다' 로 밝혀 보자O 깃털이 있다 (이미 아는 사실)O 새다 (규칙으로 밝혀짐)O 헤엄친다 (이미 아는 사실)O 펭귄이다 (규칙으로 밝혀짐) 판정: True
여섯 줄이고, 가장 깊이 들어간 자리가 2단입니다.
이 여섯 줄을 위에서 아래로 소리 내어 읽어 보세요.
📖 트리를 말로 옮기면
“펭귄이라고 본 까닭은, 새이면서 헤엄치기 때문입니다.
새라고 본 까닭은 깃털이 있기 때문이고, 깃털이 있다는 것은 관찰한 사실입니다.
헤엄친다는 것도 관찰한 사실입니다.”
이것이 설명입니다. 사람이 따로 문장을 지어 붙인 것이 아니라,
프로그램이 실제로 밟은 경로를 그대로 읽은 것이에요.
그래서 세 가지 성질을 자동으로 갖습니다.
빠뜨린 근거가 없다. 규칙의 조건은 전부 밝혀져야 O가 되므로,
트리에 안 나온 근거로 결론이 났을 수는 없습니다.
어디가 바닥인지 안다. 잎사귀는 언제나 “이미 아는 사실”입니다.
설명이 무한히 이어지지 않고 관찰에서 멈춘다는 뜻이에요.
되짚어 흔들 수 있다. “깃털이 있다”가 사실이 아니었다면
어느 가지가 무너지는지 트리를 보면 바로 압니다. 설명이 검증 가능해집니다.
1970년대의 감염병 진단 시스템 MYCIN은 의사가 WHY나 HOW를 입력하면
바로 이 사슬을 보여 주었습니다. 설명 가능한 인공지능(XAI)이라는 말이 생기기
수십 년 전 일이에요. 규칙 기반은 처음부터 설명 가능했습니다.
설명을 잃어버린 것은 오히려 뒤에 온 방법들입니다 — 2단원에서 만날 기계학습 모형은
정확도가 훨씬 높지만 “왜 그렇게 판단했는가”를 이렇게 여섯 줄로 내놓지 못합니다.
실패한 트리가 더 값지다
같은 사실로 이번에는 prove("돌고래다")를 불러 봅시다.
결과는 다섯 줄이고 판정은 False입니다.
? 돌고래다 <- 규칙 'IF 포유류다 AND 헤엄친다' 로 밝혀 보자? 포유류다 <- 규칙 'IF 젖을 먹인다' 로 밝혀 보자X 젖을 먹인다 (밝힐 방법이 없다)X 포유류다 (밝힐 방법이 없다)X 돌고래다 (밝힐 방법이 없다) 판정: False
여기서 눈여겨볼 것이 둘 있습니다.
첫째, 막힌 자리가 정확히 한 곳으로 지목됩니다.
세 줄이 모두 X지만 진짜 원인은 맨 안쪽의 젖을 먹인다 하나예요.
나머지 둘은 그것 때문에 딸려 무너진 것입니다. 기계가 하는 말을 우리말로 옮기면
“안 됩니다”가 아니라 “젖을 먹이는지를 알려 주시면 됩니다”가 됩니다.
둘째, 두 번째 조건은 아예 물어보지도 않았습니다.돌고래다의 규칙은 IF 포유류다 AND 헤엄친다인데, 트리에 헤엄친다가 없지요.
앞의 조건이 무너지는 순간 뒤는 확인할 필요가 없기 때문입니다.
코드의 all(prove(c) for c in conds)가 첫 실패에서 곧바로 멈추기 때문에 생기는 일이에요.
낭비를 줄이는 장치이지만, 설명을 읽을 때는 “안 물어본 것”과 “물었는데 없는 것”을 구별해야 합니다.
그리고 막힌 그 사실 하나만 알려 주면 실패가 성공으로 뒤집힙니다.
아는 사실에 젖을 먹인다를 더하고 같은 물음을 던지면
맨 안쪽 줄이 X에서
O로 바뀌고, 그 위의 두 줄이 차례로 살아나
판정이 True가 됩니다. 여는 장면의 대출 이야기로 돌아가 보면 이것이 곧
“연체 기록이 정정되면 승인됩니다”에 해당해요.
좋은 설명은 왜 안 되는지를 넘어 무엇을 바꾸면 되는지까지 말해 줍니다.
바다를 무리 지어 헤엄치는 아델리펭귄 — 규칙 IF 새다 AND 헤엄친다로 여섯 줄 만에 밝혀지는 쪽.
깃털이라는 관찰 하나가 사슬의 첫 단추가 된다.
출처: Jason Auch, Wikimedia Commons (CC BY 2.0)물 위로 등을 내민 병코돌고래 — 같은 관찰로는 밝힐 수 없는 쪽. 사진만 봐서는 새끼에게 젖을 먹이는지 알 수 없듯,
기계가 막힌 자리로 지목한 것도 젖을 먹인다 하나였다.
출처: Nilfanion, Wikimedia Commons (CC BY-SA 3.0)
🌳 설명 트리 — 거꾸로 캐묻기INTERACTIVE
밝힐 목표를 고르고, 기계에게 알려 줄 사실을 켜고 끕니다.
그 자리에서 후향 추론이 돌아 물음의 사슬이 위에서 아래로 한 줄씩 펼쳐집니다.
초록은 밝혀진 가지, 빨강은 막힌 가지, 노랑은 돌고 있어서 접은 가지입니다.
줄을 눌러 보세요 — 그 줄이 왜 그렇게 되었는지와, 막힌 줄이라면
무엇을 알려 주면 되는지가 아래에 뜹니다.
? 이 규칙으로 캐본다O 밝혀졌다X 밝힐 방법이 없다~ 돌고 있어 접었다
6물음의 줄 수
2가장 깊은 단
2캐물은 규칙 수
0막힌 줄 수(X)
O판정
[안내] 목표와 사실을 바꾸면 그 자리에서 다시 캐묻습니다.
💡 해 보기 — 공책에 표를 채웁니다
세 가지를 돌려 보고 (줄 수, 막힌 목표, 판정)을 적으세요.
확인 문제 2번이 이 표를 묻습니다.
사실 = 깃털·헤엄, 목표 = 펭귄이다 → ( ___ 줄, 막힌 곳 ___ , 판정 ___ )
사실 = 깃털·헤엄, 목표 = 돌고래다 → ( ___ 줄, 막힌 곳 ___ , 판정 ___ )
여기에 젖을 먹인다를 켜고 다시 돌고래다 → ( ___ 줄, 막힌 곳 ___ , 판정 ___ )
그다음 반례를 만들어 보세요.
① 사실을 두 개나 켰는데도 여섯 목표가 전부 X가 되는 조합을 찾으세요.
찾았다면 그 두 사실의 공통점이 무엇인지 한 줄로 적어 보세요.
② ⚠️ 도는 규칙 두 개 넣기를 켜고 사실을 헤엄친다 하나만 남긴 뒤
펭귄이다를 캐 보세요. 노란 ~ 줄이 어디에 생기고, 그 줄이 없으면
어떤 일이 벌어질지 말해 보세요.
3
그런데 왜 세상은 규칙 기반에서 떠났는가 — 다섯 개의 벽
지금까지 셋을 얻었습니다. 규칙으로 지식을 적을 수 있고(10차시), 그 규칙이 스스로 연쇄해
고정점까지 간다는 것(11차시), 그리고 거꾸로 캐물으면 설명이 따라 나온다는 것(오늘).
깔끔합니다. 그런데 1980년대에 크게 번졌던 이 방식은 1990년대에 대부분 물러났습니다.
왜 그랬는지를 알아야 2단원이 왜 시작되는지가 보입니다.
컴퓨터 역사 박물관에 나란히 선 두 리스프 머신 — 왼쪽은 10차시에서 본 것과 같은 Symbolics 3620,
오른쪽은 LMI사의 Lambda다. 리스프로 짠 인공지능 프로그램(전문가 시스템도 여기에 든다)을 빨리 돌리려고 만든 전용 컴퓨터로,
여러 회사가 만들어 팔 만큼 기대가 컸다. 그러나 1980년대 후반 규칙 기반에 대한 기대가 식고
값싼 범용 컴퓨터가 성능을 따라잡자 이 시장은 통째로 사라졌다.
출처: Jason Riedy, Wikimedia Commons (CC BY 2.0)
벽 ① 지식 획득의 병목 — 10차시에 이름을 붙였던 그것
10차시 마지막에 여러분은 “규칙으로 적으려다 실패한 지식”을 하나씩 적어 냈습니다.
그때 그 종이를 다시 꺼내 놓으세요. 오늘 그것이 재료입니다.
의사의 “얼굴이 안 좋아 보여서요”, 정비공의 “소리가 평소랑 달랐어요” —
전문가가 실제로 아는 것과 말로 옮길 수 있는 것 사이의 그 간격을
지식 획득의 병목이라고 불렀지요.
오늘 한 가지를 더 보탤 수 있습니다. 후향 추론은 이 병목을 더 아프게 만듭니다.
전향 추론은 적힌 규칙만큼만 굴러가고 멈추면 그만이지만,
후향 추론은 목표를 캐물으며 없는 규칙을 계속 요구하기 때문입니다.
오늘 [B]에서 본 X 젖을 먹인다가 바로 그 요구예요 —
“이것을 알려 주지 않으면 나는 아무 말도 못 한다”입니다.
설명을 잘 하는 기계일수록 적어 주어야 할 것의 목록이 길어집니다.
2단원에서 만날 기계학습은 이 벽을 정면으로 겨냥합니다 —
전문가에게 규칙을 물어보는 대신, 전문가가 내린 판정 결과를 잔뜩 모아 놓고
그 안에서 규칙에 해당하는 것을 기계가 뽑아내게 하자는 발상이에요.
벽 ② 예외가 끝나지 않는다
“새는 난다”는 좋은 규칙처럼 보입니다. 그런데 펭귄은 못 납니다. 타조도 못 납니다.
다친 매도 못 날고, 새장에 갇힌 새도 못 날고, 알에서 갓 깬 새도 못 납니다.
예외를 만날 때마다 규칙을 하나씩 덧붙이면 어떻게 될까요.
규칙이 결국 사실의 목록이 됩니다.
그러면 규칙을 적는 값어치 — 적은 수의 규칙으로 많은 경우를 덮는다 — 가 사라집니다.
11차시에서 펭귄을 알아맞히려고 조건을 새다 AND 헤엄친다 두 개로 늘렸던 것을 떠올려 보세요.
그때는 두 개로 충분했습니다. 그러나 세상의 새를 다 담으려면 몇 개가 필요할까요.
사람은 “새는 대개 난다, 펭귄만 빼고”라고 말하고 끝내지만,
규칙 엔진에는 ‘대개’를 적을 칸이 없습니다.
벽 ③ 규칙이 늘면 서로 다툰다
11차시에서 규칙 순서를 random.seed(2026)으로 다섯 번 섞어 돌렸을 때,
발동 순서는 다섯 번 모두 달랐지만 결론 집합은 다섯 번 모두 같았습니다.
기분 좋은 결과였지요. 그런데 그것은 우리 규칙 여섯 개가 서로 다투지 않았기 때문입니다.
후향 추론에서도 판정 자체는 순서를 타지 않습니다.
먼저 시도한 규칙이 실패하면 다음 규칙을 마저 시도하니까요.
그런데 여기에는 11차시에 없던 손실이 하나 더 있습니다. 순서가 바뀌면 설명이 바뀝니다.
한 목표에 규칙이 여럿 붙어 있으면 먼저 성공한 규칙에서 멈추므로,
어느 규칙을 위에 적어 두었느냐에 따라 화면에 찍히는 트리가 달라져요.
오늘 [D]에서 새다에 규칙이 둘 붙지요.
그 둘을 코드에서 바꿔 적으면 판정은 X 그대로, 줄 수도 아홉 줄 그대로인데
깃털 가지와 날개 가지가 찍히는 차례가 뒤바뀝니다.
전향 추론에서는 결론 목록만 보면 순서가 티 나지 않았지만,
후향 추론에서는 그 트리가 곧 답입니다.
같은 판정에 서로 다른 “왜”가 붙는 셈이고, 어느 설명이 더 나은지는 기계가 정하지 못합니다.
규칙을 적는 순서까지 사람이 책임져야 하는 것이지요.
배달 로봇에게 이런 두 규칙이 있다고 해 봅시다.
“위험하면 멈춰라”와 “늦으면 서둘러라”.
위험하면서 늦은 상황에서는 둘 다 조건이 갖춰집니다. 무엇을 먼저 할까요?
기계는 스스로 정하지 못합니다. 그래서 충돌 해소 규칙을 또 사람이 적어야 하고,
그 규칙끼리 또 충돌하면 그 위에 또 적어야 합니다.
규칙이 열 개일 때는 사람이 전부 읽고 검토합니다. 백 개가 되면 못 읽습니다.
규칙 하나를 고쳤을 때 어디가 함께 바뀌는지를 아무도 모르게 되는 순간,
그 시스템은 사실상 손댈 수 없는 것이 됩니다.
벽 ④ 불확실한 것을 담을 칸이 없다
우리 엔진에서 사실은 집합에 있거나 없거나 둘뿐입니다.
“기침이 좀 있는 것 같다”, “아마 젖었을 것이다”를 적을 자리가 없어요.
그런데 현실의 판단은 대부분 그 사이에 있습니다.
MYCIN이 규칙마다 확신도(certainty factor)라는 −1에서 +1 사이의 값을 붙였던 것이
이 벽을 넘으려는 시도였습니다. 확신도를 붙이면 판정은 부드러워지지만,
이번에는 그 값을 누가 무슨 근거로 정하는가라는 새 물음이 생깁니다.
결국 벽 ①로 돌아오는 셈이지요.
벽 ⑤ 지식이 몰래 돌기 시작한다 — 오늘 직접 보는 것
규칙이 늘어나면 사람은 지식이 원을 그리고 있다는 것을 알아채지 못합니다.
오늘 코드의 [D]가 그 상황을 일부러 만듭니다.
규칙 두 개 새다 → 날개가 있다와 날개가 있다 → 새다를 넣으면
후향 추론은 새다를 밝히려고 날개가 있다를 캐고,
그것을 밝히려고 다시 새다를 캐러 내려갑니다. 끝이 없습니다.
? 펭귄이다 <- 규칙 'IF 새다 AND 헤엄친다' 로 밝혀 보자? 새다 <- 규칙 'IF 깃털이 있다' 로 밝혀 보자X 깃털이 있다 (밝힐 방법이 없다)? 새다 <- 규칙 'IF 날개가 있다' 로 밝혀 보자? 날개가 있다 <- 규칙 'IF 새다' 로 밝혀 보자~ 새다 (이미 캐묻는 중인 목표다 — 돌고 있으니 여기서 접는다)X 날개가 있다 (밝힐 방법이 없다)X 새다 (밝힐 방법이 없다)X 펭귄이다 (밝힐 방법이 없다)
노란 ~ 한 줄이 순환을 끊은 자리입니다.
이것을 가능하게 하는 것이 prove()의 캐묻는중 명단이에요 —
지금 내려오는 길에 이미 캐묻기 시작한 목표를 적어 두고, 같은 것을 또 만나면 접습니다.
이 검사를 빼면 파이썬이 RecursionError로 멈춰 세웁니다.
실제로 재어 보니 깊이 332에서 걸렸습니다.
⚠️ 왜 어떤 안전장치는 파이썬이 대신 해 주고, 어떤 것은 우리가 넣어야 하는가
순환하는 재귀는 파이썬이 스스로 멈춰 세웁니다 —
호출이 쌓이는 깊이에 한도가 있기 때문이에요(측정값 332). 그래서 브라우저가 굳지는 않습니다.
그러나 오늘 뒤에서 쓸 A*의 while 반복은 아무도 대신 세어 주지 않습니다.
그래서 코드에 LIMIT = 20000과 경로 되짚기 순환 검사를 우리가 직접 넣어 두었습니다.
이 페이지의 파이썬은 웹워커 없이 화면과 같은 흐름에서 돌기 때문에,
끝나지 않는 반복은 곧 탭이 멈추는 일입니다. 실습에서 그 줄들을 지우지 마세요.
그런데 다섯 벽을 다 알고도 규칙을 쓰는 자리가 있다
10차시에서 이미 보았듯이 세금 계산·항공권 요금·보험 심사처럼
규칙이 명문화되어 있고 틀리면 안 되는 곳에서는 지금도 규칙 기반이 정답입니다.
오늘은 거기에 하나를 더 붙일 수 있습니다.
규칙이 명문화되어 있지 않아도, 설명이 의무인 곳이라면 규칙 기반이 남습니다.
정확도 99%짜리 학습 모형을 대출 심사에 쓴다고 해 봅시다. 규칙 기반보다 잘 맞힙니다.
그런데 거절당한 사람이 “왜죠?”라고 물으면 답할 말이 없습니다.
1%가 왜 틀렸는지도, 99%가 왜 맞았는지도 여섯 줄로 내놓을 수 없어요.
정확도와 설명 가능성은 서로 맞바꾸는 관계일 때가 많고,
어느 쪽을 살지는 문제가 정합니다 — 7차시에서 w를 5로 올려
2걸음(17→19)을 주고 둘러보는 칸을 52에서 20으로 샀던
그 판단과 똑같은 종류의 저울질입니다.
📌 두 방식을 한 줄로 견주면
규칙 기반(1단원)
기계학습(2단원)
지식은 어디서 오나
사람이 적는다
데이터에서 뽑는다
예외가 생기면
규칙을 사람이 덧붙인다
사례를 더 넣고 다시 학습한다
왜 그렇게 판단했나
설명 트리로 다 보인다
따로 애써야 겨우 보인다
잘 맞는 문제
규칙이 이미 정해진 문제
규칙을 적기 어려운 문제
2단원은 오른쪽 칸으로 건너가는 단원입니다.
오늘 왼쪽 칸의 세 번째 줄이 초록이라는 것을 기억해 두세요 — 건너가면서 잃는 것이 그것입니다.
4
추론이 정한 값이 탐색의 비용이 된다 — 두 기둥을 잇는 한 줄
이 단원은 두 갈래로 걸어왔습니다. 1~9차시는 길을 찾았고(탐색),
10~12차시는 결론을 끌어냈습니다(추론). 서로 만난 적은 없었어요.
이제 잇습니다. 이음매는 놀랄 만큼 짧습니다 — 함수 하나, 사실상 한 줄입니다.
무대는 4차시부터 여섯 차시를 함께 써 온 그 미로입니다.
7행 12열, 벽이 19칸이고 다닐 수 있는 칸이 65칸, 출발 S=(0,0), 목표 G=(6,11),
최단은 17걸음이었지요. 오늘은 이것을 학교 복도라고 부르겠습니다.
배달 로봇이 (0,0) 배달실에서 (6,11) 교무실까지 갑니다.
달라진 것은 하나뿐입니다. 칸마다 센서가 관찰한 속성이 붙어 있습니다.
젖은 보도, 몰려 걷는 사람들 사이를 지나는 배달 로봇(에스토니아 타르투) — 오늘 표의 젖음·사람많음이 바로 이런 장면이다.
9차시에서는 잔디·모래·물이라는 지형이 비용을 정했다.
오늘은 규칙 추론이 내린 판정이 비용을 정한다.
로봇이 보는 것은 여전히 숫자뿐이고, 그 숫자를 무엇으로 만들지가 달라졌을 뿐이다.
출처: Sillerkiil, Wikimedia Commons (CC BY-SA 4.0)
칸
센서가 관찰한 것
규칙이 끌어낸 것
cost()
(0, 3)
젖음
미끄럼
1
(0, 4)
젖음 · 경사
미끄럼 · 위험
9
(1, 7)
사람많음
위험
9
(1, 9)
젖음 · 경사
미끄럼 · 위험
9
(2, 6)
젖음
미끄럼
1
(3, 9)
사람많음
위험
9
속성이 적힌 칸은 여섯입니다. 그중 위험으로 판정된 칸이 넷이고,
나머지 둘은 미끄럼까지만입니다. 이 판정을 만든 지식은 규칙 셋뿐이에요.
왜 (0,3)은 젖었는데 위험이 아닐까요? 사슬이 두 단이기 때문입니다.
젖음은 미끄럼까지만 끌어냅니다. 거기서 위험으로 넘어가려면 경사가 함께 있어야 해요.
(0,3)은 평평한 복도의 물기이고, (0,4)는 젖은 비탈입니다.
기계는 이 차이를 규칙 두 줄로 구별합니다.
그리고 이 판정을 만드는 infer()는 11차시의 전향 추론 엔진을 줄여 쓴 것이에요 —
더 나올 사실이 없을 때까지, 곧 고정점까지 돌립니다.
💭 이음매 — 이 세 줄이 두 기둥을 붙인다
def cost(cell):
return9 if 위험한가(cell) else 1# ← 추론의 결론이 곧 비용이 되는 자리
위험한가()의 왼쪽은 추론입니다. 규칙과 사실의 세계예요.
9와 1의 오른쪽은 탐색입니다. 9차시에서 잔디·모래·물의 비용을 정하던 그 자리입니다.
두 세계가 이 한 줄에서 만납니다.
그리고 A* 쪽에서 고치는 것은 이웃까지의 비용을 재는 딱 한 줄뿐입니다.
# 9차시의 A* 그대로. 다른 것은 단 하나 — 한 걸음의 값을 cost() 가 정한다.
ng = gc + (cost(n)if 위험반영 else 1)
위험반영이 False면 모든 걸음이 1입니다 — 그러면 7차시에서 짠 A*와 완전히 같은 프로그램이 됩니다.
True면 추론이 비용을 정합니다. 두 번 돌린 결과가 이렇습니다.
설정
둘러본 칸
경로
총비용
지나간 위험 칸
위험을 무시하면
52
17걸음
17
3개 — (0,4) (1,7) (1,9)
위험을 반영하면
45
17걸음
17
0개
표를 세 번 읽어야 합니다.
걸음 수가 17로 같습니다. 이 미로의 최단은 17걸음인데,
17걸음짜리 길이 여럿 있었고 그중에 위험 칸을 하나도 밟지 않는 것이 섞여 있었습니다.
로봇은 그것을 골랐어요. 더 걷지 않고 위험만 덜어낸 것입니다.
인공지능이 값어치를 내는 방식이 이 한 줄에 있습니다.
총비용도 17로 같습니다. 위험 칸을 하나도 안 밟았으니 모든 걸음의 값이 1이니까요.
비용 9는 실제로 치른 값이 아니라 계획할 때 겁을 준 값이었던 셈입니다.
둘러본 칸이 52에서 45로 줄었습니다. 이 줄이 가장 뜻밖입니다.
생각할 것을 더 붙였는데 계산이 줄었어요.
까닭은 위험 칸의 g가 커지면서 f = g + h도 커져
대기실 뒤로 밀려나 아예 꺼내지지 않기 때문입니다.
지식이 탐색의 범위를 좁혔습니다. 좋은 지식은 답만 고치는 것이 아니라 계산까지 줄입니다.
💡 7차시 값과 맞춰 보기
‘위험을 무시하면’ 줄의 52칸 · 17걸음은
7차시에서 w = 1로 A*를 돌려 얻었던 값과 정확히 같습니다.
같은 미로, 같은 astar()이니 당연한 결과예요.
이 일치가 오늘 프로그램이 망가지지 않았다는 증거입니다 —
여러분 화면에서 52가 아닌 다른 수가 나온다면 미로나 neighbors()를 건드린 것입니다.
🤖 추론 → 비용 → A* 종합 지도INTERACTIVE
규칙을 켜고 끄면 위험 판정이 그 자리에서 다시 계산되고,
그 판정이 비용이 되어 A*가 다시 길을 찾습니다.
붓을 골라 칸을 누르면 속성을 칠할 수 있고, 👀 살펴보기 상태에서 누르면
그 칸의 관찰·추론·비용을 아래에 읽어 줍니다. 파란 칸은 A*가 둘러본 칸,
노란 선은 찾아낸 길, 빨간 테두리는 위험으로 판정된 칸입니다.
둘러본 칸찾아낸 길위험 판정지나간 위험 칸벽글자: 젖 · 경 · 사 · 계 = 센서가 관찰한 속성
52둘러본 칸
17걸음 수
17총비용
3지나간 위험 칸
4위험 판정 칸
[안내] 지금은 7차시의 A*와 완전히 같습니다. 위험을 비용에 반영을 켜 보세요.
💡 해 보기 — 표를 채우고, 문턱을 찾고, 반례를 만듭니다
① 표 채우기. 네 설정을 차례로 돌려 공책에 적으세요. 확인 문제 5번이 이 표를 묻습니다.
설정
둘러본 칸
걸음
지나간 위험 칸
위험 반영 끔
위험 반영 켬
위험 반영 켬 + 어림 h 끔
어림 h를 다시 켜고 + 내 규칙 켬 & (2,6)에 🪜계단 칠하기
② 문턱 찾기. ‘위험 반영’을 켠 채 위험 칸 비용 슬라이더를
9에서 1씩 내리며 결과가 처음 달라지는 값을 찾으세요. 몇에서 바뀌나요?
그 값에서 무슨 일이 일어난 것인지 한 줄로 적어 보세요.
③ 반례 만들기. 붓으로 속성을 칠해
“위험을 반영하면 17걸음으로는 도저히 갈 수 없는” 복도를 만들어 보세요.
걸음 수가 몇으로 늘었나요? 그리고 그때 지나간 위험 칸이 0인지도 함께 확인하세요 —
0이 아니라면 그것은 무슨 뜻일까요?
💻
손으로 — 캐묻는 엔진을 완성하고, 추론을 탐색에 꽂는다
아래 코드에 빈칸이 네 곳 있습니다. 앞의 두 곳은 후향 추론이고,
뒤의 두 곳은 추론을 A*에 꽂는 자리예요. 코드 맨 위의 두 블록 —
10차시의 RULES 여섯 줄과 4차시의 MAZE·neighbors() — 은
손대지 않습니다. 화면 속 파이썬은 차시마다 새로 뜨기 때문에
앞 차시에서 만든 것을 물려받을 수 없어서, 이렇게 매번 다시 싣습니다.
빈칸 ①②를 채워 prove()를 완성합니다.
①은 순환 감지(“지금 캐묻는 중인 목표를 또 캐묻고 있는가”),
②는 재귀 호출(“이 규칙의 조건을 전부 밝힐 수 있는가”)입니다.
실행해서 [A]가 6줄, [B]가 5줄로 나오면 성공.
[B]의 막힌 자리를 짚습니다.X가 세 줄인데
진짜 원인은 하나입니다. 어느 것인가요? 그리고 [C]에서 그 하나를 알려 주었을 때
몇 번째 줄부터 색이 바뀌는지 손가락으로 따라가 보세요.
빈칸 ③④를 채웁니다. ③은 cost() — 위험이면 9, 아니면 1.
④는 이웃까지의 새 비용 — gc에 이번 한 걸음의 값을 더하되,
위험반영이 꺼져 있으면 모든 걸음이 1입니다.
[F]에 52칸·17걸음·위험 3개와
45칸·17걸음·위험 0개가 나오면 성공.
일부러 부숩니다. 빈칸 ①에 채운 검사를 if False:로 바꾸고
[D]까지 실행해 보세요. 무슨 오류가 나고, 몇 줄쯤에서 멈추나요?
이 오류는 파이썬이 스스로 세워 준 것입니다. 그렇다면 A*의 LIMIT = 20000은
왜 우리가 직접 넣어야 했을까요?
지식만 고쳐 길을 바꿉니다. 맨 아래 [G]는 규칙 하나
(계단 AND 젖음 → 위험)와 관찰 하나((2,6)이 계단이다)를 더합니다.
프로그램은 한 줄도 고치지 않습니다. 걸음 수가 어떻게 되나요?
그다음 여러분의 규칙을 하나 더 만들어 넣고, 길이 또 어떻게 달라지는지 보세요.
⚠️ 지우면 안 되는 줄
이 코드에는 안전장치가 셋 있습니다 —
prove()의 캐묻는중 명단, astar()의 LIMIT = 20000,
그리고 경로를 되짚을 때의 고리 검사(if cur in walked)입니다.
군더더기처럼 보이지만 셋 다 실제로 화면이 굳는 일을 겪고 나서 넣은 것이에요.
특히 [G]에서 여러분이 규칙을 새로 만들다 비용을 이상하게 주면
LIMIT이 없을 때 탭이 그대로 멈춥니다.
망가지더라도 말은 하고 망가지게 만드는 것 — 그것이 이 세 줄이 하는 일입니다.
빈칸 ① — “지금 내려오는 길에 이미 올려 둔 명단”이 캐묻는중입니다.
목표가 그 명단 안에 들어 있는지를 묻는 한 낱말짜리 조건이에요.
집합에 무엇이 들어 있는지는 in으로 묻습니다.
빈칸 ② — 조건 c 하나하나에 대해 prove를 다시 부르고,
그것들이 전부 참인지를 all( )로 묶습니다.
깊이는 depth + 1로 한 단 늘리고, 캐묻는중은 그대로 넘겨야
순환 감지가 아래까지 이어집니다. 이것을 빠뜨리면 ①이 있어도 소용이 없어요.
빈칸 ③ — 개념 4의 상자에 그대로 적혀 있습니다.
위험한가(cell)이 참이면 9, 아니면 1을 돌려주는 한 줄입니다.
빈칸 ④ — 7차시의 ng = gc + 1에서 1 자리만 바뀝니다.
위험반영이 참이면 cost(n), 아니면 1이에요.
주의: cost(cur)가 아니라 cost(n)입니다 —
한 걸음의 값은 도착하는 칸이 정합니다.
③④를 다 채웠는데 52·45가 안 나온다면 미로나 neighbors()를 건드린 것입니다.
↺ 처음 코드로를 누르고 다시 시작하세요.
실습 4 — 순환 감지를 죽이면.[D]에서
새다 → 날개가 있다 → 새다 → …가 끝없이 내려가다
파이썬이 RecursionError로 멈춰 세웁니다.
잰 값은 깊이 332였어요. 화면에는 같은 물음이 수백 줄 쏟아집니다.
그런데 이 오류는 파이썬이 대신 세어 준 것입니다. 함수 호출이 쌓이는 깊이에 한도가 있으니까요.
반면 astar()의 while openq:는 아무도 세어 주지 않습니다.
비용을 잘못 주어 대기실이 계속 불어나면 그냥 영원히 돕니다.
그래서 LIMIT은 우리가 넣어야 했습니다.
“내가 만든 반복은 내가 끝을 책임진다”가 여기서 얻어 갈 규칙입니다.
실습 5 — 지식만 고치면.[G]는 규칙 하나와 관찰 하나만 더합니다.
그러자 아까 지나가던 (2,6)이 위험해지고, A*는 아래로 크게 돌아
둘러본 칸 54 · 21걸음 · 총비용 21 · 위험 칸 0개가 됩니다.
17걸음이 21걸음으로 늘었습니다. 이번에는 공짜가 아니었어요 —
4걸음을 더 걷고 위험을 피한 것입니다.
여기서 두 가지를 함께 보세요. 하나는 프로그램의 코드가 한 줄도 안 바뀌었다는 것
(고친 것은 SAFE와 ATTR, 곧 지식뿐입니다).
다른 하나는 어떨 때는 공짜고 어떨 때는 값을 치른다는 것입니다.
앞서 45칸짜리 경우에는 위험을 피하고도 17걸음이었지만,
위험이 길목을 막으면 돌아가는 값을 치러야 합니다.
그 값을 치를지 말지를 정하는 것은 프로그램이 아니라 사람입니다 —
비용 9라는 숫자를 정한 사람이요.
📖
정리 — 이 단원을 한 장으로
열두 차시를 걸어왔습니다. 낱말 일곱 개로 다시 세우면 이렇게 이어집니다.
지도를 왼쪽에서 오른쪽으로 읽어 보면 하나가 눈에 들어옵니다.
탐색도 추론도, 사람이 무언가를 적어 주어야 굴러갑니다.
탐색에서는 비용과 어림을 적어 주었고(9차시에서 잔디 1·모래 3·물 5를 정한 것은 사람이었지요),
추론에서는 규칙을 적어 주었습니다. 오늘 이은 프로그램에서도
9라는 숫자와 규칙 세 줄은 전부 사람이 정한 것입니다.
그 ‘적는 일’이 감당되는 동안 규칙 기반은 잘 작동합니다.
감당이 안 되는 순간 — 새를 알아보는 자기 감을 못 적을 때, 예외가 끝없이 나올 때 —
다른 길이 필요해집니다. 규칙을 사람이 적는 대신, 데이터에서 뽑아낼 수는 없을까?
이 물음이 2단원 기계학습의 첫 문장입니다.
그리고 그쪽으로 건너가면서 우리가 내려놓게 될 것이 무엇인지도 오늘 확인했지요 —
오늘 여섯 줄로 읽어 낸 그 설명 트리입니다.
🔁 되돌아보기
오늘 목표에서 거꾸로 캐묻는 엔진을 짜서 설명이 따라 나오게 만들었고,
그 추론이 정한 위험을 A*의 비용에 꽂아 같은 17걸음으로 위험 칸을 3개에서 0개로 줄였습니다.
오늘 화면에서 본 숫자 하나를 골라, 왜 그 숫자가 놀라웠는지 한 줄로 적어 보세요.
(예: “52가 45로 줄었다는 것 — 생각할 것을 더 붙였는데 계산이 줄어서”)
다음 시간에는 단원 마무리로 열두 차시를 한 번에 되짚습니다.
✅
확인 문제
✍️ 문제마다 답을 쓰고 제출하기를 누르세요. 제출하면 모범 답안이 열리고, 제출한 답은 선생님께 전달됩니다.
1. 전향 추론과 후향 추론이 각각 어디서 출발해 어디로 가는지를
구별해 쓰고, 같은 지식 베이스를 쓰면서도 두 방식이 갈라지는 까닭을 한 문장으로 정리하시오.
📖 모범 답안
전향 추론은 아는 사실에서 출발해 조건이 갖춰진 규칙을 발동시키며
결론 쪽으로 굴러간다. 더 나올 사실이 없는 고정점에서 멈추고,
그 결과 묻지 않은 결론까지 전부 나온다.
후향 추론은 밝히려는 목표에서 출발해 그 목표를 결론으로 갖는 규칙을 찾고,
그 규칙의 조건을 새 목표로 삼아 사실 쪽으로 내려간다. 물은 것만 캔다.
갈라지는 까닭은 지식이 아니라 엔진이 다르기 때문이다.
규칙 여섯 개는 두 방식에서 한 글자도 바뀌지 않았고, 규칙을 읽는 방향만 반대였다.
지식과 엔진이 분리되어 있기에 같은 지식을 두 방향으로 쓸 수 있다.
2. 오늘 얻은 ‘돌고래다’ 실패 트리를 보고 답하시오.
⑴ 몇 줄이었고 판정은 무엇이었는가. ⑵ X가 세 줄인데 진짜로 막힌 자리는 어디인가.
⑶ 무엇을 알려 주면 성공으로 뒤집히는가. ⑷ 규칙 IF 포유류다 AND 헤엄친다의 두 번째 조건
헤엄친다는 왜 트리에 나오지 않았는가.
📖 모범 답안
⑴ 5줄, 판정은 False다.
⑵ 맨 안쪽의 젖을 먹인다. 나머지 두 줄
(포유류다, 돌고래다)은 그것 때문에 딸려 무너진 것이지 스스로 막힌 것이 아니다.
실패 트리를 읽을 때는 가장 깊은 X를 먼저 본다.
⑶ 젖을 먹인다를 사실로 알려 주면 된다.
그러면 맨 안쪽 줄이 O가 되고 그 위 두 줄이 차례로 살아나 판정이 True가 된다.
좋은 설명은 “안 된다”가 아니라 “무엇을 알려 주면 되는지”를 말해 준다.
⑷ all(prove(c) for c in conds)가 첫 실패에서 곧바로 멈추기 때문이다.
앞 조건이 무너지면 뒤는 확인할 필요가 없다. 계산을 아끼는 장치이지만,
설명을 읽을 때는 “안 물어본 것”과 “물었는데 없는 것”을 구별해야 한다.
트리에 헤엄친다가 없다고 해서 그것이 거짓이라는 뜻은 아니다.
3. 여는 장면의 대출 거절 상황에 후향 추론을 대입하여,
이 방식이 설명 가능한 AI의 오래된 형태라고 불리는 까닭을 설명하시오.
답에는 성공 트리와 실패 트리가 각각 무엇에 해당하는지를 함께 쓰시오.
📖 모범 답안
‘승인 대상이다’를 목표로 두고 거꾸로 캐물으면,
? 승인 대상이다 ← 규칙 'IF 등급이 기준 이상' … 하는 사슬이 화면에 그대로 그려진다.
이 사슬 자체가 설명이다. 사람이 따로 설명문을 지은 것이 아니라
프로그램이 실제로 밟은 경로를 읽은 것이므로,
빠뜨린 근거가 없고, 관찰한 사실에서 멈추며, 되짚어 반박할 수 있다.
그래서 규칙 기반은 XAI라는 말이 생기기 훨씬 전부터 설명이 가능했다.
성공 트리는 “왜 승인되었는가”의 근거 목록이고,
실패 트리는 “왜 거절되었는가”와 “무엇이 바뀌면 승인되는가”다.
실패 트리에서 막힌 자리가 연체 없음이라면,
기계의 답은 “안 됩니다”가 아니라 “연체 기록이 정정되면 승인됩니다”가 된다.
여는 장면의 세 번째 답이 정확히 이 모양이었다.
4. 규칙 기반 인공지능의 한계를 세 가지 들고,
그중 하나를 10차시에서 자기가 직접 규칙을 적어 보았을 때 막혔던 경험과 이어 설명하시오.
그리고 그런 한계에도 규칙 기반을 써야 하는 자리를 하나 들고 까닭을 쓰시오.
📖 모범 답안
한계(다섯 중 셋을 고르면 된다) ① 지식 획득의 병목 — 전문가도 자기 감을 다 못 적는다.
② 예외의 끝없음 — 예외마다 규칙을 붙이면 규칙이 사실의 목록이 된다.
③ 규칙끼리의 충돌 — “위험하면 멈춰라”와 “늦으면 서둘러라”가 함께 조건을 갖추면
무엇을 먼저 할지 사람이 또 적어야 한다.
④ 불확실을 담을 칸이 없다 — 사실은 있거나 없거나 둘뿐이라 “좀 그런 것 같다”를 못 적는다.
⑤ 지식이 몰래 순환한다 — 오늘 [D]에서 본 것.
경험과 잇기(예시) — 10차시에서 “새를 어떻게 알아보는가”를 규칙으로 적으려다
“그냥 보면 아는데”에서 손이 멈췄다면, 그것이 바로 ①이다.
자기 판단은 분명한데 그것을 IF ... THEN ...의 형태로 옮길 수가 없다.
이 벽 때문에 2단원에서는 규칙을 묻는 대신 판정 결과를 잔뜩 모아 기계가 규칙을 뽑게 한다.
그래도 규칙 기반인 자리 — 세금·수당 계산, 안전 연동장치, 항공기 점검 절차처럼
규칙이 이미 명시적으로 정해져 있고, 틀리면 안 되고, 왜 그렇게 판정했는지 반드시 설명해야 하는 곳.
2차시 적합도 점수표에서 세금 계산이 0/0/0으로 0점이었던 것이 같은 이야기다 —
어려운 문제라서가 아니라 규칙이 이미 법으로 적혀 있어서 AI에게 맡길 까닭이 없었다.
5. 종합 프로그램에서 둘러본 칸 52 → 45,
걸음 수는 17 그대로, 지나간 위험 칸 3 → 0이 되었다.
⑴ 걸음 수가 그대로인데 위험 칸이 0이 된 까닭을, 추론 결과가 비용으로 들어간 자리를 짚어 설명하시오.
⑵ 둘러본 칸이 오히려 줄어든 까닭을 f = g + h로 설명하시오.
⑶ 시뮬레이터에서 위험 칸 비용을 9에서 1씩 내렸을 때 결과가 처음 달라진 값은 얼마였는가.
📖 모범 답안
⑴ 이음매는 def cost(cell): return 9 if 위험한가(cell) else 1과
ng = gc + (cost(n) if 위험반영 else 1) 두 줄이다.
추론이 ‘위험’이라고 판정한 칸은 한 걸음의 값이 1에서 9로 바뀐다.
그런데 이 미로에는 17걸음짜리 최단 경로가 여럿 있었고,
그중에 위험 칸을 하나도 지나지 않는 것이 섞여 있었다.
A*는 총비용이 가장 작은 길을 고르므로 같은 17걸음 중에서 위험을 안 밟는 쪽을 골랐다.
그래서 총비용도 17 그대로다 — 겁을 준 9는 계획할 때만 쓰였고 실제로 치르지 않았다.
⑵ 위험 칸의 g가 커지면 f = g + h도 커진다.
f가 큰 칸은 대기실(우선순위 큐)에서 뒤로 밀려 아예 꺼내지지 않는다.
그래서 둘러본 칸이 52에서 45로 줄었다. 좋은 지식은 답만 고치는 것이 아니라 계산까지 줄인다.
(참고로 어림 h를 끄면 다익스트라가 되어 45가 63으로 늘어난다.
17걸음과 위험 0개는 그대로다 — 어림은 답이 아니라 답을 찾는 속도를 바꾼다.)
⑶ 1이다. 9에서 2까지는 45칸·17걸음·위험 0개로 결과가 전혀 바뀌지 않다가,
1이 되는 순간 52칸·17걸음·위험 3개 — 곧 ‘위험을 무시한’ 경우와 완전히 같아진다.
위험 칸의 값이 1이면 보통 칸과 구별되지 않으니 당연한 결과다.
여기서 얻을 것: 9라는 숫자 자체는 중요하지 않았다.
중요한 것은 위험 칸이 보통 칸보다 비싸다는 사실 하나뿐이었다.
6. 이 단원을 한 장으로 정리하시오.
지능적 판단 · 상태 공간 · 맹목적 탐색 · 정보 이용 탐색 ·
A* · 지식 표현 · 추론 일곱 낱말을 화살표로 잇고,
두 줄기가 만나는 자리와 2단원이 시작되는 자리를 표시한 뒤,
2단원이 왜 거기서 시작되는지 두 문장으로 쓰시오.
📖 모범 답안
이어지는 모양(예시)
지능적 판단(1·2차시) → 탐색 줄기: 상태 공간(3) → 맹목적 탐색(4) → 정보 이용 탐색(5·6) → A*(7·8·9)
지능적 판단(1·2차시) → 추론 줄기: 지식 표현(10) → 추론(11 전향 · 12 후향)
두 줄기가 만나는 자리 = 12차시. 이음매는 cost() = 9 if 위험 else 1 —
추론의 결론이 탐색의 비용이 된다.
2단원이 시작되는 자리는 그 만난 지점의 오른쪽,
곧 사람이 규칙과 비용을 적어 주는 일이 벽에 부딪히는 곳이다.
까닭 두 문장(예시) — 탐색도 추론도 사람이 무언가를 적어 주어야 굴러가는데
(탐색은 비용과 어림을, 추론은 규칙을), 그 적는 일이 지식 획득의 병목과 끝없는 예외에 부딪힌다.
그래서 2단원은 규칙을 사람에게 묻는 대신 데이터에서 뽑아내는 방법으로 넘어가며,
그 대가로 오늘 얻은 설명 트리를 내려놓게 된다.
🔎
더 알아보기
거꾸로 캐묻는 엔진이 언어가 된 자리, 설명을 '지어내야' 하는 자리, 그리고 판정이 비용이 되는 거리
원리 더 깊이
프롤로그 — 오늘의 prove()가 곧 한 언어의 실행 방식이다
1972년 프랑스 마르세유에서 알랭 콜메로에(Alain Colmerauer)와 동료들이 만든 논리 프로그래밍 언어
프롤로그(Prolog)에서는 프로그램이 사실의 목록과 규칙의 목록으로만 이루어집니다.
그림의 penguin(X) :- bird(X), swims(X).는 우리 RULES의
(["새다", "헤엄친다"], "펭귄이다")와 같은 말이고, :-는 '조건이 이러면'으로 읽습니다.
그리고 프롤로그를 실행한다는 것 자체가 후향 추론입니다.
?- 뒤에 목표를 던지면 처리기가 그 목표를 결론으로 갖는 규칙을 찾고, 조건을 새 목표로 삼아
왼쪽 조건부터, 깊이 먼저 내려가며, 막히면 되돌아와 다른 규칙을 시도합니다.
4차시의 깊이 우선 탐색에 되돌아가기를 붙인 모양이지요. 오늘 주석과 빈 줄을 빼면 열일곱 줄인
prove()가 한 언어의 실행 방식 전체를 담고 있었던 셈입니다.
다른 점도 하나 있습니다. 표준 프롤로그의 기본 실행에는 오늘 넣은 캐묻는중 명단이 없습니다.
그래서 [D]처럼 서로를 부르는 규칙을 적으면 끝없이 내려가다 멈춰 버립니다.
프롤로그 프로그래머는 규칙을 적는 순서를 조심하거나, 이미 캐물은 목표를 표에 적어 두는
테이블링(tabling) 기능이 있는 처리기를 씁니다 — 벽 ⑤를 언어 차원에서 막는 장치입니다.
오해 바로잡기
"설명이 있다"와 "설명이 맞다"는 다른 말이다
오늘 얻은 설명은 공짜였습니다. 따로 만든 것이 아니라 프로그램이 밟은 경로를 그대로 찍었을 뿐이니까요.
그런데 2단원에서 만날 기계학습 모형에는 밟는 경로라는 것이 없습니다.
수많은 숫자가 한꺼번에 곱해지고 더해질 뿐이어서, 설명이 필요하면 따로 지어내야 합니다.
가장 흔한 방법은 그림처럼 흔들어 보는 것입니다. 입력의 한 부분을 가리거나 바꿔 넣고
판정 점수가 얼마나 달라지는지 재서, 많이 달라지는 부분을 "근거"라고 부르지요.
그림의 숫자는 원리를 보이려고 든 예시입니다. 널리 쓰이는 설명 도구 LIME·SHAP도
입력을 바꿔 가며 출력의 변화를 재는 이 계열에 속합니다.
여기서 오늘 배운 것과의 차이를 보세요. 후향 추론의 설명은 프로그램이 실제로 쓴 근거이고,
흔들어서 얻은 설명은 바깥에서 관찰해 추측한 근거입니다. 그럴듯하지만 틀릴 수 있고,
같은 모형을 다른 방법으로 흔들면 다른 설명이 나오기도 합니다.
여섯 줄짜리 트리를 손에 쥐어 본 사람만이 이 둘이 다르다는 것을 또렷이 압니다.
현장
판정이 비용이 되는 거리 — 그 숫자는 누가 정하나
사진은 경기도 군포의 한 학교 앞 길입니다. 도로를 붉게 칠하고 바닥에 '어린이 보호구역'과
30을 적어 두었지요. 사람은 이 표시를 보고 "여기서는 천천히, 조심해서"라고 판단합니다.
오늘 복도 칸에 젖음·사람많음을 붙였듯이, 도로 한 구간에 '어린이 보호구역이다'라는 속성이 붙은 셈입니다.
오늘 만든 구조 — "속성을 규칙으로 판정하고, 그 판정을 경로의 비용으로 바꾼다" — 로 옮기면
IF 어린이 보호구역 → 조심 구간, cost = 조심 구간이면 크게가 됩니다.
그러면 A*는 코드 한 줄 고치지 않고도 되도록 그 구간을 비껴가는 길을 냅니다.
배달 로봇이 보도의 공사 구간이나 붐비는 곳을 피해 가는 것도, 내비게이션이 '유료 도로 피하기' 같은
선택지를 주는 것도 이 구조로 이해할 수 있습니다.
여기서 중요한 것은 그 비용을 정하는 사람이 누구인가입니다.
오늘 우리가 9를 정했듯이, 현실에서도 누군가 그 숫자를 정합니다.
너무 작으면 위험한 길로 들어서고, 너무 크면 먼 길을 돌아 다른 곳을 더 붐비게 만들 수 있습니다.
"위험을 얼마나 두려워할 것인가"는 프로그램이 아니라 사람이 정해서 넣어 주는 값이고,
그 숫자가 곧 판단의 기준이 됩니다.
사진: 경기 군포시의 어린이 보호구역 도로 · 출처: LandAndTree, Wikimedia Commons (CC0)