-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.json
1 lines (1 loc) · 186 KB
/
index.json
1
[{"authors":["young-kim","whi-kwon"],"categories":[],"content":" Multi-scale 이번 장 에서는 다해상도(Multi-scale)에 대한 개념과 전통적인 Computer Vision에서 Multi-scale Image 처리를 하는 방법을 알아보겠습니다. 일반적으로 하나의 해상도에 최적화된 Computer Vision Model보다 다해상도를 처리할 수 있는 Computer Vision Model이 더 좋은 성능을 낼 가능성이 높기 때문에 Multi-scale 문제는 꼭 해결해야만 하는 문제입니다. 여기에서는 가장 단순하고 오래된 기법인 Image Pyramid기법만을 알아보겠습니다. 단순하게 요약하면 피라미드로 쌓은 것 같이 다양한 크기의 Image를 많이 준비하는 방법 입니다. Image pyramid Import Libraries import os import sys import math from platform import python_version import cv2 import matplotlib.pyplot as plt import matplotlib import imutils import numpy as np print(f\u0026quot;Python version : {python_version()}\u0026quot;, ) print(f\u0026quot;Opencv version : {cv2.__version__}\u0026quot;, ) Python version : 3.6.9 Opencv version : 4.1.2 Data load sample_image_path = '../image/' sample_image = 'kitten.jpg' img = cv2.imread(os.path.join(sample_image_path, sample_image), cv2.IMREAD_GRAYSCALE) h, w = img.shape matplotlib.rcParams['figure.figsize'] = (8.0, 8.0) Image\u0026nbsp;Pyramid 전통적인 Computer Vision이나 Deep Learning 모두 공통적으로 크기 변화에 취약하다는 단점을 가지고 있습니다. 즉, 같은 모델로 더 크거나 작은 Image를 분석할 경우 결과가 전혀 달라질 수 있다는 말 입니다. 이에 대응하기 위해 하여 Feature추출, 추론 등에서 다양한 해상도의 Image를 사용하는 것이 보통입니다. Image Pyramid[2]란, Image를 다양한 해상도의 Image로 변환하고 쌓아올려서 마치 피라미드와 같은 형상을 띄도록 준비하는 전처리 기법입니다. 이는 Multi-scale 문제를 해결해야 할 때 자주 쓰이던 기법이며, Deep Learning에서 쓰이는 FPN 등의 방법들이 이 Image Pyramid 기법을 개선하는 과정에서 고안된 것임을 감안할 때, Image Pyramid기법은 Multi-scale 문제 해결의 시작점 이라고 할 수 있습니다. 다해상도 처리 Image Pyramid에서 결국 관건은 다양한 해상도의 Image를 어떻게 준비할 것이냐 인데, 크기가 작은 Image라면 Upsampling을 해서 더 큰 해상도로 만들어야 하고, 크기가 큰 Image라면 Downsampling을 해서 Image 크기를 줄여야 합니다. 그러나 두 방법 모두 단순히 적용하면 정보량의 변화로 인해 원래 Image보다 다소 부자연스러워 보이게 되는 Aliasing이라는 문제가 발생하게 되는데, 이를 보완하는 방법에 대해 간단히 알아보겠습니다. Upsample Upsample에서 발생하는 Aliasing문제는 대부분의 경우 지난 장에서 확인한 Interpolation 방법으로 해결합니다. 생성모델이나 한층 더 높은 정교함을 요구하는 모델의경우 데이터에 맞게 학습된 Filter를 이용하는 Deconvolution 등이 사용되기도 합니다. Downsample Downsample의 경우 특정 화소를 선택적으로 제거해야 하므로 문제가 발생합니다. 단순히 짝수번째나 홀수번째 화소를 제거하는 방식을 사용할 경우, 제거되는 화소만큼 그대로 손실이 되기 때문에 Image의 품질이 빠르게 나빠지는 것을 확인할 수 있습니다. img_half = cv2.resize(img, (w // 2, h // 2)) img_quard = cv2.resize(img, (w // 4, h // 4)) img_eight = cv2.resize(img, (w // 8, h // 8)) plt.subplot(221) plt.imshow(img, cmap='gray') plt.title('Original image') plt.subplot(222) plt.imshow(img_half, cmap='gray') plt.title('1/2 sized') plt.subplot(223) plt.imshow(img_quard, cmap='gray') plt.title('1/4 sized') plt.subplot(224) plt.imshow(img_eight, cmap='gray') plt.title('8/1 sized') plt.suptitle('Kitten with many size', size=15) plt.show() 이러한 문제를 해결하기 위한 대안은 원본 Image에 Smoothing을 적용한 후 Downsampling을 적용하는 것 입니다. 선택적으로 제거되는 픽셀의 정보를 주변 픽셀들에 조금씩 반영해주는 원리입니다. 아래 예제는 교재에서 사용된 커널 함수로 Smoothing을 적용한 결과입니다. kernel = np.array([[0.05, 0.25, 0.4, 0.25, 0.05]]) kernel = np.dot(kernel.T, kernel) blur_img_half = cv2.resize(cv2.filter2D(img, -1, kernel), (w // 2, h // 2)) blur_img_quard = cv2.resize( cv2.filter2D(blur_img_half, -1, kernel), (w // 4, h // 4)) blur_img_eight = cv2.resize( cv2.filter2D(blur_img_quard, -1, kernel), (w // 8, h // 8)) plt.subplot(221) plt.imshow(img, cmap='gray') plt.title('Original') plt.subplot(222) plt.imshow(blur_img_half, cmap='gray') plt.title('Blur_half') plt.subplot(223) plt.imshow(blur_img_quard, cmap='gray') plt.title('Blur_quard') plt.subplot(224) plt.imshow(blur_img_eight, cmap='gray') plt.title('Blur_eight') plt.suptitle('Soft Kitten with many size', size=15) plt.show() Conclusion Multi-scale Image를 생성할 때 발생하는 문제와 이에 대응하기 위해 필요한 작업들을 살펴보았습니다. 여기에서 Smoothing 작업을 진행할 때, 다양한 커널을 이용할 수 있는데, Image에 따라 목적에 따라 최적의 커널이 따로 존재합니다. 이 말은 그때 그때 알맞은 커널을 직접 찾아서 사용해야 한다는 뜻이기도 합니다. 이러한 부분이 전통적인 방식의 Computer Vision이 가지고 있었던 고질적인 약점입니다. Reference [1] 오일석, \u0026ldquo;다해상도,\u0026rdquo; in 컴퓨터 비전, vol.4, Republic of Korea:한빛아카데미, 2014, pp. 93-96 [2] Accessed: \u0026lsquo;Image Pyramids\u0026rsquo;, opencv official, [Online] Avaliable: https://docs.opencv.org/3.4/dc/dff/tutorial_py_pyramids.html ","date":1593480000,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1593480000,"objectID":"cd0ca439f351e600735eee7a47d1c293","permalink":"/post/2020-06-30-multi_scale/","publishdate":"2020-06-30T10:20:00+09:00","relpermalink":"/post/2020-06-30-multi_scale/","section":"post","summary":"Handling multi-scale images using OpenCV","tags":[],"title":"[Tutorial] Multi-scale","type":"post"},{"authors":["young-kim","whi-kwon"],"categories":[],"content":" Morphology 이번 장 에서는 Morphology Operation[2]에 대하여 알아보겠습니다. Morphology Operation이란, Image의 형태를 조작하는 연산의 종류를 통칭합니다. 적용 대상이 어떤 Image냐에 따라 Binary, Grayscale로 나눌 수 있고, 연산 방식에 따라 Dilation(확산)과 Erosion(침식)으로 나눌 수 있습니다. 두 연산 모두 공통적으로 Source Image Kernel을 통해 Target Image를 생성하는 과정을 갖습니다. Morphology Operation을 응용하면 Edge Detection이나 Image Denoising 등의 작업을 할 수 있습니다. 목차는 아래와 같습니다. Binary Morphology Grayscale Morphology Composited Morphological Operations Import Libraries import os import sys import math from platform import python_version import cv2 import matplotlib.pyplot as plt import matplotlib import numpy as np print(\u0026quot;Python version : \u0026quot;, python_version()) print(\u0026quot;Opencv version : \u0026quot;, cv2.__version__) Python version : 3.6.9 Opencv version : 4.1.2 Data load sample_image_path = '../image/' sample_image = 'kitten.jpg' img = cv2.imread(os.path.join(sample_image_path, sample_image), cv2.IMREAD_GRAYSCALE) h, w = [int(x) for x in img.shape] matplotlib.rcParams['figure.figsize'] = (8.0, 8.0) Binary\u0026nbsp;Morphology 전체 Image가 0 또는 1로 이루어진 Image를 Binary Image라고 합니다. 아래 설명은 모두 Binary Image를 기준으로 하겠습니다. 이러한 Image는 보통 Image 자체로 이용되기보다 RoI(Region of Interest)를 선택하기 위한 Mask로서 이용됩니다. Binary Image에 Morphology를 적용하면 자잘한 Noise를 제거하는데 도움이 됩니다. Erosion 연산은 침식이라는 말 뜻이 의미하듯이 1에 해당하는 밝은 영역이 조금씩 줄어드는 모습을 보입니다. RoI 바깥에 1의 값을 갖는 Noise가 발생하는 경우에 Erosion 연산을 통해 Noise를 보정할 수 있습니다. Dilation 연산은 팽창이라는 뜻인데, 흰색 영역이 조금 커지는 모습을 보입니다. RoI 중간에 0의 값을 갖는 Noise가 발생하는 경우에 Dilation 연산으로 보정할 수 있습니다. 한 번의 호출로 몇 번씩 연산을 반복할지를 인자 \u0026lsquo;iterations\u0026rsquo;로 조절할 수 있습니다. ret, th = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) kernel = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]], dtype=np.uint8) erosion = cv2.erode(th, kernel, iterations=1) dilation = cv2.dilate(th, kernel, iterations=1) th = cv2.cvtColor(th, cv2.COLOR_GRAY2RGB) erosion = cv2.cvtColor(erosion, cv2.COLOR_GRAY2RGB) dilation = cv2.cvtColor(dilation, cv2.COLOR_GRAY2RGB) th = cv2.rectangle(th, (200, 140), (400, 340), (255, 0, 0), 3) erosion = cv2.rectangle(erosion, (200, 140), (400, 340), (255, 0, 0), 3) dilation = cv2.rectangle(dilation, (200, 140), (400, 340), (255, 0, 0), 3) plt.subplot(221) plt.imshow(th, cmap='gray') plt.title('Binary Kitten') plt.subplot(223) plt.imshow(erosion, cmap='gray') plt.title('Erosed Kitten') plt.subplot(224) plt.imshow(dilation, cmap='gray') plt.title('Dilated Kitten') plt.suptitle('Binary Kitten with morphology', size=15) plt.show() Grayscale\u0026nbsp;Morphology Morphology Operation을 Grayscale Image에 적용하게 되면 기본 원리는 동일하지만 결과가 아주 달라집니다. 1, 0의 값을 사용하는 것이 아니라 Dilation의 경우 Max값을, Erosion의 경우 Min 값을 사용한다는 점이 다른 점 입니다. 자세한 것은 아래 수식을 통해 확인할 수 있습니다. grayscale dilation : $ (I\\oplus k)(j,i)=max_{(y,x)\\subseteq k} (I(j-y,i-x)+k(y,x))$ grayscale erosion : $ (I\\ominus k)(j,i)=min_{(y,x)\\subseteq k} (I(j+y,i+x)-k(y,x))$ I = Image, k = kernel 수식에서 알 수 있듯 Min, Max연산이 적용됩니다. Dilation의 경우 큰 값을 더 크게, 작은 값을 더 작게 하여 픽셀값간의 차이를 극대화하는 연산이고, Erosion의 경우 큰 값을 작게, 작은 값을 크게 하여 전체적으로 평평하게 만드는 연산입니다. kernel = np.array([[1, 2, 1]]) gray_kernel = np.dot(kernel.T, kernel) gray_erosion = cv2.erode(img, gray_kernel, iterations=1) gray_dilation = cv2.dilate(img, gray_kernel, iterations=1) plt.subplot(221) plt.imshow(img, cmap='gray') plt.title('Gray Kitten') plt.subplot(223) plt.imshow(gray_erosion, cmap='gray') plt.title('Gray Erosed Kitten') plt.subplot(224) plt.imshow(gray_dilation, cmap='gray') plt.title('Gray Dilated Kitten') plt.suptitle('Gray Kitten with morphology', size=15) plt.show() 어떤 Image에 커널을 적용하느냐가 Morphology Operation 의 핵심입니다. 물론 어떤 커널을 설계하느냐도 중요하지만, 어떤 연산을 어떤 순서로 몇 번 씩 적용할 것인가 또한 결과물에 많은 영향을 끼칩니다. 위 결과물을 얻는데 사용한 kernel은 가운데쪽에 더 많은 가중치를 주게 되어 주변과의 명암 차이를 더 크게 하는 효과가 있습니다. Morphology연산은 Heuristic한 특성이 크게 드러나는 연산입니다. 다양한 특성이 존재하는 Image 전체에 일괄적으로 동일한 Morphology Operation을 적용하는 것은 대부분 의미가 없고, 동일한 특성을 가진 부분에 특정한 목적 위해 적용하는 편이 좋습니다. 이러한 작업을 잘 하기 위해서는 결국 다양한 Image에 다양한 방법으로 다양한 커널을 적용해보면서 감을 잡아야 합니다. Composited\u0026nbsp;Morphological\u0026nbsp;Operations 앞서 소개한 두 Morphology Operation을 번갈아 한 번 씩 적용하는 작업 또한 상당히 빈번하게 사용됩니다. 한 번 변형한 Mask를 원래 크기로 되돌리기 위해서인데, 이러한 작업을 통해 원하는 노이즈만 제거된 결과를 얻을 수 있습니다. 작업을 진행하는 순서에 따라 아래 두 가지로 나눌 수 있습니다. Erosion\u0026rarr;Dilation의 경우 Open(열기) Dilation의\u0026rarr;Erosion 경우 Close(닫기) Open은 1 값을 갖는 노이즈를 줄이고, Close는 0값을 갖는 노이즈를 줄이는데 사용됩니다. ret, th = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3)) erosion = cv2.erode(th, kernel, iterations=1) dilation = cv2.dilate(th, kernel, iterations=1) opened = cv2.dilate(erosion, kernel, iterations=1) closed = cv2.erode(dilation, kernel, iterations=1) plt.subplot(221) plt.imshow(th, cmap='gray') plt.title('Binary Kitten') plt.subplot(223) plt.imshow(opened, cmap='gray') plt.title('Opened Kitten') plt.subplot(224) plt.imshow(closed, cmap='gray') plt.title('Closed Kitten') plt.suptitle('Binary Kitten with double morphology', size=15) plt.show() Gray Scale Image에도 동일한 작업을 진행할 수 있습니다. gray_open = cv2.dilate(gray_erosion, kernel, iterations=2) gray_close = cv2.erode(gray_dilation, kernel, iterations=2) plt.subplot(221) plt.imshow(img, cmap='gray') plt.title('Gray Kitten') plt.subplot(223) plt.imshow(gray_open, cmap='gray') plt.title('Gray opened Kitten') plt.subplot(224) plt.imshow(gray_close, cmap='gray') plt.title('Gray closed Kitten') plt.suptitle('Gray Kitten with double morphology', size=15) plt.show() Conclusion Morphology Operation은 주로 Binary Image로 생성한 RoI Mask를 다루는데 많이 쓰입니다. 개인적으로 RoI Mask의 Denoising에 매우 유용하게 사용하고 있고, Edge Detection 등의 연산과 연계하는 등 활용 방안이 아주 많으니 꼭 익혀두시는 것을 추천드립니다. Reference [1] 오일석, \u0026ldquo;모폴로지,\u0026rdquo; in 컴퓨터 비전, vol.4, Republic of Korea:한빛아카데미, 2014, pp. 97-103 [2] Accessed: \u0026lsquo;Mathematical morphology\u0026rsquo;, Wikipedia. [Online]. Available: https://en.wikipedia.org/wiki/Mathematical_morphology ","date":1593479400,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1593479400,"objectID":"db9e772e7f6e9f40621baead20d8c3ab","permalink":"/post/2020-06-30-morphology/","publishdate":"2020-06-30T10:10:00+09:00","relpermalink":"/post/2020-06-30-morphology/","section":"post","summary":"Morphology Operations using OpenCV","tags":[],"title":"[Tutorial] Morphology","type":"post"},{"authors":["young-kim","whi-kwon"],"categories":[],"content":" Basic image operation 이번 장 에서는 이미지에 다양한 효과를 줄 수 있는 이미지 연산 방법에 대하여 알아보겠습니다. 이미지로 할 수 있는 기본 연산을 총 네 가지로 나누어서 설명하겠습니다. 각각의 기본 연산들을 조합해서 훨씬 더 많은 효과를 낼 수 있습니다. 네 가지 기본 연산은 아래와 같습니다. Dot Operation Area Operation Geometric Operation Interpolation Import Libraries import os import sys import math from platform import python_version import cv2 import matplotlib.pyplot as plt import matplotlib import numpy as np print(\u0026quot;Python version : \u0026quot;, python_version()) print(\u0026quot;Opencv version : \u0026quot;, cv2.__version__) matplotlib.rcParams['figure.figsize'] = (4.0, 4.0) Python version : 3.6.9 Opencv version : 4.1.2 Data load sample_image_path = '../image/' sample_image = 'kitten.jpg' img = cv2.imread(os.path.join(sample_image_path, sample_image), cv2.IMREAD_GRAYSCALE) h, w = img.shape Data description 본 예제에서 사용할 데이터는 아래와 같습니다. 귀여운 아기 고양이 입니다[7]. plt.imshow(img, cmap='gray') plt.title('Kitten') plt.show() Dot\u0026nbsp;operation Dot Operation이란, Source Image의 Pixel과 Target Image의 Pixel간의 1:1 연산을 말합니다. 이것을 수식으로는 아래와 같이 표현할 수도 있습니다. $pixel(i, j)_{after} = f(pixel(i, j)_{before})$ 여기에서 다시 함수 $f$에 따라 Affine[2] , Gamma[3] 연산으로 나눌 수 있습니다. 아래 코드는 몇 가지 Affine Operation 예시 입니다. bright_img = img + 50 bright_img[img \u0026gt; 155] = 255 dark_img = img - 50 dark_img[img \u0026lt; 100] = 0 reverse_img = 255 - img plt.figure(figsize=(8, 8)) plt.subplot(2, 2, 1) plt.imshow(img, cmap='gray') plt.title('Gray Kitten') plt.subplot(2, 2, 2) plt.imshow(bright_img, cmap='gray') plt.title('Bright Kitten') plt.subplot(2, 2, 3) plt.imshow(dark_img, cmap='gray') plt.title('Dark Kitten') plt.subplot(2, 2, 4) plt.imshow(reverse_img, cmap='gray') plt.title('Reversed Kitten') plt.suptitle('Kitten with affine transform.', size=15) plt.show() 아래 코드는 Gamma Correlation Operation 예시 입니다. bright_gamma = 0.5 dark_gamma = 1.5 bright_gamma_image = np.uint8(255 * np.power(img / 255, bright_gamma)) dark_gamma_image = np.uint8(255 * np.power(img / 255, dark_gamma)) plt.figure(figsize=(8, 8)) plt.subplot(2, 2, 1) plt.imshow(img, cmap='gray') plt.title('Gray Kitten') plt.subplot(2, 2, 3) plt.imshow(bright_gamma_image, cmap='gray') plt.title('Gamma Bright Kitten') plt.subplot(2, 2, 4) plt.imshow(dark_gamma_image, cmap='gray') plt.title('Gamma Dark Kitten') plt.suptitle('Kitten with gamma correlation transform.', size=15) plt.show() Gamma Correlation Transform과 Affine Transform이 각각 Image에 끼치는 영향이 어떤 차이가 있을까요? 변환된 각 Image의 Histogram을 확인해보면 차이를 확실히 알 수 있습니다. def histogram_cv(img): h, w = img.shape[:2] hist = cv2.calcHist([img], [0], None, [256], [0, 256]) hist = hist / (h * w) return hist plt.figure(figsize=(12, 8)) plt.subplot(2, 3, 1) plt.imshow(img, cmap='gray') plt.title('Kitten') plt.subplot(2, 3, 2) plt.imshow(bright_img, cmap='gray') plt.title('Affine bright Kitten') plt.subplot(2, 3, 3) plt.imshow(bright_gamma_image, cmap='gray') plt.title('Gamma bright Kitten ') plt.subplot(2, 3, 4) plt.plot(histogram_cv(img)) plt.title('Kitten Histogram') plt.subplot(2, 3, 5) plt.plot(histogram_cv(bright_img)) plt.title('Affine bright Kitten Histogram') plt.subplot(2, 3, 6) plt.plot(histogram_cv(bright_gamma_image)) plt.title('Gamma bright Kitten Histogram') plt.suptitle('Histogram comparison', size=15) plt.show() 원래 Image와 변환된 Image들의 Histogram 입니다. Affine 변환의 경우 픽셀값에 상수를 더하여 밝게 만들고, 픽셀값의 최대치인 255에 도달하면 그냥 255에 놔두는 반면, Gamma Correlation 변환의 경우 히스토그램의 분포 형태를 어느 정도 유지하며 밝아지는 모습을 확인할 수 있습니다. 이 두 연산의 차이는 그림과 히스토그램을 같이 볼 때 더 크게 체감이 됩니다. Affine Operation을 적용한 경우, 가장 밝은 부분부터 뭉개지는 듯한 모습인 반면, Gamma Operation을 적용할 경우 원래 형태를 유지하며 밝아지는 모습입니다. Area\u0026nbsp;operation Area Operation이란, Target Image의 한 Pixel값을 결정하기 위해 Source Image의 여러 개의 Pixel값을 필요로 하는 연산을 말합니다. Source Image의 여러 Pixel값들에 특정 가중치를 부여하고, Source Image와 가중치의 곱의 합을 구하여 Target Image를 구하는 방법이 일반적 입니다. 여기에서 특정 가중치를 구할 때, 일정한 크기의 Mask에만 유효한 값을 부여하고 나머지 영역에는 0을 부여하곤 합니다. 이러한 연산을 Correlation, 혹은 Convolution이라고 합니다. Correlation과 Convolution은 엄밀히 말하면 서로 다른 연산이나, Image Processing의 특성상 거의 같은 연산인 것으로 생각하고 넘어가겠습니다. OpenCV에서 \u0026lsquo;cv2.filter2D()\u0026rsquo; 를 통해 쉽게 적용할 수 있고, 몇몇 자주 쓰이거나 특별한 연산의 경우 따로 정의된 함수가 존재하기도 합니다. (e.g)Median Filter[4] 는 \u0026lsquo;cv2.medianBlur(img,kernel)\u0026rsquo; 을 통해 제공되는데, 엣지 정보를 잘 남겨두면서 노이즈를 제거하는 방법으로 알려져 있습니다. 어떠한 Mask를 사용하느냐에 따라 결과 영상의 특성이 천차 만별로 달라질 수 있습니다. 아래 예시중 수평, 수직방향 Edge를 각각 구한 결과가 있습니다. 예시에서 사용된 Mask가 Sobel Filter의 초기 모델이며, Edge Detection에서 자세히 다루겠습니다. Sharpen이라는 기법은 물체의 Edge를 강하게 드러내는 방법중 하나 입니다. 위 연산들은 앞서 말했다시피 완전히 다른 결과를 만들지만, 적용하는 Mask만 다를 뿐 같은 함수 호출을 통해 만들어낸 결과임을 주목합시다. blur_mask = np.ones((3, 3), dtype=np.uint8) / 9 horiz_edge_mask = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]]) vert_edge_mask = np.array([[1, 0, -1], [1, 0, -1], [1, 0, -1]]) sharp_mask = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]]) dst1 = cv2.filter2D(img, -1, blur_mask) dst2 = cv2.filter2D(img, -1, horiz_edge_mask) dst3 = cv2.filter2D(img, -1, vert_edge_mask) dst4 = cv2.filter2D(img, -1, sharp_mask) dst4_blur = cv2.medianBlur(dst4, 3) plt.figure(figsize=(12,8)) plt.subplot(231) plt.imshow(dst1, cmap='gray') plt.title('Blurring') plt.subplot(232) plt.imshow(dst4, cmap='gray') plt.title('Sharpen') plt.subplot(233) plt.imshow(dst4_blur, cmap='gray') plt.title('Sharpen with Median') plt.subplot(234) plt.imshow(dst2, cmap='gray') plt.title('Horizontal edge') plt.subplot(235) plt.imshow(dst3, cmap='gray') plt.title('Vertical edge') plt.suptitle('Kitten with different operation', size=15) plt.show() Geometric\u0026nbsp;operation 세 번째 Geometric Operation은 영상에 이동, 크기, 회전, 기울임 등의 효과를 주는 것을 말합니다. 물체의 기하학적 특징이 탄력적으로 보존되는 변환입니다. 찢거나 구기거나 흐릿하게 만들거나 하지 않고, 눈 두개 사이에 코가 있다는 등의 특성이 기울어지든, 회전하든 그대로 유지된다는 의미로 받아들이시면 됩니다. 4가지 기본적인 연산을 순차적으로 조합하여 수 많은 변환을 수행할 수 있습니다[5]. e.g. 특정 점을 기준으로 회전, 좌우 반전(Flip), 시점 변환(Perspective transform) 등 OpenCV에서 지원하는 \u0026lsquo;cv2.getAffineTransform()\u0026rsquo;, \u0026lsquo;cv2.warpAffine()\u0026rsquo; 함수를 통해 Geometric Operation을 적용할 수 있습니다. 여기에서 함수 이름에 들어가는 Affine 때문에 헷갈리는 경우가 있을 수 있을 것 같습니다. Dot Operation에서 소개한 Affine Operation은 개별 픽셀값 하나에 대한 Affine연산이며, 여기에서 나온 Affine의 의미는 Image의 전체 픽셀들에 대하여 지역적으로 적용하는 Affine 연산입니다. 이 둘의 차이는, 어떤 픽셀에 대하여 그 \u0026lsquo;값\u0026rsquo;을 바꾸느냐, 혹은 그 \u0026lsquo;위치\u0026rsquo;를 바꾸느냐에 따라 나뉘는 것으로 생각하시면 되겠습니다. pts1 = np.float32([[50, 50], [200, 50], [50, 200]]) pts2 = np.float32([[10, 100], [200, 50], [100, 250]]) M = cv2.getAffineTransform(pts1, pts2) dst1 = cv2.warpAffine(img, M, (w, h)) M = cv2.getRotationMatrix2D((w / 2, h / 2), -30, 1) dst2 = cv2.warpAffine(img, M, (w, h)) plt.figure(figsize=(12, 4)) plt.subplot(1, 3, 1) plt.imshow(img, cmap='gray') plt.title('Input') plt.subplot(1, 3, 2) plt.imshow(dst1, cmap='gray') plt.title('Affine') plt.subplot(1, 3, 3) plt.imshow(dst2, cmap='gray') plt.title('Rotation') plt.suptitle('Lena with geometric transform') plt.show() 간단하게 고양이 Image를 뒤틀고, 회전시켜본 예시입니다. 각 함수의 자세한 사용법은 OpenCV 공식 문서[6]에서 확인할 수 있습니다. Interpolation Image의 크기를 바꾸는 경우(특히 확대할 때), 원본 Image의 픽셀과 픽셀 사이에 새로운 값이 생성되는 것이므로 이 새로운 값을 어떻게 채워야 할 지에 대한 문제가 발생하게 됩니다. 단순하게 한 쪽 픽셀 값을 그대로 가져다가 적용할 경우 영상이 실질적으로 해상도가 커지는 것이 아니라, 단순히 크기만 키우는 것 이라고 볼 수 있습니다. 이와 반대로 (머신러닝 등의 방법 없이)더 좋은 해상도의 Image를 얻기 위하여 Interpolation을 사용합니다. OpenCV는 다양한 Interpolation(보간법)을 제공하는데, \u0026lsquo;cv2.resize()\u0026rsquo; 함수의 인자 \u0026lsquo;interpolation\u0026rsquo; 으로 조절할 수 있습니다. \u0026lsquo;cv2.INTER_NEAREST\u0026rsquo; - 최근접 이웃 픽셀의 값을 사용함. (size의 단순한 확대) \u0026lsquo;cv2.INTER_LINEAR\u0026rsquo; - 양 선형 보간 (default 값) \u0026lsquo;cv2.INTER_AREA\u0026rsquo; - 영역의 넓이에 기반한 방법. (사이즈를 줄일 때 좋은 성능) \u0026lsquo;cv2.INTER_CUBIC\u0026rsquo; - 양 3차 보간 : 양 선형 보간법 보다 4배 많은 정보를 활용. \u0026lsquo;cv2.INTER_LANCZOS4\u0026rsquo; - Lanczos 보간 : 양 3차 보간법 보다 4배 많은 정보를 활용. h, w = [int(x) for x in img.shape] face_img = img[h // 2 - 60 : h // 2 + 80, w // 2 - 110 : w // 2 + 30] h, w = [int (x) for x in face_img.shape] dst3 = np.zeros([h * 2, w * 2]) for i in range(h): for j in range(w): dst3[2 * i, 2 * j] = face_img[i, j] dst3[2 * i + 1, 2 * j + 1] = face_img[i, j] dst3[2 * i, 2 * j + 1] = face_img[i, j] dst3[2 * i + 1, 2 * j] = face_img[i, j] dst4 = cv2.resize(face_img, (w * 2, h * 2)) dst5 = cv2.resize(face_img, (w * 2, h * 2), interpolation=cv2.INTER_CUBIC) dst6 = cv2.resize(face_img, (w * 2, h * 2), interpolation=cv2.INTER_LANCZOS4) plt.figure(figsize=(4, 4)) plt.imshow(face_img, cmap='gray') plt.title('original') plt.show() plt.figure(figsize=(16, 16)) plt.subplot(2, 2, 1) plt.imshow(dst3, cmap='gray') plt.title('resize manual') plt.subplot(2, 2, 2) plt.imshow(dst4, cmap='gray') plt.title('resize bilinear') plt.subplot(2, 2, 3) plt.imshow(dst5, cmap='gray') plt.title('resize cubic') plt.subplot(2, 2, 4) plt.imshow(dst6, cmap='gray') plt.title('resize lanczos4') plt.show() 아기 고양이의 얼굴만 확대한 Image를 통해 Interpolation 방법에 따른 Image 품질 차이를 확인해보겠습니다. Manual Resize된 Image와 Interpolation이 적용된 Image와의 품질 차이는 확실히 드러납니다. 나머지 Interpolation이 적용된 Image들의 품질을 여러분의 눈으로는 확인 가능하신가요? 자세히 보시면 보일겁니다. Bilinear Interpolation은 새로운 픽셀의 값을 계산할 때 양 옆의 두 픽셀만을 고려하기 때문에 계산량이 다소 적은 편 입니다. Cubic, Lanczos4 등의 방법론은 더 많은 주변 픽셀들을 고려하기 때문에 일반적으로 Bilinear보다 더 높은 품질의 결과물을 보여줍니다. 연산 효율이 중요할 경우에는 bilinear interpolation을, 결과물의 품질이 중요한 경우에는 Cubic이나 Lanczos4중에서 선택하시면 됩니다. Conclusion Image에 적용하는 기본 연산들을 알아보았습니다. 원하는 효과를 내기 위해 다양한 방식으로 연산을 조합해서 눈으로 직접 확인해보시면 많은 도움이 될 것 입니다. Reference [1] 오일석, \u0026ldquo;영상 처리의 세 가지 기본 연산,\u0026rdquo; in 컴퓨터 비전, vol.4, Republic of Korea:한빛아카데미, 2014, pp. 76-92 [2] Accessed: \u0026lsquo;Affine transformation\u0026rsquo;, Wikipedia. 2019 [Online]. Available: https://en.wikipedia.org/wiki/Affine_transformation [3] Accessed: \u0026lsquo;Gamma correction\u0026rsquo;, Wikipedia. 2019 [Online]. Available: https://en.wikipedia.org/wiki/Gamma_correction [4] Accessed: \u0026lsquo;Median filter\u0026rsquo;, Wikipedia. 2019 [Online]. Available: https://en.wikipedia.org/wiki/Median_filter [5] Accessed: \u0026lsquo;Denavit–Hartenberg parameters\u0026rsquo;, Wikipedia. 2019 [Online]. Available: https://en.wikipedia.org/wiki/Denavit%E2%80%93Hartenberg_parameters [6] Accessed: \u0026lsquo;Geometric Image Transformations\u0026rsquo;, \u0026lsquo;OpenCV 2.4.13.7 documentation\u0026rsquo;. 2019 [Online]. Available: https://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html [7] Accessed: \u0026lsquo;Free Cat, Kitten Adoptions In Anne Arundel\u0026rsquo;, Patch. 2018 [Online]. Available: https://patch.com/maryland/annearundel/free-cat-kitten-adoptions-anne-arundel ","date":1593478800,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1593478800,"objectID":"0795699c344e6fe9679e04ea4e40b01a","permalink":"/post/2020-06-30-basic_image_operation/","publishdate":"2020-06-30T10:00:00+09:00","relpermalink":"/post/2020-06-30-basic_image_operation/","section":"post","summary":"Image Operations using OpenCV","tags":[],"title":"[Tutorial] Basic Image Operation","type":"post"},{"authors":["kyunghwan-kim"],"categories":[],"content":" 강화학습의 혈관 속 탐험 시리즈 강화학습의 혈관 속 탐험 (1) - 로봇과 심혈관 중재 시술 강화학습의 혈관 속 탐험 (2) - 강화학습과 제어 이론의 비교 강화학습의 혈관 속 탐험 (3) - 실험환경 구성과 강화학습 알고리즘 소개\nIntro 강화학습으로 특정 task를 학습하기 위해서는 에이전트가 될 강화학습 알고리즘을 선정하고 에이전트가 상호작용할 환경을 구성해야합니다. 이번 포스트에서는 저희가 강화학습으로 PCI 로봇을 제어하기 위해 사용한 알고리즘과 환경에 대해 소개하겠습니다.\n 실험 환경 구성 PCI 시술 환경 혈관 모형을 이용한 실험 환경 구성 알고리즘 선정 On-policy vs Off-policy Human demo 활용 유 vs 무 Discrete action vs Continuous action 학습 결과 마치며 \n실험 환경 구성 강화학습 에이전트(Agent)는 아래 그림과 같이 상태(state)에서의 행동(action)을 선택하고 얻는 보상(reward)을 통해 학습합니다. 이때 상태와 보상 등의 정보들을 환경과의 상호작용을 통해 얻습니다. 이러한 학습 프로세스를 그림으로 표현하면 아래 그림과 같습니다. 환경이 제대로 구성되지 않으면 어떤 강화학습 알고리즘을 쓰더라도 제대로 학습할 수 없습니다. 그렇기 때문에 강화학습에서 환경은 아주 중요한 개념입니다. 강화학습의 환경은 주로 우리가 풀고 싶은 문제를 시뮬레이터로 제작하여 가상 환경으로 구성하는 방법과 해당 문제를 실제 real world에서 반복 가능한 형태로 실험 환경을 구성하는 방법이 있습니다. 저희는 PCI에서의 가이드와이어 제어 문제를 풀고자 하기 때문에 시술 과정을 강화학습 에이전트가 상호작용 가능한 환경의 형태로 만들 필요가 있습니다. 이를 위해 PCI의 과정을 알아봅시다.\n\n\nPCI 시술 환경 PCI 시술에서 시술자가 환자의 혈관 모양과 현재 가이드와이어의 위치를 X-ray 조영 영상을 통해 봅니다. 현재 병변 위치가 어디인지, 제어하고 있는 가이드와이어의 모양과 위치가 어디인지 등의 정보를 모두 2D 이미지를 통해 확인합니다. 시술자는 이미지 정보를 바탕으로 가이드와이어를 어떻게 움직여야 할지 판단합니다. 가이드와이어를 움직이면 다시 조영 영상이 바뀌게 되고 시술자는 영상을 보고 다시 와이어를 움직입니다. 숙련된 시술자는 이러한 과정을 굉장히 빠르게 수행하여 환자의 병변 부위를 치료합니다. 이런 프로세스를 위의 강화학습 프로세스에 맞게 표현하면 다음 그림과 같습니다 [1]. 시술자는 에이전트, 환자의 혈관과 X-ray 시술 장비가 환경, X-ray 조영 영상이 상태, 가이드와이어를 움직이는 것이 행동이 됩니다.\n PCI 시술에 대한 자세한 내용은 이전 포스트인 강화학습의 혈관 속 탐험 (1) - 로봇과 심혈관 중재 시술을 참고하시기 바랍니다.\n \n\n혈관 모형을 이용한 실험 환경 구성 이전 포스트에서 언급한 것처럼 PCI 시술은 가이드와이어의 마찰, 사람의 호흡, 심장의 박동 등의 이유로 모델링이 굉장히 어렵습니다. 모델링이 어렵다는 것은 다시 말해 시뮬레이터와 같은 가상 환경으로 제작하기 어렵다는 뜻입니다. 따라서 저희는 시뮬레이터보다는 혈관 모형을 이용한 real world 실험 환경을 구성하였습니다. 실제 시술에서 의사가 X-ray 이미지를 보고 가이드와이어를 어떻게 제어할 지 판단하듯이 강화학습 에이전트는 2D 혈관 모형의 이미지를 보고 결정합니다. 결정한 제어 신호를 PCI 로봇으로 전달하여 실제 가이드와이어를 제어하게 됩니다. 이를 위의 시술 과정 프로세스와 같이 표현하면 아래 그림과 같습니다. 강화학습 알고리즘이 에이전트, 로봇과 2D 혈관 모형이 환경, 2D 혈관 모형 이미지가 상태, 가이드와이어 제어 로봇을 움직이는 것이 행동이 됩니다. \n\n알고리즘 선정 이렇게 강화학습 에이전트를 학습시키기 위한 환경이 준비가 되었습니다. 이제 에이전트가 상호작용할 환경이 준비가 되었으니 이제 어떤 에이전트를 학습시킬 것인가를 결정해야합니다. 즉, 어떤 강화학습 알고리즘을 쓸 지 결정해야합니다. 현재까지도 굉장히 많은 강화학습 알고리즘들이 연구되고 있고 각 알고리즘들마다 특성이 다르고 장단점이 있기 때문에 저희 환경에 적합하고 저희가 실험하고자 하는 방향과 맞는 알고리즘을 선택할 필요가 있었습니다. 여러가지 고려사항 중 저희가 크게 고민했던 부분은 다음과 같습니다.\n On-policy vs Off-policy Human demo 활용 유 vs 무 Discrete action vs Continuous action \nOn-policy vs Off-policy On-policy와 Off-policy는 강화학습에서 많이 언급되는 내용 중 하나입니다. 이 두 가지 개념을 이해하려면 몇 가지 강화학습의 개념들을 알아야합니다.\n 정책 (Policy): 강화학습에서 정책은 어떤 상태가 주어졌을때 행동에 대한 확률분포를 말합니다. 정책은 학습을 통해 우리가 원하는 더 좋은 정책으로 만들 수 있습니다. 만약 현재 정책이 최적의 정책이라면 이 정책으로 모든 상태에 대해서 행동을 했을 때 가장 높은 누적 보상을 받게 됩니다. 아래 이미지에서 정책의 예시를 표현하였습니다. 각 네모칸이 상태이고 회색 네모칸이 보상을 받는 상태라고 한다면 $\\pi_4$가 최적의 정책이라 할 수 있습니다. \n아래 이미지에서 정책의 다른 예시를 보여줍니다. 각 상황에서 캐릭터가 죽지 않으려면 점프하는 행동이 가장 확률이 높아야합니다. \n 이 아래부터는 정책이라는 단어보다 policy라는 단어를 사용하도록 하겠습니다.\n 경험 (Experience): 강화학습 알고리즘을 학습하기 위해서는 환경과 상호작용해서 얻은 상태와 행동, 보상 등의 경험(experience)을 얻어야 합니다. 이러한 경험들이 강화학습에서의 데이터라고 할 수 있습니다. On-policy는 학습하는 policy와 행동하는 policy가 같은 알고리즘을 말합니다. 즉, On-policy는 현재 학습하는 policy를 통해서 얻은 경험만을 이용해 학습할 수 있습니다. 다른 policy가 얻은 경험 뿐만 아니라 과거의 policy로 얻은 경험 또한 사용할 수 없습니다. Off-policy는 이와 반대로 학습하는 policy와 행동하는 policy가 다른 알고리즘을 말합니다. 현재 학습하고 있는 에이전트가 과거에 모았던 경험 뿐만 아니라 지금 학습하고 있는 에이전트와 완전히 다른 에이전트가 만든 경험들까지도 학습에 사용할 수 있습니다.\n딥 강화학습 알고리즘에서 on-policy와 off-policy는 experience replay의 사용 여부에서 차이가 납니다. Experience replay는 환경을 통해 얻은 경험들을 버퍼에 쌓고 batch 단위로 샘플링하여 학습하기 때문에 off-policy 방법이라고 할 수 있습니다. 딥 강화학습에서 on-policy는 대표적으로 TRPO [2], PPO [3]가 있으며 off-policy는 DQN [4], DDPG [5]가 있습니다. 아래 이미지는 experience replay를 사용하는 off-policy 알고리즘의 학습 사이클을 설명합니다.\n\nPPO와 같은 On-policy 알고리즘은 이전 경험을 사용할 수 없기 때문에 현재 데이터를 많이 모으기 위해서 주로 환경을 분산처리시키는 방법을 사용합니다. 그렇지 않으면 과거의 데이터를 사용할 수 없기 때문에 off-policy와 학습 속도에서 차이가 나게 됩니다. 하지만 저희가 구축한 환경은 가상 시뮬레이션 환경이 아닌 real world 환경이기 때문에 분산처리 환경을 구축하기가 어렵습니다. 4개의 환경을 분산처리 하려면 4개의 로봇과 혈관 모형, 카메라 세트가 필요하기 때문이죠. 이러한 이유로 저희는 real world 환경에서는 off-policy 알고리즘이 적합하다고 생각하였습니다.\n\nHuman demo 활용 유 vs 무 Off-policy 알고리즘은 현재 학습하고 있는 에이전트가 모은 경험 뿐만아니라 다른 경험 또한 학습 데이터로 사용할 수 있습니다. 이는 에이전트가 아닌 사람이 만든 경험도 마찬가지입니다. 강화학습 에이전트는 학습 초기에는 환경을 탐험해도 무작위 행동과 같은 수준의 경험만을 모을 수 있습니다. 이러한 경험들도 물론 학습에 유용한 경험들이지만 무작위 행동만으로 해당 환경의 목표(goal)에 도달하는 경험을 많이 얻는 데에는 오랜 시간이 필요합니다. 그런데 만약 이미 숙련된 사람이 만든 경험을 학습에 사용할 수 있다면 어떨까요? 특정 환경에 숙련된 사람이 만든 경험은 에이전트 입장에서는 완벽히 이상적인 경험이 아닐 수도 있지만 적어도 학습 초기의 에이전트보다는 훨씬 좋은 경험일 것입니다. 또한 환경의 목표(goal)에 도달하는 경험이기 때문에 무작위로 탐험한 경험만을 이용해 학습하는 것보다 훨씬 빠르게 에이전트를 학습시킬 수 있습니다. 이런 사람이 만든 경험을 human demonstration 이라고 합니다.\n강화학습에 human demo를 사용해서 학습 성능을 높히려는 연구가 많이 되고 있습니다 [6, 7, 8]. 특히 저희의 환경은 real world 환경이기 때문에 가상 환경에 비해 환경의 안정성을 보장하기 어렵습니다. 예를 들어 장시간 학습을 돌리다 보면 로봇에 이상이 생기거나 가이드와이어, 카테터와 같은 의료 도구들이 파손되어 같은 행동을 해도 기존과는 다른 동작이 되는 경우가 생깁니다. 이를 방지하기 위해서는 최대한 학습 속도를 빠르게 하는 것이 중요합니다. 빠른 학습이 환경의 안정성을 높히는 길인 것이죠. 따라서 저희는 human demo를 활용한 알고리즘을 사용하기로 하였습니다.\n\nDiscrete action vs Continuous action 강화학습에서의 행동은 Discrete action과 Continuous action으로 나눌 수 있습니다. 알고리즘에 따라 특정 action space는 학습이 아예 불가능한 경우도 있기 때문에 강화학습 알고리즘을 선정할 때 중요한 요인 중 하나입니다.\nDiscrete action Discrete 하게 결정되는 행동을 말합니다. 즉, 중간 값이 없고 0 또는 1의 값을 갖습니다. 예를 들어, [전진, 후진, 회전] 이라는 행동이 있을 때 전진 행동은 [1, 0, 0]과 같이 선택합니다. 중간 값은 없으며 Discrete action으로 다양한 행동을 표현하려면 행동의 개수를 늘려야합니다. 예시: [전진 1cm, 전진 2cm, 후진 1cm, 후진 2cm, 회전] 주로 Q learning과 같은 value-based 알고리즘으로 학습합니다. Continuous action Continuous action은 실수 값을 가지며 값의 크기를 표현할 수 있습니다. 예를 들어, [전/후진, 회전] 이라는 행동이 있을 때 [0.3, 0.4]과 같이 전/후진, 회전 값을 실수 값으로 지정할 수 있습니다. 행동 값의 범위가 무한하기 때문에 action space의 크기가 큽니다. 주로 Policy gradient와 같은 policy-based 알고리즘으로 학습합니다. \n저희가 구성한 혈관 모형 환경에서 action space를 결정하기 위해 저희가 고려한 사항은 다음과 같습니다.\n PCI 로봇의 동작: 기계 구조상 전진과 회전 동작을 동시에 조작할 경우 가이드와이어가 이탈하거나 꼬일 위험이 있음. human demo 제작의 용이성: 키보드 입력으로 손쉽게 human demo의 생성이 가능해야함. 중간 값의 필요성: 혈관 모형 환경에서는 전진과 회전 값의 scale을 고정하는 것이 더 유리하다고 판단함. 이외에도 여러 상황을 고려했을 때 혈관 모형 학습 환경은 discrete action으로 구성하여도 충분하다고 판단하였습니다.\n따라서 off-policy + discrete action인 DQN을 학습 알고리즘으로 선정하였습니다. DQN은 많은 연구를 통해 기존 DQN의 여러 단점을 보완한 다양한 변형 DQN들이 나왔는데 그 중 state-of-the-art로 알려진 Rainbow를 사용하기로 하였습니다. 추가로 human demo를 이용해 학습하는 아이디어인 from demonstration(fD) 알고리즘을 결합하여 RainbowfD로 최종 결정하였습니다 [9].\n\n학습 결과 저희가 혈관 모형 환경을 구성한 환경과 에이전트의 최종 목표는 로봇으로 가이드와이어를 제어하여 원하는 위치까지 이동시키는 것이었습니다. 이를 학습시키기 위해 상태 이미지를 다양한 컴퓨터 비전 기술을 이용해 전처리하였습니다. 그리고 목표(goal)를 상태 이미지에 표시해주어 에이전트가 목표를 명확하게 알 수 있도록 해주었습니다.\n\n이렇게 구성한 환경에서 선정한 RainbowfD 알고리즘을 통해 학습시킨 결과 가이드와이어를 원하는 위치까지 성공적으로 제어하였습니다! 학습 결과는 아래 영상을 통해 확인할 수 있습니다.\n 아래 영상은 TCT 2019 학회의 포스터 세션에서 발표한 영상입니다 [10].\n \n\n마치며 이번 포스트에서는 강화학습으로 PCI에서의 가이드와이어 제어를 학습하기 위한 방법을 구체적으로 소개하였습니다. 강화학습으로 특정 문제를 풀기 위해서는 환경을 구축해야하고, 환경과 문제에 맞는 강화학습 알고리즘을 선택해야합니다. 이러한 환경 구축과 알고리즘 선정 과정에서 저희가 했던 방식을 설명하였습니다. 강화학습은 보통 게임이나 가상환경에서 학습한 예제는 많지만 실제 환경에 적용한 사례는 드뭅니다. 다른 환경에 강화학습을 시도하고자 하는 분들에게 저희가 시도하고 고민했던 방식이 한 가지 예시로써 많은 도움이 되기를 바랍니다. 이번 포스트를 끝으로 강화학습의 혈관 속 탐험 시리즈는 마무리됩니다. 차후 다른 내용으로 포스트 올리도록 하겠습니다.\n 이 포스트는 2019년에 RL Korea와 모두콘에서 발표한 \u0026ldquo;Rainbow의 혈관 속 탐험\u0026rdquo; 발표를 기반으로 작성하였습니다.\n Reference [1] CAG 이미지 출처: https://www.researchgate.net/figure/CAG-images-of-the-first-PCI-a-Coronary-stenosis-in-the-proximal-mid-portion-of-LAD_fig1_316498381 [2] TRPO: Schulman, John et al., \u0026ldquo;Trust region policy optimization.\u0026rdquo; In International Conference on Machine Learning (ICML), 2015a. [3] PPO: J. Schulman et al., \u0026ldquo;Proximal Policy Optimization Algorithms.\u0026rdquo; arXiv preprint arXiv:1707.06347, 2017. [4] DQN: V. Mnih et al., \u0026ldquo;Human-level control through deep reinforcement learning.\u0026rdquo; Nature, 518(7540):529–533, 2015. [5] DDPG: T. P. Lillicrap et al., \u0026ldquo;Continuous control with deep reinforcement learning.\u0026rdquo; arXiv preprint arXiv:1509.02971, 2015. [6] DQfD: T. Hester et al., \u0026ldquo;Deep Q-learning from Demonstrations.\u0026rdquo; arXiv preprint arXiv:1704.03732, 2017. [7] DDPGfD: Mel Vecerik et al., \u0026ldquo;Leveraging Demonstrations for Deep Reinforcement Learning on Robotics Problems with Sparse Rewards.\u0026rdquo; CoRR, 2017. [8] Behavior Cloning: A. Nair et al., \u0026ldquo;Overcoming Exploration in Reinforcement Learning with Demonstrations.\u0026rdquo; arXiv preprint arXiv:1709.10089, 2017. [9] Rainbow: M. Hessel et al., \u0026ldquo;Rainbow: Combining Improvements in Deep Reinforcement Learning.\u0026rdquo; arXiv preprint arXiv:1710.02298, 2017. [10] TCT 2019 Reinforcement learning for guidewire navigation in coronary phantom 포스터 자료: https://www.tctmd.com/slide/reinforcement-learning-guidewire-navigation-coronary-phantom ","date":1590627600,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1590627600,"objectID":"7968452e8b7d31c89c6d04df7c0df54a","permalink":"/post/2020-05-28-adventure_of_rl_in_vessel_3/","publishdate":"2020-05-28T10:00:00+09:00","relpermalink":"/post/2020-05-28-adventure_of_rl_in_vessel_3/","section":"post","summary":"Introduction to guide-wire control for PCI by RL (3) - How to apply RL","tags":[],"title":"강화학습의 혈관 속 탐험 (3) - 실험환경 구성과 강화학습 알고리즘 소개","type":"post"},{"authors":["chaehyeuk-lee","kyunghwan-kim"],"categories":[],"content":" 강화학습의 혈관 속 탐험 시리즈 강화학습의 혈관 속 탐험 (1) - 로봇과 심혈관 중재 시술\n강화학습의 혈관 속 탐험 (2) - 강화학습과 제어 이론의 비교\n강화학습의 혈관 속 탐험 (3) - 실험환경 구성과 강화학습 알고리즘 소개\nIntro 이번 포스트에서는 저희가 왜 PCI 로봇 제어 방법으로 강화학습을 선택하게 되었는지 얘기해보고자 합니다. 이미 수많은 학자와 엔지니어들이 로봇을 위한 효율적이고 뛰어난 제어 이론들을 개발해왔습니다. 이러한 제어 이론들이 어떠한 점에서 강화학습과 다른지 살펴보겠습니다. 먼저, 제어 이론 중 가장 보편적이고 널리 쓰이는 PID 제어와의 비교로 시작하겠습니다.\n PID Control PID Control? Problem in PID Control Reinforcement Learning PID Control vs RL Optimal Control Optimal Control vs RL Model-free를 향해 Conclusion \nPID Control \nPID Control? PID 제어는 Proportional-Integral-Derivative Control의 약자입니다. 현재 산업 현장의 80~90% 이상의 제어기는 이 PID제어 이론을 이용하여 동작을 수행합니다. 그 만큼 이 PID 제어에는 장점이 많습니다. 먼저 알고리즘이 코드 10줄 안에 끝날 정도로 가볍고, 사용하기 쉬우며, 제어 성능이 뛰어납니다. 하지만 이 PID 제어는 단순한 만큼 한가지 문제에만 집중합니다. 바로 Tracking 문제입니다.\n아래 식은 PID 제어를 표현하는 가장 기본적인 식입니다. 아래 식을 살펴보면, 시간 $t$에서의 최종 출력 ${u}_t$는 목표 상태 ${x}_g$와 현재 상태 ${x}_t$의 차이, ${e}_t$에 의해서 결정되는 것을 알 수 있습니다. 즉, PID 제어는 목표 상태와 현재 상태를 가장 최단거리로 잇는 경로 위에서만 동작합니다 [1]. $${u}_t = {K}_p {e}_t + {K}_i \\int_0^t {e}_t dt + {K}_d d{e}_t/dt$$\n그림과 함께 좀 더 자세히 이야기해보겠습니다. 아래 그림에 목표 위치 ${x}_g$와 현재 위치 ${x}_t$가 있습니다. PID제어를 이용하면, ${l}_1$과 같은 경로로 현재 상태가 이동하게 됩니다. 제어기 설계에 따라서 속도가 느려지거나 빨라질 수도, 목표 지점을 넘어갈 수도 있습니다. 하지만 직선 ${l}_1$에서 벗어나지는 않습니다. 예측 불가능한 외란으로 인해 ${x}_2$나 ${x}_3$와 같이 경로에서 벗어날 수 있습니다. 하지만 PID 제어기는 그 경로에서 벗어난 현재 상태로부터 다시 직선 ${l}_2$을 만들고, 그 직선을 따라 움직이려고 합니다. 즉 목표 지점이 바뀌지 않는 한, 현재 상태가 움직이는 경로는 바뀌지 않습니다. \n따라서 PID제어를 이용하여 복잡한 시스템을 제어하기 위해서는, 상태에 따라 목표 지점을 변경해주는 알고리즘, 즉 경로를 생성해주는 알고리즘이 추가로 필요합니다. 하나의 예로 아래와 같은 단순한 로봇팔을 생각해보겠습니다. 로봇팔이 목표 지점을 향해 움직일 때, 로봇 핸드가 직선으로 움직이려면 1번 축과 2번 축은 서로 다른 방향으로 움직여야합니다. 이 각 축의 움직이는 방향과 속도, 즉 최적 경로는 기구학이라는 추가적인 알고리즘을 이용하여 생성해야 합니다. \n\nProblem in PID Control 이처럼 PID 제어를 적용하기 위해서는, 경로를 찾는 문제를 먼저 풀어야합니다. 문제는 가이드와이어의 최적 경로를 찾는 일이 매우 어렵다는 것입니다.\n가이드와이어 로봇 제어의 가장 큰 문제 중 하나는, 가이드와이어가 어떠한 경로로 움직여야 목표 지점까지 도달할 수 있는지 직관적으로 알기 어렵다는 것입니다. 단순하게 생각하면 가이드와이어가 혈관의 중심선을 따라 움직이면 되는 것처럼 보입니다. 하지만 실제로는 가이드와이어와 카데터 사이의 마찰, 혈관 내벽과의 마찰 등으로 인해 중심선만 따라가서는 목표까지 도달할 수 없습니다.\n아래 그림은 저희가 수행한 실험 중 하나로, 한 개의 분지 혈관을 통과하기 위해 가이드와이어가 선택한 경로를 보여줍니다 [2]. 그림을 보시면 가이드와이어의 경로는 중심선이 아니라, 대부분 혈관 벽에서 벽으로 이동하며 상당 부분 마찰력을 이용해 움직이는 것을 알 수 있습니다. 이러한 경로는 수학적인 방법이나 직관으로 구해내기 매우 어렵습니다. 따라서 최적 경로를 쉽게 만들어낼 수 없고, 최적 경로를 얻어낼 수 없다면 PID 제어를 적용하기 어렵습니다. \n\nReinforcement Learning 강화학습은 이러한 문제를 푸는데 최적화되어 있습니다. 사실 강화학습과 PID 제어는 동일선 상에서 비교하는 것이 불공평할 수도 있습니다. 두 알고리즘이 각각 목표하는 바가 다르기 때문입니다. PID 제어는 위에서 말씀드렸듯이 Tracking에 최적화되어 있고, 강화학습은 최적 경로를 찾는 것에 최적화되어 있습니다.\n강화학습이 목표로 하는 것은 agent가 각 상태(state)에서 보상(reward)을 최대로 하는 행동(action)을 하는 것입니다. 이러한 목표를 달성하기 위해 각 상태에서 어떤 행동을 선택하는 것이 좋은지 경험을 통해 판단합니다. 이러한 경험을 통한 판단을 정책(policy)이라고 하며, agent는 환경과 상호작용하며 얻는 보상을 최대로 하는 방향으로 정책을 업데이트 해나갑니다. 즉 강화학습 agent는 문제에 대한 최적의 정책을 찾게 되고 이는 곧 최적 경로를 찾는 것과 같습니다.\n\nPID Control vs RL 지금까지 왜 PID 제어로는 PCI 로봇을 제어하기 어려운지 알아보았습니다. 이 두 알고리즘의 차이는 결국 최적 경로를 만들어낼 수 있는가 없는가의 차이입니다. 강화학습은 병변부위까지 가이드와이어를 이동시키는 최적의 경로를 찾는 것이 가능하지만, PID 제어로는 그 경로를 찾을 수 없습니다. 그저 경로를 따라갈 뿐입니다.\n하지만 독자분들께서는 여기서 의문을 제기하실 수 있습니다. 왜냐하면 기존 제어이론에도 최적 경로를 찾는 알고리즘이 있기 때문입니다. 이는 최적제어 (Optimal Control)이라는 이론입니다. 아래부터는 이 최적제어 이론이 강화학습과 어떻게 다른지, 왜 저희는 최적경로를 위한 두 알고리즘 중에서도 강화학습을 선택하게 되었는지 이야기해보겠습니다.\n\nOptimal Control \nOptimal Control vs RL 강화학습과 최적제어는 모두 최적 경로를 찾기 위한 알고리즘입니다. 목적이 같은 만큼 두 알고리즘은 많은 면에서 유사한 모습을 보입니다. 실제로 강화학습의 아버지라고 불리는 Richard S. Sutton 교수는 최적제어의 한 부분으로서 강화학습을 활용하는 것을 제안하기도 했습니다 [3].\n먼저 강화학습과 최적제어의 공통점부터 살펴보겠습니다. 강화학습과 최적제어 모두 다양한 이론들이 소개되어 있습니다. 이 글에서는 강화학습의 기초 이론 중 하나인 Dynamic Programming과, 가장 대표적인 최적제어이론 중 하나인 LQR Control (Linear Quadratic Regulator)을 비교해보도록 하겠습니다 [4][5]. 강화학습과 최적제어는 용어와 계산하는 과정만 조금 차이가 있을 뿐, 거의 동일한 개념과 구조를 갖고 있습니다. 두 방법 모두 1) 모델링, 2) 목적함수 결정, 3) 정책 결정, 4) 최적해 계산의 4개 단계를 이용하여 이 문제를 해결합니다.\n예시를 위해 아래 그림과 같은 문제를 가정하겠습니다. 자동차가 목적지 Goal까지 장애물을 피하여 최대한 빨리 도달하는 것이 목표입니다. \nStep 1. 모델링 모델은 로봇 혹은 agent가 어떠한 동작을 취했을 때, agent의 상태나 환경이 어떻게 변하고 반응할지를 수학적으로 나타낸 것입니다. 최적경로 탐색은 정확하면서도 해를 찾을 수 있는 모델을 만드는 것에서부터 시작합니다.\n Dynamic Programming : 본 글에서는 편의를 위하여 Dynamic Programming에서는 Grid 환경을 가정합니다. Grid 환경에서는 인접한 Grid 간의 이동확률인 상태전이확률 $p$로 환경이 모델링 될 수 있습니다. 현재 상태가 $s$이고, 여기서 행동 $a$를 취했을 때, 상태전이확률 $p$에 의해 다음 상태 $s\u0026rsquo;$가 결정됩니다. 이 때 발생하는 보상(reward) $r$ 또한 모델에 의해 정의됩니다. $$ p(s\u0026rsquo;,r|s,a) = Pr({S}_t=s\u0026rsquo;, {R}_t = r | {S}_{t-1}=s, {A}_{t-1}=a) $$ \n LQR Control : LQR 제어에서는 아래와 같은 상태 공간 방정식이라는 방법을 이용하여 환경을 모델링 합니다. 상태 공간 방정식은 주로 동역학 해석을 통해 이루어집니다. $x$는 자동차의 상태를 표현하고, $u$ 자동차의 행동, 즉 제어 입력을 의미합니다. $A$는 환경의 관성, 마찰 등 자동차와 환경의 동역학 특성을 나타냅니다. $B$는 제어 입력이 어떻게 시스템에 적용되는지 표현합니다. 산과 같은 장애물은 가까이 갔을 때 중력의 영향이 커지는 형태로 모델링하거나, 아예 산의 위치에 도달하지 못하도록 constraint 조건 $[{x}_{m,1}, {x}_{m,2}]$을 이용하여 표현할 수 있습니다. $ \\dot{x} = Ax + Bu $ subject to $ 0\u0026lt;x\u0026lt;{x}_{m,1}, \\ \\ {x}_{m,2}\u0026lt;x $ \n Step 2. 목적함수 결정 목적함수란 로봇 혹은 agent가 어떠한 경로를 선택했을 때, 그 경로를 수치적으로 평가할 수 있게 해주는 식입니다. 최적제어에서는 Performance measure라고 표현합니다. agent는 자신이 행동을 취하고 상태가 변할 때마다, 상태 전이로 인해 얻어지는 변화들을 모두 저장합니다. 이러한 정보를 이용하여 경로 하나를 마쳤을 때 그 경로에 대한 평가를 진행하게 됩니다.\n Dynamic Programming : 강화학습에서는 각 상태(state)에서의 보상(reward) $R$를 이용하여 목적함수 $G$를 계산합니다. 간단하게는 단순히 지금까지 얻은 모든 보상(reward)을 더하여 얻습니다. 이러한 경우 목적함수의 출력이 무한히 커지는 문제가 있는데, 과거의 보상(reward)의 비율을 점점 줄이는 방법을 통해 (감가율(discount rate), $\\gamma$) 이를 해결하기도 합니다. 강화학습은 이 목적함수를 최대화하는 것을 목표로 합니다. $${G}_t = {R}_{t+1} + \\gamma {R}_{t+2} + \\gamma^2 {R}_{t+3} + \u0026hellip; = \\sum_{k=0}^{\\infty} \\gamma^k {R}_{t+k+1}$$\n LQR Control : 아래 식은 가장 일반적으로 사용되는 performance measure $J$입니다. LQR 제어는 이 $J$를 최소화하는 것을 목표로 합니다. $x$가 있는 첫번째 항은 자동차가 얼마나 빨리 목표 상태로 도달하는지 평가하는 식이고, $u$가 포함된 두번째 항은 얼마나 효율적으로 (최소한의 입력 $u$를 이용하여) 목표까지 도달하는지를 평가합니다. $Q$와 $R$은 $x$와 $u$의 중요도 비율을 바타냅니다. $$ J = \\int_0^\\infty (x^T Q x + u^T R u) dt $$\n Step 3. 정책 결정 Dynamic Programming : 최대 state value $v(s)$를 쫓아가도록 정책 (policy) $\\pi$를 설정합니다. State value란 각 상태(state)에서 미래에 얻을 수 있는 총 보상(reward)의 평균, 즉 목적함수 $G$의 기대값입니다. ${v}_\\pi(s) = {\\mathbb{E}}_\\pi[{G}_t|{S}_t=s] $ $\\pi = \\underset{a}{\\arg\\max}\\ \\ v(s,a) $\n LQR Control : Performance measure $J$의 $Q$와 $R$의 값을 설정하여 어떠한 요소에 가중치를 둘 지 결정합니다.\n Step 4. 최적해 계산 Step 1의 모델, Step 2의 목적함수, Step 3의 정책을 이용하여, 목적함수가 최대가 되는 경로를 찾습니다. 강화학습에서는 주로 목적함수의 최대값을 찾고, 최적제어에서는 최소값을 찾습니다만, 기본 원리는 동일합니다.\n Dynamic Programming : Bellman Equation과 value iteration을 이용하여 각 상태(state)에서의 value를 계산합니다. Iteration 횟수가 많아질수록 state value는 정확해지고, 이를 무한대로 수행하면 결국 하나의 값에 수렴하게 됩니다. 아래 그림은 iteration에 따라 변화하는 state value를 보여줍니다. State value가 클수록 진한 색으로 표현됩니다. ${v}_{k+1}(s) = \\underset{a}{\\max} \\sum_{s\u0026rsquo;,r} p(s\u0026rsquo;,r|s,a) [r + \\gamma{v}_k(s\u0026rsquo;)]$ \n LQR Control : 최적제어에서는 Step 1 모델의 $A$, $B$와 같은 상수 행렬을 이용하여 performance measure $J$가 최소가 되는 u를 계산합니다. u는 아래 두번째 식과 같이 상태 $x$에 대한 식으로 표현됩니다. 이 해는 Riccati Equation 등을 활용하여 구하게 되는데, 이는 본 글의 범위에서 벗어나므로 제외합니다. minimize $ \\int_0^\\infty (x^T Q x + u^T R u) dt$ $$u = Kx$$\n \nModel-free를 향해 위의 두 알고리즘의 구조를 보면, 모델의 형태와 사용하는 목적함수( or performance measure)만 다를 뿐, 그 구조는 완전히 동일하다고 해도 무방합니다. Dynamic Programming, LQR Control 두 방법 모두 모델이 있다는 것을 가정하고 문제를 풀어나갑니다. 최적제어에서는 상태 공간 방정식을 이용해 모델을 표현하고, 강화학습에서는 상태, 행동, 상태 전이 확률로 모델을 표현합니다. 이 모델을 이용하여 목적함수의 최적해를 계산하고, 그 결과에 따라 로봇에 적용되는 입력을 결정합니다.\n그런데, 만약 저희가 이 모델을 구할 수 없는 상황이 되면 어떻게 될까요? 단순히 파라미터의 값이 조금 틀린 정도가 아니라, 모델에 영향을 미치는 요소가 너무 많아 모델에 다 담을 수 없다면? 실제 환경의 제약으로 인해 그 요소들을 모두 측정할 수 없는 상황에서는 어떠한 방법을 써야 할까요?\n강화학습은 이 문제를 trial \u0026amp; error, 즉 경험을 이용한 방법으로 풀어냅니다. Dynamic Programming 이후의 강화학습 이론, Monte-Carlo, Q-learning 등이 그 예입니다. 실제 경험을 이용해 각 상태에서 목적함수의 측정값을 수집한 후에, 목적함수의 예측값과 실제 측정값이 같아지도록 목적함수를 업데이트 합니다. 목적함수를 계산하는데 환경 모델을 사용하지 않습니다. 즉, Model-free 조건에서 문제를 푸는 방법입니다 [6]. \nPCI 로봇 제어는 이러한 Model-free 방법이 필요합니다. 모델을 만드려면 가이드와이어에 작용하는 힘 요소들을 모두 알아야 하는데, 가이드와이어의 어느 부분이 휘어져있는지, 어느 부분이 혈관과 카데터와 닿아있는지, 가이드와이어와 혈관 사이 마찰력은 얼마나 강한지 등을 모두 알아야합니다. 이를 모두 측정할 수 있으면 좋겠지만, 아쉽게도 현재 판매 중인 가이드와이어 중 그 모든 것을 측정할 수 있는 제품은 없습니다. 심지어 이 요소들은 시간에 따라 불규칙하게 변하는, time-variant 특성을 갖고 있고, 그 변화 폭이 커 모델로 표현하기가 더더욱 어렵습니다. 결국 이러한 요소들을 경험을 통해서 알아내야 한다는 결론에 저희는 도달했습니다.\n\nConclusion 제어이론과 강화학습 중 저희가 왜 강화학습을 선택했는지 이야기해보았습니다. 최적경로 탐색, Model-free 접근이 가능하다는 것이 저희가 PCI 로봇에 강화학습을 적용한 가장 큰 이유입니다. 다음 글에서는 저희가 강화학습을 실제로 어떻게 PCI 로봇에 적용했는지 이야기해보겠습니다.\nReference [1] Wikipedia (PID Controller) https://en.wikipedia.org/wiki/PID_controller [2] J. Kweon, H. Kwon, J. Park and Y. Kim, \u0026ldquo;Reinforcement Learning for Guidewire Navigation in Coronary Phantom\u0026rdquo;, TCT 2019, San Francisco, Sep 2019. [3] R.S. Sutton, A.G. Barto and R.J. Williams, \u0026ldquo;Reinforcement Learning is Direct Adaptive Optimal Control\u0026rdquo;, American Control Conference, Boston, June 1991. [4] R.S. Sutton and A.G. Barto, \u0026ldquo;Reinforcement Learning: An Introduction 2nd Edition\u0026rdquo;, The MIT Press, Cambridge, 2018. [5] D.E Kirk, \u0026ldquo;Optimal Control Theory: An Introduction\u0026rdquo;, Dover Publication, New York, 2004. [6] C.B. Black and D.C. Rucker, \u0026ldquo;Parallel Continuum Robots: Modeling, Analysis, and Actuation-Based Force Sensing\u0026rdquo;, IEEE Transactions on Robotics, vol.34, no.1, Feb 2018.\n","date":1574730000,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1574730000,"objectID":"2a6c2ac190143e1a1c52f1c1c2991524","permalink":"/post/2019-11-26-adventure_of_rl_in_vessel_2/","publishdate":"2019-11-26T10:00:00+09:00","relpermalink":"/post/2019-11-26-adventure_of_rl_in_vessel_2/","section":"post","summary":"Introduction to guide-wire control for PCI by RL (2) - RL vs Control Theory","tags":[],"title":"강화학습의 혈관 속 탐험 (2) - 강화학습과 제어 이론의 비교","type":"post"},{"authors":["kyunghwan-kim","chaehyeuk-lee"],"categories":[],"content":" 강화학습의 혈관 속 탐험 시리즈 강화학습의 혈관 속 탐험 (1) - 로봇과 심혈관 중재 시술\n강화학습의 혈관 속 탐험 (2) - 강화학습과 제어 이론의 비교 강화학습의 혈관 속 탐험 (3) - 실험환경 구성과 강화학습 알고리즘 소개\nIntro 이번 포스트에서는 저희가 연구 중인 강화학습을 이용한 심혈관 중재시술 로봇 제어에 대해 소개하려고 합니다. 처음 이 주제에 대해 들으시면 \u0026ldquo;심혈관 중재시술이 뭐지?\u0026rdquo;, \u0026ldquo;왜 로봇을 제어를 하는데 강화학습을 쓰지?\u0026rdquo; 와 같이 여러 궁금증이 먼저 생기실 것입니다. 그래서 포스트를 통해 이런 궁금증을 해소하는 시간을 가지려 합니다.\n 심혈관 중재시술? 허혈성 심장 질환 관상동맥 중재시술(PCI) 심혈관 중재시술 자동화의 필요성 가이드와이어 제어 마치며 \n심혈관 중재시술? 저희는 심혈관 질환의 진단 및 치료를 돕는 솔루션을 연구 개발 하고 있습니다. 심혈관 질환에는 여러 종류가 있고 그에 따른 치료방법도 다양합니다. 그 중 현재 저희가 연구하는 내용과 가장 연관이 있는 허혈성 심장 질환과 이를 치료하기 위한 심혈관 중재시술에 대해 설명하려 합니다.\n\n허혈성 심장 질환 심장은 우리 몸 전체에 혈액을 보내는 펌프 역할을 하고 있습니다. 혈액을 통해 산소와 영양소를 공급하여 우리 몸이 에너지를 만들고 생활을 할 수 있도록 합니다. 심장이 펌프 역할을 수행하려면 심장을 이루고 있는 심근에도 산소와 영양소를 공급해주어야 합니다. 이를 위해 심근에 혈액을 공급하는 혈관이 관상동맥입니다 [1].\n\n허혈성 심장 질환은 심장에 혈액을 공급해주는 혈관인 관상동맥에 지방질, 콜레스테롤, 칼슘 등이 쌓여 혈관이 좁아지거나 막혀 심장근육의 일부에 혈액 공급이 부족하여 발생하는 질환입니다 [2]. 허혈성 심장 질환은 국내 사망 원인 통계를 보면 암에 이어 2위를 차지하고 있으며 전세계 통계에서는 1위를 차지하고 있습니다 [3]. 그만큼 많은 사람들이 이 질환을 겪고 있으며 사망에 이를 정도로 위험한 질환이라는 것을 알 수 있습니다. 허혈성 심장 질환에는 협심증, 심근경색 등이 있습니다. 아래 이미지는 심혈관 질환의 예시입니다 [4].\n\n\n관상동맥 중재시술(PCI) 관상동맥 중재시술(PCI; Percutaneous Coronary Intervention)은 허혈성 심혈관 질환에서 큰 비중을 차지하고 있습니다. PCI는 팔이나 다리의 혈관을 통하여 심장까지 들어간 다음, 막히거나 좁아진 심장 혈관을 넓히는 시술입니다 [5]. 가슴을 절개하는 수술이 아니기 때문에 전신 마취가 필요없고 가슴에 흉터를 남기지 않아 비교적 환자의 부담이 덜한 치료방법입니다. 스텐트라는 시술 도구로 병변을 치료하기 때문에 일반적으로 스텐트 시술이라는 이름으로 많이 알려져 있습니다. 시술 방법은 다음과 같습니다 [6].\n 허벅지 위쪽 또는 팔의 동맥 혈관을 통해 가이드와이어를 넣어 관상동맥의 병변부위에 접근. 가이드와이어를 통해 다른 시술도구들을 병변 부위까지 이동. 벌룬으로 막힌 혈관 부분을 넓히고, 병변에 따라 스텐트라는 그물망으로 고정 \n이 때, 시술자는 조영제와 X-ray를 이용한 혈관조영영상을 이용해 병변을 확인하고 시술 위치를 파악합니다. 시술이 진행되는 도중에도 계속해서 혈관조영영상을 확인하여 정확한 시술을 진행합니다. 아래는 혈관조영영상의 일부입니다 [7].\n\n\n심혈관 중재시술 자동화의 필요성 PCI는 허혈성 심장 질환을 효과적으로 치료할 수 있는 시술 방법이지만 개선해야할 부분도 있습니다.\n 의료진의 방사능 피폭\n PCI는 혈관의 모양과 현재 시술도구의 위치를 확인하기 위해 시술 중 혈관조영영상을 계속해서 촬영해야합니다. 촬영 기기 앞에 방사선 가림막을 두기는 하지만 매일 시술을 진행하는 의료진들은 많은 양의 방사능에 노출될 수 밖에 없습니다. 긴 시술 시간\n PCI는 일반적으로 1시간 정도의 시술시간이 소요됩니다. 하지만 병변 부위의 난이도에 따라 시술시간이 2시간에서 많게는 4시간 이상 걸리기도 합니다. 시술 시간이 길어질수록 시술자 뿐만 아니라 환자에게도 많은 부담이 됩니다. 환자의 경우 혈관조영영상 촬영시 환자의 혈관에 투입되는 조영제의 양이 늘어나게 되고 이는 가려움증, 구토와 같은 과민반응을 일으킬 수 있습니다. 숙련도에 따른 차이\n PCI는 시술자의 숙련도에 따라 시술 속도나 도구 사용량 등에서 편차가 있습니다. 특히 PCI의 시술 도구들은 1회용 소모품인 것에 비해 고가의 도구들이 많습니다. 숙련된 시술자라면 경험을 통해 병변 부위나 환자의 상태를 보고 한번에 적합한 시술 도구로 시술을 진행할 수 있지만 비숙련자는 여러 번의 시행착오를 통해 도구를 선택하게 됩니다. 이 때문에 자연스럽게 시술 시간이 길어지게 되어 환자나 시술자에게 부담을 주게 됩니다. 위와 같은 점들을 개선하기 위해 PCI 로봇에 대한 연구가 진행되고 있습니다. 대표적으로 Corindus의 시술 로봇이 있습니다 [8]. 저희는 이보다 더 나아가 인공지능으로 로봇을 제어하여 시술을 자동화하는 연구를 진행하고 있습니다. PCI의 자동화를 통해 환자와 시술자 모두의 부담을 줄이게 되며, 특히 이상적으로 자동화가 된다면 시술의 숙련도에 따른 차이를 없앨 수 있습니다.\n\n가이드와이어 제어 시술 자동화의 첫 단계로 로봇을 이용한 가이드와이어의 자동제어를 연구하고 있습니다. PCI는 위의 시술 과정에서 설명드린 것처럼 가이드와이어를 병변 부위까지 위치시킨 후 이 가이드와이어를 이용해 다른 시술 도구들을 이동시킵니다. 그렇기 때문에 가이드와이어를 병변 부위까지 잘 도달시키는 것이 시술의 가장 중요한 부분입니다. 하지만 혈관조영영상으로도 정확히 알 수 없는 혈관의 구조와 모양, 와이어 이동 시 생기는 혈관에 의한 마찰, 시술 중 환자의 호흡과 박동, 혈관에 들어가기 위해 얇고 부드럽게 제작되어 제어가 어려운 와이어 등 가이드와이어를 제어하는데 많은 어려움이 있습니다. 실제 의사들은 의료 지식을 통한 혈관 모양 예측, 손의 감각과 경험을 통한 미세한 조종으로 가이드와이어를 이동시켜 시술합니다. 저희는 가이드와이어 제어 문제를 로봇과 인공지능을 결합하여 해결하려 합니다.\n\n위 이미지 [9]에서 의사가 가이드와이어를 조작하는 모습과 로봇(Manipulator)를 이용해 가이드와이어를 조작하는 모습을 볼 수 있습니다. 실제 시술에서 시술자는 가이드와이어를 병변 부위로 이동시키기 위해 회전(rotation)과 전후진(translation) 동작을 합니다. 저희가 이용하는 로봇도 이러한 두 가지 동작을 재현할 수 있도록 설계되었습니다. 가이드와이어의 상태에 따라 두 가지 동작 중 어떤 동작을 할 지 선택하는 것이 인공지능의 역할입니다.\n\n마치며 이번 포스트에서는 심혈관 중재시술과 저희가 진행하고 있는 연구 주제인 심혈관 중재시술 자동화의 필요성에 대해 설명드렸습니다. 다음 포스트에서는 PCI를 자동화하는 방법으로 인공지능 기법 중 강화학습을 선택한 이유에 대해서 포스팅하도록 하겠습니다.\nReference [1] 심장 이미지 (wiki): https://ko.wikipedia.org/wiki/%EA%B4%80%EC%83%81%EB%8F%99%EB%A7%A5 [2] 허혈성 심질환 설명(서울아산병원): http://www.amc.seoul.kr/asan/healthinfo/disease/diseaseDetail.do?contentId=30275 [3] 연도별 국내 사망 원인 통계(e-나라지표), 세계 사망 원인(WHO): http://www.index.go.kr/potal/stts/idxMain/selectPoSttsIdxMainPrint.do?idx_cd=1012\u0026amp;board_cd=INDX_001, https://www.who.int/news-room/fact-sheets/detail/the-top-10-causes-of-death [4] 심혈관질환의 종류 이미지(아스피린프로텍트): http://www.aspirinprotect.co.kr/ko/disease-and-prevention/cardiovascular-diseases/#tab_tab0 [5] 관상동맥 중재시술의 이해(서울아산병원 심장병원): http://heart.amc.seoul.kr/asan/depts/heart/K/bbsDetail.do?menuId=4634\u0026amp;contentId=264501 [6] 사람 몸과 혈관 이미지: http://www.secondscount.org/image.axd?id=c8a00122-bb66-46c6-8ab7-333a9a0cd46a\u0026amp;t=635566481777430000, https://www.mcvs.co.nz/wp-content/uploads/2017/05/stent-balloon-angioplasty.png [7] 관상동맥 조영술 이미지 (강남세브란스병원): http://gs.iseverance.com/dept_clinic/department/cardiology/treatment/view.asp?con_no=82261 [8] Corindus: https://www.corindus.com/ [9] 수기 시술과 로봇 이미지: 아산메디컬센터 ","date":1571965200,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1571965200,"objectID":"67962c312824919fd36425bec73b8a48","permalink":"/post/2019-10-25-adventure_of_rl_in_vessel_1/","publishdate":"2019-10-25T10:00:00+09:00","relpermalink":"/post/2019-10-25-adventure_of_rl_in_vessel_1/","section":"post","summary":"Introduction to guide-wire control for PCI by RL - PCI aided by Robot","tags":[],"title":"강화학습의 혈관 속 탐험 (1) - 로봇과 심혈관 중재 시술","type":"post"},{"authors":["kyunghwan-kim","curt-park"],"categories":[],"content":" 이번 포스트에서는 강화학습에서 reward shaping의 기반이 되는 논문인 \u0026ldquo;Policy invariance under reward transformation: Theory and application to reward shaping\u0026rdquo; (A. Y. Ng et al., 1999) [1]을 읽고 정리한 내용을 공유합니다.\n 글쓴이의 의견이나 부연 설명은 이 문장과 같이 블록으로 표시합니다.\n Introduction 강화학습에서 task는 Reward function을 통해 표현됩니다. 이 reward function에 변화를 주는 것으로 학습의 성능을 향상시킬 수 있습니다. 이를 Reward shaping 이라고 합니다. 하지만 reward function은 굉장히 민감하기 때문에 reward shaping의 방법에 따라 agent는 의도와 다른 행동을 하기도 합니다. 본 논문에서는 이런 의도하지 않은 학습 결과를 bug라고 표현하며 그 예시로 두 가지 경우를 설명합니다.\n 자전거 주행 agent를 빨리 학습시키기 위해 goal 방향으로 갈때 positive reward를 주었더니 시작 지점을 중심으로 원을 그리며 도는 agent가 되었다. 이유는 goal에서 멀어질때 penalty를 안주었기 때문에 계속 돌기만 해도 goal에 가까워질때 받은 positive reward가 무한히 쌓이기 때문이다. 축구 로봇을 학습할 때 공을 계속 점유하고 있는 것이 중요하다. 그래서 공을 건드릴 때 reward를 주었더니 공 바로 옆에서 진동하는 agent가 되었다. 공을 계속 건드려서 reward를 반복적으로 받을 수 있기 때문이다. 위의 예시에서 우리가 바라는 것은 자전거 주행 agent는 goal에 도착하는 것이고 축구 로봇은 공을 상대 골대에 넣는 것입니다. 하지만 잘못된 reward shaping으로 전혀 다른 목표를 달성하는 agent를 학습시키게 되었습니다. 이처럼 reward shaping은 강화학습의 성능 향상을 위해 효과적인 방법이지만 의도한 방향으로 shaping 하는 것은 어렵습니다. 특히 위와 같이 positive reward가 계속해서 쌓이는 것을 positive reward cycle 이라고 논문에서 표현합니다.\n이런 현상이 발생하는 이유는 reward function에 따라 agent가 학습하고자 하는 optimal policy가 아닌 suboptimal로 잘못 학습했기 때문입니다. 본 논문에서 optimal policy는 우리가 해당 문제에 대해 agent에게 학습시키고자 하는 정책이고 suboptimal은 우리가 원하는 policy는 아니지만 높은 reward를 받을 수 있는 정책을 말합니다. reward function의 변화가 학습하고자 하는 policy에도 영향을 주어 reward를 최대로 받는 방향으로 학습하여도 우리가 원하지 않는 방향으로 행동하는 agent로 학습되는 것입니다. 그렇기 때문에 우리는 reward function에 변화를 주어도 optimal policy가 변하지 않는 reward function의 형태가 필요합니다. 이런 성질을 본 논문에서 Policy invariance이라고 표현합니다.\n본 논문에서는 reward function이 변화에 대해 policy invariance를 보장하는, 특히 positive reward cycle을 방지하는 reward function의 형태를 제안합니다.\nPreliminaries Definitions (finite-state) Markov decision process (MDP) $M$ : $(S, A, T, \\gamma, R) $\n $S$ : a finite set of states $A$ : a set of actions $T$ : the next state transition probabilities $\\gamma$ : discount factor $R$ : reward function, $R: S \\times A \\times S \\mapsto \\mathbb{R}$ with $R(s, a, s\u0026rsquo;)$\n $\\pi$ : policy over set of states $S$ is any function $\\pi : S \\mapsto A$\n Value function : $ V^{\\pi}_{M}(s) = E[r_1 + \\gamma r_2 + \u0026hellip;; \\pi, s만] $\n Q-function : $ Q^{\\pi}_{M}(s, a) = E_{s\u0026rsquo; \\sim P_{sa}(\\cdot)}[R(s, a, s\u0026rsquo;) + \\gamma V^{\\pi}_{M}(s\u0026rsquo;) ] $\n $\\textbf s_0$: 본 논문에서는 $s_0$를 absorbing state라 하며, undiscounted MDP($\\gamma$ = 1) 일 때 더이상 reward를 주지 않는 state를 표현합니다. 이는 episodic task를 continuing task로 일반화할 때 terminal state와 같은 역할을 합니다. $s_0$에서는 모든 action이 $s_0$로의 state transition (상태 전이) 만을 발생시킵니다. 아래 그림이 하나의 예시입니다. (본 논문의 figure 3)[2] \n 일반적으로 $s_0$는 episode의 가장 첫번째 state를 표현하지만 본 논문에서는 absorbing state를 뜻합니다.\n Shaping Rewards 본 논문에서는 reward shaping function을 추가한 새로운 reward function 형태를 제안합니다.\n$$ R\u0026rsquo; = R + F $$\n$$ F : S \\times A \\times S \\mapsto \\mathbb{R} $$\n그리고 $R\u0026rsquo;$ 을 이용해 MDP를 새롭게 정의합니다.\n$$ M\u0026rsquo; = (S, A, T, \\gamma, R\u0026rsquo;) $$\n$F$ 는 shaping reward function 라고 합니다. $F$를 이용해 원하는 shaping term을 추가할 수 있습니다. 예를들어 agent가 goal에 가까워지도록 reward shaping을 하고 싶다면 다음과 같이 $F$를 정의할 수 있습니다.\n$$ F(s, a , s\u0026rsquo;) = \\begin{cases} r, \u0026amp; \\mbox{if } s\u0026rsquo; \\ closer \\ to \\ the \\ goal \\ than \\ s. \\\\\\ 0, \u0026amp; \\mbox{otherwise} \\end{cases} \\text{, where } r \\text{ is some positive reward.}$$\n$M\u0026rsquo;$은 $M$과 같은 state, action, transition probablities, discount factor를 사용하기 때문에 강화학습 알고리즘을 동일하게 적용할 수 있습니다.\n우리의 목표는 정의한 MDP 모델과 강화학습 알고리즘을 이용해 최적의 policy를 찾아내는 것입니다. 그러기 위해서는 다음의 질문들에 대답할 필요가 있습니다.\n 어떤 형태의 $F$ 를 사용해야 $M\u0026rsquo;$ 에서의 optimal policy가 $M$에서도 동일하게 optimal policy라는 것을 보장할 수 있을지? 이 때의 $M\u0026rsquo;$는 positive reward cycle을 방지할 수 있는지? Main results 이번 절에서는 어떤 형태의 $F$가 policy invariance를 보장하는지 알아봅시다.\n앞서 Introduction에서 자전거 문제를 예시로 들었습니다. 이 문제에서 단순히 goal로 가까워질때 추가적인 reward를 발생시켰고, 이로 인해 시작지점을 기준으로 원을 그리며 계속해서 회전하는 policy가 학습되었습니다. 이런 현상이 발생하는 이유는 agent가 특정 state를 순환($ s_1 \\rightarrow s_2 \\rightarrow \u0026hellip; \\rightarrow s_n \\rightarrow s_1 \\rightarrow \u0026hellip; $)하는 경우에 $F$의 총합이 0보다 큰 값을 갖게 되기 때문입니다.\n$$F(s_1, a_1, s_2) + F(s_2, a_2, s_3) + \u0026hellip; + F(s_n, a_n, s_1) \u0026gt; 0$$\nGoal에 도달하는 agent를 학습시키기 위해서는 목적을 성취(goal에 도달)하는 경우에 대해서만 positive reward를 발생시켜야 합니다. 허나, 위의 경우 $F$에 의해 특정 state들을 순환하는 것으로도 reward가 증가하게 되고, 그로 인해 agent는 특정 구간을 순환하는 suboptimal policy를 학습하게 됩니다. 이러한 positive reward cycle 문제를 해결하기 위해 본 논문에서는 다음과 같은 형태의 $F$를 제안합니다.\n$$ F(s,a,s\u0026rsquo;) = \\Phi (s\u0026rsquo;) - \\Phi (s) $$\n여기서 $\\Phi$ 를 potential function 이라 하며 $F$ 를 potential-based shaping function 이라고 합니다. $F$ 가 다음 state와 현재 state에 대한 함수의 차이로 정의되었기 때문에 위의 예시처럼 cycle이 발생하더라도 reward가 계속해서 증가하지 않습니다.\n$$F(s_1, a_1, s_2) + F(s_2, a_2, s_3) + \u0026hellip; + F(s_n, a_n, s_1) = 0 $$\n더 나아가 본 논문에서는 transition probablity와 reward function이 prior knowledge로 주어지지 않았을 때, potential-based shaping function $F$가 policy invariance를 보장하는 유일한 $F$임을 증명합니다.\nTheorem 1 임의의 $S$, $A$, $\\gamma$에 대해 임의의 shaping reward function는 다음과 같습니다.\n$$F:S\\times A \\times S \\mapsto \\mathbb{R} $$\n이때, 모든 $s \\in S - {s_0}, a \\in A, s\u0026rsquo; \\in S$에 대해 아래 식을 만족하는 real-valued function $\\Phi: S \\mapsto \\mathbb{R}$ 가 존재하면 $F$를 potential-based shaping function 이라고 합니다.\n$$ F(s,a,s\u0026rsquo;) = \\gamma\\Phi(s\u0026rsquo;) - \\Phi(s), \\text{where} \\ S - {s_0} = S \\ \\text{if} \\ \\gamma \u0026lt; 1. $$\n그리고 potential-based shaping function $ F $ 는 optimal policy consistency를 보장하기 위한 필요충분 조건입니다.\n (충분조건) $F$ 가 potential-based shaping function 이면 $M\u0026rsquo;$에서의 모든 optimal policy는 $M$에서도 optimal이다. (필요조건) $F$ 가 potential-based shaping function이 아니라면 $M\u0026rsquo;$에서의 optimal policy가 $M$에서도 optimal임을 만족하는 transition과 reward function이 존재하지 않는다. Theorem 1에 따르면 위에서 언급한 optimal policy consistency를 만족하는 shaping function $F$가 식 (2)의 형태이고, 이 형태가 optimal policy consistency를 만족하는 유일한 $F$입니다.\nProof: 충분조건 MDP $M$에 대한 optimal Q-function $Q^{*}_{M}(s,a)$는 다음과 같습니다.\n$$ Q^{*}_{M}(s,a) = E_{s\u0026rsquo; \\sim P_{sa}(\\cdot)} \\bigg[R(s,a,s\u0026rsquo;) + \\gamma \\underset{a\u0026rsquo; \\in A}{\\max} Q^{*}_{M} (s\u0026rsquo;, a\u0026rsquo;)\\bigg] $$\n이 식에 $\\Phi$을 추가해서 전개합니다.\n$$ \\begin{align} Q^{*}_{M}(s,a) - \\Phi(s) \u0026amp;= E_{s\u0026rsquo; \\sim P_{sa}(\\cdot)} \\bigg[R(s,a,s\u0026rsquo;) + \\gamma \\big(\\underset{a\u0026rsquo; \\in A}{\\max} Q^{*}_{M} (s\u0026rsquo;, a\u0026rsquo;) + \\Phi(s\u0026rsquo;) - \\Phi(s\u0026rsquo;)\\big)\\bigg] - \\Phi(s) \\\\\n\u0026amp;= E_{s\u0026rsquo; \\sim P_{sa}(\\cdot)} \\bigg[R(s,a,s\u0026rsquo;) + \\gamma \\Phi(s\u0026rsquo;) - \\Phi(s) + \\gamma \\big(\\underset{a\u0026rsquo; \\in A}{\\max} Q^{*}_{M} (s\u0026rsquo;, a\u0026rsquo;) - \\Phi(s\u0026rsquo;)\\big)\\bigg] \\\\\n\\end{align} $$\n여기서 $ \\hat Q_{M\u0026rsquo;} (s,a) \\triangleq Q^{*}_{M}(s,a) - \\Phi(s) $ 라 정의하고 $F(s,a,s\u0026rsquo;) = \\gamma \\Phi(s\u0026rsquo;) - \\Phi(s)$ 로 치환합니다.\n$$ \\begin{align} \\hat Q_{M\u0026rsquo;} \u0026amp;= E_{s\u0026rsquo; \\sim P_{sa}(\\cdot)} \\bigg[R(s,a,s\u0026rsquo;) + F(s,a,s\u0026rsquo;) + \\gamma \\underset{a\u0026rsquo; \\in A}{\\max} \\hat Q_{M\u0026rsquo;} (s\u0026rsquo;, a\u0026rsquo;)\\bigg] \\\\\n\u0026amp;= E_{s\u0026rsquo; \\sim P_{sa}(\\cdot)} \\bigg[R\u0026rsquo;(s,a,s\u0026rsquo;) + \\gamma \\underset{a\u0026rsquo; \\in A}{\\max} \\hat Q_{M\u0026rsquo;} (s\u0026rsquo;, a\u0026rsquo;)\\bigg] \\\\\n\\end{align} $$\n위 식에 따르면 $ \\hat Q_{M\u0026rsquo;} (s,a) $는 결국 MDP $ M\u0026rsquo;(S, A, T, R\u0026rsquo;, \\gamma) $ 에서의 Q function $ Q_{M\u0026rsquo;} (s,a)$ 와 같은 형태가 됩니다. 그리고 $M\u0026rsquo;$이 undiscounted case ($ \\gamma = 1 $)이고 $\\Phi(s_0) = 0 $이라 가정했을 때 $$ \\hat Q_{M\u0026rsquo;}(s_0, a) = Q^{*}_{M}(s_0,a) - \\Phi(s_0) = 0 - 0 = 0 $$ 을 만족하게 됩니다. 따라서 $\\hat{Q}_{M\u0026rsquo;} (s,a)$는 Bellman equation을 만족하며 unique optimal Q-function을 반드시 갖게 됩니다.\n그러므로 $M\u0026rsquo;$에서의 optimal policy $\\pi^*_{M\u0026rsquo;}(s)$는 다음 식을 만족합니다.\n$$ \\begin{align} \\pi^*_{M\u0026rsquo;}(s) \u0026amp;\\in \\underset{a\\in A}{\\arg\\max} Q^*_{M\u0026rsquo;}(s,a) \\\\\n\u0026amp;= \\underset{a\\in A}{\\arg\\max} Q^*_{M}(s,a) - \\Phi(s) \\\\\n\u0026amp;= \\underset{a\\in A}{\\arg\\max} Q^*_{M}(s,a) \\end{align} $$\n즉, $M\u0026rsquo;$에서의 optimal policy $\\pi^*_{M\u0026rsquo;}(s)$는 $M$에서 또한 optimal policy임을 알 수 있습니다.\n 필요조건의 증명은 논문의 Appendix A를 참고하시기 바랍니다.\n 위의 Theorem 1의 필요충분 조건에 대한 증명을 통해 potential-based shaping function이 policy invariance를 보장하는 유일한 $F$임을 증명하였습니다. 그렇다면 potential-based shaping function의 $\\Phi$는 어떤 식으로 정의해야할까요? 논문에서는 Corollary 2를 통해 $\\Phi$를 구하는 한가지 방법을 서술합니다.\n Corollary(따름 정리)는 Theorem으로부터 바로 증명할 수 있는 참인 명제를 말합니다.\n Corollary 2 $ F(s,a,s\u0026rsquo;) = \\gamma \\Phi(s\u0026rsquo;) - \\Phi(s) $ 이고 $ \\gamma = 1 $ 일 때 $ \\Phi(s_0) = 0 $를 가정하면, 모든 $ s \\in S, a \\in A $ 대해 다음 식을 만족합니다.\n$$ Q^*_{M\u0026rsquo;}(s,a) = Q^*_{M}(s,a) - \\Phi(s), \\\\\nV^*_{M\u0026rsquo;}(s) = V^*_{M}(s) - \\Phi(s). $$\nProof: Corollary 2 식 (3)은 Theorem 1의 충분조건의 증명과정을 통해 증명되었습니다. $ V^*(s) = \\underset{a \\in A}{\\max}Q^*(s,a) $ 이기 때문에 식 (3)을 만족하면 식 (4)도 만족합니다.\nCorollary 2를 통해 $ V^*_{M\u0026rsquo;}(s) = V^*_{M}(s) - \\Phi(s) $이 참임을 알게 되었습니다. 논문에서는 (4)를 통해 $ \\Phi $의 가장 쉬운 형태를 제안합니다.\npotential-based function 실제 환경에서 $ \\Phi $를 정의하기 위해서는 domain에 대한 expert knowledge가 필요합니다. 만약 domain knowledge (MDP $M$)를 충분히 알고 있다면 $\\Phi$를 다음과 같이 가정할 수 있습니다.\n$$ \\Phi(s) = V^*_{M}(s) $$\n$\\Phi$를 위와 같이 가정하면 Corollary 2의 (4)에 따라 $M\u0026rsquo;$에 대한 value function은 $V^*_{M\u0026rsquo;}(s) \\equiv 0$입니다. 논문에서는 이런 형태의 value function이 학습에 용이하다고 합니다. 또한 위와 다른 형태의 $\\Phi$를 이용해도 충분히 policy invariance를 보장한다고 주장합니다.\n $M\u0026rsquo;$에서의 (near-) optimal policy가 $M$에서도 (near-) optimal policy임을 보장한다 라고 서술하며 Remark 1 을 통해 optimal이 아닌 near optimal 에서도 Theorem 1이 성립함을 언급합니다. Experiments Experiments 절에서는 두 가지 grid world 환경에서 potential-based shaping function에 변화를 주며 비교 실험한 결과를 보여줍니다. 본 논문에서는 이 실험을 통해 학습 속도 향상을 위한 합리적인 $\\Phi$를 정하는 방향을 설명하는 것이 목적이라고 말합니다.\n10 x 10 grid world 10 x 10 grid world 환경은 no discount setting ($ \\gamma = 1 $)이며 매 step 당 -1의 reward(penalty)를 받습니다. 1 step action을 할 때 80% 확률로 exploitation 하고 20% 확률로 exploration (random action) 합니다. 저자들은 이전 절에서 좋은 shaping potential $ \\Phi(s) = V^*_{M}(s) $ 를 제안했습니다. 이 실험환경에서의 $ V^*_{M} $ 은 현재 state에서 Goal 까지의 Manhattan distance로 볼 수 있습니다. 여기에 80%의 확률로 exploitation하는 것을 감안하여 $V^*_{M}$에 가까운 $\\Phi$ 를 다음과 같이 정의합니다.\n$$ \\Phi_0(s) = \\hat{V}_M(s) = - {MANHATTAN}(s, GOAL) / 0.8 $$\n 참고: Manhattan distance wiki\n 그리고 $V^*_{M}$와 좀 더 먼 $\\Phi$ 에 대해서도 shaping potential이 잘 동작하는 것을 보이기 위해 $ \\Phi(s) = 0.5 \\Phi_0(s) = 0.5 \\hat{V}_M(s) $ 에 대해서도 실험합니다. 실험 결과는 아래와 같습니다.\n위 그래프를 통해 $0.5 \\Phi_0(s)$와 $\\Phi_0(s)$를 shaping potential로 사용했을때, shaping을 사용하지 않은 경우에 비해 학습이 빠른 속도로 수렴함을 확인 할 수 있습니다. 또한 $0.5\\Phi_0(s)$를 사용하더라도 $\\Phi_0(s)$를 사용했을 때와 거의 유사하게 학습 속도가 향상됨을 보여줍니다. 나아가 조금 더 큰 환경인 50 x 50 grid world 환경에서도 potential-based shaping reward를 사용한 경우에 성능이 더 빠르게 향상됨을 확인 할 수 있습니다.\n5 x 5 grid world with subgoals 이번 실험에서는 subgoal이 있는 환경에서도 potential-based shaping reward이 잘 작동하는지 확인합니다.\nAction과 reward function의 설정은 이전 10 x 10 grid world 환경과 동일합니다. 위 그림의 grid 내부에 표시된 숫자는 각각 flag를 의미하고, agent는 모든 flag를 순서대로 (오름차순) 획득한 뒤 goal에 도착해야합니다. 이 환경에 대한 potential-function을 정의해봅시다. 만약 subgoal의 위치를 모두 알고 있고 이전 환경과 동일하게 80%의 exploitation을 한다면 우리는 goal에 도착하기까지의 timestep t를 예측할 수 있습니다. 이 환경에서는 이전 subgoal에서 다음 subgoal로 가기까지 필요한 step의 갯수가 모두 유사하기 때문에 n번째 subgoal에 도달하기 위한 step은 $((5-n_s)/5)t$ step이라고 할 수 있습니다. 이때 $n_s$는 $s$ 일때 통과한 subgoal의 수가 됩니다.\n위에서 도출한 식을 이용하여 potential-function을 다음과 같이 정의합니다. $$ \\Phi_0(s) = -((5 - n_s - 0.5)/5 )t $$\n 0.5는 일반적으로 agent가 n번째 subgoal과 n+1번째 subgoal 중간에 있기 때문에 이를 보정해주기 위한 값입니다.\n 또 다른 potential-function으로 10 x 10 grid world 환경에서 사용했던 $\\hat{V}_M(s)$를 사용합니다. $$ \\Phi_1(s) = \\hat{V}_M(s) = - {MANHATTAN}(s, GOAL) / 0.8 $$ 이렇게 정의한 potential function을 통해 실험한 결과는 다음과 같습니다.\n위 그래프는 위에서 부터 no shaping, $\\Phi = \\Phi_0(s)$, $\\Phi = \\Phi_1(s)$에 해당합니다. 이전 실험에서 정의한 $\\Phi_1$ 뿐만 아니라 새로 정의한 $\\Phi_0$을 사용하였을때에도 마찬가지로 shaping을 사용하지 않은 경우보다 학습속도가 향상되었음을 확인 할 수 있습니다.\nDiscussion and Conclusions 이번 논문에서는 reward shaping을 위한 function $F$를 제안하였습니다. $F$는 potential-based shaping reward $\\gamma \\Phi(s\u0026rsquo;) - \\Phi$로 정의하며 이것이 (near-) optimal을 유지하는 shaping reward임을 증명하였습니다. 또한 실험을 통해 distance-based 환경과 subgoal-based 환경에서 potential function을 정의해보고 성능이 향상됨을 확인하였습니다. 이번 논문에서 알아본 potential-based shaping function의 형태는 추후 IRL과 이후의 reward shaping 논문에서 계속해서 사용되고 인용됩니다.\nReference [1] A. Y. Ng et al., \u0026ldquo;Policy invariance under reward transformation: Therory and application to reward shaping.\u0026rdquo; Proceedings of the Sixteenth International Conference on Machine Learning(pp.278-287), 1999.\n [2] Sutton, R. and Barto, A., \u0026ldquo;3.4 Unified Notation for Episodic and Continuing,\u0026rdquo; in Reinforcement Learning: An Introduction, 2nd ed., MIT Press, 2018.\n","date":1561522500,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1561522500,"objectID":"3b66bdea0d4ebb65aa1c834d85d9b250","permalink":"/post/2019-06-26-policy-invariance-under-reward-transformation_theory-and-application-to-reward-shaping/","publishdate":"2019-06-26T13:15:00+09:00","relpermalink":"/post/2019-06-26-policy-invariance-under-reward-transformation_theory-and-application-to-reward-shaping/","section":"post","summary":"Reward shaping method to assure policy invaraiance in RL","tags":[],"title":"[Paper Study] Policy invariance under reward transformation","type":"post"},{"authors":["young-kim","whi-kwon"],"categories":[],"content":" Introduction SOTA 성능을 내는 많은 detector에서 anchor를 활용해서 BBox coordination을 학습합니다. 이번 글에서는 anchor가 무엇인지, 어떻게 one-stage, two-stage detector에서 사용되는지에 관해 살펴보겠습니다.\n이 글에 사용된 script 및 jupyter notebook은 medipixel repository에 업로드 되어 있으니 참고하시기 바랍니다.\n코드 위주로 소개하기 때문에 object detection, anchor가 익숙하지 않으신 분께서는 Andrew Ng 교수님이 소개하시는 영상과 Jonathan Hui의 object detection 소개 자료를 보시면 이해에 도움이 되실겁니다.\nImport Libraries 코드는 mmdet.v0.6rc0을 기준으로 참고하여 제작하였습니다.\nimport cv2 import numpy as np import matplotlib.pyplot as plt import matplotlib.ticker as plticker import torch import torch.nn.functional as F from matplotlib.lines import Line2D from matplotlib.patches import Patch from anchor_generator import (gen_base_anchors, get_anchors, grid_anchors, meshgrid) from assigner import assign_wrt_overlaps, bbox_overlaps from loss import binary_cross_entropy, smooth_l1_loss from prediction import predict_anchors from transforms import bbox2delta, delta2bbox from visualize import (draw_anchor_gt_overlaps, draw_anchor_samples_on_image, draw_base_anchor_on_grid, draw_pos_assigned_bboxes) What is Anchor? 첫 등장: anchor라는 개념은 Faster R-CNN에서 처음으로 제안되었습니다. 주요 사용처: anchor는 대부분의 one-stage, two-stage detector에서 사용하며 대표적으로는 RetinaNet(one-stage)와 Faster R-CNN(two-stage)가 존재합니다. [1] anchor를 사용하는 목적 object detection 문제에서 우리는 이미지 상에 물체 (object)가 있는 영역을 예측하여 Bounding Box(BBox)를 그려야 합니다. 이 때에, 이미지 전체를 한꺼번에 보고 특정 위치를 예측하는 것보다 특정 영역 BBox만을 보고 이 안에 물체가 있는지를 예측하는 편이 더 쉽습니다. 따라서 이미지 상에 균일하게 많은 BBox(즉, anchor)를 그린 뒤에 이 anchor들 중 gt와 서로 겹치는 영역의 넓이를 기준으로 선별된 Anchor를 학습에 활용하게 됩니다. 각 object detector 모델은 위 과정을 통해 선별된 anchor를 이용하여 anchor와 정답(ground-truth)과의 차이에 대해서 예측하도록 학습하게 됩니다. (BBox regression) (이 때, anchor의 크기가 적절하지 못한 경우에는 차이의 편차가 커지게 될 것이므로 학습이 어려워질 수 있어서 적절한 크기를 선정하는게 중요합니다.) anchor는 균일한 간격, 일정한 규칙으로 생성 하여, 물체가 특정 위치에 존재할 때만 탐지가 잘 되거나, 혹은 특정 위치에서는 탐지가 잘 되지 않는 현상을 줄입니다. 이러한 특성을 translation-Invariance라고 하며, 대부분의 object detector 모델이 개선하려고 노력하는 특징입니다. [2] Parameters 설명 scale: feature map에서의 anchor 크기(scale)입니다. ratio: feature map에서의 anchor 비율(ratio)입니다. stride: 이미지를 기준으로 어느 정도 간격으로 anchor를 생성할 것인지 나타내는 값입니다.(주로 이미지와 feature map 크기의 비율 값을 사용합니다.) scale과 ratio가 feature map 내에서의 anchor_base_size를 만들게 됩니다. feature map의 크기는 이미지의 너비, 높이를 stride로 나눈 값이기 때문에 이게 반영된 이미지에서의 anchor 크기는 anchor_base_size * stride 입니다. How to draw grid anchors 이제부터 anchor를 이미지 상에 그리기 위하여 base_anchor와 stride에 대하여 알아보겠습니다.\n base_anchor\n 하나의 anchor bbox는 left top, right bottom의 x, y 좌표를 각각 따서 [x1, y1, x2, y2]로 표현할 수 있습니다. 한 이미지 위에 그려진 anchor의 집합을 뜻하는 grid_anchor는 feature map의 예측 값에 매칭되어야 하기 때문에 feature map과 동일한 width, height를 가지며 channel은 4로 갖습니다. base_anchor는 scale, ratio 2개 parameter로 결정되는 anchor의 작은 집합이며 모든 bbox가 같은 중심을 갖습니다. 크기 단위는 1 anchor_base_size 입니다. [3] RetinaNet의 경우 Octave scale을 사용하였습니다. Faster R-CNN에서 사용한, $2,4,6$ 등 $n$배로 올라가는 scale 간격 대신 $2^0, 2^{\\frac 1 3}, 2^{\\frac 2 3}$과 같이 (base scale)^(octave scale)을 사용하였습니다. [4] anchor_base_size는 주로 feature map의 이미지 대비 stride 값으로 많이 사용하며 이런 경우, feature map이 작은 경우 stride가 커지고 anchor bbox도 커져서 큰 물체를 검출하기에 적합해집니다. 반대의 경우엔 작은 물체를 검출하기에 적합합니다. 통상적으로 CNN이 작은 feature map이 high-level 정보를 잘 나타내어 큰 물체 정보를 잘 다루기 때문에 anchor_base_size를 stride로 사용하는 것이 합리적입니다. 반대의 경우엔 작은 물체 정보를 잘 다루기 때문에 마찬가지로 anchor_base_size를 stride로 다루는 것이 합리적입니다. stride\n feature map 상에서 grid cell의 간격은 실제 이미지 상에서 1 stride (image_width(height) // feature_map_width(height)) 입니다. 즉, 이미지 상에서 생각하면 anchor의 중심 좌표가 stride 만큼 떨어져서 존재하고 그 위에 base_anchor가 그려진다고 볼 수 있습니다. 이렇게 이미지 상에 그려진 것을 가정한 anchors는 각 bbox 들에 존재하는(혹은 존재하지 않는) 물체를 예측하도록 학습할 때 사용됩니다. Settings anchor를 그리기 위한 hyperparameter들을 설정하겠습니다.\n gt_bboxes_list: 예측하고자 하는 정답인 gt의 bbox 목록입니다. gt bbox 크기를 크게 잡으면 다양한 positive anchor 후보들이 생기는 것을 확인할 수 있습니다. scales, ratios: base_anchor의 크기를 조정해주는 값입니다. 이 값들을 조정하면 anchor bbox의 형태를 편향되게 만들 수 있습니다. anchor_base_size: feature map 상에 존재하는 anchor가 이미지 상에서 존재할 때의 크기를 결정해주는 비율 값입니다. anchor_stride(image_size // featmap_size)의 값을 주로 갖습니다. 이 자료에서는 anchor_base_size == anchor_stride == image_size // featmap_size를 가정하겠습니다. 이번 자료에서는 1개 feature map에 대해서만 anchor 분석을 진행하겠습니다. multi-level feature map(FPN 등)이 사용되는 경우는 후속 자료에서 살펴보도록 하겠습니다.\nanchor_base_size = anchor_stride = 32 scales = torch.Tensor([2, 4, 8]) ratios = torch.Tensor([0.5, 1.0, 2.0]) featmap_size = [16, 16] device = 'cpu' image_shape = [256, 256, 3] anchors_per_grid = len(scales) * len(ratios) # x1y1x2y2 gt_bboxes_list = torch.FloatTensor([[32, 32, 32*3, 32*3]]).to(device) Base Anchor 간단한 base_anchor를 생성하여 feature map의 첫 번째 grid cell 위치에 해당하는 이미지 상의 좌표에 그려보겠습니다. 이 base_anchor가 실제 실행시에는 scales * ratios의 개수만큼 생성되며 feature map 의 각 grid cell의 위치에 존재하게 됩니다.\n 각 feature map의 grid cell은 원래의 이미지를 기준으로 하는 좌표를 가지고 있습니다. 이 좌표들마다 base_anchor를 위치시키면 (feature map 기준 각 grid cell에 base_anchor가 존재하게 되면) 이미지 기준으로 stride 만큼 띄엄띄엄 base_anchor가 존재하는 모습을 볼 수 있습니다. base_anchor = gen_base_anchors(anchor_base_size, ratios, scales[:1]) draw_base_anchor_on_grid(base_anchor, anchor_base_size) 각 좌표에 위치한 base_anchor를 한 번에 그리면 도저히 알아볼 수 없을 정도로 빽빽한 사각형들이 만들어지기 때문에 몇 개의 샘플만을 시각화하고 실제 이미지 상에서 어떤 규칙으로 anchor를 그려내는지 확인해보겠습니다.\n아래 그림에서 각각의 anchor들이 일정한 거리(shifts)를 간격으로 하여 만들어지는 것을 볼 수 있습니다.\ndraw_anchor_samples_on_image(image_shape, anchor_base_size, featmap_size, scales, ratios) get_anchors는 gen_base_anchor로 base_anchor를 만들고, feature map의 위치를 나타내는 grid에 base_anchor를 더하고 각 anchor의 valid 여부를 계산해서 anchors, flags를 반환하는 함수입니다. 각 step 별 상세한 내용은 코드를 참고해주시기 바랍니다.\n flags은 anchor가 이미지를 벗어날 때 학습에서 배제하기 위한 flag 입니다. anchors, flags = get_anchors(image_shape, featmap_size, anchor_base_size, anchor_stride, scales, ratios, device) # feature map 32x32 각 pixel에 9개의 anchors assert anchors.shape[0] == featmap_size[0] * featmap_size[1] * 9 # anchor를 사용할 지 말지 결정하는 flags와 anchors의 개수는 같아야 합니다. assert len(flags) == len(anchors) Anchor Selection 각 anchor들은 gt와의 overlap 정도에 따라 positive, negative로 나뉘고 각각을 샘플링해서 학습에 활용합니다.\n one-stage에서는 positive anchor에 1, negative anchor에 0을 배정해서 RPNHead를 학습합니다. two-stage에서는 positive anchor에 가장 overlap이 큰 gt의 class를 배정하고 negative anchor에 0을 배정해서 BBoxHead를 학습합니다. positive anchor는 classification, regression 학습 모두에 활용됩니다. 그래야 특정 BBox에 대해서 object의 class와 BBox 좌표을 예측할 수 있게 됩니다. negative anchor는 classification에만 활용됩니다. 그 이유는 negative의 경우 background라는 정보는 가지고 있지만, 어느 위치에 물체가 있다는 정보는 가지고 있지 않기 때문입니다. [5] overlap은 IoU(Intersection over Union)를 통해 계산합니다. overlaps = bbox_overlaps(gt_bboxes_list, anchors) assert overlaps.shape == (len(gt_bboxes_list), anchors.shape[0]) anchor와 gt의 bbox overlaps인 IoU 값을 feature map에 나타내보겠습니다. 파란색 box는 gt의 위치를 나타내며 gt와 가까울 수록 IoU 값이 커지는 것을 볼 수 있습니다.\ndraw_anchor_gt_overlaps(overlaps, gt_bboxes_list, featmap_size, anchors_per_grid, anchor_stride=anchor_stride, draw_gt=True) 위 그림에서 gt를 제거하고 overlaps인 IoU 값을 위치 별로 heatmap으로 나타내었습니다. 역시나, gt에 가까워질 수록 IoU 값이 커지는 것을 알 수 있습니다.\ndraw_anchor_gt_overlaps(overlaps, gt_bboxes_list, featmap_size, anchors_per_grid, anchor_stride) 아래 코드에서는 overlaps를 이용하여 각 anchor를 postive sample 또는 negative sample로 할당합니다. gt와의 IoU가 높은 anchor를 positive sample로 삼고, IoU가 낮은 anchor를 무작위로 positive sample 개수만큼 뽑아 negative sample로 사용합니다. 그리고 학습을 하기 위해서 classification, regression의 label을 구성합니다.(pos_neg_cls_label, pos_gt_bboxes)\n# gt와의 `overlaps`에 따라 pos, negative를 배정합니다. num_gts, assigned_gt_inds, max_overlaps = assign_wrt_overlaps(overlaps) # positive indices pos_inds = torch.nonzero(assigned_gt_inds \u0026gt; 0).squeeze(-1).unique() # negative indices neg_inds = torch.nonzero(assigned_gt_inds == 0).squeeze(-1).unique() # positive와 1:1 비율로 학습에 사용할 negative sample을 얻습니다. sampled_neg_inds = neg_inds[torch.randint(0, len(neg_inds), size=(len(pos_inds),))] # positive, negative의 label을 0, 1로 구성합니다. pos_neg_cls_label = torch.cat([torch.ones(len(pos_inds)), torch.zeros(len(sampled_neg_inds))]) bboxes = anchors # bboxes pos_bboxes = bboxes[pos_inds] # positive boxes pos_assigned_gt_inds = assigned_gt_inds[pos_inds] - 1 pos_gt_bboxes = gt_bboxes_list[pos_assigned_gt_inds, :] Anchor as a Target 앞서 언급한 것 처럼 anchor를 학습에 사용하기 위하여 gt-anchor 차이를 계산합니다. 이 과정은 [6] anchor bbox를 coordination([x1, y1, x2, y2]) 형태에서 target(target_delta)으로 변환해주는 과정을 의미합니다.(bbox2delta)\ntarget_deltas = bbox2delta(pos_bboxes, pos_gt_bboxes) # 변환이 제대로 되었는지 확인합니다. bboxes_reversed = delta2bbox(pos_bboxes, target_deltas) assert torch.equal(bboxes_reversed[0], gt_bboxes_list[0]) Train anchor anchor target을 만들었다면 앞에서 나온 feature를 network(anchor_head)를 통과시켜 \u0026ensp; \u0026ensp; 1) regression 예측 값(reg_pred)으로 delta를 예측 \u0026ensp; \u0026ensp; 2) class 예측 값(cls_pred)으로 실제 class를 예측 \u0026ensp; \u0026ensp; 하도록 학습시키면 모델이 anchor를 기반으로 object의 class와 위치 정보를 예측할 수 있게 됩니다.\n loss는 one/two-stage network 마다 다르게 적용되나 공통적으로 regression은 smooth-l1를, classification은 cross entropy를 가장 많이 사용합니다. loss 계산에는 positive, negative sample을 모두 다 사용할 수는 있지만, positive sample에 비해 negative sample의 개수가 압도적으로 많으므로, 일부 정해진 숫자 만큼만의 sample을 선정하여 학습에 사용합니다. (e.g. positive:negative=1:1.) [7] 이렇게 anchor prediction을 구하고 그 중에 neg_inds, pos_inds에 해당하는 결과만 가져오는 과정을 거쳐 최종 예측결과인 pos_neg_cls_pred, pos_delta_pred를 구합니다. loss를 구한 뒤에 gradient descent 하는 과정은 생략하겠습니다. pos_neg_cls_pred, pos_delta_pred = predict_anchors(anchors.shape, target_deltas, sampled_neg_inds) # regression, class loss를 각각 계산합니다. reg_loss = smooth_l1_loss(pos_delta_pred, target_deltas, beta=1.0) print(\u0026quot;reg_loss:\u0026quot;, reg_loss) cls_loss = binary_cross_entropy(pos_neg_cls_pred, pos_neg_cls_label) print(\u0026quot;cls_loss:\u0026quot;, cls_loss) reg_loss: tensor(0.0795) cls_loss: tensor(2.7997) Test feature map을 받아 bbox의 cls_pred, delta_pred를 예측할 때 delta를 예측하기 때문에, delta를 bbox로 변환해주는 과정이 필요합니다.(delta2bbox) delta는 gt-anchor의 차이라는 점을 참고하시면 anchor bbox의 coordination 정보를 바탕으로 재변환을 수식적으로 풀어가는 과정을 어렵지 않게 이해하실 수 있습니다. 최종적으로 object 예측 결과는 cls_pred가 특정 threshold 이상인 값들에 대해서 Non-maximum suppresion(NMS)를 통과시킨 결과입니다. cls_pred threshold, nms가 모두 고려되었다고 가정하고 위에서 얻은 pos_delta_pred를 test 결과로 얻었다고 가정하겠습니다. pos_bboxes_pred = delta2bbox(pos_bboxes, pos_delta_pred) 아래 그림에서는 positve predictions에 대해서 예측한 값들을 index 순서대로 시각화해보았습니다.\n# blue: gt, green: anchor, red: prediction draw_pos_assigned_bboxes(image_shape, anchor_base_size, gt_bboxes_list, pos_bboxes, pos_bboxes_pred) Conclusion 이번 글을 통해 object detection에서 anchor의 사용 목적과 구현 방법에 대해서 살펴보았습니다. 다음 글에서는 잠깐 언급한 바 있는, anchor에 positive, negative label을 assign하고 학습에 사용할 sample을 뽑는 과정에 대해 살펴보겠습니다. Reference Faster R-CNN arXiv:1506.01497[cs.CV]\n [2] Translation-Invariant Anchors An important property of our approach is that it is translation invariant, both in terms of the anchors and the functions that compute proposals relative to the anchors. If one translates an object in an image, the proposal should translate and the same function should be able to predict the proposal in either location.\n [3] Multi-Scale Anchors as Regression References Our design of anchors presents a novel scheme for addressing multiple scales (and aspect ratios). The second way is to use sliding windows of multiple scales (and/or aspect ratios) on the feature maps.\n [5] For training RPNs, we assign a binary class label (of being an object or not) to each anchor. We assign a positive label to two kinds of anchors: (i) the anchor/anchors with the highest Intersection-overUnion (IoU) overlap with a ground-truth box, or (ii) an anchor that has an IoU overlap higher than $0.7$ with any ground-truth box. Note that a single ground-truth box may assign positive labels to multiple anchors. We assign a negative label to a non-positive anchor if its IoU ratio is lower than $0.3$ for all ground-truth boxes. Anchors that are neither positive nor negative do not contribute to the training objective.\n [6] For bounding box regression, we adopt the parameterizations of the 4 coordinates following: $$ t_x = (x - x_a) / w_a,\\ t_y = (y - y_a) / h_a, \\ t_w = \\log(w / w_a),\\ t_h = \\log(h / h_a), \\\\\nt_x^{\\ast} = (x^{\\ast} - x_a) / w_a,\\ t_y^{\\ast} = (y^{\\ast} - y_a) / h_a, \\ t_w^{\\ast} = \\log(w^{\\ast} / w_a),\\ t_h^{\\ast} = \\log(h^{\\ast} / h_a) $$\n [7] It is possible to optimize for the loss functions of all anchors, but this will bias towards negative samples as they are dominate. Instead, we randomly sample $256$ anchors in an image to compute the loss function of a mini-batch, where the sampled positive and negative anchors have a ratio of up to $1:1$.\nRetinaNet arXiv:1708.02002[cs.CV]\n [1] The design of our RetinaNet detector shares many similarities with previous dense detectors, in particular the concept of \u0026lsquo;anchors\u0026rsquo; introduced by RPN and use of features pyramids as in SSD and FPN.\n [4] We use translation-invariant anchor boxes similar to those in the RPN variant. The anchors have areas of $32^2$ to $512^2$ on pyramid levels $P_3$ to $P_7$, respectively. at each pyramid level we use anchors at three aspect ratios ${1:2, 1:1, 2:1}$. For denser scale coverage, at each level we add anchors of sizes ${2^0,2^{\\frac 1 3}, 2^{\\frac 2 3}}$ of the original set of 3 aspect ratio anchors. This improve AP in our setting. In total there are $A=9$ anchors per level and across levels they cover the scale range $32-813$ pixels with respect to the network\u0026rsquo;s input image. Each anchor is assigned a length $K$ one-hot vector of classification targets, where $K$ is the number of object classes, and a $4$-vector of box regression targets. We use the assignment rule from RPN but modified for multi-class detection and with adjusted thresholds. Specifically, anchors are assigned to ground-truth object boxes using an intersection-over-union(IoU) threshold of $0.5$; and to background if their IoU is in $[0, 0.4)$. As each anchor is assigned to at most one object box, we set the corresponding entry in its length $K$ label vector to $1$ and all other entries to $0$. If an anchor is unassigned, which may happen with overlap in $[0.4, 0.5)$, it is ignored during training. Box regression targets are computed as the offset between each anchor and its assigned object box, or omitted if there is no assignment.\n[8] The classification subnet predicts the probability of object presence at each spatial position for each of the $A$ anchors and $K$ object classes.\n[9] In parallel with the object classification subnet, we attach another small FCN to each pyramid level for the purpose of regressing the offset from each anchor box to a nearby ground-truth object, if one exists. For each of the $A$ anchors per spatial location, these $4$ outputs predict the relative offset between the anchor and the ground-truth box.\n","date":1560485700,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1560485700,"objectID":"46b0c95da20c175a5768139e7ef4f474","permalink":"/post/2019-06-14-anchor-target/","publishdate":"2019-06-14T13:15:00+09:00","relpermalink":"/post/2019-06-14-anchor-target/","section":"post","summary":"Anchor algorithm in MMDetection","tags":[],"title":"[Tutorial] Anchor","type":"post"},{"authors":["young-kim","whi-kwon"],"categories":[],"content":" Introduction OpenCV와 Python으로 Image processing을 알아봅시다. 이 글에서는 Image thresholding을 간단히 알아보고, 어떻게 응용되는지 Blob labeling예제를 통해 확인하겠습니다. Import Libraries import os import sys import math from platform import python_version import cv2 import matplotlib.pyplot as plt import matplotlib import numpy as np print(\u0026quot;Python version : \u0026quot;, python_version()) print(\u0026quot;OpenCV version : \u0026quot;, cv2.__version__) matplotlib.rcParams['figure.figsize'] = (4.0, 4.0) Python version : 3.6.7 OpenCV version : 3.4.5 Data load sample_image_path = '../image/' sample_image = 'lena_gray.jpg' img = cv2.imread(sample_image_path + sample_image, cv2.IMREAD_GRAYSCALE) coin_image = 'coins.jpg' mask = np.array([[0, 1, 0],[1, 1, 1], [0, 1, 0]], dtype=np.uint8) coin_img = cv2.imread(sample_image_path + coin_image, cv2.IMREAD_GRAYSCALE) ret, coin = cv2.threshold(coin_img, 240, 255, cv2.THRESH_BINARY_INV) coin = cv2.dilate(coin, mask, iterations=1) coin = cv2.erode(coin, mask, iterations=6) Data description 본 예제에서 사용할 데이터는 아래와 같습니다. Lena : 지난 예제에서 사용한 Lena 입니다. Coins : Blob labeling 예제에서 사용될 이미지 입니다. blob labeling이라는 주제에 맞게 전처리가 된 이미지 입니다. (blob labeling에서 자세하게 설명합니다.) plt.subplot(1, 2, 1) plt.imshow(img, cmap='gray') plt.title('Lena') plt.subplot(1, 2, 2) plt.imshow(coin, cmap='gray') plt.title('Coins') plt.show() Binarization Binarization(이진화)이란, grayscale의 이미지를 기준에 따라 0 또는 1의 값만을 갖도록 만드는 작업입니다. 일반적으로 특정 픽셀 값을 기준으로 더 작은 값은 0으로, 더 큰 값은 1로 만듭니다. 사용 목적에 따라 결과 값을 반전시킬 때도 있는데, 추후에 코드 예시로 알아보겠습니다. 이진화 자체는 단순한 작업이나, 추후에 보다 발전된 알고리즘을 다루기 위한 기본이 됩니다. def simple_img_binarization_npy(img, threshold): w, h = img.shape b_img = np.zeros([w, h]) b_img[img \u0026gt; threshold] = 1 return b_img plt.figure(figsize=(8, 8)) b_img1 = simple_img_binarization_npy(img, 200) b_img2 = simple_img_binarization_npy(img, 150) b_img3 = simple_img_binarization_npy(img, 100) plt.subplot(2, 2, 1) plt.imshow(img, cmap='gray') plt.title('Gray Lena') plt.subplot(2, 2, 2) plt.imshow(b_img1, cmap='gray') plt.title('Lena over 200') plt.subplot(2, 2, 3) plt.imshow(b_img2, cmap='gray') plt.title('Lena over 150') plt.subplot(2, 2, 4) plt.imshow(b_img3, cmap='gray') plt.title('Lena over 100') plt.suptitle('Lena with different threshold value (numpy)', size=15) plt.show() 위에서 numpy를 이용했다면, 이번엔 OpenCV 내장 함수를 이용하여 image threshold를 해보겠습니다. OpenCV 함수를 이용하면 numpy로 작성하는 것 보다 편리하게 다양한 결과물을 만들어낼 수 있습니다. cv2.threshold() 함수에 전달하는 인자를 통해 threshold 알고리즘을 다양하게 변경할 수 있습니다. ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) ret, thresh2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV) ret, thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC) ret, thresh4 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO) ret, thresh5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV) plt.figure(figsize=(8, 12)) plt.subplot(3, 2, 1) plt.imshow(thresh1, cmap='gray') plt.title('threshold lena') plt.subplot(3, 2, 2) plt.imshow(thresh2, cmap='gray') plt.title('inversed threshold lena') plt.subplot(3, 2, 3) plt.imshow(thresh3, cmap='gray') plt.title('truncated threshold lena') plt.subplot(3, 2, 4) plt.imshow(thresh4, cmap='gray') plt.title('zero threshold lena') plt.subplot(3, 2, 5) plt.imshow(thresh5, cmap='gray') plt.title('inversed zero threshold lena') plt.suptitle('Lena with different threshold algorithm(OpenCV)', size=15) plt.show() Otsu\u0026nbsp;Algorithm Otsu algorithm(오츄 알고리즘)은 특정 threshold값을 기준으로 영상을 둘로 나눴을때, 두 영역의 명암 분포를 가장 균일하게 할 때 결과가 가장 좋을 것이다는 가정 하에 만들어진 알고리즘입니다. 여기서 균일함 이란, 두 영역 각각의 픽셀값의 분산을 의미하며, 그 차이가 가장 적게 하는 threshold 값이 오츄 알고리즘이 찾고자 하는 값입니다. 위에 기술한 목적에 따라, 알고리즘에서는 특정 Threshold $T$를 기준으로 영상을 분할하였을 때, 양쪽 영상의 분산의 weighted sum이 가장 작게 하는 $T$값을 반복적으로 계산해가며 찾습니다.\n weight는 각 영역의 넓이로 정합니다. 어떤 연산을 어떻게 반복하는지에 대한 내용이 아래 수식에 자세히 나와있습니다. $$ \\begin{align} \u0026amp; T = argmin_{t\\subseteq {1,\\cdots,L-1}} v_{within}(t) \\\\\n\u0026amp; v_{within}(t) = w_{0}(t)v_{0}(t) + w_{1}(t)v_{1}(t) \\\\\n\\\\\n\u0026amp; w_{0}(t) = \\Sigma_{i=0}^{t} \\hat h(i),\\hspace{2cm} \u0026amp;\u0026amp; w_{1}(t) = \\Sigma_{i=t+1}^{L-1} \\hat h(i)\\\\\n\u0026amp; \\mu_{0}(t)=\\frac{1}{w_{0}(t)}\\Sigma_{i=0}^{t}i\\hat h(i) \u0026amp;\u0026amp; \\mu_{1}(t)=\\frac{1}{w_{1}(t)}\\Sigma_{i=t+1}^{L-1}i\\hat h(i)\\\\\n\u0026amp; v_{0}(t) = \\frac{1}{w_{0}(t)}\\Sigma_{i=0}^{t}i\\hat h(i)(i-\\mu_{0}(t))^2 \u0026amp;\u0026amp; v_{1}(t) = \\frac{1}{w_{1}(t)}\\Sigma_{i=t+1}^{L-1}i\\hat h(i)(i-\\mu_{1}(t))^2\\\\\n\\end{align} $$ $w_{0}(t), w_{1}(t)$는 threshold 값으로 결정된 흑색 영역과 백색 영역의 크기를 각각 나타냅니다.\n $v_{0}(t), v_{1}(t)$은 두 영역의 분산을 뜻합니다.\n 위 수식을 그대로 적용하면 시간복잡도가 $\\Theta(L^{2})$이므로 실제로 사용하기 매우 어려워집니다.\n 그러나, $\\mu$와 $v$가 영상에 대해 한번만 계산하고 나면 상수처럼 취급된다는 사실에 착안하여 다음 알고리즘이 완성되었습니다. $$ \\begin{align} \u0026amp;T = argmax_{t\\subseteq{0,1,\\cdots,L-1}}v_{between}(t)\\\\\n\u0026amp;v_{between}(t)=w_{0}(t)(1-w_{0}(t))(\\mu_{0}(t)-\\mu_{1}(t))^2\\\\\n\u0026amp;\\mu = \\Sigma_{i=0}^{L-1}i\\hat h(i)\\\\\n\\\\\n\u0026amp;\\text{초깃값}(t=0):w_{0}(0)=\\hat h(0),\\ \\mu_{0}(0)=0\\\\\n\u0026amp;\\text{순환식}(t\u0026gt;0):\\\\\n\u0026amp; \\hspace{1cm} w_{0}(t)=w_{0}(t-1)+\\hat h(t)\\\\\n\u0026amp; \\hspace{1cm} \\mu_{0}(t)=\\frac{w_{0}(t-1)\\mu_{0}(t-1)+t\\hat h(t)}{w_{0}(t)}\\\\\n\u0026amp; \\hspace{1cm} \\mu_{1}(t)=\\frac{\\mu-w_{0}(t)\\mu_{0}(t)}{1-w_{0}(t)}\\\\\n\\end{align} $$\n 위 순환식을 $t$에 대하여 수행하여 가장 큰$v_{between}$를 갖도록 하는 $t$를 최종 threshold $T$로 사용합니다.\n 이와 같은 알고리즘이 OpenCV의 threshold함수에 구현되어있으며, cv2.THRESH_OTSU 파라미터를 아래 코드와 같이 사용하면 적용이 됩니다.\n plt.figure(figsize=(8, 4)) ret, th = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) plt.subplot(1, 2, 1) plt.imshow(img, cmap='gray') plt.title('Gray Lena') plt.subplot(1, 2, 2) plt.imshow(th, cmap='gray') plt.title('Otsu Lena') plt.suptitle('Lena with Otsu threshold value', size=15) plt.show() Blob\u0026nbsp;labeling Threshold를 통해 할 수 있는 일은 그야말로 무궁무진한데, 그 중 하나로 이미지 분할(image segmentation)을 예시로 들 수 있습니다.\n 만일 threshold 등의 알고리즘을 이용하여 특정 목적에 따라 영상을 분할할 수 있다면(e.g. 사람 손 or 도로의 차선) 1로 정해진 픽셀끼리 하나의 object라고 생각할 수 있을것이고, 우리는 이 object를 묶어서 사용하고 싶게 될 것입니다. 서로 다른 object인지를 판단하기 위하여 픽셀의 연결성 [2] 을 고려한 알고리즘을 수행하고 각기 다른 label을 할당하는데, 이를 Blob labeling이라 합니다.\n Blob labeling을 하면 개별 object에 대해 각각 접근하여 우리가 하고싶은 다양한 영상처리를 개별적으로 적용할 수 있게 되니, 활용도가 아주 높은 기능입니다.\n 본 예제에서는 blob labeling에 대한 개념적인 소개와 OpenCV에 구현된 함수의 간단한 사용법을 확인하겠습니다. [3] 직관적으로 원의 형상을 띄는 위치에 하나의 blob을 의미하는 파랑색 동그라미를 생성하는 모습입니다. 잘못된 위치에 그려진 blob이 눈에 띄는데요, 이와 같은 결과를 parameter를 통해 handling하는 내용에 대해서 차후 다가올 주제인 Image Segmentation에서 확인하겠습니다. ret, coin_img = cv2.threshold(coin, 200, 255, cv2.THRESH_BINARY_INV) params = cv2.SimpleBlobDetector_Params() params.minThreshold = 10 params.maxThreshold = 255 params.filterByArea = False params.filterByCircularity = False params.filterByConvexity = False params.filterByInertia = False detector = cv2.SimpleBlobDetector_create(params) # Blob detector 선언 keypoints = detector.detect(coin_img) # Blob labeling 수행 im_with_keypoints = \\ cv2.drawKeypoints(coin_img, keypoints, np.array([]), (0, 0, 255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) # 원본 이미지에 찾은 blob 그리기 plt.figure(figsize=(15,15)) plt.imshow(im_with_keypoints) plt.title('Coin keypoint', size=15) plt.show() Conclusion Image thresholding의 사용법과 다양한 응용방법, threshold 값을 선택해주는 Otsu 알고리즘을 알아보았습니다. 마지막에 알아본 Blob labeling은 Image processing 분야 전반에 걸쳐 사용되는 곳이 아주 많으니 추후에 더 깊이 알아보는 시간을 갖겠습니다. Reference [1] 오일석, 컴퓨터 비전, 2014, pp. 67-75 [2] \u0026lsquo;Pixel connectivity\u0026rsquo;, Wikipedia. 2019 [Online]. Available: https://en.wikipedia.org/wiki/Pixel_connectivity [3] Satya Mallick., \u0026lsquo;Blob Detection Using OpenCV ( Python, C++ )\u0026rsquo;, \u0026lsquo;Learn OpenCV. 2019 [Online]. Available: https://www.learnopencv.com/blob-detection-using-opencv-python-c/ ","date":1559876400,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1559876400,"objectID":"085a588014c7b89adc4a8bdd5e611276","permalink":"/post/2019-06-07-image-thresholding/","publishdate":"2019-06-07T12:00:00+09:00","relpermalink":"/post/2019-06-07-image-thresholding/","section":"post","summary":"Image threshold using OpenCV","tags":[],"title":"[Tutorial] Image Thresholding","type":"post"},{"authors":["young-kim","whi-kwon"],"categories":[],"content":" Introduction OpenCV와 python으로 Image processing을 알아봅시다. 이 글은 첫 번째 posting으로, Image processing에서 Histogram이란 무엇인지에 대하여 알아보겠습니다. Import Libraries import os import sys import math from platform import python_version import cv2 import matplotlib import matplotlib.pyplot as plt import numpy as np print(\u0026quot;Python version : \u0026quot;, python_version()) print(\u0026quot;OpenCV version : \u0026quot;, cv2.__version__) matplotlib.rcParams['figure.figsize'] = (4.0, 4.0) Python version : 3.6.6 OpenCV version : 3.4.3 Data load sample_image_path = '../image/' sample_image = 'lena_gray.jpg' img = cv2.imread(sample_image_path + sample_image, cv2.IMREAD_GRAYSCALE) Data description 본 예제에서 사용할 데이터는 아래와 같습니다. 거의 대부분의 OpenCV 예제에서 볼 수 있는 Lena 입니다. 단순한 특징의 배경과 복잡한 특징의 인물이 함께 존재하여 다양한 condition을 test하기 좋은 data로 널리 알려져 있습니다. plt.imshow(img, cmap='gray') plt.title('Lena') plt.show() Histogram Histogram이란, 이미지에서 특정 픽셀값의 등장 빈도를 전체 픽셀 갯수 대비 비율로 나타낸 그래프 입니다. 이미지의 전체적인 명암 분포를 한 눈에 확인할 수 있습니다. 두 가지 예제 코드를 통해 Histogram에 대해 알아보겠습니다. def plot_histogram_npy(img): w, h = img.shape w, h = int(w), int(h) hist_cnt = np.zeros(255) hist = np.zeros(255) for j in range(h): for i in range(w): hist_cnt[img[j, i]] += 1 hist = hist_cnt / (w * h) plt.plot(hist) plt.title('Histogram of Lena, numpy', size=15) plot_histogram_npy(img) OpenCV등을 이용하지 않고 numpy만을 이용하여 구한 Lena의 Histogram 입니다. 이미지에서 개별 픽셀값이 몇 번씩 등장하는지 확인하고 전체 픽셀 수로 normalize하여 Histogram을 얻게 됩니다. def plot_histogram_cv(img): w, h = img.shape hist = cv2.calcHist([img], [0], None, [256], [0, 256]) hist_norm = hist / (w * h) # normalize plt.plot(hist_norm) plt.title('Histogram of Lena, OpenCV', size=15) plot_histogram_cv(img) OpenCV를 이용하면 함수 호출을 통해 간단하게 Histogram을 구할 수 있습니다. numpy로 구한 Histogram과 비교해 보면, 두 결과물이 완전히 동일한 것을 알 수 있습니다. \u0026lsquo;cv2.calcHist()\u0026rsquo; 를 수행하면 픽셀값 별 등장 횟수의 그래프를 얻고, 이를 normalize하여 최종적으로 Histogram을 얻게 됩니다. \u0026lsquo;cv2.calcHist()\u0026rsquo; 의 자세한 사용법은 OpenCV 공식 tutorial page를 통해 확인할 수 있습니다. [2] Histogram\u0026nbsp;Equalization Histogram Equalization(히스토그램 평활화)란, pixel값 0부터 255까지의 누적치가 직선 형태가 되도록 만드는 이미지 처리 기법 입니다. 히스토그램 평활화 기법은 이미지가 전체적으로 골고루 어둡거나 골고루 밝아서 특징을 분간하기 어려울 때 자주 쓰입니다. 설명이 난해하니 코드를 통해 자세히 알아보겠습니다. def show_stacked_histogram(img): stack_hist = np.zeros(255, dtype=np.float32) eq_hist = np.zeros(255, dtype=np.float32) w, h = img.shape hist = cv2.calcHist([img], [0], None, [256], [0, 256]) for i in range(255): stack_hist[i] = np.sum(hist[:i]) eq_hist[i] = round(stack_hist[i]) eq_hist /= (w * h) plt.plot(eq_hist) plt.title('Stacked Histogram', size=15) plt.show() show_stacked_histogram(img) 0부터 255까지의 Histogram의 누적치 입니다. 쉽게 말하면 Histogram을 적분한 것이라고 할 수 있습니다. e.g) eq_hist[150] = 0.675 \u0026rarr; 이미지 내에서 0부터 150까지의 pixel이 차지하는 비율 = 67.5% 당연히 항상 eq_hist[0] = 0이며, eq_hist[255] = 1.0 입니다. 전체적으로 직선에 가까운 형태지만 x좌표기준 0 근처와 255 근처는 수평인 것을 알 수 있습니다. 이 말은 Lena image에서 pixel 값 기준 0 근처와 255 근처가 존재하지 않는다는 말 입니다. 즉, 다시 말해 전체 pixel 값들에 대하여 분포가 균일하지 않다는 말 입니다. 히스토그램 평활화는 이와 같이 균일하지 않은 픽셀값의 분포를 고르게 만드는 작업입니다. \u0026mdash; 그럼 이제 히스토그램 평활화를 해보겠습니다. equ = cv2.equalizeHist(img) show_stacked_histogram(equ) OpenCV에 구현되어있는 cv2.equalizeHist()함수를 통해 평활화한 Lena의 Histogram입니다. 이제 Histogram 누적치가 직선 형태라는 말이 확실하게 이해 되실 것 같습니다. \u0026mdash; 마지막으로 이렇게 변화시킨 이미지가 원본 이미지와 어떻게 다른지 확인해 보겠습니다. plt.figure(figsize=(8,8)) plt.subplot(121) plt.imshow(img, cmap='gray') plt.title('Original Lena') plt.subplot(122) plt.imshow(equ, cmap='gray') plt.title('Equalized Lena') plt.show() 전체적인 톤의 변화를 확인할 수 있는데, 밝은 부분은 더 밝아지고 어두운 부분은 더 어두워지는 모습을 볼 수 있습니다. 이는 원본 이미지가 중간 정도 밝기의 픽셀을 다수 포함하고 있었고, 상대적으로 아주 어둡거나 아주 밝은 부분은 적었기 때문입니다. 히스토그램 평활화를 통해 모든 픽셀값이 동일한 비율로 등장하게끔 수정하여 이와 같은 변화가 일어났다고 볼 수 있습니다. 히스토그램 평활화에 대한 자세한 내용은 마찬가지로 OpenCV 공식 tutorial page를 통해 확인할 수 있습니다. [3] Conclusion 이미지 분석의 기초인 히스토그램에 대하여 알아보았습니다. 또한 이미지 처리 기법중 하나인 히스토그램 평활화를 알아보았으며, 실질적으로 히스토그램에 어떤 변화를 주는지 확인할 수 있었습니다. Reference [1] 오일석, 컴퓨터 비전, 2014, pp. 58-63 [2] Alexander Mordvintsev \u0026amp; Abid K., \u0026lsquo;Histograms - 1 : Find, Plot, Analyze !!!\u0026lsquo;, OpenCV-python tutorials. 2013 [Online]. Available: https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_histograms/py_histogram_begins/py_histogram_begins.html#histogram-calculation-in-opencv [Accessed: 29- Mar- 2019] [3] Alexander Mordvintsev \u0026amp; Abid K., \u0026lsquo;Histograms - 2: Histogram Equalization\u0026rsquo;, OpenCV-python tutorials. 2013 [Online]. Available: https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_histograms/py_histogram_equalization/py_histogram_equalization.html#histogram-equalization [Accessed: 29- Mar- 2019] ","date":1559271600,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1559271600,"objectID":"3a9e3a0c8005a7b8fbca52856eb129e2","permalink":"/post/2019-05-31-histogram/","publishdate":"2019-05-31T12:00:00+09:00","relpermalink":"/post/2019-05-31-histogram/","section":"post","summary":"Histogram using OpenCV","tags":[],"title":"[Tutorial] Histogram","type":"post"},{"authors":["hyungkyu-kim"],"categories":[],"content":" 이번 posting에서는 competition에 적용하였던 reward shaping 방법론과 imitation learning 방법론을 기본으로 reward, penalty를 바꿔가며 했던 여러 가지 실험 결과에 관해 이야기해보겠습니다.\n Reward shaping Google deep mind에서 2015년 발표한 Human-level control through deep reinforcement를 보면 다양한 atari game environment에서 DQN의 성능을 볼 수 있습니다. montezuma\u0026rsquo;s revenge 같은 경우 거의 바닥에 수렴(randome play와 같은 수준)하는 결과치를 볼 수 있는데요. 이 게임은 stage를 클리어하기 위해 주인공 캐릭터가 거쳐야 하는 단계가 너무 복잡하고 많습니다. 이것을 강화학습 관점에서 이야기하면 reward가 너무 sparse 하여 강화학습 agent가 어떻게 상황을 헤쳐나갈 지에 대해 갈피를 잡지 못한다고 할 수 있습니다. Comparison of the DQN agent with the best reinforcement learning methods15 in the literature.\nfrom Human-level control through deep reinforcement , V Mnih et al. 2015 \n그렇다면 어떻게 sparse 한 reward를 dense 하게 만들 수 있을까요? 크게 2가지 해결책이 있을 수 있습니다.\n manually design: 수작업으로 직접 reward function을 만듦 learn from demonstration: 전문가의 demonstration trajectory를 모방하게 함 이번 competition에서도 위와 비슷한 문제가 있었습니다. 각 time step 별로 따라가야 할 속도는 나와 있었지만 나머지 정보는 전혀 없는 상태였죠. 특히 자세같은 경우는 상당히 중요한데, 현재의 자세가 다음 자세에 영향을 미치기 때문입니다. 이러한 연속적인 자세의 모음으로 원하는 속도가 제대로 나느냐 안 나느냐가 판가름 나기 때문에, 자세에 대한 상벌은 굉장히 중요한 요소였습니다. 우선 manually design 한 방식으로 접근하기 시작했습니다.\n처음에는 아주 간단한 reward와 penalty부터 출발하였습니다. NIPS2017 competition solution에 공개된 후기들을 탐색한 결과 거의 모든 참가자가 적용하였던 부분이 있었습니다.\n 골반은 전방으로 기울어 져야 한다 -\u0026gt; pelvis의 각도 머리는 항상 골반보다 앞서 위치하여야 한다 -\u0026gt; head, pelvis의 위치 넘어지면 penalty 위 3가지를 넣고 수행하며 결과를 지켜봤는데, round 1 같은 경우 생각보다 괜찮은 결과물이 나왔습니다.\nImitation Learning Learn from demonstration은 Imitation Learning이라고도 불립니다. manually design 전략에서 꽤 괜찮은 결과물을 내었지만, 더 정밀한 reward를 만들기 위해 얼마 안 가 Imitation Learning 관련 리써치를 시작하였습니다. 본격적으로 Imitation learning을 적용하기 시작했을 시기는 competition이 어느 정도 진행된 후였습니다. 앞선 Opensim posting에서 언급했던 것과 같이 여러 가지 시행착오를 겪으며 리써치를 수행한 후에야 어느정도 기본적인 Demonstration을 만들 수 있었기 때문이죠.\nDemonstration으로 쓸 kinematics 데이터셋이 완성되었을 초기에는 이번 competition을 금방 끝낼 수 있을 것만 같은 착각에 빠져있었습니다. 아직 opensim에 대해 조사가 깊이 이루어지기 전이어서, opensim tool들을 사용해서 주어진 kinematics로부터 action을 만들어 낼 수 있다고 파악했기 때문이었죠. 다음 그림과 같이 말이죠. Typical workflow for generating a muscle-driven simulation. from Overview of the OpenSim Workflow action을 만들어내는 것이 왜 중요 했느냐 하면, demonstration과 그에 따른 action이 있다면 Behavioral cloning 방법론을 사용할 수 있었기 때문입니다.\nBehavioral Cloning Brief description 우선 간단하게 Behavioral cloning(BC) 방법론에 대해 살펴봅시다. 기본 컨셉은 매우 간단합니다. 그 이름과 같이 agent를 사람과 같은 experts의 행동을 유사하게 따라 하게 만들겠다는 것입니다. End to End Learning for Self-Driving Cars를 보며 알아봅시다. 우선 training 과정부터 살펴보면 다음 그림과 같이 이루어지게 됩니다.\n from CMU 10703 Deep Reinforcement Learning and Control - Imitation Learning 1 마치 Deep learning에서 CNN Classifier를 학습시키는 것과 유사한데요. Classifier 학습에 빗대자면 Input은 camera를 통해 들어오는 observation 데이터, Output은 steering command 라고 생각할 수 있습니다. 그리고 Label로 제시된 사람이 입력한 steering command와의 차이를 loss로 back propagation을 통해 학습됩니다. 정리하자면 다음과 같습니다.\n 사람의 운전 데이터 수집 Left, Center, Right camera를 통해 observation 데이터를 수집 steering wheel angle 녹화를 통해 action 데이터를 수집 CNN 네트워크 학습 Data augmentation: Left camera에서 수집된 데이터는 action에 우측으로 가는 bias를 더해줌(가운데로 가기 위해) Right camera에서 수집된 데이터는 action에 좌측으로 가는 bias를 더해줌(가운데로 가기 위해) 학습(supervised learning) 학습된 agent를 이용한 test는 매우 단순합니다. 다만 이 방법론은 한계점은 train 데이터셋에서 볼 수 없었던 observation이 test 시에 입력되게 된다면, action에서 미정의 동작이 발생하게 됩니다. deep-learning과는 달리 시시각각 변하는 환경에서 데이터를 입력받기 때문에, 이런 확률은 상당히 높은 편에 속하죠. 정리해서 표현하자면 expert의 trajectory 데이터셋 $P_{\\text{data}}(o_t)$ 와 agent가 현재 policy $\\pi_{\\theta}$를 통해 경험할 수 있는 trajectory 데이터셋 $P_{\\pi_{\\theta}}(o_t)$ 의 분포가 다르기 때문입니다. 식으로 표현하면 다음과 같습니다.\n$$ P_{\\text{data}}(o_t) \\neq P_{\\pi_{\\theta}}(o_t) $$\n이런 문제들을 해결하기 위해 train 데이터셋을 augmentaion하기 위한 여러 가지 방법들이 사용됩니다. DAgger(Dataset Aggregation algorithm)가 대표적인 방법론이죠. The trained network is used to generate steering commands from a single front-facing center camera.\nfrom End to End Learning for Self-Driving Cars , Bojarski et al. 2016 \nOur works 이 방법론을 적용하려고 고민하고 있을 때는 round 1을 진행 중이었기 때문에 금방 끝낼 수 있다는 안일한 생각에 박차를 가했는데요. round 1 같은 경우는 주변 지형지물이나 기타 변화 없이 static 한 환경에서 등속도로 뛰어가기만 하면 되는 문제였기 때문입니다. 정해진 action을 입력한다면 변경 없이 항상 정해진 observation state가 나오게 되고 이런 변화 없는 state만 입력된다면 Behavioral cloning으로 학습된 agent에게는 최적의 환경이라는 생각이었습니다. round 2의 경우 속도가 변화한다는 사실은 알고 있었지만, agent를 우선 기본속도인 1.25m/s로 기본적인 policy를 학습시켜놓고, 가변하는 속도는 학습된 agent를 갖고 재트레이닝하는 방식으로 접근하려고 했습니다.\n그러나 이런 섣부른 기쁨?은 그리 오래가지 못했습니다. 앞선 posting에서 기술했듯이 action을 만들어내는 것이 실패했기 때문입니다. 그렇기 때문에 action 없이 observation state만을 이용한 방법론들을 탐색하게 되었습니다. 여러 논문과 아티클들을 리써치하던 중 적합한 논문을 발견하게 되었는데 그것이 Behavioral cloning from observation입니다.\nBehavioral Cloning from Observation Brief description Behavioral Cloning from Observation(BCO)는 model-based 방법론입니다. Agent의 학습에는 그대로 BC를 사용하지만, observation으로부터 action을 예측하는 model이 추가됩니다. 이 Neural network로 만들어진 model(Inverse Dynamics Model)을 이용, 비어있는 Demonstration의 action을 inference 해서 BC에서 사용할 state, action을 만들어내는 것이죠.\n논문에서 BCO(0)와 BCO(α)의 버전을 두었는데, 차이는 environment와 interaction을 일회성으로 하느냐 지속해서 하느냐의 여부입니다. BCO(0)는 model 학습 시 agent의 최초로 설정된 policy를 통해 interaction(Pre-demonstration)을 하여 만들어낸 state transition 데이터와 action 데이터만 이용합니다. BCO(α)는 agent의 update 된 policy를 이용하여 추가적인 interaction(Post-demonstration)를 수행하고 이 데이터들을 이용합니다. 여기서는 BCO(α)를 사용하였습니다.\n Behavioral Cloning from Observation (BCO(α)) framework. from Behavioral Cloning from Observation , Torabi et al. 2018 전체 프로세스를 간단하게 살펴보면 다음과 같습니다.\n Initialize policy $\\pi_{\\phi}^{i=0}$ agent는 최초에 random policy로 시작 다음 반복 Run policy $\\pi_{\\phi}^i$: agent는 각 time step 별로 environment와 interaction 하여 samples($s_t^a, s_{t+1}^a$), action($a_t$) pair 생성 Append to $\\mathcal{T}_{\\pi_{\\phi}}^a, \\mathcal{A}_{\\pi_{\\phi}}$: 생성된 Samples는 $\\mathcal{T}_{\\pi_{\\phi}}^a$ 에 action들은 $\\mathcal{A}_{\\pi_{\\phi}}$에 넣어줌 Update model $\\mathcal{M}_{\\theta}^i$: $\\mathcal{T}_{\\pi_{\\phi}}^a, \\mathcal{A}_{\\pi_{\\phi}}$를 사용하여 model 업데이트 Infer action: model이 여러 demonstration trajectory의 모음인 $D_{\\text{demo}}$ 사용하여 action inference Update policy $\\pi_{\\phi}^i$: agent의 policy 업데이트. demonstration state들과 inference 된 action들 $\\mathcal{S}_{\\text{demo}}, \\tilde{\\mathcal{A}}_{\\text{demo}}$를 사용하여 behavioral Cloning 수행\n 조금 더 엄밀한 정의를 이야기하자면 모델 $\\mathcal{M}_{\\theta}$ 를 학습시키는 것은 observed transitions를 가장 잘 만들어낼 수 있는 $\\theta^*$를 찾는 것입니다. 수식으로 표현하면 다음과 같습니다.\n$$ \\theta^* = {arg\\,max}_\\theta \\prod_{i=0}^{|\\mathcal{I}^{\\text{pre}}|}p_{\\theta}(a_i | s_i^a, s_{i+1}^a) $$\n이제 imitation policy $\\pi_{\\phi}$를 살펴보면 demonstration의 state들과 model을 통해 inference된 action의 pair {$s_i^a, \\tilde{a}_i$}를 가장 잘 매칭 시킬 수 있는 $\\phi^*$를 찾습니다.\n$$ \\phi^* = {arg\\,max}_\\phi \\prod_{i=0}^{N}\\pi_{\\phi}(\\tilde{a}_i | s_i) $$\nOur works Behavioral cloning 방법론을 택했던 또 다른 중요한 이유는 강화학습 분산처리를 위해 사용하고 있었던 framework인 Ray에서 agent가 미리 구현돼 있었다는 점입니다. 시간에 쫓기는 competition에서 이는 굉장한 이점이었습니다. 그러므로 새로운 학습방법론을 선정하는 과정에서 학습성능과 컨셉 못지않게 비중을 두었던 부분이 어떻게 하면 기존에 있던 모듈을 이용하여 구현시간을 단축할 수 있느냐는 점이었습니다. BCO는 이에 딱 알맞은 방법론이었죠. ray에서 이미 구현되어있는 BC agent를 활용해서 BCO agent를 구현하였습니다.1\n그러나 결과는 생각보다 좋지 않았습니다. 결론부터 이야기하자면 behavioral cloning이 가진 근본적인 문제점이 해결되지 않았습니다. BCO에서 사용하는 action을 inference 해주는 model도 학습하지 못했던 observation 데이터가 들어온다면, 이상한 action을 결과로 만든다는 점이었습니다. 학습이 되지 않은 agent가 environment에서 얻어낼 수 있는 데이터는 고작 넘어지는 동작들뿐이었는데, Demonstration의 복잡한 달리기 싸이클에 대한 action은 당연히도 만들어 낼 수 없었습니다.\n그래서 이러한 model을 학습시키기 위한 데이터 부족현상에 대한 해결책으로, DAgger와 비슷하게 train 데이터를 augmentation 하는 방법을 생각하게 되었습니다. 기존에 실험을 위해 여러 방법론으로 학습시키고 있었던 다른 agent들을 이용하여 state transition 데이터와 action 데이터를 만들어 내었습니다. BCO를 사용하여 학습하기 전에 미리 생성해놓은 데이터셋으로 model을 학습시킨 후, 이 pretrained model을 BCO agent 학습에서 이용하였습니다.\n기대와는 달리 이 결과도 문제가 많았습니다. 다른 방식으로 학습시킨 agent의 동작과 demonstration 동작이 매우 달랐기 때문인데요. reward shaping을 통해 동작에 대한 최소한의 가이드만을 줘서 학습시킨 agent들은 달리는 동작이 각기 제멋대로였습니다. 이 agent들은 자세보다 달성하고자 하는 목적에 좀 더 맞는 형식으로 학습되기 때문에, 사람이 봤을 때 괴상해 보일 수 있지만, reward 상으로 봤을 때는 높은 점수를 얻습니다. 그래서 이 동작들은 demonstration의 달리기 동작처럼 일반적인 데이터가 거의 없었습니다. 아래 그림을 봅시다.\n Round 1 Demonstration Round 1 ARS result 두 그림 모두 round 1 용 데이터들입니다. 좌측은 demonstration 데이터, 우측은 Augmented Random Search(ARS)로 학습시킨 agent의 결과입니다. 그림을 보면 알 수 있지만, 두 동작이 매우 다릅니다. 서 있는 자세에서 달리기까지의 출발 동작은 특히 차이가 심해서 문제가 많았습니다. model이 필요로 하는 참고할만한 transition 데이터가 매우 적었기 때문에, 제대로 된 action을 만들어내지 못했고 결과적으로 이 전략 또한 실패로 마무리되었습니다.\nBC 계열 같은 경우 동작의 시퀀스를 알려줘서 자연스럽게 목적을 달성하게 됩니다. 우리가 goal이나 해야 할 task를 명확하게 지정해주지 않죠. agent에게 각 time step 별로 따라 해야 할 동작들만을 힌트로 제공합니다. 그렇다 보니 time step 별로 지정된 동작의 시퀀스가 한번 깨지게 되고 이런 부분이 쌓이게 되면 결과적으로 달성해야 할 목적에서 크게 벗어나게 됩니다. from CMU 10703 Deep Reinforcement Learning and Control - Imitation Learning 1 \n그러므로 자세를 참고는 하되 달성해야 할 목적을 계속해서 염두에 두고 수행하는, 나아가 참고해야 할 자세와 수행해야 할 목적의 비율을 조정해가며 실험해볼 수 있는 새로운 방법론이 필요하다는 생각을 하였습니다. 또다시 많은 탐색 과정을 거쳐 DeepMimic이라는 방법론을 사용하게 되었습니다.\nDeepMimic Brief description DeepMimic은 Task 목적과 reference의 motion을 모사하는 것을 동시에 고려하는 방법론입니다. 이 방법론의 주요 아이디어는 크게 다음과 같습니다. - Reward - Imitation, Task - Reference State Initialization (RSI) - Early termination (ET) - Multi-Clip Reward\nReward - Imitation, Task DeepMimic 아이디어 중 가장 핵심적인 부분으로 볼 수 있습니다. reward를 크게 2 부분의 합산으로 계산합니다. 얼마나 reference motion을 잘 imitation했는가와 agent가 수행하려는 task를 얼마나 달성했는가입니다. 우선 수식을 봅시다. 특정 time step(t)의 reward인 $r_t$는 다음과 같이 계산됩니다.\n$$ r_t = w^Ir_t^I + w^Gr_t^G $$\n $r_t^I$: imitation reward $r_t^G$: task reward $w^I$: imitation weights $w^G$: task weights 여기서 imitation reward는 다음 수식과 같이 세분됩니다. 전체적인 수식을 먼저 보고, 각 내용에 대해 이야기해 보겠습니다.\n$$ r_t^I = w^pr_t^p + w^vr_t^v + w^er_t^e + w^cr_t^c \\ w^p = 0.65, w^v = 0.1, w^e = 0.15, w^c = 0.1 $$\n $r_t^p$: joint orientations reward $r_t^v$: velocity reward $r_t^e$: end-effector reward $r_t^c$: center-of-mass reward 이제 각 reward들을 조금 더 자세히 봅시다. 먼저 $ r_t^p $는 의 joint orientations의 유사 정도에 따라 reward를 주게 됩니다. 전체 imitation reward에서도 0.65로 가중치가 가장 큰데요. 그만큼 중요한 position 관련 factor라고 볼 수 있겠습니다. opensim에서 봐왔던것처럼, character의 joint의 angle들이 pose를 결정하기 때문입니다. 이것이 kinematics 데이터로 표현돼 있고요. 각 joint들의 least squares error의 가중치 합으로 계산됩니다. 수식을 보면 다음과 같습니다.2\n$$ r_t^p = exp[-2(\\sum_j|\\hat{q}_t^j - q_t^j|^2)] $$\n $\\hat{q}_t^j$: time step t일때, reference의 j번째 joint의 orientations $q_t^j$: time step t일때, agent의 j번째 joint의 orientations 두 번째로 velocity reward는 다음과 같이 계산합니다.\n$$ r_t^v = exp[-0.1(\\sum_j|\\hat{\\dot{q}}_t^j - \\dot{q}_t^j|^2)] $$\n $\\hat{\\dot{q}}_t^j$: time step t일때, reference의 j번째 joint의 각속도 $\\dot{q}_t^j$: time step t일때, agent의 j번째 joint의 각속도 세 번째는 end-effector reward입니다. character의 손과 발같은 말단부(end-effector)의 위치가 reference와 유사한 정도를 계산합니다.\n$$ r_t^e = exp[-40(\\sum_e|\\hat{p}_t^e - p_t^e|^2)] $$\n $\\hat{p}_t^e$: time step t일때, reference의 e번째 end-effector의 위치 $p_t^e$: time step t일때, agent의 e번째 end-effector의 위치 마지막으로 center-of-mass reward입니다. character의 질량중심(center-of-mass)의 위치가 reference와의 차이 정도에 따라서 reward가 달라집니다.\n$$ r_t^c = exp[-10(\\sum_e|\\hat{p}_t^c - p_t^c|^2)] $$\n $\\hat{p}_t^c$: time step t일때, reference의 center-of-mass 의 위치 $p_t^c$: time step t일때, agent의 center-of-mass 의 위치 task reward는 agent가 달성하고자 하는 목표마다 달라지는데 기본적으로 수식의 형태는 imitation reward와 비슷하게 exp[sum(least square error)] 형태입니다.\n의미들을 우선 살펴보았는데, reward 수식의 형태를 조금 더 자세히 분석해 보겠습니다. 수식의 가장 안쪽에 reference와 차이를 계산하는 error sum 부분을 봅시다.\n$$ r_t^p = exp[\\underbrace{-2(\\sum_j|\\hat{q}_t^j - qt^j|^2)}{\\text{error sum}}] $$\n일단 $-x^2$의 그래프는 다음과 같은 형태입니다. \n여기서 x를 reference와 agent의 특정 factor의 차이라고 보면, 차이가 커지면 커질수록 결괏값이 - 방향으로 커지고, 작아지면 작아질수록 0에 가까워집니다. 또한, factor의 차이가 작아지면 결과로 나오게 되는 결괏값의 차이가 작습니다. 그래프를 보면 직관적으로 알 수 있지만, 결괏값이 0에 가까워질수록 그래프가 뭉뚝해집니다. factor 간의 차이가 크면 클수록 더 강한 페널티를 준다고 볼 수 있습니다.\n이제 바깥쪽 부분을 봅시다.\n$$ r_t^p = exp[\\text{error sum}] $$\nexponential의 그래프는 다음과 같은 형태입니다. \n여기서 y축은 reward, x축은 위에서 설명한 error sum의 결괏값입니다. error sum 결괏값은 무조건 0보다 작은 값을 갖기 때문에 reward는 0~1 사이의 값을 갖게 됩니다. reward의 max 값이 1로 설정되는 셈이죠. 또한, error sum 결괏값(reference와의 차이)이 커지면 커질수록 x값은 exp그래프의 마이너스 방향으로 찍히게 되므로, 결과로 나오는 reward 값은 0에 한없이 가까워지게 됩니다. 이 차이 값이 -3 정도가 넘어가게 되면 얻게 되는 reward는 0.05 이하로 매우 낮아지게 됩니다. 여기서 알 수 있는 중요한 사실은 error sum의 결괏값이 어느 범위내에 들어오는 것을 적법한 reward로 인정할 것이냐를 error sum 수식 앞에 붙은 계수를 통해서 조절한다는 것입니다. 즉, reference와의 차이의 허용치를 조절한다는 말입니다. factor들은 다양한 물리량을 다룹니다. 어떤 것은 angle이 될 수도 있고, position 값들이 될 수도 있습니다. 이런 값들이 표현되는 고유한 형식에 따라 분포된 범위가 달라질 수 있습니다. 그리고 agent를 학습시키는 개발자들의 필요에 따라 유효한 범위를 조절하고 싶을 수 있습니다. 이런 부분들을 -2, -0.1, -40, -10과 같은 계수들을 통해 통제합니다. \nReference State Initialization (RSI) 일반적인 강화학습에서는 각 episode 시작 시에 initial state가 고정되어 있습니다. 게임을 시작할 때 시작 포인트와 캐릭터가 항상 똑같은 곳에 위치하는 것처럼요. 복잡한 동작을 배우기에는 이런 전략이 유효하지 않을 수 있습니다. 왜냐하면, agent의 policy는 항상 초기의 reference의 motion부터 차례대로 학습이 되는데, 초기 동작을 확실하게 마스터하기 전까지는 후속 동작을 학습하기 어렵습니다. 또한, 강화학습은 이전에 경험한 trajectory에서 높은 reward를 한 번이라도 얻어야만 제대로 된 학습이 가능한데, backflip같이 복잡하고 어려운 동작은 random exploration을 통해 성공적인 결과를 얻기가 매우 어렵습니다. from Towards a Virtual Stuntman \n그러므로 RSI에서는 이 initial state를 변경합니다. reference motion의 state 중 한 포인트에서 무작위로 시작합니다. backflip으로 예를 들자면 어떤 때는 땅에서 시작할 수도 있지만, 어떤 때는 공중에서 몸이 돌아가는 중이 될 수도 있겠지요. from Towards a Virtual Stuntman \nEarly termination (ET) agent가 특정 상황에 끼어서(stuck) 더는 학습을 진행할 수 없는 상태일 때, 학습을 일찍 종료시킵니다. 달리기를 배우는 환경인데 넘어졌다던가 하는 상황같이요. 이번 competition에서 골반의 위치가 특정 높이 이하로 떨어지면 ET를 수행시키는 코드가 기본적으로 들어가 있습니다.\n Comparison of policies trained without RSI or ET. RSI and ET can be crucial for learning more dynamics motions. Left: RSI+ET. Middle: No RSI. Right: No ET.\nfrom Towards a Virtual Stuntman Multi-Clip Reward 여러 reference motion을 활용하여 agent를 학습시킵니다. 매 time step 별로 여러 reference 중 적합한 것을 골라내는 manually crafted kinematic planner와 같은 방식보다 간단하면서 좋은 성능을 보였다고 합니다. 수식을 보면 명확한데, 해당 time step에서 가장 reward가 높은(max) reference의 reward를 사용합니다.\n$$ r_t^I = \\max_{j=1, \u0026hellip; ,k}r_t^j $$\n $r_t^j$: j번째 motion clip의 imitation reward Our works DeepMimic을 적용하기 위해 opensim-rl의 reward function을 새로 정의하였습니다. DeepMimic에서 사용하였던 모든 주요 아이디어를 적용하려고 하였지만, RSI 같은 경우는 시뮬레이션 환경 자체를 뜯어고쳐야 하는 번거로움이 있었고, opensim 시뮬레이터를 그 정도로 깊게 연구할 시간이 없었기 때문에 Reward, ET, Multi-Clip Reward 정도만 적용할 수 있었습니다. 이 작업을 수행하며 고민했던 포인트는 다음과 같습니다.\n demonstration 데이터의 신뢰성 문제 reference와 어떤 factor들의 수치를 비교할 것인가? reward들의 각각의 weight는 어떤 식으로 설정할 것인가? penalty 설정 여부 task reward는 어떻게 설정할 것인가? 우선 demonstration의 신뢰성 문제부터 이야기해 보겠습니다. 기반이 되었던 kinematics같은 경우 실험데이터를 기본으로 작업이 되었지만, 수작업으로 데이터 수정을 통해 만들어냈기 때문에 이것이 실제 시뮬레이션 환경에서 동작할지 미지수였습니다. \n물론 수정한 kinematics가 동작하는 것을 opensim gui tool에서 확인하였지만, 이것은 근육의 action을 통한 동작이 아닌 단순히 pose들의 연속인 껍데기만 동작시킨 것이기 때문입니다. 앞선 BCO에서는 action 데이터를 만들 때 이미 시뮬레이션을 이용하기 때문에 그리 큰 문제로 생각하지 않았습니다. 그러나 여기서는 오로지 kinematics의 차이만을 가지고 학습에 사용하기 때문에 문제가 될 수 있었습니다. 그렇기 때문에 demonstration을 validation 하기 위해 여러모로 연구를 하였지만, 뾰족한 수를 찾을 수가 없었습니다. 결국, imitation reward와 task reward의 weight를 바꿔가며 실험적으로 성공적인 수치를 찾아내기로 하였습니다. 우선 만들어져 있는 demonstration에 대해 신뢰성이 떨어졌으므로 task reward weight를 조금 더 크게 잡는 쪽으로 실험을 시작하였습니다.\n그리고 imitation reward를 설정하기 위해 어떤 factor들을 비교할 것인지를 알아내야 했습니다. 우선 현재 reference로 사용할 demonstration의 데이터 중 사용 가능한 필드들의 파악이 중요했는데요. 이것은 kinematics의 유효성과는 별개의 문제였습니다. 이전 posting에서 언급했듯 kinematics 데이터를 통해 demonstration의 state들을 만들어주는 opensim tool을 이용한 script의 결과가 얼마나 유효한 데이터인지 알 수 없었기 때문입니다. 이 프로그램의 역할을 조금 더 자세히 설명하면, kinematics 데이터에 있는 각 time step 별 position, joint angle 값들을 바탕으로 velocity, acceleration 같은 값들을 계산해서 state들에 추가합니다. 그래서 새로 추가된 데이터들의 유효성을 검증하고자, 다음 그림과 같은 과정을 사용하였습니다. \nobservation의 데이터에는 모든 position, velocity, acceleration 값들이 포함되어 있습니다. 여기서 얻은 데이터를 정답으로 했을 때, script를 통해 새로 만들어낸 데이터와 얼마나 유사한지를 검사하였습니다. 그 결과 acceleration을 제외한 값들은 80% 이상의 유사도를 보였고, 이 정도면 가중치를 통해 경중을 조절해가며 reference로 이용할만한 값이라고 판단했습니다. 그렇게 해서 최종적으로 reference로 사용하기로 한 factor들은 joint angle(pose), joint velocities, center-of-mass이 3가지입니다.\nreward의 weight 및 penalty를 결정하는 일은 굉장히 시간이 많이 소요되는 일이었습니다. 끝이 언제일지 모를 hyper parameter tuning 작업이었는데요. imitation reward와 task reward의 비율부터, imitation factor들의 계수들, penalty 사용 여부 및 설정까지. 수정하고 실험해야 할 것들이 엄청나게 많았습니다. 또한, 실험을 진행하며 새로운 파라미터들을 추가해야만 했는데, kinematics 데이터의 불확실성 때문인 듯 rotation 값과 position 값들의 단순 비교만으로는 제대로 된 학습이 이루어지지 않았습니다. 해결책을 찾던 중 opensim IK tool에서 계산하는 것을 참고하여, joint들에 weight를 각각 따로 부여하여 중요한 부분은 오류에 민감하게 반응하도록 하니 학습이 이루어졌습니다. 그래서 최종적으로 아래 예제와 같이 parameter configuration을 만들고 hyper parameter tuning을 진행하였습니다.\n************************************ reward configuration step limit: 150 task reward: True reward proportion: - task: 3 - imi: 7 imitation reward weight: - rot weight: -4 - vel weight: -0.1 - center pos weight: -10 - task weight: -2.5 joint weight: - pelvis_tilt : 15 - pelvis_list : 5 - pelvis_rotation : 1 - hip_flexion_r : 3 - hip_adduction_r : 3 - knee_angle_r : 0.5 - hip_flexion_l : 3 - hip_adduction_l : 3 - knee_angle_l : 0.5 - ankle_angle_l : 2 demo files: - /home/medipixel/demos/GIL02_free2_181019.xlsx - /home/medipixel/demos/GIL02_free2_181026_3.xlsx - /home/medipixel/demos/GIL02_free2_181026_2.xlsx ************************************ 학습 시에 시뮬레이션을 처음부터 끝까지 돌려서 결과를 확인하지 않고 time step을 150~200 step 정도에서 끊고 추이를 지켜보았는데요. 튜닝을 위한 시간을 아끼기 위해서였기도 하지만 출발 자세가 제일 중요하다고 판단했기 때문입니다. 우선 이 과정이 가속을 시작하는 부분이었기 때문에 빠르게 목표 속도에 진입하기 위해 가장 중요한 부분이었고, gait cycle에 안정적으로 진입하기만 한다면 같은 움직임이 반복되기 때문에 큰 어려움 없이 학습이 가능하다고 생각했기 때문입니다. 여러 실험을 하며 다음과 같은 결과들을 얻을 수 있었습니다.\n 마지막으로 문제의 task reward 부분입니다. task reward 같은 경우는 deepmimic에서 사용하는 exp[error sum]형태를 사용하였는데, 출발 동작을 학습시킬 때까지는 문제없이 동작하는 것처럼 보였습니다. 그러나 제출 3일 전 거의 모든 parameter를 확정하고 본격적으로 최종 트레이닝을 시키려고 할 때 정작 이 task reward로는 전진이 안 된다는 것이 밝혀졌습니다.\n물론 다른 전략으로 ARS agent를 트레이닝 중이어서 최악의 상황에도 제출은 할 수 있었지만, 여러 실험을 통해 출발자세를 다잡아놓은 agent를 포기하기 너무 아까웠습니다. 시간은 매우 촉박했지만, round 1 agent는 동작을 그나마 잘했던 것에 착안, 초심으로 돌아가서 round 1의 설정부터 살펴보기로 하였습니다.\nConclusion round 2를 진행하며 task reward 부분을 deepmimic처럼 exp 형태로 바꾼 결정적인 이유가 있었는데, task reward를 기본 reward 형태로 설정해놓으면 전진하지 않고 그 자리에 가만히 서 있기 때문이었습니다. 그러나 round 1 같은 경우는 task reward를 변형하지 않고 기본형으로 쓰더라도 아무 문제 없이 학습이 잘되었죠. 심지어 imitation learning을 쓰지 않더라도요. 그런 이유에서 round 1의 reward를 살펴보며 차이점을 파악하려 했습니다. 이런저런 검토를 하던 중 중요한 점을 발견했습니다. 설명에 앞서 round 1과 round 2의 비교를 먼저 해보겠습니다. 우선 round 1 reward의 코드는 다음과 같습니다.\nreward = 9.0 - (state_desc[\u0026quot;body_vel\u0026quot;][\u0026quot;pelvis\u0026quot;][0] - 3.0)**2 이를 그래프로 그려보면 다음과 같습니다. x축은 속도 y축은 reward입니다. 그리고 round 2의 기본 reward 코드를 보면 다음과 같습니다.3\n# target_vel = 1.25 penalty += (state_desc[\u0026quot;body_vel\u0026quot;][\u0026quot;pelvis\u0026quot;][0] - state_desc[\u0026quot;target_vel\u0026quot;][0])**2[0])**2 reward = 10.0 reward - penalty 그래프는 다음과 같습니다. \n이 둘의 차이점은 그래프를 보면 명확해지는데, round 1이 전진에 성공했던 이유는 속도가 0일 때 reward를 얻지 못하기 때문입니다. 그에 반해 round 2는 당연히도 전진하지 않았습니다. 서 있으면(속도가 0일 때) 안전하게 8 이상의 reward 취득이 가능하기 때문입니다. 전진하는 것은 굉장한 risk를 짊어지는 일입니다. 현재 자세를 망쳐가며 불안정한 자세에 진입하는 것이기 때문이죠. 비교적 손쉽게 얻을 수 있는 reward를 포기하는 것 입니다. 그래서 상대적으로 쉬운 reward에 overfitting 되는 것이었습니다. 아주 재미있게도 약삭빠른 사람처럼 꼼수부터 배운 것이죠.\n여기서 개선 가능한 부분을 발견했습니다. round 2의 리워드를 round 1처럼 속도가 0일 때 리워드 취득을 못하도록 바꾸는 것입니다. 그리고 더 나아가 오히려 가만히 서 있으면 penalty를 주는 방법을 적용했습니다. 속도가 0일 때 약간의 벌점을 받도록 했습니다. 벌점이 너무 세면 agent가 주눅?들어서 오히려 아무 행동도 취하지 못했습니다. 이렇게 task reward를 개편하니 드디어 전진을 시작했습니다. 그러나 가장 중요한 자원인 시간부족으로 학습을 완료할 수 없었습니다…. 마지막 학습 결과는 다음과 같습니다. \n결국, 최종 결과물은 imitation learning이 아닌 ARS에서 학습하였던 agent가 되었습니다.\n이번 competition에 imitation learning을 사용하여 학습시킨 결과물 제출은 실패했지만 위 일련의 과정을 진행하며 얻었던 경험과 지식은 앞으로 개발에 있어 피와 살이 될만한 것들이었습니다. 마지막으로 여기서 알 수 있었던 가장 중요한 점은 agent가 타고 올라갈 수 있는 reward function을 만들어줘야 한다는 점입니다. 적당한 채찍과 적당한 당근이 필요합니다. reward를 통해 나의 의도를 agent에 심을 수 있어야 합니다. 더하지도 덜하지도 않게 말이죠.\nReferences Bojarski, M., Del Testa, D., Dworakowski, D., Firner, B., Flepp, B., Goyal, P., \u0026hellip; \u0026amp; Zhang, X. (2016). End to end learning for self-driving cars. arXiv preprint arXiv:1604.07316. Ross, S., Gordon, G., \u0026amp; Bagnell, D. (2011, June). A reduction of imitation learning and structured prediction to no-regret online learning. In Proceedings of the fourteenth international conference on artificial intelligence and statistics (pp. 627-635). Torabi, F., Warnell, G., \u0026amp; Stone, P. (2018). Behavioral Cloning from Observation. arXiv preprint arXiv:1805.01954. Peng, X. B., Abbeel, P., Levine, S., \u0026amp; van de Panne, M. (2018). DeepMimic: Example-Guided Deep Reinforcement Learning of Physics-Based Character Skills. arXiv preprint arXiv:1804.02717. Liu, M. Q., Anderson, F. C., Schwartz, M. H., \u0026amp; Delp, S. L. (2008). Muscle contributions to support and progression over a range of walking speeds. Journal of biomechanics, 41(15), 3243-3252. Mnih, V., Kavukcuoglu, K., Silver, D., Rusu, A. A., Veness, J., Bellemare, M. G., \u0026hellip; \u0026amp; Petersen, S. (2015). Human-level control through deep reinforcement learning. Nature, 518(7540), 529. Xue Bin (Jason) Peng. (2018). Towards a Virtual Stuntman. Available at: https://bair.berkeley.edu/blog/2018/04/10/virtual-stuntman [Accessed 13 Dec. 2018]. UC Berkeley. (2018). Deep Reinforcement Learning. Available at: http://rail.eecs.berkeley.edu/deeprlcourse/ [Accessed 11 Dec. 2018]. Carnegie mellon university. (2018). Imitation Learning. Available at: http://www.andrew.cmu.edu/course/10-703/slides/Lecture_Imitation_supervised-Nov-5-2018.pdf [Accessed 12 Dec. 2018]. 구현 내용에 대한 설명은 다음 posting에서 다룰 예정입니다. ^ 논문에서는 이 수식에 - 기호가 아닌 $\\ominus$ 가 사용됩니다. 이유는 논문에서 사용된 데이터가 joint orientation을 quaternion로 표현하기 때문인데, quaternion difference를 구하는 것을 $\\ominus$라고 한 것입니다. 여기서는Towards a Virtual Stuntman에 언급한 것처럼 일반 - 를 사용하였습니다. ^ 사실 round2 reward에는 z축 penalty가 더 있습니다. 다만 여기서는 가장 큰 점수 차이가 발생하는 부분이 x축 penalty이기 때문에 간소화를 위해 생략했습니다. ^ ","date":1545139337,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1545139337,"objectID":"560003bdab8e68a5b8d3bbb0e877ff10","permalink":"/post/2018-12-18-nips2018-imitation_learning/","publishdate":"2018-12-18T22:22:17+09:00","relpermalink":"/post/2018-12-18-nips2018-imitation_learning/","section":"post","summary":"Imitation Learning for AI for Prosthetics Challenge","tags":[],"title":"[Competition] AI for Prosthetics Challenge - Imitation Learning","type":"post"},{"authors":["hyungkyu-kim"],"categories":[],"content":" 이번 파트에서는 Opensim 환경과 Task 에 대해 설명하도록 하겠습니다. (competition이 종료된 후 새로운 webinar 가 나왔습니다. 자세히 설명되어 있으니 참고 바랍니다.)\n I. Opensim 강화 학습에서 환경(environment)이란 매우 중요한 요소입니다. 강화학습 Agent가 interaction을 통해 주어진 task를 수행하는 공간이 바로 이곳이기 때문에 당연한 말이겠죠. 어떤 방식으로 접근하던 환경에 대한 깊은 이해가 선행되어야만 좋은 솔루션이 나올 수 있다해도 과언이 아닙니다. 때문에 저희 팀은 이번 컴페티션을 진행하면서 opensim이라는 환경을 심도 있게 이해하기 위해 많은 노력을 기울였습니다.\nOpensim은 신경근 골격 모델(neuromusculoskeletal model)의 움직임을 시뮬레이션 하기위한 소프트웨어입니다. 실험데이터를 분석하고 움직임을 시뮬레이션하여 해부학, 생리학, 운동역학 등의 접근을 가능하게 합니다. 굉장히 다양한 분야에서 쓰일 수 있는데, 운동 시퀀스를 분석해서 개선한다든가, Modeling Evaluation and Control Optimization of Exosuit with OpenSim 와 같이 의족이나 기타 보조기기 착용 시 움직임 예측 등등에 쓰입니다. 시스템의 모든 부분을 전부 언급하기에는 너무나 방대하므로 여기서는 개괄적인 부분과 opensim-rl에 관련된 부분 위주로 기술하도록 하겠습니다.\nWorkflow 우선 opensim을 이용한 기본적인 분석 시퀀스는 다음과 같습니다.\n Elements of a typical musculoskeletal simulation in OpenSim. from OpenSim: Simulating musculoskeletal dynamics and neuromuscular control to study human and animal movement 방대한 시스템답게 생체역학적 움직임에 대한 다양한 분석이 가능한데요. 어떤 방향으로 문제를 보는가에 따라 크게 2가지로 나뉠 수 있습니다.\n Inverse problem Forward problem 1. Inverse problem 일반적으로 opensim을 쓰는 많은 생체 역학 분야의 연구자들이 쓰는 방식입니다. 실험데이터를 통해 움직임에 관련된 여러 가지 분석을 하기 위해 사용되죠. 위의 시퀀스 그림에서 보면 Movement -\u0026gt; Neural command 방향으로 진행되는 프로세스라고 볼 수 있습니다. 마커를 부착해서 실험으로부터 특정 모션에 관한 데이터를 얻어내고, 이를 통해 움직임의 역학 모델을 만들어 근육의 활성화 정도와 근육을 활성화 시키는 데 필요한 신경의 흥분 정도를 계산합니다. 다음과 같은 문제들의 답을 얻어내는 과정을 통해 motion에 관련된 여러 가지 수치를 얻을 수 있습니다.\n Inverse problem. from Tutorial 3 - Scaling, Inverse Kinematics, and Inverse Dynamics Inverse kinematic 해당 motion을 만들어내는 각 joint의 angle 값들을 구합니다. pose와 관계된 내용이므로, 질량이나 관성 같은 값들은 필요 없습니다.\nCF) Forward kinematics VS Inverse kinematics\n Forward kinematics는 주어진 joint position(angles)들로부터 말단장치(end effector)의 위치를 구합니다. Forward kinematics. from Inverse Kinematics Inverse kinematics는 주어진 말단장치(end effector)의 위치로부터 joint position(angles)들을 구합니다. Inverse Kinematics. from Inverse Kinematics Inverse dynamics 해당 motion을 유발하는 force와 moment값들을 구합니다. 여기서 얻어낸 force들을 사용해서 어떤 근육들이 얼마만큼의 힘을 받는지 알아냅니다. 이를 계산하기 위해 질량과 관성 같은 값들이 필요합니다.\n기본적으로 뉴턴과 오일러의 수식이 사용됩니다.\n Newton (linear): F = m.a (Force = mass x linear acceleration) Euler (angular): M = I.α (Moment = mass moment of inertia x angular acceleration) 그리고 다음 가정들이 적용됩니다.\n Joint는 무마찰 핀 조인트(frictionless pin joint) 질량 중심에 집중질량이 있다고 가정된 각 강체들의 조합 주동근과 길항근( agonist and antagonist)의 공동(동시)수축은 없음 공기 저항은 최소 완전히 정밀한 인체 동작 연구까지는 불가능하지만, 상당히 유의미한 결과를 얻을 수 있습니다.\n2. Forward problem 이번 competition에서 쓰이는 opensim-rl에서 사용되는 방식입니다. Neural command -\u0026gt; Movement 방향으로 진행됩니다. 일반적인 인간, 동물의 움직임을 떠올리면 됩니다. neural command의 excitation 정도에 따라 근육의 수축/이완의 길이와 속도가 결정되고 그에 따른 motion이 만들어집니다.\nArchitecture Opensim의 전체 구조는 다음 그림과 같습니다. 하부 단은 simtk API 를 이용하여 이루어져 있는데 실제 시뮬레이션 관련 계산은 대부분 여기서 이루어집니다. OpenSim\u0026rsquo;s Architecture. from OpenSim\u0026rsquo;s Architecture and API \nExacutables Opensim API를 이용한 여러 가지 응용 시스템들입니다. opensim gui app부터 이번 competition에서 사용되는 opensim-rl 까지 모두 이 부분에 속합니다.\n대략 다음과 같은 인터페이스를 통해 opensim을 사용 가능합니다.\n GUI command line XML Python scripting MATLAB scripting C++ Opensim API 시뮬레이션 수행을 위한 모델의 구조를 정의합니다. 근골격 관련 ,신경 관련 등의 설정 관련 모듈들을 갖고 있습니다. SimTK를 이용하여 시뮬레이션을 수행합니다.\n Model: 근골격 모델 class. xml 파일을 통해 설정을 읽어올 수 있습니다. ModelComponents 들을 포함합니다. OpenSim Model Class Structure. from OpenSim\u0026rsquo;s Architecture and API \n ModelComponent: 근골격 모델의 특정 부분을 나타내는 class. simtk의 multibodySystem에서 사용되어 계산됩니다. OpenSim ModelComponent. from OpenSim\u0026rsquo;s Architecture and API \n Manager: 전체 시뮬레이션 동작을 관리하는 class. SimTK::Integrator 와 SimTK::TimeStepper를 이용하여 시뮬레이션을 수행합니다.\n Analysis: 분석 관련 plug-in class. 시뮬레이션과 관련된 여러 가지 분석된 수치들을 기록할 때 사용합니다.\n SimTK 시뮬레이션 동작을 위한 연산 엔진입니다. SimTK::Integrator 와 SimTK::TimeStepper이 time step 별로 시뮬레이션의 변화를 계산합니다. 내부적으로 봤을 때 그림과 같이 subsystem 들로 구성되어 있습니다. Systems are composed of Subsystems. from Simbody User\u0026rsquo;s Guide \u0026ndash; start here 이 subsystem들이 시뮬레이션의 현재 time step의 state들을 이용하여 다음 state들을 만들어냅니다. state들은 stage를 갖고 있으며 순차적으로 계산되어 저장됩니다. 이전 stage의 결과는 다음 stage의 계산에서 사용되어 집니다. 전체 구조는 다음과 같습니다. The organization of a computation into ordered stages. from Simbody User\u0026rsquo;s Guide \u0026ndash; start here state에서 사용되는 주요 변수들은 다음과 같습니다.\n t: time q: generalized coordinates u: generalized speeds z: auxiliary variables Structure 자 이제 위에서 언급했던 모든 모듈들과 시스템들이 합쳐진 전체 구조를 봅시다. opensim에서 visualization되는 model부터 하부의 simtk까지 다음 그림과 같은 연결 구조로 되어 있습니다. The OpenSim modeling layer. from OpenSim\u0026rsquo;s Architecture and API \nTools Opensim은 필요한 수치들을 구할 수 있도록 미리 구현된 application인 computational tool들을 제공해줍니다. Opensim GUI app에서 사용할 수 있고, script 방식으로 matlab이나 python에서도 직접 함수를 호출하여 사용 가능합니다.\ntool은 기본적으로 필요한 설정파일, 데이터 파일들을 load해서 사용하는데요. RRA tool의 예제를 보면 다음과 같습니다. Inputs and Outputs for performing residual reduction. from Getting Started with RRA 좌측의 subject01_walk1_ik.mot, subject01_walk1_grf.xml, subject01_simbody.osim 이 인풋되는 데이터와 모델들이고, 상단의 gait2354_RRA_Actuators.xml, gait2354_RRA_Tasks.xml이 관련 설정들 입니다. 설정파일은 한번에 합쳐서 subject01_Setup_RRA.xml로 입력할 수 있습니다. 우측의 파일들은 결과물로 나오게되는 아웃풋들입니다.\nGUI app에서의 사용법은OpenSim: Complete Run-through youtube를 참고하시기 바랍니다.\n또한 라이브러리 형태로 제공된 tool들을 코드상에서 사용하는 예제는 medipixel git 을 참고하시기 바랍니다.\nScale 실험 데이터는 보통 모션캡쳐를 통해 얻게 됩니다. 신체 여러 부위의 마커를 달고 측정되는 각각의(x, y, z)좌표를 기록하는데요, 여기서 획득하게 되는 좌푯값들은 마커를 달고 있는 사람의 신체비율에 따라 조금씩 달라집니다. 따라서 정확한 시뮬레이션을 위해서는 실제 측정한 사람의 신체 비율과 시뮬레이션에 사용될 모델의 비율을 맞춰주는 작업이 필요한데, 이 단계에서 사용되는 tool이 Scale tool입니다. Experimental and Virtual Markers. from How Scaling Works 그림과 같이 마커 측정 비율 e1, e2 와 모델의 m1, m2와 같이 각기 대응되는 점들 간의 거리를 맞춰줍니다.\nInverse Kinematics IK(Inverse Kinematics) tool은 각 실험 데이터로부터 opensim model의 포즈를 만들기 위해 사용됩니다. 각 time step 별로 측정된 marker의 좌푯값과 가장 일치하는 포즈로 모델을 위치시키는 일반화된 좌표(generalized coordinate)값들을 계산합니다. 일치하는 포즈는 모델의 마커와 실험데이터 마커의 거리인 marker error를 최소화하는 방향으로 계산하는데요. marker의 중요도에 따라서 가중치를 부여합니다. 그래서 각 marker들의 weighted least square값을 합하여 이것의 min 값이 되는 포즈를 찾아냅니다. 수식으로 표현하면 다음과 같습니다.\n$$ min_q \\left[ \\sum_{i\\in{markers}}w_i |x_i^{exp} - x_i(q)|^2 \\right] $$\nResidual Reduction Algorithm 실험 데이터는 noise를 포함합니다. noise 생기는 이유는 여러 가지가 있으나 가장 중요한 요인은 크게 3가지가 있습니다.\n 팔이 없다 측정상의 noise 측정 위치 마커 에러 이러한 요인들에의해 inverse dynamics를 수행할때 residual force라는 추가적인 힘이 발생하게 됩니다. 그렇기 때문에 전체 inverse dynamics를 통해 구하여진 force에서 residual force를 근접(최소화하여)하게 산출 해서 빼줘야 정확한 force를 얻어 낼 수 있습니다. 아래식과 같이 나타내게 됩니다.\n$$ F + F_{\\text{residual}} = ma $$\nRRA tool은 이런 기능을 수행합니다.\nStatic Optimization Inverse dynamics를 dicrete time별로 풀어냅니다. 여기서 알아낸 force와 moments를 사용하여, 근육의 활성화 정도를 계산합니다. 여기서 활성화 정도를 계산할 때 근력이 가지고 있는 한계를 넘어가지 않도록 제한합니다. 수식을 보면 다음과 같습니다.\n$$ \\sum_{m=1}^n(a_mF_m^0)r_{(m,j)} = \\tau_j $$\n $a_m$: 근육의 activation level $F_m^0$: 최대 수축 힘 $r_{(m,j)}$: moment arm 이를 force-length-velocity 속성을 추가하여 바꾸면 다음과 같습니다.\n$$ \\sum_{m=1}^n[a_mf(F_m^0,l_m,v_m)]r_{(m,j)} = \\tau_j $$\n $f(F_m^0,l_m,v_m)$: force-length-velocity이용한 힘 관련 함수 $l_m$: 근육의 길이 $v_m$: 수축 속도 Computed Muscle Control 아래와 같이 Static Optimization과 Forward dynamics를 번갈아 수행하며, 해당 kinematics를 만들어낼 수 있는 근육의 activation level을 계산합니다. Schematic of the Computed Muscle Control Algorithm Applied to Gait. from How CMC Works \nForward dynamics Forward problem을 수행합니다. 일반적으로 전통적인 opensim 실험데이터에는 신경의 excitation은 포함되어 있지 않습니다. 따라서 아래와 같은 tool들을 차례대로 이용하여 얻어낸 excitation(control) 값을 사용합니다. - Scale - Inverse Kinematics - Residual Reduction Algorithm - Computed Muscle Control Typical workflow for generating a muscle-driven simulation. from Overview of the OpenSim Workflow \n II. Opensim-rl Opensim-rl은 아래 그림에서 main()과 같이 opensim 모델과 manager를 이용하여 시뮬레이션을 수행하는 프로그램입니다. from OpenSim\u0026rsquo;s Architecture and API \nswig를 사용하여 python scripting 방식으로 구현되어 있습니다. 위의 설명에서 forward problem 과 같은 방향으로 진행됩니다. agent는 neural command(action)을 이용하여 model을 컨트롤 합니다.\n III. Walking/Running gait 이번 competition에서 주어진 Task는 다음과 같습니다.\n Round1: 3초간 3m/s에 맞춰 뛰기 Round2: 10초간 1.25m/s에 맞춰 걷기 1 저희 팀은 이 Task 해결을 위해 환경파악 못지않게 \u0026ldquo;Walking/Running gait\u0026rdquo; 문제에 관한 탐구에도 많은 시간을 투자하였습니다.\n강화학습에서 Task가 파악이 잘되었다면 reward 설정도 잘할 수 있습니다. Task를 잘 파악한다면 agent 학습 시 그 목적에 따라 어떤 부분을 reward로 설정하여 더 격려할지 아니면 penalty로 설정하여 억제할지 명확해지기 때문에, 원활한 학습이 가능해집니다. 또한, 다음 part에서 언급할 imitation learning과 같은 방법론을 사용할 때에도 Task에 대한 명확한 이해가 있어야만 가이드로 사용할 demonstration이 잘되었는지 안되었는지에 대해 알 수 있습니다. 운전을 잘 알려주려면 운전에 대해 잘 알아야 하고, 달리기를 잘 알려주려면 달리기를 잘 알아야 합니다. Task에 대한 이해도가 높으면 높을수록 좋은 agent를 만들 수 있는 확률이 올라갑니다. 그런 의미에서 걷기와 달리기 메커니즘에 대한 이해는 매우 중요한 부분이었습니다.\nExperimental Data 마침 nips2018에서는 작년과는 다르게 experimental data를 사용할 수 없다는 제약사항이 사라졌습니다. 우선 simtk 커뮤니티를 검색하면서 여러 공개데이터 셋과 기존 연구들을 조사하였는데요, 가장 중점적으로 확인한 사항은 gait cycle 중 kinematic의 변화들, 즉 joint들의 움직임이 어떤 패턴을 갖는가였습니다. 다행히 이것에 대해서는 여러 가지 그래프와 데이터의 형태로 많은 분석이 진행되어 있었습니다. 그 중 Multiple Speed Walking Simulations라는 연구에서 round 2에서 사용할만한 데이터셋을 발견할 수 있었습니다. walkning speed가 정확하게 1.25m/s는 아니었지만 subject 2, 3의 free speed의 경우에는 그와 비슷한 속도(1.21, 1.29)로 사용할만한 수치였습니다. round1은 opensim-rl page에 예시로 제공된 Muscle contributions to mass center accelerations over a range of running speeds 연구에서 제공된 데이터셋이 정확하게 3m/s로 달리는 데이터였기 때문에 비교적 쉽게 결론을 내릴 수 있었습니다.\n위의 데이터셋을 opensim에서 동작시키면 다음과 같은 모습입니다. 먼저 round1 용 데이터는 다음과 같습니다. 그 다음은 round 2용 데이터 입니다. \nProper data-type ※ 아래 나오는 Imitation learning 관련 자세한 내용 설명은 Imitation learning posting에서 다룰 예정입니다.\n그러고 나서 했던 고민은 이 데이터들을 어떻게 하면 imitation learning에서 사용할만한 demonstration형태로 바꿀 수 있는가였습니다. 최초의 시도는 완전한 Behavioral cloning을 생각 하였기 때문에, action에 관련된 데이터도 만들어내기 위해 노력하였습니다. 위 opensim tool에서 설명하였지만, 기존 opensim을 이용한 연구자들이 forward problem을 해결하는 방식처럼 Data -\u0026gt; CMC tool 과정을 거쳐 Neural command 즉 action을 만들어내려고 했지요. 다만 이 시도는 몇 가지 제약사항 때문에 난관에 봉착하였는데\n 기존에 연구된 데이터들은 각기 다른 opensim model들을 사용했다 사용된 model에 따라 관절의 자유도(DoF: Degree of Freedom)가 다르다 사용된 model에 따라 근육의 개수가 다르다 CMC tool을 사용할 때 보통 external forces, reserve actuators를 등록하여 사용하는데, opensim-rl환경에서는 사용 불가능이다 결국, 이런 문제점들 때문에, Behavioral cloning으로 문제를 해결하려는 접근은 폐기되었습니다.\n그래서 action에 대한 data 없이 관찰되는 모습(kinematics)의 data만 이용하여 학습할 수 있는 방법론2을 찾아내었고, 실험데이터를 적합한 demonstration으로 가공하기 위해 고민하였습니다.\nMaking Demonstration 실험데이터는 기본적으로 다음과 같은 제약들이 있었습니다.\n Round1은 3초간 동작, Round2는 10초간 동작해야 함에 비해 demo 시간이 너무 짧다(1초 이하) 제자리 혹은 짧은 거리만 이동한다 스타팅 동작이 없다 위 제약은 kinematics 데이터를 수정하여 해결하였습니다. 실험데이터에 있는 gait cycle(걷는 동작)을 반복적으로 이어붙이고, 중간에 어색한 부분은 데이터를 새로 만들어 넣었습니다.\n그렇게 만들어진 round 1의 Demo는 다음과 같았습니다. round 2의 Demo는 다음과 같이 만들어졌습니다. \n또한, 해결해야 했던 부분은 여기서 만들어진 kinematic 데이터의 형태와 opensim-rl에서 관측되는 observation state의 형태가 다르다는 점이었습니다.\n이를 해결하기 위해 opesim python script를 이용하여 간단한 transfer 프로그램을 만들었습니다. 해당 코드는 medipixel git에서 확인 가능합니다. 변환과정을 간단하게 설명하면\n motion 데이터를 읽어온다 0.01 초마다 아래 과정을 반복 motion 데이터의 time step 별로 저장된 데이터를 통해 시뮬레이션을 구동시킨다 model의 정보(observation)를 읽어와서 list에 저장한다 list에 저장된 정보의 shape을 변환한다 위와 같은 과정을 거쳐 새로운 demonstration으로 사용 가능한 형태로 변환시킵니다.\n References Seth, A., Hicks, J. L., Uchida, T. K., Habib, A., Dembia, C. L., Dunne, J. J., \u0026hellip; \u0026amp; Hamner, S. R. (2018). OpenSim: Simulating musculoskeletal dynamics and neuromuscular control to study human and animal movement. PLoS computational biology, 14(7), e1006223. Delp, S. L., Anderson, F. C., Arnold, A. S., Loan, P., Habib, A., John, C. T., \u0026hellip; \u0026amp; Thelen, D. G. (2007). OpenSim: open-source software to create and analyze dynamic simulations of movement. IEEE transactions on biomedical engineering, 54(11), 1940-1950. Liu, M. Q., Anderson, F. C., Schwartz, M. H., \u0026amp; Delp, S. L. (2008). Muscle contributions to support and progression over a range of walking speeds. Journal of biomechanics, 41(15), 3243-3252. University of Michigan. (2018). Inverse Kinematics. Available at: http://web.eecs.umich.edu/~ocj/courses/autorob/autorob_10_ik_closedform.pdf [Accessed 01 Dec. 2018]. Chris Kirtley. (unknown). Inverse Dynamics. Available at: http://www.clinicalgaitanalysis.com/teach-in/inverse-dynamics.html. [Accessed 01 Dec. 2018]. Michael Sherman. (2011). Simbody documentations. Available at: https://simtk.org/docman/?group_id=47. [Accessed 01 Dec. 2018]. NCSRR. (2018). Opensim documentations. Available at: https://simtk-confluence.stanford.edu/display/OpenSim/Documentation. [Accessed 07 Dec. 2018]. overfit 검사를 위해 맞춰야 할 속도는 가변적이기는 하나 기본적으로 1.25m/s입니다. ^ Behavioral cloning from observation, DeepMimic ^ ","date":1544361737,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1544361737,"objectID":"17196bfbd7ebac42cfbbb6df808c0679","permalink":"/post/2018-12-09-nips2018-opensim/","publishdate":"2018-12-09T22:22:17+09:00","relpermalink":"/post/2018-12-09-nips2018-opensim/","section":"post","summary":"Opensim in AI for Prosthetics Challenge","tags":[],"title":"[Competition] AI for Prosthetics Challenge - Opensim","type":"post"},{"authors":["hyungkyu-kim"],"categories":[],"content":" 저희 Medipixel은 이번 NIPS 2018 - AI for Prosthetics Challenge에 참여하여 401팀 중 17위라는 성적으로 마감하게 되었습니다. competitoin을 진행하며 시행착오 끝에 많은 것들을 배울 수 있었는데요. 그간 여러 가지 리써치와 시도를 하며 얻었던 지식과 경험들을 본 post를 기점으로 몇 회에 걸쳐 정리하고자 합니다. 이번 Post에서는 우선 본격적인 내용 탐구에 앞서 이 대회는 어떤 대회였는지, 어떤 방식으로 접근을 하였는지에 대해 간단하게 정리하겠습니다.\n AI for Prosthetics Challenge AI for Prosthetics Challenge는 NeurIPS 2018 Competition Track에 속한 공식 competition입니다. Opensim 시뮬레이터 환경에서 진행되었는데요, 오른쪽 다리에 의족을 착용한 사람(그래서 이 competition의 이름이 Prosthetics입니다.)의 근골격 모델을 강화학습 agent를 통해 제어하여 주어진 속도와 일치하게 전진시키는 것이 이번 competition의 주제였습니다.\nWorks 우선 생소한 환경을 분석해야 했습니다. Opensim 시뮬레이터 및 주어진 걷기/달리기 시퀀스 모두 저희 팀이 원래 하고 있던 업무와는 어느 정도 거리가 있던 일이었기 때문에, 환경과 task에 대한 분석에 많은 시간을 들였습니다.\n그리고 일반적인 3d 모델을 이용한 강화학습 환경처럼 전진, 후진, 회전등의 동작을 직접 주는 것이 아닌, 각 근섬유 1개 1개를 모두 따로 제어해야 했기 때문에, 상당히 복잡한 환경이었습니다. 또한, 관측할 수 있는 값들도 수백 개 이상으로 마찬가지로 복잡했습니다. 그래서 당연히도 로컬머신만으로의 학습은 시간이 너무 오래 걸렸고, 필연적으로 분산처리를 이용한 강화학습 방법론을 사용할 수밖에 없었습니다. 또한, 학습속도를 높이기 위해 reward shaping, imitation learning 등의 방법을 사용하게 되었습니다.\n강화학습 방법론은 competition 기간 내내 계속해서 탐색과 보완을 거듭하였습니다. 비슷한 환경에서 치러진 NIPS2017 competition solution을 참고하여 리써치를 시작하였는데, 이번 환경에서 적용되지 않는 부분도 많았고, 생각지도 못한 난관이 발생하여서 여러 가지 개선 끝에 안정화할 수 있었습니다.\nContents 다음 내용으로 Posting을 진행할 예정입니다.\n Opensim Imitation learning Distributed reinforcement learning Agent ","date":1544275337,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1544275337,"objectID":"c4b6d3c2a4e95e831295051fbc05cd82","permalink":"/post/2018-12-08-nips2018-intro/","publishdate":"2018-12-08T22:22:17+09:00","relpermalink":"/post/2018-12-08-nips2018-intro/","section":"post","summary":"Introduction to AI for Prosthetics Challenge","tags":[],"title":"[Competition] AI for Prosthetics Challenge - Intro","type":"post"}]