Xây dựng phân loại và các đầu hồi quy hộp

Một phần của tài liệu LUẬN văn THẠC sĩ tìm HIỂU MẠNG TÍCH CHẬP và xây DỰNG ỨNG DỤNG đếm các vật THỂ THÔNG DỤNG (Trang 67)

CHƯƠNG 2 GIỚI THIỆU VỀ MẠNG CNN VÀ RETINANET

3.2. TRIỂN KHAI HỆ THỐNG

3.2.10. Xây dựng phân loại và các đầu hồi quy hộp

Mơ hình RetinaNet có các đầu riêng biệt để hồi quy hộp giới hạn và để dự đoán xác suất lớp cho các đối tượng. Các đầu này được chia sẻ giữa tất cả các bản đồ đặc trưng của kim tự tháp đối tượng.

def build_head(output_filters, bias_init):

head = keras.Sequential([keras.Input(shape=[None, None, 256])]) kernel_init = tf.initializers.RandomNormal(0.0, 0.01)

for _ in range(4): head.add(

keras.layers.Conv2D(256, 3, padding="same", kernel_initializer=kernel_init) ) head.add(keras.layers.ReLU()) head.add( keras.layers.Conv2D( output_filters, 3, 1, padding="same", kernel_initializer=kernel_init, bias_initializer=bias_init, ) ) return head 3.2.11. Xây dựng RetinaNet class RetinaNet(keras.Model):

def __init__(self, num_classes, backbone=None, **kwargs): super(RetinaNet, self).__init__(name="RetinaNet", **kwargs) self.fpn = FeaturePyramid(backbone)

self.num_classes = num_classes

prior_probability = tf.constant_initializer(-np.log((1 - 0.01) / 0.01)) self.cls_head = build_head(9 * num_classes, prior_probability) self.box_head = build_head(9 * 4, "zeros")

def call(self, image, training=False):

features = self.fpn(image, training=training) N = tf.shape(image)[0]

cls_outputs = [] box_outputs = [] for feature in features:

box_outputs.append(tf.reshape(self.box_head(feature), [N, -1, 4])) cls_outputs.append(

tf.reshape(self.cls_head(feature), [N, -1, self.num_classes]) )

cls_outputs = tf.concat(cls_outputs, axis=1) box_outputs = tf.concat(box_outputs, axis=1) return tf.concat([box_outputs, cls_outputs], axis=-1)

3.2.12. Triển khai lớp tùy chọn để giải mã dự đoán

class DecodePredictions(tf.keras.layers.Layer): def __init__( self, num_classes=80, confidence_threshold=0.05, nms_iou_threshold=0.5, max_detections_per_class=100, max_detections=100, box_variance=[0.1, 0.1, 0.2, 0.2], **kwargs ): super(DecodePredictions, self).__init__(**kwargs) self.num_classes = num_classes self.confidence_threshold = confidence_threshold self.nms_iou_threshold = nms_iou_threshold self.max_detections_per_class = max_detections_per_class self.max_detections = max_detections self._anchor_box = AnchorBox() self._box_variance = tf.convert_to_tensor( [0.1, 0.1, 0.2, 0.2], dtype=tf.float32 )

def _decode_box_predictions(self, anchor_boxes, box_predictions): boxes = box_predictions * self._box_variance

boxes = tf.concat( [

boxes[:, :, :2] * anchor_boxes[:, :, 2:] + anchor_boxes[:, :, :2], tf.math.exp(boxes[:, :, 2:]) * anchor_boxes[:, :, 2:],

axis=-1, )

boxes_transformed = convert_to_corners(boxes) return boxes_transformed

def call(self, images, predictions):

image_shape = tf.cast(tf.shape(images), dtype=tf.float32)

anchor_boxes = self._anchor_box.get_anchors(image_shape[1], image_shape[2]) box_predictions = predictions[:, :, :4]

cls_predictions = tf.nn.sigmoid(predictions[:, :, 4:])

boxes = self._decode_box_predictions(anchor_boxes[None, ...], box_predictions) return tf.image.combined_non_max_suppression( tf.expand_dims(boxes, axis=2), cls_predictions, self.max_detections_per_class, self.max_detections, self.nms_iou_threshold, self.confidence_threshold, clip_boxes=False, )

3.2.13. Triển khai Smooth L1 loss và Focal Loss

class RetinaNetBoxLoss(tf.losses.Loss): def __init__(self, delta):

super(RetinaNetBoxLoss, self).__init__(

reduction="none", name="RetinaNetBoxLoss" )

self._delTôi = delta def call(self, y_true, y_pred): difference = y_true - y_pred

absolute_difference = tf.abs(difference) squared_difference = difference ** 2 loss = tf.where( tf.less(absolute_difference, self._delta), 0.5 * squared_difference, absolute_difference - 0.5, )

return tf.reduce_sum(loss, axis=-1)

"""Implements Focal loss""" def __init__(self, alpha, gamma):

super(RetinaNetClassificationLoss, self).__init__(

reduction="none", name="RetinaNetClassificationLoss" )

self._alpha = alpha self._gamma = gamma def call(self, y_true, y_pred):

cross_entropy = tf.nn.sigmoid_cross_entropy_with_logits( labels=y_true, logits=y_pred

)

probs = tf.nn.sigmoid(y_pred)

alpha = tf.where(tf.equal(y_true, 1.0), self._alpha, (1.0 - self._alpha)) pt = tf.where(tf.equal(y_true, 1.0), probs, 1 - probs)

loss = alpha * tf.pow(1.0 - pt, self._gamma) * cross_entropy return tf.reduce_sum(loss, axis=-1)

class RetinaNetLoss(tf.losses.Loss):

"""Wrapper to combine both the losses"""

def __init__(self, num_classes=80, alpha=0.25, gamma=2.0, delta=1.0):

super(RetinaNetLoss, self).__init__(reduction="auto", name="RetinaNetLoss") self._clf_loss = RetinaNetClassificationLoss(alpha, gamma)

self._box_loss = RetinaNetBoxLoss(delta) self._num_classes = num_classes

def call(self, y_true, y_pred):

y_pred = tf.cast(y_pred, dtype=tf.float32) box_labels = y_true[:, :, :4] box_predictions = y_pred[:, :, :4] cls_labels = tf.one_hot( tf.cast(y_true[:, :, 4], dtype=tf.int32), depth=self._num_classes, dtype=tf.float32, ) cls_predictions = y_pred[:, :, 4:]

positive_mask = tf.cast(tf.greater(y_true[:, :, 4], -1.0), dtype=tf.float32) ignore_mask = tf.cast(tf.equal(y_true[:, :, 4], -2.0), dtype=tf.float32) clf_loss = self._clf_loss(cls_labels, cls_predictions)

box_loss = self._box_loss(box_labels, box_predictions) clf_loss = tf.where(tf.equal(ignore_mask, 1.0), 0.0, clf_loss) box_loss = tf.where(tf.equal(positive_mask, 1.0), box_loss, 0.0) normalizer = tf.reduce_sum(positive_mask, axis=-1)

clf_loss = tf.math.divide_no_nan(tf.reduce_sum(clf_loss, axis=-1), normalizer) box_loss = tf.math.divide_no_nan(tf.reduce_sum(box_loss, axis=-1), normalizer) loss = clf_loss + box_loss

return loss

3.2.14. Cài đặt các tham số huấn luyện

model_dir = "retinanet/" label_encoder = LabelEncoder() num_classes = 80

batch_size = 2

learning_rates = [2.5e-06, 0.000625, 0.00125, 0.0025, 0.00025, 2.5e-05] learning_rate_boundaries = [125, 250, 500, 240000, 360000]

learning_rate_fn = tf.optimizers.schedules.PiecewiseConstantDecay( boundaries=learning_rate_boundaries, values=learning_rates )

3.2.15. Khởi tạo và biên dịch model

resnet50_backbone = get_backbone() loss_fn = RetinaNetLoss(num_classes)

model = RetinaNet(num_classes, resnet50_backbone)

optimizer = tf.optimizers.SGD(learning_rate=learning_rate_fn, momentum=0.9) model.compile(loss=loss_fn, optimizer=optimizer)

3.2.16. Cài đặt các gàm callbacks

callbacks_list = [

tf.keras.callbacks.ModelCheckpoint(

filepath=os.path.join(model_dir, "weights" + "_epoch_{epoch}"), monitor="loss", save_best_only=False, save_weights_only=True, verbose=1, ) ] 3.2.17. Nạp tập dữ liệu sử dụng TensorFlow

# set `data_dir=None` to load the complete dataset

(train_dataset, val_dataset), dataset_info = tfds.load(

"coco/2017", split=["train", "validation"], with_info=True, data_dir="data" )

3.2.18. Cài đặt đường ống tf.data

sẽ sử dụng API tf.daTôi để tạo đường dẫn đầu vào của tơi. Quy trình đầu vào bao gồm các bước xử lý chính sau:

Áp dụng chức năng tiền xử lý cho các mẫu

Tạo lơ với kích thước lơ cố định. Vì hình ảnh trong lơ có thể có các kích thước khác nhau và cũng có thể có số lượng đối tượng khác nhau, tôi sử dụng padded_batch để thêm phần đệm cần thiết để tạo ra các tensors hình chữ nhật

 Tạo mục tiêu cho từng mẫu trong lô bằng LabelEncoder

autotune = tf.data.experimental.AUTOTUNE

train_dataset = train_dataset.map(preprocess_data, num_parallel_calls=autotune) train_dataset = train_dataset.shuffle(8 * batch_size)

train_dataset = train_dataset.padded_batch(

batch_size=batch_size, padding_values=(0.0, 1e-8, -1), drop_remainder=True ) train_dataset = train_dataset.map( label_encoder.encode_batch, num_parallel_calls=autotune ) train_dataset = train_dataset.apply(tf.data.experimental.ignore_errors()) train_dataset = train_dataset.prefetch(autotune)

val_dataset = val_dataset.map(preprocess_data, num_parallel_calls=autotune) val_dataset = val_dataset.padded_batch(

batch_size=1, padding_values=(0.0, 1e-8, -1), drop_remainder=True )

val_dataset = val_dataset.map(label_encoder.encode_batch, num_parallel_calls=autotune) val_dataset = val_dataset.apply(tf.data.experimental.ignore_errors())

val_dataset = val_dataset.prefetch(autotune)

3.2.20. Huấn luyện model

epochs = 1

# Running 100 training and 50 validation steps, # remove `.take` when training on the full dataset

model.fit( train_dataset.take(100), validation_data=val_dataset.take(50), epochs=epochs, callbacks=callbacks_list, verbose=1,

)

3.2.20. Nạp weights

weights_dir = "data"

latest_checkpoint = tf.train.latest_checkpoint(weights_dir) model.load_weights(latest_checkpoint)

3.2.21. Xây dựng giao diện model

image = tf.keras.Input(shape=[None, None, 3], name="image") predictions = model(image, training=False)

detections = DecodePredictions(confidence_threshold=0.5)(image, predictions) inference_model = tf.keras.Model(inputs=image, outputs=detections)

3.2.21. Sinh các kết quả nhận diện

def prepare_image(image):

image, _, ratio = resize_and_pad_image(image, jitter=None) image = tf.keras.applications.resnet.preprocess_input(image) return tf.expand_dims(image, axis=0), ratio

val_dataset = tfds.load("coco/2017", split="validation", data_dir="data") int2str = dataset_info.features["objects"]["label"].int2str

for sample in val_dataset.take(20):

image = tf.cast(sample["image"], dtype=tf.float32) input_image, ratio = prepare_image(image) detections = inference_model.predict(input_image) num_detections = detections.valid_detections[0] class_names = [

int2str(int(x)) for x in detections.nmsed_classes[0][:num_detections] ] visualize_detections( image, detections.nmsed_boxes[0][:num_detections] / ratio, class_names, detections.nmsed_scores[0][:num_detections], )

3.2.22. Kết quả

Để minh họa cho kết quả, tôi sẽ thực hiên xây dựng một hệ thống RetinaNet nhằm mục đích nhận diện những đối tượng cụ thể và đếm chúng, ở đây tôi sẽ xây dựng hệ thống chỉ nhận diện và đếm 2 đối tượng là Person (con người) và Cup (chiếc cốc)

Hệ thống thử nghiệm được triển khai theo mơ hình sau :

Hình 3.4. Mơ tả kiến trúc thử nghiệm

Mạng RetinaNet sẽ được thiết lập trên một máy chủ, một hệ thống Restful API đơn giản được dựng lên để xử lý việc liên lạc gửi / nhận dữ liệu của ứng dụng điện thoại di động. Ứng dụng điện thoại sẽ thơng qua các hình thức : chụp ảnh / chọn ảnh và dung mạng Internet để kết nối đến hệ thống sau đó gửi hình ảnh cần xử lý, hệ thống sẽ lưu hình ảnh xuống máy chủ, tiến hành xử lý và trả về kết quả cho người dung. Ứng dụng điện thoại di động sẽ hiển thị kết quả đã xử lý gồm hình ảnh đã xử lý với các bounding box, các nhãn đã nhận diện được và số lượng của chúng. Trường hợp hình ảnh khơng được

nhận diện sẽ được lưu trữ lại để phục vụ cho việc huấn luyện nhằm tăng tính đa dạng của dữ liệu.

Thực hiện trên dữ liệu chuẩn bị sẵn và khơng có sẵn trong tập huấn luyện trước đó gồm:

- Dữ liệu về người : các tệp dữ liệu từ 1 người đến hơn 15 người - Dữ liệu về chiếc cốc: các tệp dữ liệu từ 1 chiếc cốc đến hơn 15 chiếc

Hình 3.5. Dữ liệu thử nghiệm lớp Person

Hình 3.6. Dữ liệu thử nghiệm lớp Cup

Sau khi tiến hành thử nghiệm với các tệp dữ liệu thật, kết quả được tổng hợp phía dưới theo biểu đồ sau:

1 2 5 10 15 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 0.98 0.92 0.87 0.78 0.59 0.81 0.75 0.62 0.61 0.57 Chart Title Person Cup

Biểu đồ 1.Biểu đồ minh họa chỉ số IOU với số lượng đối tượng tăng dần

1 2 5 10 15 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5 4.4 3.4 3.9 2.8 2.9 2.18 2.05 3.06 2.18 2.65 Chart Title Person Cup

Biểu đồ 2.Biểu đồ minh họa thời gian thực thi với số lượng đối tượng tăng dần

Tơi có thể nhận thấy, chỉ số IOU sẽ giảm dần tỉ lệ nghịch với số đối tượng trong bức ảnh. Nếu số đối tượng tăng, thì các ground box và anchor box cũng tăng, như vậy thì tỉ lệ chính xác cũng giảm đi bởi vì hình ảnh đã phức tạp hơn về nội dung. Ngồi ra cịn 1 số vấn đề ảnh hưởng đến kết quả như: chất lượng hình ảnh, sự sắp xếp bối cảnh trong bức ảnh, góc chụp của đối tượng...vv làm ảnh hưởng đến kết quả. Để khắc phục điều này, chúng Tơi

có thể tiếp tục tăng độ đa dạng của mẫu huấn luyện để xử lý vấn đề này.

Về thời gian, có vẻ khơng có sự ảnh hưởng về đối tượng đối với thời gian, tôi nhận thấy rằng sự ảnh hưởng lớn đến thời gian là chất lượng bức ảnh, vì nó sẽ tiêu tốn tài ngun để chương trình đọc ảnh và xử lý, nhưng đồng nghĩa với độ chính xác của kết quả sẽ cao hơn. Số lượng đối tượng trong bức ảnh tang nhưng không ảnh hưởng đáng kể đến thời gian xử lý nếu chất lượng hình ảnh kém, và dẫn đến sai số trong kết quả sẽ cao. Vậy, rút ra kết luận là phương pháp sẽ xử lý tốt hơn nếu bổ sung thêm đa dạng mẫu huấn luyện, chất lượng hình ảnh đầu vào tốt và tài nguyên máy tính mạnh sẽ cho ra kết quả trong thời gian nhanh hơn, chính xác hơn.

KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN CHO ĐỀ TÀI Kết luận:

Luận văn đã giới thiệu về học máy và mối liên hệ với các lĩnh vực khác. Luận văn tập trung vào tìm hiểu về mạng nơ-ron tích chập và cụ thể hơn là cách xây dựng một mạng nơ-ron tích chập cụ thể là RetinaNet. Các kết quả của luận văn bao gồm:

- Nắm một số định nghĩa khái niệm cơ bản về học máy, các lĩnh vực khác của trí tuệ nhân tạo và mối liên quan đến học máy.

- Nắm được khái niệm về mạng nơ-ron tích chập.

- Nắm được về một số mạng nơ-ron tích chập phổ biến.

- Xây dựng mô phỏng mạng RetinaNet và thử nghiệm hoạt động hiệu quả.

- Vẫn chưa xử lý được một số trường hợp hình ảnh có chất lượng kém, hình ảnh có nhiều sự đan xen bố cục phức tạp

Hướng phát triển cho đề tài

- Xây dựng tập huấn luyện đa dạng để có thể hoạt động tốt hơn

- Tìm hiểu thêm các trường hợp có thể ứng dụng mơ hình vào thực tế. - Tìm hiểu các mạng nơ-ron tích chập khác để có cơ sở so sánh với mạng hiện tại.

- Xây dựng mơ hình đa dạng hơn để có thể nhận diện hơn nữa nhiều đối tượng.

[1] Focal Loss for Dense Object Detection – Tsung Yi Lin, Priya goyal, Ross Girshick, Kaiming He, Piotr Dollár.

Một phần của tài liệu LUẬN văn THẠC sĩ tìm HIỂU MẠNG TÍCH CHẬP và xây DỰNG ỨNG DỤNG đếm các vật THỂ THÔNG DỤNG (Trang 67)

w