https://arxiv.org/abs/2209.07753
링크는 여기에.
콜라 캔을 조금 오른쪽으로 옮기는 간단한 명령을 내렸다고 치자.

그림은 간략한 이 LMP 구조. 프롬프트를 입력하면 이를 LLM에 넣어 policy에 맞는 코드를 출력하는 방식이다.
LLM에 대한 복잡한 아키텍쳐라던가 그런게 있을 줄 알았는데...없더라구요?
//빈 그릇에 블록 쌓기.
empty_bowl_name = parse_obj('empty bowl')
block_names = parse_obj('blocks')
obj_names = [empty_bowl_name] + block_names
stack_objs_in_order(obj_names=obj_names)
저 주석 부분이 입력이고, 나머지는 생성한 코드이다.
코드는 일반적으로 알려진 함수들로 조합하거나, 임의의 함수를 쓰고 그 함수에 대해서도 LMP 작업을 진행하는 방식으로 작성된다.
ret_val = a
//변수 a와 b의 합을 찾습니다.
ret_val = a + b
//xs라는 리스트 내에서 어떤 숫자가 3으로 나누어 떨어지는지 확인합니다.
ret_val = any(x % 3 == 0 for x in xs)이런식으로 프롬프트 입력에 따라서 코드가 작성된다.
import numpy as np
#pts_np의 모든 포인트를 오른쪽으로 이동합니다.
ret_val = pts_np + [0.3, 0]
//pt_np를 위쪽으로 이동합니다.
ret_val = pt_np + [0, 0.3]
//pts_np에서 가장 왼쪽의 포인트를 가져옵니다.
ret_val = pts_np[np.argmin(pts_np[:, 0]), :]
//pts_np의 중앙을 가져옵니다.
ret_val = np.mean(pts_np, axis=0)
//pt_np와 가장 가까운 pts_np의 포인트를 가져옵니다.
ret_val = pts_np[np.argmin(np.sum((pts_np - pt_np)**2, axis=1))]
LMP는 자주 사용되는 일부 서드파티 라이브러리 코드의 사용 역시 자유롭다.
from utils import get_pos, put_first_on_second
//보라색 그릇을 왼쪽으로 이동합니다.
target_pos = get_pos('purple bowl') + [-0.3, 0]
put_first_on_second('purple bowl', target_pos)
objs = ['blue bowl', 'red block', 'red bowl', 'blue block']
//빨간 블록을 약간 오른쪽으로 이동합니다.
target_pos = get_pos('red block') + [0.1, 0]
put_first_on_second('red block', target_pos)
//파란 블록을 같은 색의 그릇 위에 놓습니다.
put_first_on_second('blue block', 'blue bowl')
LMP는 훈련 데이터에 없는 퍼스트파티 라이브러리 및 API 사용 역시 자유롭다.
또한, 서드파티/퍼스트파티 라이브러리 사용 시 만들어지는 함수는 유의미한 이름을 가지게 되며, 이는 힌트 및 예제에서 제공된다.
//빨간 블록이 파란 그릇의 왼쪽에 있는 동안, 5cm씩 오른쪽으로 이동시킵니다.
while get_pos('red block')[0] < get_pos('blue bowl')[0]:
target_pos = get_pos('red block') + [0.05, 0]
put_first_on_second('red block', target_pos)
objs = ['red block', 'blue bowl', 'blue block', 'red bowl']
//가장 왼쪽 블록이 빨간 블록일 때, 오른쪽으로 이동합니다.
block_name = parse_obj('the left most block')
while block_name == 'red block':
target_pos = get_pos(block_name) + [0.3, 0]
put_first_on_second(block_name, target_pos)
block_name = parse_obj('the left most block')
이러한 중첩 함수 형태의 경우, LMP가 이전에 생성한 코드를 살펴보면서 미정의된 함수를 찾고, 이를 생성하는 데 특화된 또 다른 LMP를 호출해 생성하는 방식으로 작동한다. 따라서 프롬프트를 입력할 때 전체에 대해 알려주지 않더라도, 대략적인 개요만으로 온전한 코드를 만들 수 있다.
//함수 정의: get_obj_bbox_area(obj_name).
def get_obj_bbox_area(obj_name):
x1, y1, x2, y2 = get_obj_bbox_xyxy(obj_name)
return (x2 - x1) * (y2 - y1)
이런 식으로 기능을 나눠넣으면서, 코드를 읽기 쉽게 만든다. 여기서 get_obj_bbox_xyxy가 무슨 역할인지 명시되지는 않았지만, 그 이름에서 대략적인 역할을 추론할 수도 있다.
로봇 policy의 맥락에서 볼 때, 자연어 지침을 바탕으로 인식-제어 피드백 논리를 구성할 수 있다. 사용 가능한 인식 및 제어 API에 대한 이전 정보는 예제 및 힌트를 통해 안내되고, 그 API들은 LMP와 로봇을 실질적으로 연결해주는 역할을 맡는다.
LMP 기반 policy가 가지는 이점은 다음과 같다.

4가지 LLM에 대해, LLM이 생성한 코드가 얼마나 인간이 작성한 테스트 기준을 통과했는지에 대한 지표.
GPT에 비해 Codex 모델이, Flat 보다는 계층적 모델이 더 우수한 성능을 거두었다.

아까에서 더 나아가, 계층적 코드 생성 LLM 부분에 특히나 주목한 실험 결과. 4가지 방식 모두 Flat에 비해 계층적인 모델이 더 강점을 가진다.
