├── .DS_Store
├── README.md
├── edge
├── .DS_Store
└── edge.py
├── images
├── .DS_Store
├── analysis-DRL.png
├── analysis-local-only.png
├── processed-img.png
└── system-model.png
└── local
├── .DS_Store
├── local.py
├── local_only.py
└── local_torch.py
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeonduing/DRL-based-MEC/ccc3026bd3a28005a2b093af57ef62ce865baffe/.DS_Store
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title : "영상처리를 위한 강화학습 기반 에지 컴퓨팅"
3 | category :
4 | - project
5 | tag :
6 | - MEC
7 | - EC
8 | - image processing
9 | - DRL
10 | - socket
11 | toc : true
12 | use_math : true
13 | ---
14 |
15 | ## Introduction
16 |
17 | > Edge Computing based on Deep Reinforcement Learning for Image Processing
18 |
19 | 본 프로젝트의 주제는 강화 학습을 적용한 에지 컴퓨팅(Edge Computing) 기술이 실시간 처리를 필요로 하는 데이터를 얼마나 잘 처리 하는지 보여주는 것이다. 이에 대한 시나리오로 많은 컴퓨팅 자원을 요구하는 영상 편집을 골랐다. 로컬(Local)에 낮은 컴퓨팅 자원을 가진 컴퓨터를 두고, 에지(Edge)에 높은 컴퓨팅 자원을 가진 컴퓨터를 두어 낮은 레이턴시(Latency)로 실시간 영상 처리하는 것을 보여주는 것이 프로젝트의 목표이다.
20 |
21 | ## System Model
22 |
23 | 시스템은 Local과 Edge로 나뉜다. Local의 경우 Computation Resource Selection, Socket Communication, Image Processing과 Image Merger 총 네 부분으로 나뉜다. Edge의 경우 Socket Communication과 Image Processing 총 두 부분으로 나뉘며, Local과 Edge 모두 각 부분은 스레드로 분리하여 동시에 작동할 수 있도록 하였다.
24 |
25 | 
26 |
fig. 1 The DRL-based system architecture
27 |
28 | ### Computation Resource Allocation
29 |
30 | 한 프레임이 처리 대기버퍼에서 나와 재생 대기 버퍼에 들어가기까지의 시간을 직전 처리 시간이라 하고 이를 Local 과 Edge 각각에 대하여 구한다. 두 수를 활용하여 주어진 프레임을 어디에서 처리하는 것이 빠른지 판단한다. 본 프로젝트에서는 판단 알고리즘에 대해 두 가지 방법으로 실험하였다.
31 |
32 | **이전 값을 통한 예측 알고리즘**
33 | Local과 Edge 각각에 대하여 기존 평균 처리 시간과 직전 처리 시간을 적절한 비율로 더하여 평균 처리 시간을 계산한다. 각각의 평균 처리 시간과 대기 중인 프레임 수를 비교하여 현재 주어진 프레임을 어디에서 처리하는 것이 빠른지 판단한다.
34 | $${이전 평균 처리 시간 \times a + 직전 처리 시간 \times ( 1 – a )}\ (0 < a < 1) (1)$$
35 |
36 | **DRL을 적용한 알고리즘**
37 | 현재 state $s_t$의 action $a_t$에 대한 Q 값 $Q(s_t)$는 다음과 같다.
38 | $$ Q(s_t) = r_t\ +\ γ maxQ(s_{t+1}) (2) $$
39 | 위 식에서 $r_t$는 현재 받는 reward값이고, $γ$는 discount factor 이다. State는 [Local queue , Edge queue] 로 정의하였다. Reward는 frame이 queue에 들어가서 처리가 완료되기 까지의 시간으로 정한다. Action 은 어느 곳으로 가는지에 대한 값, γ값은 일반적인 예시에서 쓰는 0.9를 사용한다.[1]
40 |
41 | ### Socket Communication
42 |
43 | Local과 Edge는 Socket을 통해 통신한다. 프레임에 해당하는 Mat변수(영상)를 uchar형태로 변환하여 배열에 저장하고 Server에 해당하는 PC의 IP 주소와 Port번호를 지정해 해당 배열을 전송한다. 데이터 송수신 과정에서 송신과 수신의 속도 차에 의한 버퍼 관리를 위하여 TCP 통신 프로토콜을 따라 소켓 프로그래밍을 했다.
44 |
45 | ### Image Processing
46 |
47 | 아래 자료는 극좌표계에서의 좌표로 계산하여 휘어진 이미지를 보여준다. 사용자가 처리 후에 받게 될 결과이며, 극좌표계에서의 좌표는 모니터 화면과 맞지 않으므로 fig.2 와 같이 평면 직사각형에 투영하여 전송한다. 이는 [2]의 코드를 참고하여 작성하였다.
48 |
49 | 
50 | fig. 2 The result image
51 |
52 | ### Imgae Merger
53 |
54 | 하나의 영상을 프레임 단위로 나누어 Local과 Edge 두 곳에서 처리하므로 사용자에게 송출할 때에는 순서를 다시 맞추는 작업이 필요하다. 이를 위해 Computation Resource Allocation 부분에서는 어느 곳에서 처리할지 분배해주면서 그것을 기록한다. 이는 전역 변수인 preSeq에 저장되며 queue 자료형이므로 입력한 순서대로 출력되어 프레임의 순서를 맞출 수 있다.
55 |
56 | ## Performance Evaluation
57 |
58 | ### Experimental Settings
59 | >Local: i5 3세대 U버전 CPU
60 | Edge: i5 - 7500
61 |
62 | 영상 처리를 CPU로만 하기에 컴퓨팅 파워를 CPU 성능으로 생각하였고, Cinebench R15 툴 기준 멀티코어 성능2배 차이, 싱글코어 성능은 1.5배 정도의 성능 차이를 가지고 있다. 랜선을 이용한 유선 상의 비교는 평균치를 이용한 방법과 DRL을 이용한 방법에서 굉장히 동적인latency의 변화에 대해 대응하는 것을 보기에는 적절치 않다고 생각하여 일반적인 54Mbps 속도의 Wi-Fi환경에서 실험을 진행하였다.
63 | 3가지 해상도(480P, 720P)의 뮤직비디오 영상을 3,4 번 정도 실험하여 Latency들의 평균값을 구하였다.
64 |
65 | ### Result Analysis
66 | 프로젝트의 목적은 계산(영상처리)을 에지 컴퓨팅을 통해 향상시키는 것이고, 나아가서는 강화학습을 적용하여 매 시각 다양하게 변화하는 네트워크 환경에 대해 Computing Resource Selection을 적절히 하여 임의로 설정한 parameter를 통한 결과보다 더 좋은 결과를 얻는 것이다. 아래의 두 사진은 각각 Local에서만 영상처리를 했을 때, 임의의 parameter를 설정하여 평균치를 이용한 분배와 학습을 이용한 분배의 비교를 나타낸 Empirical CDF이다. 세로는 확률, 가로는 프레임과 프레임 사이의 latency이다. 프레임 사이의 latency가 작을수록 영상의 frame이 옳은 순서로 더 빠르게 처리(재생)되어 더 높은 성능을 가진다고 볼 수 있다. 즉, Computing Resource Selection이 옳게 이루어져 Local혼자 처리할 때 보다 높은 성능향상을 보인다.
67 |
68 | | |  |
69 | | --- | --- |
70 | |fig. 3 The result analysis of local only | fig. 4 The result analysis of edge server |
71 |
72 | ## Conclusion
73 |
74 | Edge Computing을 이용하여 Computing 작업을 수행했을 때, Local 단독으로 충분히 빠르게 처리할 수 있는 작업은 단독으로 처리하는 것이 나으나, 그렇지 않은 경우에는 항상 Edge Computing을 적용한 경우가 좋았다(Latency가 굉장히 높아진다거나 하는 대륙-대륙 간 연결이나 Wi-Fi가 자주 끊기고 연결되는 경우를 제외한 일반적인 환경에서). 특히 DRL을 적용하였을 때가 평균치를 이용한 경우보다 좋았는데 Edge Computing과 DRL을 적용한다면 평균Latency를 거의 0.1~0.2 초 정도 줄일 수 있었다.
75 |
76 | ## Reference
77 |
78 | [1] J. Wang, L. Zhao, J. Liu, and N. Kato, “Smart resource allocation for mobile edge computing: A deep reinforcement learning approach,” IEEE Trans. Emerg. Topics Comput., to be published. doi: 10.1109/TETC.2019.2902661.
79 | [2] “Warp an image to cylindrical coordinates for cylindrical panorama stitching, using Python OpenCV,” [Online]. Available: https://gist.github.com/royshil/0b21e8e7c6c1f46a16db66c384742b2b
--------------------------------------------------------------------------------
/edge/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeonduing/DRL-based-MEC/ccc3026bd3a28005a2b093af57ef62ce865baffe/edge/.DS_Store
--------------------------------------------------------------------------------
/edge/edge.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import numpy as np
4 |
5 | import socket
6 | import sys
7 |
8 | import queue
9 |
10 | import cv2
11 | import pickle
12 |
13 | import struct ## new
14 | import zlib
15 | import math
16 | import multiprocessing
17 | import threading
18 | from threading import Thread
19 |
20 | ############## 전역 변수 ##############
21 | ### __init__ :
22 |
23 |
24 | ############## 이미지 처리 변수 ##############
25 | # 에지에서 영상처리를 해야하는 Mat 저장
26 | #q_max size
27 | q_max = 5000
28 | edgeBeforeBuff = queue.Queue(q_max)
29 | # 에지에서 영상처리를 마친 mat 저장
30 | edgeAfterBuff = queue.Queue(q_max)
31 |
32 | # 이미지 사이즈(cols, rows)를 초기화
33 | width = 1920;
34 | height = 1080;
35 |
36 | w = width
37 | h = height
38 | K = np.array([[w, 0, w / 2], [0, h, h / 2], [0, 0, 1]])
39 |
40 | encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
41 |
42 | # 처리할 프레임 개수
43 | img_cnt = 0
44 |
45 | ####### 통신 변수 #######
46 | HOST = ''
47 | PORT = 8485
48 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
49 | print('Socket created')
50 | recv_addr = (HOST, PORT)
51 | sock.bind(recv_addr)
52 | print('Socket bind complete')
53 | sock.listen(0)
54 | print('Socket now listening')
55 | clnt_sock, clnt_addr = sock.accept()
56 | ### __init__ END
57 |
58 | ############## ImageProcess 함수 ##############
59 | ### convert_pt :
60 | def convert_pt(x, y, w, h):
61 | px = x-w/2
62 | py = y-h/2
63 | #곡률
64 | f= w;
65 | #값을 바꿀수록 덜 휘거나 더 휨
66 | r= w;
67 |
68 | omega = w/2
69 | z0 = f- math.sqrt(r*r - omega * omega)
70 |
71 | zc = (2*z0 + math.sqrt(4*z0*z0 - 4*(px*px/(f*f)+1)*(z0*z0-r*r))) / (2 * (px*px/(f*f) + 1))
72 | final_x = px*zc/f + w/2
73 | final_y = py*zc/f + h/2
74 |
75 | return final_x, final_y
76 | ### convert_pt END
77 |
78 | ### img_mod : frame을 VR영상으로 변환
79 | def img_mod():
80 | # royshil's cylindricalWarping.py
81 | # https://gist.github.com/royshil/0b21e8e7c6c1f46a16db66c384742b2b
82 | while True:
83 | frame = edgeBeforeBuff.get()
84 | """This function returns the cylindrical warp for a given image and intrinsics matrix K"""
85 | h_, w_ = frame.shape[:2]
86 | # pixel coordinates
87 | y_i, x_i = np.indices((h_, w_))
88 | X = np.stack([x_i, y_i, np.ones_like(x_i)], axis=-1).reshape(h_ * w_, 3) # to homog
89 | Kinv = np.linalg.inv(K)
90 | X = Kinv.dot(X.T).T # normalized coords
91 | # calculate cylindrical coords (sin\theta, h, cos\theta)
92 | A = np.stack([np.sin(X[:, 0]), X[:, 1], np.cos(X[:, 0])], axis=-1).reshape(w_ * h_, 3)
93 | B = K.dot(A.T).T # project back to image-pixels plane
94 | # back from homog coords
95 | B = B[:, :-1] / B[:, [-1]]
96 | # make sure warp coords only within image bounds
97 | B[(B[:, 0] < 0) | (B[:, 0] >= w_) | (B[:, 1] < 0) | (B[:, 1] >= h_)] = -1
98 | B = B.reshape(h_, w_, -1)
99 |
100 | frame_rgba = cv2.cvtColor(frame, cv2.COLOR_BGR2BGRA) # for transparent borders...
101 | # warp the image according to cylindrical coords
102 | frame = cv2.remap(frame_rgba, B[:, :, 0].astype(np.float32), B[:, :, 1].astype(np.float32), cv2.INTER_AREA,
103 | borderMode=cv2.BORDER_TRANSPARENT)
104 | edgeAfterBuff.put(frame)
105 | #cv2.imshow('ImageWindow', frame)
106 | #cv2.waitKey(1)
107 | ### img_mod END
108 |
109 |
110 | ############## Socket Communicate 함수 ##############
111 | ### recv_img : client로부터 처리할 영상을 받는다.
112 | def recv_img():
113 | data = b""
114 | # clnt_sock.send(msg_go.encode('utf-8'))
115 | #calcsize @시스템에 따름. = 시스템에 따름 < 리틀 엔디안 > 빅 엔디안 !네트워크(빅 엔디안)
116 | #원본 >L
117 | payload_size = struct.calcsize(">L")
118 | print("payload_size: {}".format(payload_size))
119 |
120 | while len(data) < payload_size:
121 | print("Recv: {}".format(len(data)))
122 | data += clnt_sock.recv(4096)
123 |
124 | print("Done Recv: {}".format(len(data)))
125 | packed_msg_size = data[:payload_size]
126 | data = data[payload_size:]
127 | msg_size = struct.unpack(">L", packed_msg_size)[0]
128 | print("msg_size: {}".format(msg_size))
129 | # 소켓통신 끝내기
130 | if msg_size == 1937010544:
131 | clnt_sock.close()
132 | return True
133 |
134 | while len(data) < msg_size:
135 | data += clnt_sock.recv(4096)
136 | frame_data = data[:msg_size]
137 | data = data[msg_size:]
138 |
139 | frame = pickle.loads(frame_data, fix_imports=True, encoding="bytes")
140 | frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
141 |
142 | edgeBeforeBuff.put(frame)
143 | return False
144 | # frames.append(frame)
145 |
146 | # cv2.imshow('ImageWindow', frame)
147 | # cv2.waitKey(40)
148 | ### recv_img END
149 |
150 | ### send_img :
151 | def send_img():
152 | frame = edgeAfterBuff.get()
153 | result, frame = cv2.imencode('.jpg', frame, encode_param)
154 | data = pickle.dumps(frame, 0)
155 | size = len(data)
156 |
157 | print("{}: {}".format(img_cnt, size))
158 | clnt_sock.sendall(struct.pack(">L", size) + data)
159 | ### send_img END
160 |
161 | ### sock_commu() :
162 | def sock_commu():
163 | while True:
164 | ifEnd = recv_img()
165 | if ifEnd:
166 | print('sock_commu end 1')
167 | break
168 | send_img()
169 | ### sock_commu() END
170 |
171 | ### threads_func :
172 | if __name__ == '__main__':
173 | thread_img_process = threading.Thread(target = img_mod, daemon = True)
174 | thread_sock_commu = threading.Thread(target = sock_commu)
175 | thread_img_process.start()
176 | thread_sock_commu.start()
177 | thread_sock_commu.join()
178 | print('sock_commu end 2')
179 | sock.close()
180 | print('sock close')
181 | ### threads_func END
182 |
--------------------------------------------------------------------------------
/images/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeonduing/DRL-based-MEC/ccc3026bd3a28005a2b093af57ef62ce865baffe/images/.DS_Store
--------------------------------------------------------------------------------
/images/analysis-DRL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeonduing/DRL-based-MEC/ccc3026bd3a28005a2b093af57ef62ce865baffe/images/analysis-DRL.png
--------------------------------------------------------------------------------
/images/analysis-local-only.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeonduing/DRL-based-MEC/ccc3026bd3a28005a2b093af57ef62ce865baffe/images/analysis-local-only.png
--------------------------------------------------------------------------------
/images/processed-img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeonduing/DRL-based-MEC/ccc3026bd3a28005a2b093af57ef62ce865baffe/images/processed-img.png
--------------------------------------------------------------------------------
/images/system-model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeonduing/DRL-based-MEC/ccc3026bd3a28005a2b093af57ef62ce865baffe/images/system-model.png
--------------------------------------------------------------------------------
/local/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeonduing/DRL-based-MEC/ccc3026bd3a28005a2b093af57ef62ce865baffe/local/.DS_Store
--------------------------------------------------------------------------------
/local/local.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import io
3 | import socket
4 | import struct
5 | import time
6 | import pickle
7 | import zlib
8 |
9 | import numpy as np
10 | import math
11 |
12 | import queue
13 | import threading
14 | from threading import Thread
15 |
16 | ############## 전역 변수 ##############
17 | # 노드, 에지가 한 프레임을 처리하는데 걸리는 추정 시간
18 | node_time = 0.001
19 | edge_time = 0.002
20 | # 지연 시간을 계산할 때 사용할 상수
21 | a = 0.6
22 |
23 | ############## 이미지 처리 변수 ##############
24 | # 이미지 사이즈(cols, rows)를 초기화
25 | width = 1920;
26 | height = 1080;
27 |
28 | #width = 180
29 | #height = 176
30 |
31 | w = width
32 | h = height
33 | K = np.array([[w, 0, w / 2], [0, h, h / 2], [0, 0, 1]])
34 |
35 | # 처리할 프레임 개수
36 | img_cnt = 0
37 |
38 | #q_max size
39 | q_max = 5000
40 | # 해당 순서의 프레임을 노드와 에지중 어느곳에서 처리 했는지 표시
41 | procSeq = queue.Queue(q_max)
42 | # 노드, 에지에서 영상처리를 해야하는 Mat 저장
43 | nodeBeforeBuff = queue.Queue(q_max)
44 | edgeBeforeBuff = queue.Queue(q_max)
45 | # 노드, 에지에서 영상처리를 마친 Mat 저장
46 | nodeAfterBuff = queue.Queue(q_max)
47 | edgeAfterBuff = queue.Queue(q_max)
48 |
49 | ####### 통신 변수 #######
50 | # ip addr
51 | ip_konkuk = '192.168.86.59' # 공대
52 | ip_konkuk_univ = '192.168.37.255' # 공대
53 | ip_home = '192.168.0.3'
54 | ip_phone = '172.20.10.2'
55 | ip_server = '114.70.22.26'
56 | ip = 'ip_server'
57 | clnt_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
58 | clnt_sock.connect((ip, 8485))
59 | connection = clnt_sock.makefile('wb')
60 | # 통신 끝을 알리는 메세지
61 | msg_stop = 'stop'
62 |
63 | ####### opencv video 변수 #######
64 | cam = cv2.VideoCapture('IMG_4302.MOV')
65 | cam.set(cv2.CAP_PROP_FRAME_WIDTH, width)
66 | cam.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
67 |
68 | encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
69 |
70 | ############## ImageProcess 함수 ##############
71 | ### convert_pt :
72 | def convert_pt(x, y, w, h):
73 | px = x-w/2
74 | py = y-h/2
75 | #곡률
76 | f= w;
77 | #값을 바꿀수록 덜 휘거나 더 휨
78 | r= w;
79 |
80 | omega = w/2
81 | z0 = f- math.sqrt(r*r - omega * omega)
82 |
83 | zc = (2*z0 + math.sqrt(4*z0*z0 - 4*(px*px/(f*f)+1)*(z0*z0-r*r))) / (2 * (px*px/(f*f) + 1))
84 | final_x = px*zc/f + w/2
85 | final_y = py*zc/f + h/2
86 |
87 | return final_x, final_y
88 | ### convert_pt END
89 |
90 | ### img_mod : frame을 VR영상으로 변환
91 | def img_mod():
92 | # royshil's cylindricalWarping.py
93 | # https://gist.github.com/royshil/0b21e8e7c6c1f46a16db66c384742b2b
94 | global node_time
95 | while True:
96 | start_time = time.time()
97 | frame = nodeBeforeBuff.get()
98 | """This function returns the cylindrical warp for a given image and intrinsics matrix K"""
99 | h_, w_ = frame.shape[:2]
100 | # pixel coordinates
101 | y_i, x_i = np.indices((h_, w_))
102 | X = np.stack([x_i, y_i, np.ones_like(x_i)], axis=-1).reshape(h_ * w_, 3) # to homog
103 | Kinv = np.linalg.inv(K)
104 | X = Kinv.dot(X.T).T # normalized coords
105 | # calculate cylindrical coords (sin\theta, h, cos\theta)
106 | A = np.stack([np.sin(X[:, 0]), X[:, 1], np.cos(X[:, 0])], axis=-1).reshape(w_ * h_, 3)
107 | B = K.dot(A.T).T # project back to image-pixels plane
108 | # back from homog coords
109 | B = B[:, :-1] / B[:, [-1]]
110 | # make sure warp coords only within image bounds
111 | B[(B[:, 0] < 0) | (B[:, 0] >= w_) | (B[:, 1] < 0) | (B[:, 1] >= h_)] = -1
112 | B = B.reshape(h_, w_, -1)
113 |
114 | frame_rgba = cv2.cvtColor(frame, cv2.COLOR_BGR2BGRA) # for transparent borders...
115 | # warp the image according to cylindrical coords
116 | frame = cv2.remap(frame_rgba, B[:, :, 0].astype(np.float32), B[:, :, 1].astype(np.float32), cv2.INTER_AREA,
117 | borderMode=cv2.BORDER_TRANSPARENT)
118 |
119 | cur_node_time = time.time() - start_time
120 |
121 | node_time = node_time * a + cur_node_time * (1 - a)
122 | nodeAfterBuff.put(frame)
123 | print('img_mod')
124 | # cv2.imshow('ImageWindow', frame)
125 | # cv2.waitKey(1)
126 | ### img_mod END
127 |
128 | ############## Socket Communicate 함수 ##############
129 | ### recv_img : edge로부터 처리한 영상을 받는다.
130 | def recv_img():
131 | data = b""
132 | # clnt_sock.send(msg_go.encode('utf-8'))
133 | #calcsize @시스템에 따름. = 시스템에 따름 < 리틀 엔디안 > 빅 엔디안 !네트워크(빅 엔디안)
134 | #원본 >L
135 | payload_size = struct.calcsize(">L")
136 | # print("payload_size: {}".format(payload_size))
137 |
138 | while len(data) < payload_size:
139 | # print("Recv: {}".format(len(data)))
140 | data += clnt_sock.recv(4096)
141 |
142 | # print("Done Recv: {}".format(len(data)))
143 | packed_msg_size = data[:payload_size]
144 | data = data[payload_size:]
145 | msg_size = struct.unpack(">L", packed_msg_size)[0]
146 | # print("msg_size: {}".format(msg_size))
147 | while len(data) < msg_size:
148 | data += clnt_sock.recv(4096)
149 | frame_data = data[:msg_size]
150 | data = data[msg_size:]
151 |
152 | frame = pickle.loads(frame_data, fix_imports=True, encoding="bytes")
153 | frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
154 | # cv2.imshow('ImageWindow', frame)
155 | # cv2.waitKey(1)
156 |
157 | edgeAfterBuff.put(frame)
158 | # frames.append(frame)
159 |
160 | # cv2.imshow('ImageWindow', frame)
161 | # cv2.waitKey(40)
162 | ### recv_img END
163 |
164 | ### send_img :
165 | def send_img():
166 | frame = edgeBeforeBuff.get()
167 | result, frame = cv2.imencode('.jpg', frame, encode_param)
168 | data = pickle.dumps(frame, 0)
169 | size = len(data)
170 |
171 | # print("{}: {}".format(img_cnt, size))
172 | clnt_sock.sendall(struct.pack(">L", size) + data)
173 | ### send_img END
174 |
175 | ### sock_commu() :
176 | def sock_commu():
177 | #time.sleep(10)
178 | global edge_time
179 | while True:
180 | start_time = time.time()
181 | send_img()
182 | recv_img()
183 | cur_edge_time = time.time() - start_time
184 | edge_time = edge_time * a + cur_edge_time * (1 - a)
185 | print('socket')
186 | ### sock_commu() END
187 |
188 | ############## Judge Algorithm 함수 ##############
189 | def judge_algo():
190 | global img_cnt
191 | global node_time
192 | global edge_time
193 |
194 | while (cam.isOpened()):
195 | ret, frame = cam.read()
196 | if frame is None:
197 | break
198 | # result, frame = cv2.imencode('.jpg', frame, encode_param)
199 |
200 | node_latency = node_time * (nodeBeforeBuff.qsize() + 1)
201 | edge_latency = edge_time * (edgeBeforeBuff.qsize() + 1)
202 |
203 | if node_latency <= edge_latency:
204 | procSeq.put(1)
205 | nodeBeforeBuff.put(frame)
206 | print('node_time: ', node_time, 'node_latency: ', node_latency)
207 | else:
208 | procSeq.put(2)
209 | edgeBeforeBuff.put(frame)
210 | print('edge_time: ', edge_time, 'edge_latency: ', edge_latency)
211 |
212 | img_cnt += 1
213 | procSeq.put(0)
214 | cam.release()
215 |
216 | ############## Img Merger 함수 ##############
217 | def img_merger():
218 | while True:
219 | serv_num = procSeq.get()
220 | if serv_num == 1:
221 | frame = nodeAfterBuff.get()
222 | #cv2.imshow('ImageWindow', frame)
223 | #cv2.waitKey(40)
224 | elif serv_num == 2:
225 | frame = edgeAfterBuff.get()
226 | #cv2.imshow('ImageWindow', frame)
227 | #cv2.waitKey(40)
228 | else:
229 | break
230 |
231 | ### threads_func :
232 | if __name__ == '__main__':
233 | main_start_time = time.time()
234 | thread_img_process = threading.Thread(target = img_mod, daemon = True)
235 | thread_sock_commu = threading.Thread(target = sock_commu, daemon = True)
236 | thread_judge_algo = threading.Thread(target = judge_algo, daemon = True)
237 | #thread_img_merger = threading.Thread(target = img_merger)
238 | thread_judge_algo.start()
239 | thread_sock_commu.start()
240 | thread_img_process.start()
241 | #thread_img_merger.start()
242 | #thread_img_merger.join()
243 | while True:
244 | serv_num = procSeq.get()
245 | if serv_num == 1:
246 | frame = nodeAfterBuff.get()
247 | print('node에서 프린트')
248 | #cv2.imshow('ImageWindow', frame)
249 | #cv2.waitKey(40)
250 | elif serv_num == 2:
251 | frame = edgeAfterBuff.get()
252 | print('edge에서 프린트')
253 | else:
254 | print('끝이다')
255 | break
256 | cv2.imshow('ImageWindow', frame)
257 | cv2.waitKey(1)
258 | clnt_sock.send(msg_stop.encode('utf-8'))
259 | clnt_sock.close()
260 | main_end_time = time.time() - main_start_time
261 | print(main_end_time)
262 | ### threads_func END
263 |
264 |
--------------------------------------------------------------------------------
/local/local_only.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import io
3 | import socket
4 | import struct
5 | import time
6 | import pickle
7 | import zlib
8 | import time
9 | import numpy as np
10 | import math
11 | import queue
12 | import threading
13 | q_max = 50000
14 | nodeBeforeBuff = queue.Queue(q_max)
15 | nodeAfterBuff = queue.Queue(q_max)
16 |
17 | nodebeforebufftime = queue.Queue(q_max)
18 | nodeafterbufftime = queue.Queue(q_max)
19 |
20 | width = 1920
21 | height = 1080
22 | K = np.array([[width, 0, width / 2], [0, height, height / 2], [0, 0, 1]])
23 |
24 | isend=0
25 |
26 | cam = cv2.VideoCapture('jk_l.mp4')
27 | cam.set(cv2.CAP_PROP_FRAME_WIDTH, width)
28 | cam.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
29 |
30 | f = open("node_only_latency_1920.txt", "w")
31 |
32 | def img_mod():
33 | # royshil's cylindricalWarping.py
34 | # https://gist.github.com/royshil/0b21e8e7c6c1f46a16db66c384742b2b
35 | while True:
36 | img = nodeBeforeBuff.get()
37 | # print("hi\n")
38 | h_, w_ = img.shape[:2]
39 | # pixel coordinates
40 | y_i, x_i = np.indices((h_, w_))
41 | X = np.stack([x_i, y_i, np.ones_like(x_i)], axis=-1).reshape(h_ * w_, 3) # to homog
42 | Kinv = np.linalg.inv(K)
43 | X = Kinv.dot(X.T).T # normalized coords
44 | # calculate cylindrical coords (sin\theta, h, cos\theta)
45 | A = np.stack([np.sin(X[:, 0]), X[:, 1], np.cos(X[:, 0])], axis=-1).reshape(w_ * h_, 3)
46 | B = K.dot(A.T).T # project back to image-pixels plane
47 | # back from homog coords
48 | B = B[:, :-1] / B[:, [-1]]
49 | # make sure warp coords only within image bounds
50 | B[(B[:, 0] < 0) | (B[:, 0] >= w_) | (B[:, 1] < 0) | (B[:, 1] >= h_)] = -1
51 | B = B.reshape(h_, w_, -1)
52 |
53 | img_rgba = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA) # for transparent borders...
54 | # warp the image according to cylindrical coords
55 | img = cv2.remap(img_rgba, B[:, :, 0].astype(np.float32), B[:, :, 1].astype(np.float32), cv2.INTER_AREA,
56 | borderMode=cv2.BORDER_TRANSPARENT)
57 | check = time.time() - nodebeforebufftime.get()
58 | nodeafterbufftime.put(check)
59 | f.write(str(check)+'\n')
60 | if isend==1:
61 | f.close()
62 | nodeAfterBuff.put(img)
63 |
64 |
65 | def frame_read():
66 | while (cam.isOpened()):
67 | # print("hi2\n")
68 | ret, frame = cam.read()
69 |
70 | if frame is None:
71 | isend=1
72 | break;
73 | nodeBeforeBuff.put(frame)
74 | nodebeforebufftime.put(time.time())
75 |
76 |
77 |
78 | if __name__ == '__main__':
79 | thread_read_frame = threading.Thread(target=frame_read, daemon=True)
80 | thread_img_process = threading.Thread(target=img_mod, daemon=True)
81 | thread_read_frame.start()
82 | thread_img_process.start()
83 | while isend!=1:
84 | # print("hi3\n")
85 | frame1 = nodeAfterBuff.get()
86 | cv2.imshow('ImageWindow', frame1)
87 | cv2.waitKey(1)
88 |
89 |
90 | #cv2.imshow('ImageWindow', frame)
91 | #cv2.waitKey(1)
--------------------------------------------------------------------------------
/local/local_torch.py:
--------------------------------------------------------------------------------
1 | import collections
2 | import random
3 | import torch
4 |
5 | import cv2
6 | import io
7 | import socket
8 | import struct
9 | import time
10 | import pickle
11 | import zlib
12 |
13 | import numpy as np
14 | import math
15 |
16 | import queue
17 | import threading
18 | import torch.nn as nn
19 | import torch.nn.functional as F
20 | import torch.optim as optim
21 |
22 | from threading import Thread
23 |
24 | ############## 전역 변수 ##############
25 | # 노드, 에지가 한 프레임을 처리하는데 걸리는 추정 시간
26 |
27 |
28 | node_time = 0.0
29 | edge_time = 0.0
30 | # 지연 시간을 계산할 때 사용할 상수
31 | a = 0.6
32 | node_time_p = 0
33 | edge_time_p = 0
34 |
35 | start2 = 0
36 | start3 = 0
37 | ############## 이미지 처리 변수 ##############
38 | # 이미지 사이즈(cols, rows)를 초기화
39 | width = 2560
40 | height = 1600
41 |
42 | # width = 1920
43 | # height = 1080
44 |
45 | w = width
46 | h = height
47 | K = np.array([[w, 0, w / 2], [0, h, h / 2], [0, 0, 1]])
48 |
49 | # 처리할 프레임 개수
50 | img_cnt = 0
51 |
52 | # q_max size
53 | q_max = 5000
54 | # 해당 순서의 프레임을 노드와 에지중 어느곳에서 처리 했는지 표시
55 | procSeq = queue.Queue(q_max)
56 | procSeq2 = queue.Queue(q_max)
57 | # 노드, 에지에서 영상처리를 해야하는 Mat 저장
58 | nodeBeforeBuff = queue.Queue(q_max)
59 | edgeBeforeBuff = queue.Queue(q_max)
60 | # 노드, 에지에서 영상처리를 마친 Mat 저장
61 | nodeAfterBuff = queue.Queue(q_max)
62 | edgeAfterBuff = queue.Queue(q_max)
63 |
64 | nodeRewardBuff = queue.Queue(q_max)
65 | edgeRewardBuff = queue.Queue(q_max)
66 | nodeRewardAfterBuff = queue.Queue(q_max)
67 | edgeRewardAfterBuff = queue.Queue(q_max)
68 |
69 | ####### 통신 변수 #######
70 | # ip addr
71 | ip_server = '114.70.22.26'
72 | ip_han = '114.70.21.240'
73 | ip_home = '192.168.0.3'
74 | ip_phone = '172.20.10.2'
75 | ip = ip_server
76 | clnt_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
77 | clnt_sock.connect((ip, 8485))
78 | connection = clnt_sock.makefile('wb')
79 | # 통신 끝을 알리는 메세지
80 | msg_stop = 'stop'
81 |
82 | ####### opencv video 변수 #######
83 | cam = cv2.VideoCapture('jk_l2.mov')
84 | cam.set(cv2.CAP_PROP_FRAME_WIDTH, width)
85 | cam.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
86 |
87 | encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
88 |
89 |
90 | ############## ImageProcess 함수 ##############
91 | ### convert_pt :
92 | def convert_pt(x, y, w, h):
93 | px = x - w / 2
94 | py = y - h / 2
95 | # 곡률
96 | f = w;
97 | # 값을 바꿀수록 덜 휘거나 더 휨
98 | r = w;
99 |
100 | omega = w / 2
101 | z0 = f - math.sqrt(r * r - omega * omega)
102 |
103 | zc = (2 * z0 + math.sqrt(4 * z0 * z0 - 4 * (px * px / (f * f) + 1) * (z0 * z0 - r * r))) / (
104 | 2 * (px * px / (f * f) + 1))
105 | final_x = px * zc / f + w / 2
106 | final_y = py * zc / f + h / 2
107 |
108 | return final_x, final_y
109 |
110 |
111 | ### convert_pt END
112 |
113 | ### img_mod : frame을 VR영상으로 변환
114 | def img_mod():
115 | global node_time
116 | global node_time_p
117 | while True:
118 | start_time = time.time()
119 | frame = nodeBeforeBuff.get()
120 | """This function returns the cylindrical warp for a given image and intrinsics matrix K"""
121 | h_, w_ = frame.shape[:2]
122 | # pixel coordinates
123 | y_i, x_i = np.indices((h_, w_))
124 | X = np.stack([x_i, y_i, np.ones_like(x_i)], axis=-1).reshape(h_ * w_, 3) # to homog
125 | Kinv = np.linalg.inv(K)
126 | X = Kinv.dot(X.T).T # normalized coords
127 | # calculate cylindrical coords (sin\theta, h, cos\theta)
128 | A = np.stack([np.sin(X[:, 0]), X[:, 1], np.cos(X[:, 0])], axis=-1).reshape(w_ * h_, 3)
129 | B = K.dot(A.T).T # project back to image-pixels plane
130 | # back from homog coords
131 | B = B[:, :-1] / B[:, [-1]]
132 | # make sure warp coords only within image bounds
133 | B[(B[:, 0] < 0) | (B[:, 0] >= w_) | (B[:, 1] < 0) | (B[:, 1] >= h_)] = -1
134 | B = B.reshape(h_, w_, -1)
135 |
136 | frame_rgba = cv2.cvtColor(frame, cv2.COLOR_BGR2BGRA) # for transparent borders...
137 | # warp the image according to cylindrical coords
138 | frame = cv2.remap(frame_rgba, B[:, :, 0].astype(np.float32), B[:, :, 1].astype(np.float32), cv2.INTER_AREA,
139 | borderMode=cv2.BORDER_TRANSPARENT)
140 |
141 | cur_node_time = time.time()
142 | nodeRewardAfterBuff.put(cur_node_time)
143 | cur_node_time -= start_time
144 | node_time_p = cur_node_time
145 | if node_time != 0.0:
146 | node_time = node_time * a + cur_node_time * (1 - a);
147 | else:
148 | node_time = cur_node_time
149 | nodeAfterBuff.put(frame)
150 | # cv2.imshow('ImageWindow', frame)
151 | # cv2.waitKey(1)
152 |
153 |
154 | ### img_mod END
155 |
156 | ############## Socket Communicate 함수 ##############
157 | ### recv_img : edge로부터 처리한 영상을 받는다.
158 | def recv_img():
159 | data = b""
160 | # clnt_sock.send(msg_go.encode('utf-8'))
161 | # calcsize @시스템에 따름. = 시스템에 따름 < 리틀 엔디안 > 빅 엔디안 !네트워크(빅 엔디안)
162 | # 원본 >L
163 | payload_size = struct.calcsize(">L")
164 | # print("payload_size: {}".format(payload_size))
165 |
166 | while len(data) < payload_size:
167 | # print("Recv: {}".format(len(data)))
168 | data += clnt_sock.recv(4096)
169 |
170 | # print("Done Recv: {}".format(len(data)))
171 | packed_msg_size = data[:payload_size]
172 | data = data[payload_size:]
173 | msg_size = struct.unpack(">L", packed_msg_size)[0]
174 | # print("msg_size: {}".format(msg_size))
175 | while len(data) < msg_size:
176 | data += clnt_sock.recv(4096)
177 | frame_data = data[:msg_size]
178 | data = data[msg_size:]
179 |
180 | frame = pickle.loads(frame_data, fix_imports=True, encoding="bytes")
181 | frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
182 | # cv2.imshow('ImageWindow', frame)
183 | # cv2.waitKey(1)
184 |
185 | edgeAfterBuff.put(frame)
186 |
187 |
188 | # frames.append(frame)
189 |
190 | # cv2.imshow('ImageWindow', frame)
191 | # cv2.waitKey(40)
192 | ### recv_img END
193 |
194 | ### send_img :
195 | def send_img():
196 | frame = edgeBeforeBuff.get()
197 | result, frame = cv2.imencode('.jpg', frame, encode_param)
198 | data = pickle.dumps(frame, 0)
199 | size = len(data)
200 |
201 | # print("{}: {}".format(img_cnt, size))
202 | clnt_sock.sendall(struct.pack(">L", size) + data)
203 |
204 |
205 | ### send_img END
206 |
207 | ### sock_commu() :
208 | def sock_commu():
209 | # time.sleep(10)
210 | global edge_time
211 | global edge_time_p
212 | while True:
213 | start_time = time.time()
214 | send_img()
215 | recv_img()
216 | cur_edge_time = time.time()
217 | edgeRewardAfterBuff.put(cur_edge_time)
218 | # cur_edge_time = time.time() - start_time
219 | edge_time_p = cur_edge_time
220 | if edge_time != 0.0:
221 | edge_time = edge_time * a + cur_edge_time * (1 - a)
222 | else:
223 | edge_time = cur_edge_time
224 |
225 |
226 | ### sock_commu() END
227 |
228 | learning_rate = 0.005
229 | gamma = 0.9
230 | buffer_limit = 10000
231 | batch_size = 1
232 |
233 |
234 | class ReplayBuffer:
235 | def __init__(self):
236 | self.buffer = collections.deque(maxlen=buffer_limit)
237 |
238 | def put(self, trans):
239 | self.buffer.append(trans)
240 |
241 | def sample(self, n): # n 만큼 랜덤하게 뽑음
242 | # mini_batch = random.sample(self.buffer, n) #n > 1 일 때
243 | mini_batch = self.buffer.popleft() #n == 1 일 때
244 | state1_lst, act1_lst, rew1_lst, state_prime_lst = [], [], [], []
245 |
246 | # for trans in mini_batch:
247 | state1, act1, rew1, state_prime = mini_batch
248 | # state1, act1, rew1, state_prime = trans
249 | state1_lst.append(state1)
250 | act1_lst.append([act1])
251 | rew1_lst.append([rew1])
252 | state_prime_lst.append(state_prime)
253 | # check_done_lst.append([check_done])
254 |
255 | return state1_lst, act1_lst, rew1_lst, state_prime_lst
256 | # return torch.tensor(state1_lst, dtype=torch.float), torch.tensor(act1_lst), torch.tensor(
257 | # rew1_lst), torch.tensor(state_prime_lst, dtype=torch.float) # , torch.tensor(check_done_lst)
258 |
259 | def size(self):
260 | return len(self.buffer)
261 |
262 |
263 | class Qnet(nn.Module):
264 |
265 | def __init__(self):
266 | super(Qnet, self).__init__()
267 | self.fc1 = nn.Linear(2, 256) # 2 -> 256
268 | self.fc2 = nn.Linear(256, 256) # 256 -> 2
269 | self.fc3 = nn.Linear(256, 2)
270 |
271 | def forward(self, x):
272 | x = F.relu(self.fc1(x))
273 | x = F.relu(self.fc2(x))
274 | x = self.fc3(x)
275 | return x
276 |
277 | def sample_action(self, obs, epsilon): # epsilon greedy 를 하기 위해
278 | out = self.forward(obs)
279 | coin = random.random()
280 | if coin < epsilon: # random 하게 생성한 coin 변수가 epsilon 보다 작으면 explore
281 | return random.randint(0, 1)
282 | else: # 그렇지 않으면 exploit
283 | # print("exploit")
284 | return out.argmax().item()
285 |
286 | def train(q, q_target, memory, optimizer):
287 | s, aa, r, s_prime = memory.sample(batch_size)
288 | s = torch.tensor(s, dtype=float)
289 | aa = torch.tensor(aa)
290 | r = torch.tensor(r)
291 | s_prime = torch.tensor(s_prime, dtype=float)
292 |
293 | q_out = q(s.float())
294 | # print("q_out : " , q_out)
295 | q_a = torch.gather(q_out, 1, aa).unsqueeze(1)
296 | # q_a = torch.gat
297 | # print("aa : " , q_a)
298 | # q_a = q_out.gather(1, a) # 실제 취한 action만 사용
299 | #max_q_prime = q_target(s_prime.float()).max(1)[0].unsqueeze(1)
300 | max_q_prime = q_target(s_prime.float()).max(1)[0].unsqueeze(1)
301 | # print("r : " , r)
302 | # print("max_q_prime : " , max_q_prime)
303 | target = r + gamma * max_q_prime # * done_mask
304 | # print("target : " , target)
305 | loss = F.smooth_l1_loss(q_a, target)
306 |
307 | # print(q_target(s_prime.float()))
308 | optimizer.zero_grad()
309 | loss.backward()
310 | optimizer.step()
311 |
312 |
313 | def getObs(nodeBNum, edgeBNum):
314 | # obs = torch.tensor([nodeBNum, edgeBNum])
315 | if nodeBNum is None:
316 | nodeBNum = 0
317 | if edgeBNum is None:
318 | edgeBNum = 0
319 | obs = np.array([nodeBNum, edgeBNum])
320 | return obs
321 |
322 |
323 | ############## Judge Algorithm 함수 ##############
324 | def judge_algo():
325 | global img_cnt # 처리할 프레임 개수
326 | global node_time # 1 frame을 처리하는데 걸리는 예상시간
327 | global edge_time # 1 frame을 처리하는데 걸리는 예상시간
328 |
329 | q = Qnet()
330 | q_target = Qnet()
331 | q_target.load_state_dict(q.state_dict()) # q 에서 q_target 으로 복제
332 | memory = ReplayBuffer()
333 | optimizer = optim.Adam(q.parameters(), lr=learning_rate) # q만 update, q_target은 q에서 복제
334 |
335 | NodeSeq = queue.Queue(q_max)
336 | EdgeSeq = queue.Queue(q_max)
337 |
338 |
339 | sarr, aarr, rarr, sparr = [],[],[], []
340 |
341 | num = 0
342 | r_count = 0
343 | r_count2 = 0
344 | # while (cam.isOpened()):
345 | while(cam.isOpened()):
346 | ret, frame = cam.read()
347 | num += 1
348 |
349 | if frame is None:
350 | break
351 | # result, frame = cv2.imencode('.jpg', frame, encode_param)
352 | # 여기부터
353 |
354 |
355 |
356 | # edge_latency = edge_time * (edgeBeforeBuff.qsize() + 1)
357 |
358 | # if node_latency < edge_latency:
359 | # procSeq.put(1)
360 | # nodeBeforeBuff.put(frame)
361 | # else:
362 | # procSeq.put(2)
363 | # edgeBeforeBuff.put(frame)
364 |
365 |
366 | epsilon = max(0.01, 0.08 - 0.01 * (num / 200))
367 |
368 | obs = getObs(nodeBeforeBuff.qsize(), edgeBeforeBuff.qsize()) # current state
369 | # print("nodeQsize : ", nodeBeforeBuff.qsize())
370 | # print("edgeQsize : ", edgeBeforeBuff.qsize())
371 | sarr.append(obs)
372 | # print("state: ", obs)
373 | # print("sarr pop : ",sarr.pop())
374 |
375 | # if num <= 1000:
376 | a = q.sample_action(torch.tensor(obs).float(), epsilon) # chosen action by current state
377 | aarr.append(a)
378 | #print("action : ",a)
379 | if a == 0:
380 | procSeq.put(1)
381 | procSeq2.put(1)
382 | NodeSeq.put(num - 1)
383 | # print(NodeSeq.get())
384 | nodeRewardBuff.put(time.time())
385 | nodeBeforeBuff.put(frame)
386 | # node_latency = node_time * (nodeBeforeBuff.qsize()) + node_time_p
387 | # node_latency = start3
388 | if nodeRewardAfterBuff.qsize() != 0:
389 | r = -(nodeRewardAfterBuff.get() - nodeRewardBuff.get())
390 | # print("i am node r : ", r)
391 | # if r != 0:
392 | # print("reward start")
393 | rarr.insert(NodeSeq.get(), [r])
394 | # print("state : ", sarr[0])
395 | s1 = torch.tensor(sarr[0], dtype=float)
396 | q1 = q(s1.float())
397 | # print("now q : ", q1)
398 | r_count += 1
399 | s_prime = getObs(nodeBeforeBuff.qsize(), edgeBeforeBuff.qsize())
400 | sparr.append(s_prime)
401 |
402 | else:
403 | procSeq.put(2)
404 | procSeq2.put(2)
405 | EdgeSeq.put(num - 1)
406 | # print(EdgeSeq.get())
407 | edgeRewardBuff.put(time.time())
408 | edgeBeforeBuff.put(frame)
409 | # edge_latency = edge_time * (edgeBeforeBuff.qsize()) + edge_time_p
410 | if edgeRewardAfterBuff.qsize() != 0:
411 | r = -(edgeRewardAfterBuff.get() - edgeRewardBuff.get())
412 | # print("i am edge r : ", r)
413 | # if r != 0:
414 | # print("reward start")
415 | rarr.insert(EdgeSeq.get(), [r])
416 | # print("state : ", sarr[0])
417 | s2 = torch.tensor(sarr[0], dtype=float)
418 | q2 = q(s2.float())
419 | # print("now q : ", q2)
420 | r_count2 += 1
421 | s_prime = getObs(nodeBeforeBuff.qsize(), edgeBeforeBuff.qsize())
422 | sparr.append(s_prime)
423 | # if r is None:
424 | # print("reward is none")
425 | # while r is None:
426 |
427 | # node_latency = node_time * (nodeBeforeBuff.qsize() + 1)
428 | # edge_latency = edge_time * (edgeBeforeBuff.qsize() + 1)
429 | # print("here is error")
430 |
431 | # if node_latency != 0:
432 | # print("into node_latency")
433 | # rarr.insert(NodeSeq.get(), -node_latency)
434 | # r_count += 1
435 | #
436 | # if edge_latency != 0:
437 | # print("into edge_latency")
438 | # rarr.insert(EdgeSeq.get(), -edge_latency)
439 | # r_count += 1
440 | # print("here is second error")
441 | if r_count != 0 and r_count2 != 0:
442 | if procSeq2.get() == 1:
443 | r_count -= 1
444 | if procSeq2.get() == 2:
445 | r_count2 -= 1
446 |
447 | # print("rarr size: ",len(rarr))
448 | # print("start")
449 | # print("sarr : " , sarr.pop(0))
450 | # print("aarr : " , aarr.pop(0))
451 | # print("rarr : " , rarr.pop(0))
452 | # print("sparr : " , sparr.pop(0))
453 | spop = sarr.pop(0)
454 | # print("state ok")
455 | apop = aarr.pop(0)
456 | # print("action ok")
457 | rpop = rarr.pop(0)
458 | # print("reward ok")
459 | sppop = sparr.pop(0)
460 | # print("s prime ok")
461 | memory.put((spop, apop, rpop, sppop))
462 |
463 | train(q, q_target, memory, optimizer)
464 | q_target.load_state_dict(q.state_dict())
465 |
466 | #memory.put((obs, a, r, s_prime))
467 |
468 | # if num > 1000:
469 | #train(q, q_target, memory, optimizer)
470 |
471 | # if (a == 0):
472 | # node_latency = node_time * (nodeBeforeBuff.qsize() + 1)
473 | # procSeq.put(1)
474 | # nodeBeforeBuff.put(frame)
475 | # done_mask = 0.0 if frame is None else 1.0
476 | # memory.put((frame, a, node_latency / 100.0, f_prime, done_mask))
477 | # node_score += node_latency
478 | #
479 | # else:
480 | # edge_latency = edge_time * (edgeBeforeBuff.qsize() + 1)
481 | # procSeq.put(2)
482 | # edgeBeforeBuff.put(frame)
483 | # done_mask = 0.0 if frame is None else 1.0
484 | # memory.put((frame, a, edge_latency / 100.0, f_prime, done_mask))
485 | # edge_score += edge_latency
486 |
487 | # if memory.size() > 2000:
488 | # train(q, q_target, memory, optimizer)
489 |
490 | # if num % 50 == 0 and num != 0:
491 |
492 | #q_target.load_state_dict(q.state_dict())
493 |
494 | # print(
495 | # "# of frame : {}, avg node_latency : {:.1f}, avg edge_latency : {:.1f}, buffer size : {}, epsilon : {:.1f}%".format(
496 | # num, node_score / 50, edge_score / 50, memory.size(), epsilon * 100))
497 | #
498 | # node_score = 0.0
499 | # edge_score = 0.0
500 |
501 | img_cnt += 1
502 | # 여기까지
503 |
504 | procSeq.put(0)
505 | cam.release()
506 |
507 | # def getReward():
508 | # node_latency = node_time * (nodeBeforeBuff.qsize() + 1)
509 | # edge_latency = edge_time * (edgeBeforeBuff.qsize() + 1)
510 |
511 |
512 |
513 | ############## Img Merger 함수 ##############
514 | def img_merger():
515 | while True:
516 | serv_num = procSeq.get()
517 | if serv_num == 1:
518 | frame = nodeAfterBuff.get()
519 | # cv2.imshow('ImageWindow', frame)
520 | # cv2.waitKey(40)
521 | elif serv_num == 2:
522 | frame = edgeAfterBuff.get()
523 | # cv2.imshow('ImageWindow', frame)
524 | # cv2.waitKey(40)
525 | else:
526 | break
527 |
528 |
529 | ### threads_func :
530 | if __name__ == '__main__':
531 | main_start_time = time.time()
532 | thread_img_process = threading.Thread(target=img_mod, daemon=True)
533 | thread_sock_commu = threading.Thread(target=sock_commu, daemon=True)
534 | thread_judge_algo = threading.Thread(target=judge_algo, daemon=True)
535 | # thread_img_merger = threading.Thread(target = img_merger)
536 | thread_judge_algo.start()
537 | thread_img_process.start()
538 | thread_sock_commu.start()
539 |
540 | # thread_img_merger.start()
541 | # thread_img_merger.join()
542 | while True:
543 | serv_num = procSeq.get()
544 | if serv_num == 1:
545 | frame = nodeAfterBuff.get()
546 | # cv2.imshow('ImageWindow', frame)
547 | # cv2.waitKey(40)
548 | elif serv_num == 2:
549 | frame = edgeAfterBuff.get()
550 | else:
551 | break
552 | cv2.imshow('ImageWindow', frame)
553 | cv2.waitKey(1)
554 | clnt_sock.send(msg_stop.encode('utf-8'))
555 | clnt_sock.close()
556 | main_end_time = time.time() - main_start_time
557 | print(main_end_time)
558 | ### threads_func END
--------------------------------------------------------------------------------