.. _sec_semantic_segmentation:
Phân đoạn ngữ nghĩa và tập dữ liệu
==================================
Khi thảo luận về các tác vụ phát hiện đối tượng trong
:numref:`sec_bbox`—:numref:`sec_rcnn`, các hộp giới hạn hình chữ
nhật được sử dụng để dán nhãn và dự đoán các đối tượng trong ảnh. Phần
này sẽ thảo luận về vấn đề phân đoạn *ngữ nghĩa *, tập trung vào cách
chia hình ảnh thành các vùng thuộc các lớp ngữ nghĩa khác nhau. Khác với
phát hiện đối tượng, phân đoạn ngữ nghĩa nhận ra và hiểu những gì có
trong hình ảnh ở cấp độ pixel: ghi nhãn và dự đoán các vùng ngữ nghĩa
của nó ở mức pixel. :numref:`fig_segmentation` hiển thị nhãn của chó,
mèo và nền của hình ảnh trong phân khúc ngữ nghĩa. So với trong phát
hiện đối tượng, các đường viền cấp pixel được dán nhãn trong phân đoạn
ngữ nghĩa rõ ràng là hạt mịn hơn.
.. _fig_segmentation:
.. figure:: ../img/segmentation.svg
Labels of the dog, cat, and background of the image in semantic
segmentation.
Phân đoạn hình ảnh và Phân đoạn phiên bản
-----------------------------------------
Ngoài ra còn có hai nhiệm vụ quan trọng trong lĩnh vực thị giác máy tính
tương tự như phân đoạn ngữ nghĩa, đó là phân đoạn hình ảnh và phân đoạn
phiên bản. Chúng tôi sẽ phân biệt ngắn gọn chúng với phân khúc ngữ nghĩa
như sau.
- *Phân khúc hình ảnh* chia một hình ảnh thành nhiều vùng cấu thành.
Các phương pháp cho loại vấn đề này thường sử dụng mối tương quan
giữa các pixel trong hình ảnh. Nó không cần thông tin nhãn về pixel
hình ảnh trong quá trình đào tạo và nó không thể đảm bảo rằng các
vùng được phân đoạn sẽ có ngữ nghĩa mà chúng tôi hy vọng sẽ có được
trong quá trình dự đoán. Chụp ảnh trong :numref:`fig_segmentation`
làm đầu vào, phân đoạn hình ảnh có thể chia chó thành hai vùng: một
vùng che miệng và mắt chủ yếu là màu đen, và phần còn lại bao phủ
phần còn lại của cơ thể chủ yếu là màu vàng.
-
- Phân khúc Instance\* còn được gọi là \* phát hiện và phân đoạn
đồng thời\*. Nó nghiên cứu làm thế nào để nhận ra các vùng cấp
pixel của mỗi đối tượng trong một hình ảnh. Khác với phân đoạn ngữ
nghĩa, phân đoạn phiên bản cần phân biệt không chỉ ngữ nghĩa, mà
còn các trường hợp đối tượng khác nhau. Ví dụ, nếu có hai chú chó
trong hình ảnh, phân đoạn ví dụ cần phân biệt một pixel thuộc về
cái nào trong hai chú chó.
Tập dữ liệu phân đoạn ngữ nghĩa Pascal VOC2012
----------------------------------------------
Trên tập dữ liệu phân đoạn ngữ nghĩa quan trọng nhất là `Pascal
VOC2012 `__. Sau đây,
chúng ta sẽ xem tập dữ liệu này.
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import os
from mxnet import gluon, image, np, npx
from d2l import mxnet as d2l
npx.set_np()
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import os
import torch
import torchvision
from d2l import torch as d2l
.. raw:: html
.. raw:: html
Tệp tar của tập dữ liệu khoảng 2 GB, vì vậy có thể mất một thời gian để
tải xuống tệp. Tập dữ liệu được trích xuất nằm ở
``../data/VOCdevkit/VOC2012``.
.. raw:: html
.. raw:: html
.. code:: python
#@save
d2l.DATA_HUB['voc2012'] = (d2l.DATA_URL + 'VOCtrainval_11-May-2012.tar',
'4e443f8a2eca6b1dac8a6c57641b67dd40621a49')
voc_dir = d2l.download_extract('voc2012', 'VOCdevkit/VOC2012')
.. raw:: html
.. raw:: html
.. code:: python
#@save
d2l.DATA_HUB['voc2012'] = (d2l.DATA_URL + 'VOCtrainval_11-May-2012.tar',
'4e443f8a2eca6b1dac8a6c57641b67dd40621a49')
voc_dir = d2l.download_extract('voc2012', 'VOCdevkit/VOC2012')
.. parsed-literal::
:class: output
Downloading ../data/VOCtrainval_11-May-2012.tar from http://d2l-data.s3-accelerate.amazonaws.com/VOCtrainval_11-May-2012.tar...
.. raw:: html
.. raw:: html
Sau khi nhập đường dẫn ``../data/VOCdevkit/VOC2012``, chúng ta có thể
thấy các thành phần khác nhau của tập dữ liệu. Đường dẫn
``ImageSets/Segmentation`` chứa các tệp văn bản chỉ định các mẫu đào tạo
và thử nghiệm, trong khi các đường dẫn ``JPEGImages`` và
``SegmentationClass`` lưu trữ hình ảnh đầu vào và nhãn cho mỗi ví dụ
tương ứng. Nhãn ở đây cũng ở định dạng hình ảnh, có cùng kích thước với
hình ảnh đầu vào được dán nhãn của nó. Bên cạnh đó, các pixel có cùng
màu trong bất kỳ hình ảnh nhãn nào thuộc cùng một lớp ngữ nghĩa. Sau đây
xác định hàm ``read_voc_images`` thành đọc tất cả các hình ảnh đầu vào
và nhãn vào bộ nhớ.
.. raw:: html
.. raw:: html
.. code:: python
#@save
def read_voc_images(voc_dir, is_train=True):
"""Read all VOC feature and label images."""
txt_fname = os.path.join(voc_dir, 'ImageSets', 'Segmentation',
'train.txt' if is_train else 'val.txt')
with open(txt_fname, 'r') as f:
images = f.read().split()
features, labels = [], []
for i, fname in enumerate(images):
features.append(image.imread(os.path.join(
voc_dir, 'JPEGImages', f'{fname}.jpg')))
labels.append(image.imread(os.path.join(
voc_dir, 'SegmentationClass', f'{fname}.png')))
return features, labels
train_features, train_labels = read_voc_images(voc_dir, True)
.. raw:: html
.. raw:: html
.. code:: python
#@save
def read_voc_images(voc_dir, is_train=True):
"""Read all VOC feature and label images."""
txt_fname = os.path.join(voc_dir, 'ImageSets', 'Segmentation',
'train.txt' if is_train else 'val.txt')
mode = torchvision.io.image.ImageReadMode.RGB
with open(txt_fname, 'r') as f:
images = f.read().split()
features, labels = [], []
for i, fname in enumerate(images):
features.append(torchvision.io.read_image(os.path.join(
voc_dir, 'JPEGImages', f'{fname}.jpg')))
labels.append(torchvision.io.read_image(os.path.join(
voc_dir, 'SegmentationClass' ,f'{fname}.png'), mode))
return features, labels
train_features, train_labels = read_voc_images(voc_dir, True)
.. raw:: html
.. raw:: html
Chúng tôi vẽ năm hình ảnh đầu vào đầu tiên và nhãn của chúng. Trong hình
ảnh nhãn, màu trắng và đen đại diện cho đường viền và nền tương ứng,
trong khi các màu khác tương ứng với các lớp khác nhau.
.. raw:: html
.. raw:: html
.. code:: python
n = 5
imgs = train_features[0:n] + train_labels[0:n]
d2l.show_images(imgs, 2, n);
.. figure:: output_semantic-segmentation-and-dataset_23ff18_30_0.png
.. raw:: html
.. raw:: html
.. code:: python
n = 5
imgs = train_features[0:n] + train_labels[0:n]
imgs = [img.permute(1,2,0) for img in imgs]
d2l.show_images(imgs, 2, n);
.. figure:: output_semantic-segmentation-and-dataset_23ff18_33_0.png
.. raw:: html
.. raw:: html
Tiếp theo, chúng ta liệt kê các giá trị màu RGB và tên lớp cho tất cả
các nhãn trong tập dữ liệu này.
.. raw:: html
.. raw:: html
.. code:: python
#@save
VOC_COLORMAP = [[0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0],
[0, 0, 128], [128, 0, 128], [0, 128, 128], [128, 128, 128],
[64, 0, 0], [192, 0, 0], [64, 128, 0], [192, 128, 0],
[64, 0, 128], [192, 0, 128], [64, 128, 128], [192, 128, 128],
[0, 64, 0], [128, 64, 0], [0, 192, 0], [128, 192, 0],
[0, 64, 128]]
#@save
VOC_CLASSES = ['background', 'aeroplane', 'bicycle', 'bird', 'boat',
'bottle', 'bus', 'car', 'cat', 'chair', 'cow',
'diningtable', 'dog', 'horse', 'motorbike', 'person',
'potted plant', 'sheep', 'sofa', 'train', 'tv/monitor']
.. raw:: html
.. raw:: html
.. code:: python
#@save
VOC_COLORMAP = [[0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0],
[0, 0, 128], [128, 0, 128], [0, 128, 128], [128, 128, 128],
[64, 0, 0], [192, 0, 0], [64, 128, 0], [192, 128, 0],
[64, 0, 128], [192, 0, 128], [64, 128, 128], [192, 128, 128],
[0, 64, 0], [128, 64, 0], [0, 192, 0], [128, 192, 0],
[0, 64, 128]]
#@save
VOC_CLASSES = ['background', 'aeroplane', 'bicycle', 'bird', 'boat',
'bottle', 'bus', 'car', 'cat', 'chair', 'cow',
'diningtable', 'dog', 'horse', 'motorbike', 'person',
'potted plant', 'sheep', 'sofa', 'train', 'tv/monitor']
.. raw:: html
.. raw:: html
Với hai hằng số được định nghĩa ở trên, chúng ta có thể thuận tiện tìm
chỉ mục lớp cho mỗi pixel trong một nhãy. Chúng tôi xác định hàm
``voc_colormap2label`` để xây dựng ánh xạ từ các giá trị màu RGB ở trên
đến các chỉ số lớp và hàm ``voc_label_indices`` để ánh xạ bất kỳ giá trị
RGB nào với chỉ số lớp của chúng trong bộ dữ liệu Pascal VOC2012 này.
.. raw:: html
.. raw:: html
.. code:: python
#@save
def voc_colormap2label():
"""Build the mapping from RGB to class indices for VOC labels."""
colormap2label = np.zeros(256 ** 3)
for i, colormap in enumerate(VOC_COLORMAP):
colormap2label[
(colormap[0] * 256 + colormap[1]) * 256 + colormap[2]] = i
return colormap2label
#@save
def voc_label_indices(colormap, colormap2label):
"""Map any RGB values in VOC labels to their class indices."""
colormap = colormap.astype(np.int32)
idx = ((colormap[:, :, 0] * 256 + colormap[:, :, 1]) * 256
+ colormap[:, :, 2])
return colormap2label[idx]
.. raw:: html
.. raw:: html
.. code:: python
#@save
def voc_colormap2label():
"""Build the mapping from RGB to class indices for VOC labels."""
colormap2label = torch.zeros(256 ** 3, dtype=torch.long)
for i, colormap in enumerate(VOC_COLORMAP):
colormap2label[
(colormap[0] * 256 + colormap[1]) * 256 + colormap[2]] = i
return colormap2label
#@save
def voc_label_indices(colormap, colormap2label):
"""Map any RGB values in VOC labels to their class indices."""
colormap = colormap.permute(1, 2, 0).numpy().astype('int32')
idx = ((colormap[:, :, 0] * 256 + colormap[:, :, 1]) * 256
+ colormap[:, :, 2])
return colormap2label[idx]
.. raw:: html
.. raw:: html
Ví dụ, trong ảnh ví dụ đầu tiên, chỉ mục lớp cho phần trước của máy bay
là 1, trong khi chỉ mục nền là 0.
.. raw:: html
.. raw:: html
.. code:: python
y = voc_label_indices(train_labels[0], voc_colormap2label())
y[105:115, 130:140], VOC_CLASSES[1]
.. parsed-literal::
:class: output
(array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[0., 0., 0., 0., 0., 0., 0., 1., 1., 1.],
[0., 0., 0., 0., 0., 0., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 1., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 0., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 0., 0., 0., 1., 1.]]),
'aeroplane')
.. raw:: html
.. raw:: html
.. code:: python
y = voc_label_indices(train_labels[0], voc_colormap2label())
y[105:115, 130:140], VOC_CLASSES[1]
.. parsed-literal::
:class: output
(tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1]]),
'aeroplane')
.. raw:: html
.. raw:: html
Xử lý sơ bộ dữ liệu
~~~~~~~~~~~~~~~~~~~
Trong các thí nghiệm trước đó như trong
:numref:`sec_alexnet`—:numref:`sec_googlenet`, hình ảnh được thay
đổi lại để phù hợp với hình dạng đầu vào yêu cầu của mô hình. Tuy nhiên,
trong phân đoạn ngữ nghĩa, làm như vậy đòi hỏi phải thay đổi lại các lớp
pixel dự đoán trở lại hình dạng ban đầu của hình ảnh đầu vào. Việc tái
cặn như vậy có thể không chính xác, đặc biệt là đối với các vùng được
phân đoạn với các lớp khác nhau. Để tránh sự cố này, chúng tôi cắt hình
ảnh thành một hình dạng *fixed* thay vì rescaling. Cụ thể, sử dụng cắt
xén ngẫu nhiên từ nâng hình ảnh, chúng ta cắt cùng một vùng của hình ảnh
đầu vào và nhãn.
.. raw:: html
.. raw:: html
.. code:: python
#@save
def voc_rand_crop(feature, label, height, width):
"""Randomly crop both feature and label images."""
feature, rect = image.random_crop(feature, (width, height))
label = image.fixed_crop(label, *rect)
return feature, label
imgs = []
for _ in range(n):
imgs += voc_rand_crop(train_features[0], train_labels[0], 200, 300)
d2l.show_images(imgs[::2] + imgs[1::2], 2, n);
.. figure:: output_semantic-segmentation-and-dataset_23ff18_66_0.png
.. raw:: html
.. raw:: html
.. code:: python
#@save
def voc_rand_crop(feature, label, height, width):
"""Randomly crop both feature and label images."""
rect = torchvision.transforms.RandomCrop.get_params(
feature, (height, width))
feature = torchvision.transforms.functional.crop(feature, *rect)
label = torchvision.transforms.functional.crop(label, *rect)
return feature, label
imgs = []
for _ in range(n):
imgs += voc_rand_crop(train_features[0], train_labels[0], 200, 300)
imgs = [img.permute(1, 2, 0) for img in imgs]
d2l.show_images(imgs[::2] + imgs[1::2], 2, n);
.. figure:: output_semantic-segmentation-and-dataset_23ff18_69_0.png
.. raw:: html
.. raw:: html
Custom Semantic Segmentation Dataset Class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Chúng tôi xác định một tập dữ liệu phân đoạn ngữ nghĩa tùy chỉnh lớp
``VOCSegDataset`` bằng cách kế thừa lớp ``Dataset`` được cung cấp bởi
các API cấp cao. Bằng cách thực hiện hàm ``__getitem__``, chúng ta có
thể tùy ý truy cập vào hình ảnh đầu vào được lập chỉ mục là ``idx``
trong tập dữ liệu và chỉ số lớp của mỗi pixel trong hình ảnh này. Vì một
số hình ảnh trong tập dữ liệu có kích thước nhỏ hơn kích thước đầu ra
của cắt ngẫu nhiên, các ví dụ này được lọc ra bởi một hàm ``filter`` tùy
chỉnh. Ngoài ra, chúng tôi cũng xác định hàm ``normalize_image`` để
chuẩn hóa các giá trị của ba kênh RGB của hình ảnh đầu vào.
.. raw:: html
.. raw:: html
.. code:: python
#@save
class VOCSegDataset(gluon.data.Dataset):
"""A customized dataset to load the VOC dataset."""
def __init__(self, is_train, crop_size, voc_dir):
self.rgb_mean = np.array([0.485, 0.456, 0.406])
self.rgb_std = np.array([0.229, 0.224, 0.225])
self.crop_size = crop_size
features, labels = read_voc_images(voc_dir, is_train=is_train)
self.features = [self.normalize_image(feature)
for feature in self.filter(features)]
self.labels = self.filter(labels)
self.colormap2label = voc_colormap2label()
print('read ' + str(len(self.features)) + ' examples')
def normalize_image(self, img):
return (img.astype('float32') / 255 - self.rgb_mean) / self.rgb_std
def filter(self, imgs):
return [img for img in imgs if (
img.shape[0] >= self.crop_size[0] and
img.shape[1] >= self.crop_size[1])]
def __getitem__(self, idx):
feature, label = voc_rand_crop(self.features[idx], self.labels[idx],
*self.crop_size)
return (feature.transpose(2, 0, 1),
voc_label_indices(label, self.colormap2label))
def __len__(self):
return len(self.features)
.. raw:: html
.. raw:: html
.. code:: python
#@save
class VOCSegDataset(torch.utils.data.Dataset):
"""A customized dataset to load the VOC dataset."""
def __init__(self, is_train, crop_size, voc_dir):
self.transform = torchvision.transforms.Normalize(
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
self.crop_size = crop_size
features, labels = read_voc_images(voc_dir, is_train=is_train)
self.features = [self.normalize_image(feature)
for feature in self.filter(features)]
self.labels = self.filter(labels)
self.colormap2label = voc_colormap2label()
print('read ' + str(len(self.features)) + ' examples')
def normalize_image(self, img):
return self.transform(img.float() / 255)
def filter(self, imgs):
return [img for img in imgs if (
img.shape[1] >= self.crop_size[0] and
img.shape[2] >= self.crop_size[1])]
def __getitem__(self, idx):
feature, label = voc_rand_crop(self.features[idx], self.labels[idx],
*self.crop_size)
return (feature, voc_label_indices(label, self.colormap2label))
def __len__(self):
return len(self.features)
.. raw:: html
.. raw:: html
Đọc dữ liệu
~~~~~~~~~~~
Chúng tôi sử dụng lớp ``VOCSegDatase``\ t tùy chỉnh để tạo các phiên bản
của bộ đào tạo và bộ kiểm tra, tương ứng. Giả sử rằng chúng ta chỉ định
rằng hình dạng đầu ra của hình ảnh được cắt ngẫu nhiên là
:math:`320\times 480`. Dưới đây chúng ta có thể xem số ví dụ được giữ
lại trong bộ đào tạo và bộ kiểm tra.
.. raw:: html
.. raw:: html
.. code:: python
crop_size = (320, 480)
voc_train = VOCSegDataset(True, crop_size, voc_dir)
voc_test = VOCSegDataset(False, crop_size, voc_dir)
.. parsed-literal::
:class: output
read 1114 examples
read 1078 examples
.. raw:: html
.. raw:: html
.. code:: python
crop_size = (320, 480)
voc_train = VOCSegDataset(True, crop_size, voc_dir)
voc_test = VOCSegDataset(False, crop_size, voc_dir)
.. parsed-literal::
:class: output
read 1114 examples
read 1078 examples
.. raw:: html
.. raw:: html
Đặt kích thước lô thành 64, chúng tôi xác định bộ lặp dữ liệu cho bộ đào
tạo. Hãy để chúng tôi in hình dạng của minibatch đầu tiên. Khác với phân
loại hình ảnh hoặc phát hiện đối tượng, nhãn ở đây là hàng chục ba
chiều.
.. raw:: html
.. raw:: html
.. code:: python
batch_size = 64
train_iter = gluon.data.DataLoader(voc_train, batch_size, shuffle=True,
last_batch='discard',
num_workers=d2l.get_dataloader_workers())
for X, Y in train_iter:
print(X.shape)
print(Y.shape)
break
.. parsed-literal::
:class: output
(64, 3, 320, 480)
(64, 320, 480)
.. raw:: html
.. raw:: html
.. code:: python
batch_size = 64
train_iter = torch.utils.data.DataLoader(voc_train, batch_size, shuffle=True,
drop_last=True,
num_workers=d2l.get_dataloader_workers())
for X, Y in train_iter:
print(X.shape)
print(Y.shape)
break
.. parsed-literal::
:class: output
torch.Size([64, 3, 320, 480])
torch.Size([64, 320, 480])
.. raw:: html
.. raw:: html
Putting All Things Together
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Cuối cùng, chúng tôi xác định hàm ``load_data_voc`` sau để tải xuống và
đọc tập dữ liệu phân đoạn ngữ nghĩa Pascal VOC2012. Nó trả về bộ lặp dữ
liệu cho cả tập dữ liệu đào tạo và kiểm tra.
.. raw:: html
.. raw:: html
.. code:: python
#@save
def load_data_voc(batch_size, crop_size):
"""Load the VOC semantic segmentation dataset."""
voc_dir = d2l.download_extract('voc2012', os.path.join(
'VOCdevkit', 'VOC2012'))
num_workers = d2l.get_dataloader_workers()
train_iter = gluon.data.DataLoader(
VOCSegDataset(True, crop_size, voc_dir), batch_size,
shuffle=True, last_batch='discard', num_workers=num_workers)
test_iter = gluon.data.DataLoader(
VOCSegDataset(False, crop_size, voc_dir), batch_size,
last_batch='discard', num_workers=num_workers)
return train_iter, test_iter
.. raw:: html
.. raw:: html
.. code:: python
#@save
def load_data_voc(batch_size, crop_size):
"""Load the VOC semantic segmentation dataset."""
voc_dir = d2l.download_extract('voc2012', os.path.join(
'VOCdevkit', 'VOC2012'))
num_workers = d2l.get_dataloader_workers()
train_iter = torch.utils.data.DataLoader(
VOCSegDataset(True, crop_size, voc_dir), batch_size,
shuffle=True, drop_last=True, num_workers=num_workers)
test_iter = torch.utils.data.DataLoader(
VOCSegDataset(False, crop_size, voc_dir), batch_size,
drop_last=True, num_workers=num_workers)
return train_iter, test_iter
.. raw:: html
.. raw:: html
Tóm tắt
-------
- Phân đoạn ngữ nghĩa nhận ra và hiểu những gì trong một hình ảnh ở mức
pixel bằng cách chia hình ảnh thành các vùng thuộc các lớp ngữ nghĩa
khác nhau.
- Trên của tập dữ liệu phân khúc ngữ nghĩa quan trọng nhất là Pascal
VOC2012.
- Trong phân đoạn ngữ nghĩa, vì hình ảnh đầu vào và nhãn tương ứng
một-một trên pixel, hình ảnh đầu vào được cắt ngẫu nhiên thành một
hình dạng cố định chứ không phải rescaled.
Bài tập
-------
1. Làm thế nào phân khúc ngữ nghĩa có thể được áp dụng trong các phương
tiện tự trị và chẩn đoán hình ảnh y tế? Bạn có thể nghĩ về các ứng
dụng khác?
2. Nhớ lại các mô tả về tăng cường dữ liệu trong
:numref:`sec_image_augmentation`. Phương pháp nâng hình ảnh nào
được sử dụng trong phân loại hình ảnh sẽ không khả thi được áp dụng
trong phân khúc ngữ nghĩa?
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html