├── Thug-Life-Glasses-PNG.png ├── RFB-320 ├── RFB-320.caffemodel └── RFB-320.prototxt ├── requirements.txt ├── README.md ├── kivy_object_detector.py └── utils.py /Thug-Life-Glasses-PNG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smpurkis/kivy_object_detection_camera_app/HEAD/Thug-Life-Glasses-PNG.png -------------------------------------------------------------------------------- /RFB-320/RFB-320.caffemodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smpurkis/kivy_object_detection_camera_app/HEAD/RFB-320/RFB-320.caffemodel -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Kivy==2.1.0; python_version == "3.7" 2 | Kivy-Garden==0.1.4 3 | kivymd==0.104.2 4 | xcamera==2020.613 5 | opencv-python==4.5.5.64 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kivy object detection camera app 2 | An example of object detection for mobile using Python. Specific example is with face detection. 3 | 4 | Aims: 5 | - Show that object detection for mobile is possible using Python 6 | - Make the code adaptable to be able to implement any object detection model 7 | 8 | The packages used: 9 | - [Kivy](https://kivy.org/#home), to create the graphical interface 10 | - [Buildozer](https://buildozer.readthedocs.io/en/latest/), to package to mobile 11 | - [Opencv](https://opencv.org/), to load the neural network and manipulate the images 12 | - [Numpy](https://numpy.org/), also to manipulate the images 13 | - [KivyMD](https://kivymd.readthedocs.io/en/latest/index.html), to make the graphics look good (files copied manually from the [repo](https://github.com/HeaTTheatR/KivyMD) due to this error I [encounted](https://www.reddit.com/r/kivy/comments/detase/buildozer_question_kivymd_importing_differently/)) 14 | - [XCamera](https://github.com/kivy-garden/xcamera), to get the camera feed (the default camera in Kivy doesn't work on Android for some reason) 15 | - [Ultra fast face detection model](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB), used as an example to detect faces in real time 16 | 17 | The main file is [kivy_object_detector.py](https://github.com/smpurkis/kivy_object_detection_camera_app/blob/master/kivy_object_detector.py). 18 | With the basic structure being setup so that you can load your model in the `self.build` and add the prediction code to the `self.process_frame`. 19 | 20 | Todo: 21 | - Dig into XCamera, to see the method used to capture the camera feed when the default Kivy camera doesn't work 22 | - Stay up to date with Opencv Python4Android recipes, currently only 4.0.21 can be used on Android using Buildozer 23 | - restructure files 24 | - add images to this README -------------------------------------------------------------------------------- /kivy_object_detector.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import cv2 4 | import numpy as np 5 | # from kivy.app import App 6 | from kivy.clock import Clock 7 | from kivy.core.window import Window 8 | # from kivy.core.camera import camera_android 9 | from kivy.logger import Logger 10 | # from kivy.uix.button impordt Button 11 | from kivy.uix.floatlayout import FloatLayout 12 | from kivy.uix.image import Image 13 | from kivy.utils import platform 14 | from kivy_garden.xcamera import XCamera 15 | 16 | from kivymd.app import MDApp as App 17 | from kivymd.uix.button import MDFlatButton as Button 18 | from utils import define_img_size, find_faces, draw_on_faces, make_new_texture_frame 19 | 20 | Logger.info(f"Versions: Numpy {np.__version__}") 21 | Logger.info(f"Versions: Opencv {cv2.__version__}") 22 | 23 | image_mean = np.array([127, 127, 127]) 24 | image_std = 128.0 25 | iou_threshold = 0.3 26 | center_variance = 0.1 27 | size_variance = 0.2 28 | min_boxes = [[10.0, 16.0, 24.0], [32.0, 48.0], [64.0, 96.0], [128.0, 192.0, 256.0]] 29 | strides = [8.0, 16.0, 32.0, 64.0] 30 | 31 | 32 | class CameraCV(XCamera): 33 | def on_tex(self, *l): 34 | self.image_bytes = self._camera.texture.pixels 35 | self.image_size = self._camera.texture.size 36 | 37 | 38 | class CamApp(App): 39 | def build(self): 40 | model_dir = Path("RFB-320") 41 | Logger.info(f"Model: Model directory path: {model_dir.__str__()}") 42 | self.model = cv2.dnn.readNetFromCaffe(Path(model_dir, "RFB-320.prototxt").__str__(), 43 | Path(model_dir, "RFB-320.caffemodel").__str__()) 44 | Logger.info(f"Model: Model has loaded successfully ({self.model})") 45 | 46 | overlap_path = Path("Thug-Life-Glasses-PNG.png") 47 | self.overlap_image = cv2.imread(overlap_path.__str__(), cv2.IMREAD_UNCHANGED) 48 | self.overlap_image = cv2.resize(self.overlap_image, (320, 240)) 49 | self.thug_life = True 50 | 51 | self.image_mean = np.array([127, 127, 127]) 52 | self.image_std = 128.0 53 | self.iou_threshold = 0.3 54 | self.center_variance = 0.1 55 | self.size_variance = 0.2 56 | self.min_boxes = [[10.0, 16.0, 24.0], [32.0, 48.0], [64.0, 96.0], [128.0, 192.0, 256.0]] 57 | self.strides = [8.0, 16.0, 32.0, 64.0] 58 | self.threshold = 0.7 59 | self.size_ratio = None 60 | 61 | self.input_size = (320, 240) 62 | self.width = self.input_size[0] 63 | self.height = self.input_size[1] 64 | self.priors = define_img_size(self.input_size) 65 | 66 | self.check_window_size() 67 | 68 | self.img1 = Image(pos_hint={'center_x': 0.5, 'center_y': 0.5}) 69 | self.speed_button = Button(text="Change display size", size_hint=(0.2, 0.4), 70 | pos_hint={'center_x': 0.25, 'center_y': 0.125}) 71 | self.thug_button = Button(text="switch thug life", size_hint=(0.2, 0.4), 72 | pos_hint={'center_x': 0.75, 'center_y': 0.125}) 73 | self.thug_button.bind(on_press=self.switch_thug_life) 74 | self.speed_button.bind(on_press=self.set_display_speed) 75 | layout = FloatLayout(size=Window.size) 76 | layout.add_widget(self.img1) 77 | layout.add_widget(self.speed_button) 78 | layout.add_widget(self.thug_button) 79 | 80 | self.display_speed = 2 # 0 for best resolution, 1 for medium, 2 for fastest display 81 | desired_resolution = (720, 480) 82 | self.camCV = CameraCV(play=True, resolution=desired_resolution) 83 | self.camCV.image_bytes = False 84 | 85 | Clock.schedule_interval(self.update_texture, 1.0 / 60.0) 86 | return layout 87 | 88 | def set_display_speed(self, instance): 89 | if self.display_speed == 2: 90 | self.display_speed = 0 91 | else: 92 | self.display_speed += 1 93 | 94 | def check_window_size(self): 95 | self.window_shape = Window.size 96 | self.window_width = self.window_shape[0] 97 | self.window_height = self.window_shape[1] 98 | Logger.info(f"Screen: Window size is {self.window_shape}") 99 | 100 | def switch_thug_life(self, instance): 101 | self.thug_life = not self.thug_life 102 | 103 | def update_texture(self, instance): 104 | self.check_window_size() 105 | if type(self.camCV.image_bytes) == bool: 106 | Logger.info("Camera: No valid frame") 107 | return 108 | Logger.info(f"Camera: image bytes {len(self.camCV.image_bytes)}") 109 | Logger.info(f"Camera: image size {self.camCV.image_size}") 110 | if not self.size_ratio: 111 | self.camera_width = self.camCV.image_size[0] 112 | self.camera_height = self.camCV.image_size[1] 113 | self.size_ratio = self.camera_height / self.camera_width 114 | 115 | Logger.info(f"Camera: update texture") 116 | self.extract_frame() 117 | self.process_frame() 118 | self.display_frame() 119 | 120 | Logger.info(f"Camera: converted to gray and back to rgba") 121 | 122 | def extract_frame(self): 123 | self.frame = np.frombuffer(self.camCV.image_bytes, np.uint8) 124 | Logger.info(f"Camera: frame exist") 125 | self.frame = self.frame.reshape((self.camCV.image_size[1], self.camCV.image_size[0], 4)) 126 | Logger.info(f"Camera: frame size {self.frame.shape}") 127 | 128 | def process_frame(self): 129 | boxes = find_faces(self, platform) 130 | self.frame = draw_on_faces(self, boxes, platform) 131 | 132 | def display_frame(self): 133 | self.img1.texture = make_new_texture_frame(self) 134 | 135 | 136 | if __name__ == '__main__': 137 | CamApp().run() 138 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from math import ceil 3 | import cv2 4 | from kivy.logger import Logger 5 | from kivy.graphics.texture import Texture 6 | 7 | image_mean = np.array([127, 127, 127]) 8 | image_std = 128.0 9 | iou_threshold = 0.3 10 | center_variance = 0.1 11 | size_variance = 0.2 12 | min_boxes = [[10.0, 16.0, 24.0], [32.0, 48.0], [64.0, 96.0], [128.0, 192.0, 256.0]] 13 | strides = [8.0, 16.0, 32.0, 64.0] 14 | 15 | 16 | def define_img_size(image_size): 17 | shrinkage_list = [] 18 | feature_map_w_h_list = [] 19 | for size in image_size: 20 | feature_map = [int(ceil(size / stride)) for stride in strides] 21 | feature_map_w_h_list.append(feature_map) 22 | 23 | for i in range(0, len(image_size)): 24 | shrinkage_list.append(strides) 25 | priors = generate_priors(feature_map_w_h_list, shrinkage_list, image_size, min_boxes) 26 | return priors 27 | 28 | 29 | def generate_priors(feature_map_list, shrinkage_list, image_size, min_boxes): 30 | priors = [] 31 | for index in range(0, len(feature_map_list[0])): 32 | scale_w = image_size[0] / shrinkage_list[0][index] 33 | scale_h = image_size[1] / shrinkage_list[1][index] 34 | for j in range(0, feature_map_list[1][index]): 35 | for i in range(0, feature_map_list[0][index]): 36 | x_center = (i + 0.5) / scale_w 37 | y_center = (j + 0.5) / scale_h 38 | 39 | for min_box in min_boxes[index]: 40 | w = min_box / image_size[0] 41 | h = min_box / image_size[1] 42 | priors.append([ 43 | x_center, 44 | y_center, 45 | w, 46 | h 47 | ]) 48 | print("priors nums:{}".format(len(priors))) 49 | return np.clip(priors, 0.0, 1.0) 50 | 51 | 52 | def hard_nms(box_scores, iou_threshold, top_k=-1, candidate_size=200): 53 | scores = box_scores[:, -1] 54 | boxes = box_scores[:, :-1] 55 | picked = [] 56 | indexes = np.argsort(scores) 57 | indexes = indexes[-candidate_size:] 58 | while len(indexes) > 0: 59 | current = indexes[-1] 60 | picked.append(current) 61 | if 0 < top_k == len(picked) or len(indexes) == 1: 62 | break 63 | current_box = boxes[current, :] 64 | indexes = indexes[:-1] 65 | rest_boxes = boxes[indexes, :] 66 | iou = iou_of( 67 | rest_boxes, 68 | np.expand_dims(current_box, axis=0), 69 | ) 70 | indexes = indexes[iou <= iou_threshold] 71 | return box_scores[picked, :] 72 | 73 | 74 | def area_of(left_top, right_bottom): 75 | hw = np.clip(right_bottom - left_top, 0.0, None) 76 | return hw[..., 0] * hw[..., 1] 77 | 78 | 79 | def iou_of(boxes0, boxes1, eps=1e-5): 80 | overlap_left_top = np.maximum(boxes0[..., :2], boxes1[..., :2]) 81 | overlap_right_bottom = np.minimum(boxes0[..., 2:], boxes1[..., 2:]) 82 | 83 | overlap_area = area_of(overlap_left_top, overlap_right_bottom) 84 | area0 = area_of(boxes0[..., :2], boxes0[..., 2:]) 85 | area1 = area_of(boxes1[..., :2], boxes1[..., 2:]) 86 | return overlap_area / (area0 + area1 - overlap_area + eps) 87 | 88 | 89 | def predict(width, height, confidences, boxes, prob_threshold, iou_threshold=0.3, top_k=-1): 90 | boxes = boxes[0] 91 | confidences = confidences[0] 92 | picked_box_probs = [] 93 | picked_labels = [] 94 | for class_index in range(1, confidences.shape[1]): 95 | probs = confidences[:, class_index] 96 | mask = probs > prob_threshold 97 | probs = probs[mask] 98 | if probs.shape[0] == 0: 99 | continue 100 | subset_boxes = boxes[mask, :] 101 | box_probs = np.concatenate([subset_boxes, probs.reshape(-1, 1)], axis=1) 102 | box_probs = hard_nms(box_probs, 103 | iou_threshold=iou_threshold, 104 | top_k=top_k, 105 | ) 106 | picked_box_probs.append(box_probs) 107 | picked_labels.extend([class_index] * box_probs.shape[0]) 108 | if not picked_box_probs: 109 | return np.array([]), np.array([]), np.array([]) 110 | picked_box_probs = np.concatenate(picked_box_probs) 111 | picked_box_probs[:, 0] *= width 112 | picked_box_probs[:, 1] *= height 113 | picked_box_probs[:, 2] *= width 114 | picked_box_probs[:, 3] *= height 115 | return picked_box_probs[:, :4].astype(np.int32), np.array(picked_labels), picked_box_probs[:, 4] 116 | 117 | 118 | def convert_locations_to_boxes(locations, priors, center_variance, 119 | size_variance): 120 | if len(priors.shape) + 1 == len(locations.shape): 121 | priors = np.expand_dims(priors, 0) 122 | return np.concatenate([ 123 | locations[..., :2] * center_variance * priors[..., 2:] + priors[..., :2], 124 | np.exp(locations[..., 2:] * size_variance) * priors[..., 2:] 125 | ], axis=len(locations.shape) - 1) 126 | 127 | 128 | def center_form_to_corner_form(locations): 129 | return np.concatenate([locations[..., :2] - locations[..., 2:] / 2, 130 | locations[..., :2] + locations[..., 2:] / 2], len(locations.shape) - 1) 131 | 132 | 133 | def overlap_images(background, overlap): 134 | alpha = overlap[:, :, 3] / 255.0 135 | background[:, :, 0] = (1. - alpha) * background[:, :, 0] + alpha * overlap[:, :, 0] 136 | background[:, :, 1] = (1. - alpha) * background[:, :, 1] + alpha * overlap[:, :, 1] 137 | background[:, :, 2] = (1. - alpha) * background[:, :, 2] + alpha * overlap[:, :, 2] 138 | return background 139 | 140 | 141 | def find_faces(self, platform): 142 | if (platform == 'android'): 143 | Logger.info(f"Camera: Rotating frame") 144 | self.frame = np.rot90(self.frame) 145 | Logger.info(f"Camera: frame size {self.frame.shape}") 146 | rect = cv2.resize(self.frame, (self.width, self.height)) 147 | if (platform == 'android'): 148 | rect = cv2.flip(rect, 0) 149 | rect = cv2.cvtColor(rect, cv2.COLOR_BGR2RGB) 150 | self.model.setInput(cv2.dnn.blobFromImage(rect, 1 / image_std, (self.width, self.height), 127)) 151 | boxes, scores = self.model.forward(["boxes", "scores"]) 152 | boxes = np.expand_dims(np.reshape(boxes, (-1, 4)), axis=0) 153 | scores = np.expand_dims(np.reshape(scores, (-1, 2)), axis=0) 154 | boxes = convert_locations_to_boxes(boxes, self.priors, center_variance, size_variance) 155 | boxes = center_form_to_corner_form(boxes) 156 | boxes, labels, probs = predict(self.frame.shape[1], self.frame.shape[0], scores, boxes, self.threshold) 157 | Logger.info(f"Model: boxes detected {boxes}") 158 | return boxes 159 | 160 | 161 | def draw_on_faces(self, boxes, platform): 162 | for i in range(boxes.shape[0]): 163 | box = boxes[i, :] 164 | if any([b < 0 for b in box]): 165 | break 166 | if self.thug_life: 167 | face = self.frame[box[1]:box[3], box[0]:box[2]] 168 | result = self.frame.copy() 169 | if (platform == 'android'): 170 | result = cv2.flip(result, 0) 171 | try: 172 | overlap_image = cv2.resize(self.overlap_image, dsize=(face.shape[1], face.shape[0])) 173 | transparent_background = np.zeros(self.frame.shape, dtype="uint8") 174 | transparent_background[box[1]:box[3], box[0]:box[2]] = overlap_image 175 | overlap_image = transparent_background 176 | result = overlap_images(result, overlap_image) 177 | if (platform == 'android'): 178 | result = cv2.flip(result, 0) 179 | self.frame = result 180 | except Exception as e: 181 | Logger.info(f"Camera: Failed to resize overlap image {e}") 182 | else: 183 | cv2.rectangle(self.frame, (box[0], box[1]), (box[2], box[3]), (0, 255, 0), 4) 184 | return self.frame 185 | 186 | 187 | def make_new_texture_frame(self): 188 | Logger.info(f"Camera: Displaying frame") 189 | if self.display_speed == 0: 190 | self.frame = cv2.resize(self.frame, (int(self.window_height * self.size_ratio), self.window_height)) 191 | elif self.display_speed == 1: 192 | self.frame = cv2.resize(self.frame, (int(800 * self.size_ratio), 800)) 193 | else: 194 | self.frame = cv2.resize(self.frame, (int(600 * self.size_ratio), 600)) 195 | self.frame = self.frame.reshape((self.frame.shape[1], self.frame.shape[0], 4)) 196 | buf = self.frame.tostring() 197 | Logger.info(f"Camera: converted to bytes {len(buf)}") 198 | texture1 = Texture.create(size=(self.frame.shape[0], self.frame.shape[1]), colorfmt='rgba') 199 | texture1.blit_buffer(buf, colorfmt='rgba', bufferfmt='ubyte') 200 | return texture1 201 | -------------------------------------------------------------------------------- /RFB-320/RFB-320.prototxt: -------------------------------------------------------------------------------- 1 | layer { 2 | name: "input" 3 | type: "Input" 4 | top: "input" 5 | input_param { 6 | shape { 7 | dim: 1 8 | dim: 3 9 | dim: 240 10 | dim: 320 11 | } 12 | } 13 | } 14 | layer { 15 | name: "245" 16 | type: "Convolution" 17 | bottom: "input" 18 | top: "245" 19 | convolution_param { 20 | num_output: 16 21 | bias_term: true 22 | group: 1 23 | pad_h: 1 24 | pad_w: 1 25 | kernel_h: 3 26 | kernel_w: 3 27 | stride_h: 2 28 | stride_w: 2 29 | dilation: 1 30 | } 31 | } 32 | layer { 33 | name: "247" 34 | type: "ReLU" 35 | bottom: "245" 36 | top: "247" 37 | } 38 | layer { 39 | name: "248" 40 | type: "Convolution" 41 | bottom: "247" 42 | top: "248" 43 | convolution_param { 44 | num_output: 16 45 | bias_term: true 46 | group: 16 47 | pad_h: 1 48 | pad_w: 1 49 | kernel_h: 3 50 | kernel_w: 3 51 | stride_h: 1 52 | stride_w: 1 53 | dilation: 1 54 | } 55 | } 56 | layer { 57 | name: "250" 58 | type: "ReLU" 59 | bottom: "248" 60 | top: "250" 61 | } 62 | layer { 63 | name: "251" 64 | type: "Convolution" 65 | bottom: "250" 66 | top: "251" 67 | convolution_param { 68 | num_output: 32 69 | bias_term: true 70 | group: 1 71 | pad_h: 0 72 | pad_w: 0 73 | kernel_h: 1 74 | kernel_w: 1 75 | stride_h: 1 76 | stride_w: 1 77 | dilation: 1 78 | } 79 | } 80 | layer { 81 | name: "253" 82 | type: "ReLU" 83 | bottom: "251" 84 | top: "253" 85 | } 86 | layer { 87 | name: "254" 88 | type: "Convolution" 89 | bottom: "253" 90 | top: "254" 91 | convolution_param { 92 | num_output: 32 93 | bias_term: true 94 | group: 32 95 | pad_h: 1 96 | pad_w: 1 97 | kernel_h: 3 98 | kernel_w: 3 99 | stride_h: 2 100 | stride_w: 2 101 | dilation: 1 102 | } 103 | } 104 | layer { 105 | name: "256" 106 | type: "ReLU" 107 | bottom: "254" 108 | top: "256" 109 | } 110 | layer { 111 | name: "257" 112 | type: "Convolution" 113 | bottom: "256" 114 | top: "257" 115 | convolution_param { 116 | num_output: 32 117 | bias_term: true 118 | group: 1 119 | pad_h: 0 120 | pad_w: 0 121 | kernel_h: 1 122 | kernel_w: 1 123 | stride_h: 1 124 | stride_w: 1 125 | dilation: 1 126 | } 127 | } 128 | layer { 129 | name: "259" 130 | type: "ReLU" 131 | bottom: "257" 132 | top: "259" 133 | } 134 | layer { 135 | name: "260" 136 | type: "Convolution" 137 | bottom: "259" 138 | top: "260" 139 | convolution_param { 140 | num_output: 32 141 | bias_term: true 142 | group: 32 143 | pad_h: 1 144 | pad_w: 1 145 | kernel_h: 3 146 | kernel_w: 3 147 | stride_h: 1 148 | stride_w: 1 149 | dilation: 1 150 | } 151 | } 152 | layer { 153 | name: "262" 154 | type: "ReLU" 155 | bottom: "260" 156 | top: "262" 157 | } 158 | layer { 159 | name: "263" 160 | type: "Convolution" 161 | bottom: "262" 162 | top: "263" 163 | convolution_param { 164 | num_output: 32 165 | bias_term: true 166 | group: 1 167 | pad_h: 0 168 | pad_w: 0 169 | kernel_h: 1 170 | kernel_w: 1 171 | stride_h: 1 172 | stride_w: 1 173 | dilation: 1 174 | } 175 | } 176 | layer { 177 | name: "265" 178 | type: "ReLU" 179 | bottom: "263" 180 | top: "265" 181 | } 182 | layer { 183 | name: "266" 184 | type: "Convolution" 185 | bottom: "265" 186 | top: "266" 187 | convolution_param { 188 | num_output: 32 189 | bias_term: true 190 | group: 32 191 | pad_h: 1 192 | pad_w: 1 193 | kernel_h: 3 194 | kernel_w: 3 195 | stride_h: 2 196 | stride_w: 2 197 | dilation: 1 198 | } 199 | } 200 | layer { 201 | name: "268" 202 | type: "ReLU" 203 | bottom: "266" 204 | top: "268" 205 | } 206 | layer { 207 | name: "269" 208 | type: "Convolution" 209 | bottom: "268" 210 | top: "269" 211 | convolution_param { 212 | num_output: 64 213 | bias_term: true 214 | group: 1 215 | pad_h: 0 216 | pad_w: 0 217 | kernel_h: 1 218 | kernel_w: 1 219 | stride_h: 1 220 | stride_w: 1 221 | dilation: 1 222 | } 223 | } 224 | layer { 225 | name: "271" 226 | type: "ReLU" 227 | bottom: "269" 228 | top: "271" 229 | } 230 | layer { 231 | name: "272" 232 | type: "Convolution" 233 | bottom: "271" 234 | top: "272" 235 | convolution_param { 236 | num_output: 64 237 | bias_term: true 238 | group: 64 239 | pad_h: 1 240 | pad_w: 1 241 | kernel_h: 3 242 | kernel_w: 3 243 | stride_h: 1 244 | stride_w: 1 245 | dilation: 1 246 | } 247 | } 248 | layer { 249 | name: "274" 250 | type: "ReLU" 251 | bottom: "272" 252 | top: "274" 253 | } 254 | layer { 255 | name: "275" 256 | type: "Convolution" 257 | bottom: "274" 258 | top: "275" 259 | convolution_param { 260 | num_output: 64 261 | bias_term: true 262 | group: 1 263 | pad_h: 0 264 | pad_w: 0 265 | kernel_h: 1 266 | kernel_w: 1 267 | stride_h: 1 268 | stride_w: 1 269 | dilation: 1 270 | } 271 | } 272 | layer { 273 | name: "277" 274 | type: "ReLU" 275 | bottom: "275" 276 | top: "277" 277 | } 278 | layer { 279 | name: "278" 280 | type: "Convolution" 281 | bottom: "277" 282 | top: "278" 283 | convolution_param { 284 | num_output: 64 285 | bias_term: true 286 | group: 64 287 | pad_h: 1 288 | pad_w: 1 289 | kernel_h: 3 290 | kernel_w: 3 291 | stride_h: 1 292 | stride_w: 1 293 | dilation: 1 294 | } 295 | } 296 | layer { 297 | name: "280" 298 | type: "ReLU" 299 | bottom: "278" 300 | top: "280" 301 | } 302 | layer { 303 | name: "281" 304 | type: "Convolution" 305 | bottom: "280" 306 | top: "281" 307 | convolution_param { 308 | num_output: 64 309 | bias_term: true 310 | group: 1 311 | pad_h: 0 312 | pad_w: 0 313 | kernel_h: 1 314 | kernel_w: 1 315 | stride_h: 1 316 | stride_w: 1 317 | dilation: 1 318 | } 319 | } 320 | layer { 321 | name: "283" 322 | type: "ReLU" 323 | bottom: "281" 324 | top: "283" 325 | } 326 | layer { 327 | name: "284" 328 | type: "Convolution" 329 | bottom: "283" 330 | top: "284" 331 | convolution_param { 332 | num_output: 8 333 | bias_term: true 334 | group: 1 335 | pad_h: 0 336 | pad_w: 0 337 | kernel_h: 1 338 | kernel_w: 1 339 | stride_h: 1 340 | stride_w: 1 341 | dilation: 1 342 | } 343 | } 344 | layer { 345 | name: "286" 346 | type: "Convolution" 347 | bottom: "284" 348 | top: "286" 349 | convolution_param { 350 | num_output: 16 351 | bias_term: true 352 | group: 1 353 | pad_h: 1 354 | pad_w: 1 355 | kernel_h: 3 356 | kernel_w: 3 357 | stride_h: 1 358 | stride_w: 1 359 | dilation: 1 360 | } 361 | } 362 | layer { 363 | name: "288" 364 | type: "ReLU" 365 | bottom: "286" 366 | top: "288" 367 | } 368 | layer { 369 | name: "289" 370 | type: "Convolution" 371 | bottom: "288" 372 | top: "289" 373 | convolution_param { 374 | num_output: 16 375 | bias_term: true 376 | group: 1 377 | pad_h: 2 378 | pad_w: 2 379 | kernel_h: 3 380 | kernel_w: 3 381 | stride_h: 1 382 | stride_w: 1 383 | dilation: 2 384 | } 385 | } 386 | layer { 387 | name: "291" 388 | type: "Convolution" 389 | bottom: "283" 390 | top: "291" 391 | convolution_param { 392 | num_output: 8 393 | bias_term: true 394 | group: 1 395 | pad_h: 0 396 | pad_w: 0 397 | kernel_h: 1 398 | kernel_w: 1 399 | stride_h: 1 400 | stride_w: 1 401 | dilation: 1 402 | } 403 | } 404 | layer { 405 | name: "293" 406 | type: "Convolution" 407 | bottom: "291" 408 | top: "293" 409 | convolution_param { 410 | num_output: 16 411 | bias_term: true 412 | group: 1 413 | pad_h: 1 414 | pad_w: 1 415 | kernel_h: 3 416 | kernel_w: 3 417 | stride_h: 1 418 | stride_w: 1 419 | dilation: 1 420 | } 421 | } 422 | layer { 423 | name: "295" 424 | type: "ReLU" 425 | bottom: "293" 426 | top: "295" 427 | } 428 | layer { 429 | name: "296" 430 | type: "Convolution" 431 | bottom: "295" 432 | top: "296" 433 | convolution_param { 434 | num_output: 16 435 | bias_term: true 436 | group: 1 437 | pad_h: 3 438 | pad_w: 3 439 | kernel_h: 3 440 | kernel_w: 3 441 | stride_h: 1 442 | stride_w: 1 443 | dilation: 3 444 | } 445 | } 446 | layer { 447 | name: "298" 448 | type: "Convolution" 449 | bottom: "283" 450 | top: "298" 451 | convolution_param { 452 | num_output: 8 453 | bias_term: true 454 | group: 1 455 | pad_h: 0 456 | pad_w: 0 457 | kernel_h: 1 458 | kernel_w: 1 459 | stride_h: 1 460 | stride_w: 1 461 | dilation: 1 462 | } 463 | } 464 | layer { 465 | name: "300" 466 | type: "Convolution" 467 | bottom: "298" 468 | top: "300" 469 | convolution_param { 470 | num_output: 12 471 | bias_term: true 472 | group: 1 473 | pad_h: 1 474 | pad_w: 1 475 | kernel_h: 3 476 | kernel_w: 3 477 | stride_h: 1 478 | stride_w: 1 479 | dilation: 1 480 | } 481 | } 482 | layer { 483 | name: "302" 484 | type: "ReLU" 485 | bottom: "300" 486 | top: "302" 487 | } 488 | layer { 489 | name: "303" 490 | type: "Convolution" 491 | bottom: "302" 492 | top: "303" 493 | convolution_param { 494 | num_output: 16 495 | bias_term: true 496 | group: 1 497 | pad_h: 1 498 | pad_w: 1 499 | kernel_h: 3 500 | kernel_w: 3 501 | stride_h: 1 502 | stride_w: 1 503 | dilation: 1 504 | } 505 | } 506 | layer { 507 | name: "305" 508 | type: "ReLU" 509 | bottom: "303" 510 | top: "305" 511 | } 512 | layer { 513 | name: "306" 514 | type: "Convolution" 515 | bottom: "305" 516 | top: "306" 517 | convolution_param { 518 | num_output: 16 519 | bias_term: true 520 | group: 1 521 | pad_h: 5 522 | pad_w: 5 523 | kernel_h: 3 524 | kernel_w: 3 525 | stride_h: 1 526 | stride_w: 1 527 | dilation: 5 528 | } 529 | } 530 | layer { 531 | name: "308" 532 | type: "Concat" 533 | bottom: "289" 534 | bottom: "296" 535 | bottom: "306" 536 | top: "308" 537 | concat_param { 538 | axis: 1 539 | } 540 | } 541 | layer { 542 | name: "309" 543 | type: "Convolution" 544 | bottom: "308" 545 | top: "309" 546 | convolution_param { 547 | num_output: 64 548 | bias_term: true 549 | group: 1 550 | pad_h: 0 551 | pad_w: 0 552 | kernel_h: 1 553 | kernel_w: 1 554 | stride_h: 1 555 | stride_w: 1 556 | dilation: 1 557 | } 558 | } 559 | layer { 560 | name: "311" 561 | type: "Convolution" 562 | bottom: "283" 563 | top: "311" 564 | convolution_param { 565 | num_output: 64 566 | bias_term: true 567 | group: 1 568 | pad_h: 0 569 | pad_w: 0 570 | kernel_h: 1 571 | kernel_w: 1 572 | stride_h: 1 573 | stride_w: 1 574 | dilation: 1 575 | } 576 | } 577 | layer { 578 | name: "313" 579 | type: "Eltwise" 580 | bottom: "309" 581 | bottom: "311" 582 | top: "313" 583 | eltwise_param { 584 | operation: SUM 585 | } 586 | } 587 | layer { 588 | name: "314" 589 | type: "ReLU" 590 | bottom: "313" 591 | top: "314" 592 | } 593 | layer { 594 | name: "315" 595 | type: "Convolution" 596 | bottom: "314" 597 | top: "315" 598 | convolution_param { 599 | num_output: 64 600 | bias_term: true 601 | group: 64 602 | pad_h: 1 603 | pad_w: 1 604 | kernel_h: 3 605 | kernel_w: 3 606 | stride_h: 1 607 | stride_w: 1 608 | dilation: 1 609 | } 610 | } 611 | layer { 612 | name: "316" 613 | type: "ReLU" 614 | bottom: "315" 615 | top: "316" 616 | } 617 | layer { 618 | name: "317" 619 | type: "Convolution" 620 | bottom: "316" 621 | top: "317" 622 | convolution_param { 623 | num_output: 6 624 | bias_term: true 625 | group: 1 626 | pad_h: 0 627 | pad_w: 0 628 | kernel_h: 1 629 | kernel_w: 1 630 | stride_h: 1 631 | stride_w: 1 632 | dilation: 1 633 | } 634 | } 635 | layer { 636 | name: "318" 637 | type: "Permute" 638 | bottom: "317" 639 | top: "318" 640 | permute_param { 641 | order: 0 642 | order: 2 643 | order: 3 644 | order: 1 645 | } 646 | } 647 | layer { 648 | name: "328" 649 | type: "Reshape" 650 | bottom: "318" 651 | top: "328" 652 | reshape_param { 653 | shape { 654 | dim: 1 655 | dim: -1 656 | dim: 2 657 | } 658 | } 659 | } 660 | layer { 661 | name: "329" 662 | type: "Convolution" 663 | bottom: "314" 664 | top: "329" 665 | convolution_param { 666 | num_output: 64 667 | bias_term: true 668 | group: 64 669 | pad_h: 1 670 | pad_w: 1 671 | kernel_h: 3 672 | kernel_w: 3 673 | stride_h: 1 674 | stride_w: 1 675 | dilation: 1 676 | } 677 | } 678 | layer { 679 | name: "330" 680 | type: "ReLU" 681 | bottom: "329" 682 | top: "330" 683 | } 684 | layer { 685 | name: "331" 686 | type: "Convolution" 687 | bottom: "330" 688 | top: "331" 689 | convolution_param { 690 | num_output: 12 691 | bias_term: true 692 | group: 1 693 | pad_h: 0 694 | pad_w: 0 695 | kernel_h: 1 696 | kernel_w: 1 697 | stride_h: 1 698 | stride_w: 1 699 | dilation: 1 700 | } 701 | } 702 | layer { 703 | name: "332" 704 | type: "Permute" 705 | bottom: "331" 706 | top: "332" 707 | permute_param { 708 | order: 0 709 | order: 2 710 | order: 3 711 | order: 1 712 | } 713 | } 714 | layer { 715 | name: "342" 716 | type: "Reshape" 717 | bottom: "332" 718 | top: "342" 719 | reshape_param { 720 | shape { 721 | dim: 1 722 | dim: -1 723 | dim: 4 724 | } 725 | } 726 | } 727 | layer { 728 | name: "343" 729 | type: "Convolution" 730 | bottom: "314" 731 | top: "343" 732 | convolution_param { 733 | num_output: 64 734 | bias_term: true 735 | group: 64 736 | pad_h: 1 737 | pad_w: 1 738 | kernel_h: 3 739 | kernel_w: 3 740 | stride_h: 2 741 | stride_w: 2 742 | dilation: 1 743 | } 744 | } 745 | layer { 746 | name: "345" 747 | type: "ReLU" 748 | bottom: "343" 749 | top: "345" 750 | } 751 | layer { 752 | name: "346" 753 | type: "Convolution" 754 | bottom: "345" 755 | top: "346" 756 | convolution_param { 757 | num_output: 128 758 | bias_term: true 759 | group: 1 760 | pad_h: 0 761 | pad_w: 0 762 | kernel_h: 1 763 | kernel_w: 1 764 | stride_h: 1 765 | stride_w: 1 766 | dilation: 1 767 | } 768 | } 769 | layer { 770 | name: "348" 771 | type: "ReLU" 772 | bottom: "346" 773 | top: "348" 774 | } 775 | layer { 776 | name: "349" 777 | type: "Convolution" 778 | bottom: "348" 779 | top: "349" 780 | convolution_param { 781 | num_output: 128 782 | bias_term: true 783 | group: 128 784 | pad_h: 1 785 | pad_w: 1 786 | kernel_h: 3 787 | kernel_w: 3 788 | stride_h: 1 789 | stride_w: 1 790 | dilation: 1 791 | } 792 | } 793 | layer { 794 | name: "351" 795 | type: "ReLU" 796 | bottom: "349" 797 | top: "351" 798 | } 799 | layer { 800 | name: "352" 801 | type: "Convolution" 802 | bottom: "351" 803 | top: "352" 804 | convolution_param { 805 | num_output: 128 806 | bias_term: true 807 | group: 1 808 | pad_h: 0 809 | pad_w: 0 810 | kernel_h: 1 811 | kernel_w: 1 812 | stride_h: 1 813 | stride_w: 1 814 | dilation: 1 815 | } 816 | } 817 | layer { 818 | name: "354" 819 | type: "ReLU" 820 | bottom: "352" 821 | top: "354" 822 | } 823 | layer { 824 | name: "355" 825 | type: "Convolution" 826 | bottom: "354" 827 | top: "355" 828 | convolution_param { 829 | num_output: 128 830 | bias_term: true 831 | group: 128 832 | pad_h: 1 833 | pad_w: 1 834 | kernel_h: 3 835 | kernel_w: 3 836 | stride_h: 1 837 | stride_w: 1 838 | dilation: 1 839 | } 840 | } 841 | layer { 842 | name: "357" 843 | type: "ReLU" 844 | bottom: "355" 845 | top: "357" 846 | } 847 | layer { 848 | name: "358" 849 | type: "Convolution" 850 | bottom: "357" 851 | top: "358" 852 | convolution_param { 853 | num_output: 128 854 | bias_term: true 855 | group: 1 856 | pad_h: 0 857 | pad_w: 0 858 | kernel_h: 1 859 | kernel_w: 1 860 | stride_h: 1 861 | stride_w: 1 862 | dilation: 1 863 | } 864 | } 865 | layer { 866 | name: "360" 867 | type: "ReLU" 868 | bottom: "358" 869 | top: "360" 870 | } 871 | layer { 872 | name: "361" 873 | type: "Convolution" 874 | bottom: "360" 875 | top: "361" 876 | convolution_param { 877 | num_output: 128 878 | bias_term: true 879 | group: 128 880 | pad_h: 1 881 | pad_w: 1 882 | kernel_h: 3 883 | kernel_w: 3 884 | stride_h: 1 885 | stride_w: 1 886 | dilation: 1 887 | } 888 | } 889 | layer { 890 | name: "362" 891 | type: "ReLU" 892 | bottom: "361" 893 | top: "362" 894 | } 895 | layer { 896 | name: "363" 897 | type: "Convolution" 898 | bottom: "362" 899 | top: "363" 900 | convolution_param { 901 | num_output: 4 902 | bias_term: true 903 | group: 1 904 | pad_h: 0 905 | pad_w: 0 906 | kernel_h: 1 907 | kernel_w: 1 908 | stride_h: 1 909 | stride_w: 1 910 | dilation: 1 911 | } 912 | } 913 | layer { 914 | name: "364" 915 | type: "Permute" 916 | bottom: "363" 917 | top: "364" 918 | permute_param { 919 | order: 0 920 | order: 2 921 | order: 3 922 | order: 1 923 | } 924 | } 925 | layer { 926 | name: "374" 927 | type: "Reshape" 928 | bottom: "364" 929 | top: "374" 930 | reshape_param { 931 | shape { 932 | dim: 1 933 | dim: -1 934 | dim: 2 935 | } 936 | } 937 | } 938 | layer { 939 | name: "375" 940 | type: "Convolution" 941 | bottom: "360" 942 | top: "375" 943 | convolution_param { 944 | num_output: 128 945 | bias_term: true 946 | group: 128 947 | pad_h: 1 948 | pad_w: 1 949 | kernel_h: 3 950 | kernel_w: 3 951 | stride_h: 1 952 | stride_w: 1 953 | dilation: 1 954 | } 955 | } 956 | layer { 957 | name: "376" 958 | type: "ReLU" 959 | bottom: "375" 960 | top: "376" 961 | } 962 | layer { 963 | name: "377" 964 | type: "Convolution" 965 | bottom: "376" 966 | top: "377" 967 | convolution_param { 968 | num_output: 8 969 | bias_term: true 970 | group: 1 971 | pad_h: 0 972 | pad_w: 0 973 | kernel_h: 1 974 | kernel_w: 1 975 | stride_h: 1 976 | stride_w: 1 977 | dilation: 1 978 | } 979 | } 980 | layer { 981 | name: "378" 982 | type: "Permute" 983 | bottom: "377" 984 | top: "378" 985 | permute_param { 986 | order: 0 987 | order: 2 988 | order: 3 989 | order: 1 990 | } 991 | } 992 | layer { 993 | name: "388" 994 | type: "Reshape" 995 | bottom: "378" 996 | top: "388" 997 | reshape_param { 998 | shape { 999 | dim: 1 1000 | dim: -1 1001 | dim: 4 1002 | } 1003 | } 1004 | } 1005 | layer { 1006 | name: "389" 1007 | type: "Convolution" 1008 | bottom: "360" 1009 | top: "389" 1010 | convolution_param { 1011 | num_output: 128 1012 | bias_term: true 1013 | group: 128 1014 | pad_h: 1 1015 | pad_w: 1 1016 | kernel_h: 3 1017 | kernel_w: 3 1018 | stride_h: 2 1019 | stride_w: 2 1020 | dilation: 1 1021 | } 1022 | } 1023 | layer { 1024 | name: "391" 1025 | type: "ReLU" 1026 | bottom: "389" 1027 | top: "391" 1028 | } 1029 | layer { 1030 | name: "392" 1031 | type: "Convolution" 1032 | bottom: "391" 1033 | top: "392" 1034 | convolution_param { 1035 | num_output: 256 1036 | bias_term: true 1037 | group: 1 1038 | pad_h: 0 1039 | pad_w: 0 1040 | kernel_h: 1 1041 | kernel_w: 1 1042 | stride_h: 1 1043 | stride_w: 1 1044 | dilation: 1 1045 | } 1046 | } 1047 | layer { 1048 | name: "394" 1049 | type: "ReLU" 1050 | bottom: "392" 1051 | top: "394" 1052 | } 1053 | layer { 1054 | name: "395" 1055 | type: "Convolution" 1056 | bottom: "394" 1057 | top: "395" 1058 | convolution_param { 1059 | num_output: 256 1060 | bias_term: true 1061 | group: 256 1062 | pad_h: 1 1063 | pad_w: 1 1064 | kernel_h: 3 1065 | kernel_w: 3 1066 | stride_h: 1 1067 | stride_w: 1 1068 | dilation: 1 1069 | } 1070 | } 1071 | layer { 1072 | name: "397" 1073 | type: "ReLU" 1074 | bottom: "395" 1075 | top: "397" 1076 | } 1077 | layer { 1078 | name: "398" 1079 | type: "Convolution" 1080 | bottom: "397" 1081 | top: "398" 1082 | convolution_param { 1083 | num_output: 256 1084 | bias_term: true 1085 | group: 1 1086 | pad_h: 0 1087 | pad_w: 0 1088 | kernel_h: 1 1089 | kernel_w: 1 1090 | stride_h: 1 1091 | stride_w: 1 1092 | dilation: 1 1093 | } 1094 | } 1095 | layer { 1096 | name: "400" 1097 | type: "ReLU" 1098 | bottom: "398" 1099 | top: "400" 1100 | } 1101 | layer { 1102 | name: "401" 1103 | type: "Convolution" 1104 | bottom: "400" 1105 | top: "401" 1106 | convolution_param { 1107 | num_output: 256 1108 | bias_term: true 1109 | group: 256 1110 | pad_h: 1 1111 | pad_w: 1 1112 | kernel_h: 3 1113 | kernel_w: 3 1114 | stride_h: 1 1115 | stride_w: 1 1116 | dilation: 1 1117 | } 1118 | } 1119 | layer { 1120 | name: "402" 1121 | type: "ReLU" 1122 | bottom: "401" 1123 | top: "402" 1124 | } 1125 | layer { 1126 | name: "403" 1127 | type: "Convolution" 1128 | bottom: "402" 1129 | top: "403" 1130 | convolution_param { 1131 | num_output: 4 1132 | bias_term: true 1133 | group: 1 1134 | pad_h: 0 1135 | pad_w: 0 1136 | kernel_h: 1 1137 | kernel_w: 1 1138 | stride_h: 1 1139 | stride_w: 1 1140 | dilation: 1 1141 | } 1142 | } 1143 | layer { 1144 | name: "404" 1145 | type: "Permute" 1146 | bottom: "403" 1147 | top: "404" 1148 | permute_param { 1149 | order: 0 1150 | order: 2 1151 | order: 3 1152 | order: 1 1153 | } 1154 | } 1155 | layer { 1156 | name: "414" 1157 | type: "Reshape" 1158 | bottom: "404" 1159 | top: "414" 1160 | reshape_param { 1161 | shape { 1162 | dim: 1 1163 | dim: -1 1164 | dim: 2 1165 | } 1166 | } 1167 | } 1168 | layer { 1169 | name: "415" 1170 | type: "Convolution" 1171 | bottom: "400" 1172 | top: "415" 1173 | convolution_param { 1174 | num_output: 256 1175 | bias_term: true 1176 | group: 256 1177 | pad_h: 1 1178 | pad_w: 1 1179 | kernel_h: 3 1180 | kernel_w: 3 1181 | stride_h: 1 1182 | stride_w: 1 1183 | dilation: 1 1184 | } 1185 | } 1186 | layer { 1187 | name: "416" 1188 | type: "ReLU" 1189 | bottom: "415" 1190 | top: "416" 1191 | } 1192 | layer { 1193 | name: "417" 1194 | type: "Convolution" 1195 | bottom: "416" 1196 | top: "417" 1197 | convolution_param { 1198 | num_output: 8 1199 | bias_term: true 1200 | group: 1 1201 | pad_h: 0 1202 | pad_w: 0 1203 | kernel_h: 1 1204 | kernel_w: 1 1205 | stride_h: 1 1206 | stride_w: 1 1207 | dilation: 1 1208 | } 1209 | } 1210 | layer { 1211 | name: "418" 1212 | type: "Permute" 1213 | bottom: "417" 1214 | top: "418" 1215 | permute_param { 1216 | order: 0 1217 | order: 2 1218 | order: 3 1219 | order: 1 1220 | } 1221 | } 1222 | layer { 1223 | name: "428" 1224 | type: "Reshape" 1225 | bottom: "418" 1226 | top: "428" 1227 | reshape_param { 1228 | shape { 1229 | dim: 1 1230 | dim: -1 1231 | dim: 4 1232 | } 1233 | } 1234 | } 1235 | layer { 1236 | name: "429" 1237 | type: "Convolution" 1238 | bottom: "400" 1239 | top: "429" 1240 | convolution_param { 1241 | num_output: 64 1242 | bias_term: true 1243 | group: 1 1244 | pad_h: 0 1245 | pad_w: 0 1246 | kernel_h: 1 1247 | kernel_w: 1 1248 | stride_h: 1 1249 | stride_w: 1 1250 | dilation: 1 1251 | } 1252 | } 1253 | layer { 1254 | name: "430" 1255 | type: "ReLU" 1256 | bottom: "429" 1257 | top: "430" 1258 | } 1259 | layer { 1260 | name: "431" 1261 | type: "Convolution" 1262 | bottom: "430" 1263 | top: "431" 1264 | convolution_param { 1265 | num_output: 64 1266 | bias_term: true 1267 | group: 64 1268 | pad_h: 1 1269 | pad_w: 1 1270 | kernel_h: 3 1271 | kernel_w: 3 1272 | stride_h: 2 1273 | stride_w: 2 1274 | dilation: 1 1275 | } 1276 | } 1277 | layer { 1278 | name: "432" 1279 | type: "ReLU" 1280 | bottom: "431" 1281 | top: "432" 1282 | } 1283 | layer { 1284 | name: "433" 1285 | type: "Convolution" 1286 | bottom: "432" 1287 | top: "433" 1288 | convolution_param { 1289 | num_output: 256 1290 | bias_term: true 1291 | group: 1 1292 | pad_h: 0 1293 | pad_w: 0 1294 | kernel_h: 1 1295 | kernel_w: 1 1296 | stride_h: 1 1297 | stride_w: 1 1298 | dilation: 1 1299 | } 1300 | } 1301 | layer { 1302 | name: "434" 1303 | type: "ReLU" 1304 | bottom: "433" 1305 | top: "434" 1306 | } 1307 | layer { 1308 | name: "435" 1309 | type: "Convolution" 1310 | bottom: "434" 1311 | top: "435" 1312 | convolution_param { 1313 | num_output: 6 1314 | bias_term: true 1315 | group: 1 1316 | pad_h: 1 1317 | pad_w: 1 1318 | kernel_h: 3 1319 | kernel_w: 3 1320 | stride_h: 1 1321 | stride_w: 1 1322 | dilation: 1 1323 | } 1324 | } 1325 | layer { 1326 | name: "436" 1327 | type: "Permute" 1328 | bottom: "435" 1329 | top: "436" 1330 | permute_param { 1331 | order: 0 1332 | order: 2 1333 | order: 3 1334 | order: 1 1335 | } 1336 | } 1337 | layer { 1338 | name: "446" 1339 | type: "Reshape" 1340 | bottom: "436" 1341 | top: "446" 1342 | reshape_param { 1343 | shape { 1344 | dim: 1 1345 | dim: -1 1346 | dim: 2 1347 | } 1348 | } 1349 | } 1350 | layer { 1351 | name: "447" 1352 | type: "Convolution" 1353 | bottom: "434" 1354 | top: "447" 1355 | convolution_param { 1356 | num_output: 12 1357 | bias_term: true 1358 | group: 1 1359 | pad_h: 1 1360 | pad_w: 1 1361 | kernel_h: 3 1362 | kernel_w: 3 1363 | stride_h: 1 1364 | stride_w: 1 1365 | dilation: 1 1366 | } 1367 | } 1368 | layer { 1369 | name: "448" 1370 | type: "Permute" 1371 | bottom: "447" 1372 | top: "448" 1373 | permute_param { 1374 | order: 0 1375 | order: 2 1376 | order: 3 1377 | order: 1 1378 | } 1379 | } 1380 | layer { 1381 | name: "458" 1382 | type: "Reshape" 1383 | bottom: "448" 1384 | top: "458" 1385 | reshape_param { 1386 | shape { 1387 | dim: 1 1388 | dim: -1 1389 | dim: 4 1390 | } 1391 | } 1392 | } 1393 | layer { 1394 | name: "459" 1395 | type: "Concat" 1396 | bottom: "328" 1397 | bottom: "374" 1398 | bottom: "414" 1399 | bottom: "446" 1400 | top: "459" 1401 | concat_param { 1402 | axis: 1 1403 | } 1404 | } 1405 | layer { 1406 | name: "boxes" 1407 | type: "Concat" 1408 | bottom: "342" 1409 | bottom: "388" 1410 | bottom: "428" 1411 | bottom: "458" 1412 | top: "boxes" 1413 | concat_param { 1414 | axis: 1 1415 | } 1416 | } 1417 | layer { 1418 | name: "scores" 1419 | type: "Softmax" 1420 | bottom: "459" 1421 | top: "scores" 1422 | softmax_param { 1423 | axis: 2 1424 | } 1425 | } 1426 | 1427 | --------------------------------------------------------------------------------