Avatar
AI
Phân biệt hai vị trí Data Engineer và Data Scientist

Phân biệt hai vị trí Kỹ sư dữ liệu (Data Engineer) và nhà khoa học dữ liệu (Data Scientist)


Vẫn còn rất nhiều hiểu nhầm về hai vị trí Kỹ sư dữ liệu (Data Engineer) và nhà khoa học dữ liệu (Data Scientist) nên trong bài hôm nay ProtonX team sẽ giúp bạn phân biện hai vị trí để bạn có thể lựa chọn đúng đắn cho công việc của mình nhé.

Để dễ dàng so sánh hai vị trí này với nhau thì đầu tiên có thể ta cần tập trung vào quy trình xử lý dữ liệu.

Một quy trình xử lý dữ liệu chuẩn sẽ có các thành phần: Thu thập/Lưu trữ dữ liệu, chuẩn bị dữ liệu, hiển thị/khám phá dữ liệu và xây dựng mô hình.

Một quy trình chuẩn thì người kỹ sư dữ liệu sẽ phụ trách phần đầu tiên tức là thu thập/lưu trữ dữ liệu còn nhà khoa học dữ liệu sẽ hoàn thiện 3 phần tiếp theo.

Chi tiết các bước sẽ được diễn giải dưới đây:

  1. Thu thập/Lưu trữ dữ liệu: Các kỹ sư dữ liệu sẽ tham gia vào việc tổ chức lưu trữ dữ liệu. Ví dụ khi xây dựng Studio., team có một bạn phụ trách thu thập (crawl) dữ liệu từ trên Internet, tiền xử lý đơn giản và tổ chức lưu trữ về cơ sở dữ liệu không quan hệ (NoSQL), cụ thể database team sử dụng đó là MongoDB. Nếu bạn yêu thích công việc này có thể tìm hiểu: Học gì để trở thành kỹ sư dữ liệu?

Rõ ràng công việc này yêu cầu bạn cần hiểu về cơ sở dữ liệu, biết cách lưu trữ và truy vấn.

  1. Chuẩn bị dữ liệu: Bước này tùy theo các dự án, cả người kỹ sư dữ liệu và nhà khoa học dữ liệu đều có thể tham gia quy trình này.

Ví dụ đơn giản về các trang web thu thập từ trên mạng về có rất nhiều phần thông tin quảng cáo, ảnh hưởng đến chất lượng mô hình vì vậy khi chuẩn bị dữ liệu, người xử lý cần phải viết rất nhiều những đoạn mã để xử lý, xóa hoặc thậm chí làm mặt nạ (masking).

Ví dụ:

Câu đầu vào:

Địa điểm: Hoàng Mai, Hà Nội

Sau khi xử lý thêm mặt nạ: Câu đầu ra:

Địa điểm: [Nhập địa chỉ của bạn]
  1. Hiển thị khám phá

Khâu này rất quan trọng, nhà khoa học dữ liệu sẽ hiển thị dữ liệu, giảm chiều dữ liệu đễ lựa chọn mô hình. Ví dụ phân phối dữ liệu đơn giản ta có thể lựa chọn những mô hình nhẹ như Hồi quy tuyến tính.

Các thuật toán quen thuộc để giảm chiều ví dụ như SVD, hay PCA. Học thêm về các thuật toán này tại lớp học MLEs - Scale ML System

Tuy nhiên tùy theo dữ liệu mà ta có thể sử dụng được tối đa, ví dụ với dữ liệu dạng bảng thì dễ dàng áp dụng các cách hiển thị khác nhau nhưng với dữ liệu văn bản thì số lượng công cụ hiển thị sẽ ít hơn rất nhiều.

  1. Sau khi đã lựa chọn được mô hình, bước thứ 4 là xây dựng và đánh giá

Trong bước này, nhà khoa học dữ liệu sẽ cần kiểm thử rất nhiều lựa chọn khác nhau, theo dõi để có kết luận được mô hình cho hiệu năng tốt nhất. Không phải lúc nào dùng những công nghệ tiên tiến nhất cũng cho kết quả tốt nhất.

Thử học cách đánh giá bài toán và xây dựng mô hình mạng nơ ron.

Ngoài ra ở khâu này, còn rất quan trọng việc bạn đã từng có kinh nghiệm hiểu về dữ liệu. Nếu bạn đã từng làm việc với dữ liệu ngành này trong quá khứ, thời gian phát triển sẽ nhanh hơn rất nhiều. Ví dụ về kinh nghiệm làm việc với dữ liệu ít.

Trên đây là cách đơn giản nhất để phân biệt được hai vị trí này, hi vọng sẽ giúp bạn lựa chọn đúng nghề nghiệp của mình.

Avatar
AI
Học gì để trở thành kỹ sư dữ liệu?

Học gì để trở thành kỹ sư dữ liệu?


Nếu bạn chưa biết, công việc tiền xử lý dữ liệu là một công việc rất quan trọng trước khi training một mô hình học máy.

Người kỹ sư dữ liệu (Data Engineer) là người thiết kế, xây dựng và duy trì cơ sở hạ tầng và hệ thống hỗ trợ các ứng dụng hướng dữ liệu (data-driven), thường sử dụng các cấu trúc dữ liệu và thuật toán khác nhau để tối ưu hiệu năng. Tương lai các ứng dụng học máy sử dụng dữ liệu lớn (Big Data) sẽ trở nên phổ biến hơn vì vậy vị trí kỹ sư dữ liệu sẽ được tìm kiếm nhiều hơn bao giờ hết.

Tìm hiểu thêm về học máy tại lớp học AI miễn phí.

Đầu tiên thì kỹ sư dữ liệu cần học lập trình tốt. Ngôn ngữ phổ biến để xử lý dữ liệu tại thời điểm hiện tại là Python. Đây là ngôn ngữ được dùng nhiều nhất để làm Machine Learning vì tính đơn giản gọn nhẹ của nó.

Mình đã đóng gói các kiến thức Python vào lớp học Python miễn phí tại đây

Ngoài cấu trúc dữ liệu và giải thuật, người kỹ sư dữ liệu còn phải học rất nhiều chủ đề khác nhau bao gồm:

  • Lưu trữ và quản lý dữ liệu: Các kỹ sư dữ liệu nên có hiểu biết tốt về các loại hệ thống lưu trữ dữ liệu khác nhau, chẳng hạn như cơ sở dữ liệu quan hệ (SQL) và cơ sở dữ liệu không quan hệ (NoSQL), và có thể thiết kế và triển khai các giải pháp lưu trữ dữ liệu hiệu quả.

  • Xử lý và phân tích dữ liệu: Các kỹ sư dữ liệu nên nắm bắt được các kỹ thuật xử lý và phân tích dữ liệu, chẳng hạn như batch processing và stream processing, và có thể thiết kế và triển khai các dữ liệu dòng sử dụng các công cụ như Apache Kafka và Apache Spark.

  • Cloud: Các kỹ sư dữ liệu nên quen thuộc với các nền tảng tính toán Cloud, chẳng hạn như Amazon Web Services (AWS), Microsoft Azure và Google Cloud Platform (GCP), và có thể thiết kế và triển khai các giải pháp cơ sở hạ tầng dữ liệu trên các nền tảng này.

  • Quản lý, bảo mật và tuân thủ dữ liệu: Một phần rất quan trọng đó là quản lý, bảo mật, mã hóa dữ liệu, kiểm soát truy cập dữ liệu.

  • Giao tiếp: Và cuối cùng là kỹ năng giao tiếp tốt để có thể hợp tác với đồng nghiệp, giải thích các khái niệm kỹ thuật phức tạp cho các nhà quản lý không phải người làm kỹ thuật và trình bày công việc của mình trước đám đông.

Hi vọng bài viết này đã giúp bạn có cái nhìn tổng quan về vị trí này.

Avatar
Ba
Ước lượng giá trị mất mát tối ưu dựa vào số lượng tham số

Ước lượng giá trị mất mát tối ưu dựa vào số lượng tham số


1) Khi bạn làm việc đủ lâu với một mô hình, bạn sẽ nắm được rất nhiều thông số quan trọng để tăng tốc trong những lần training tiếp theo

Có một điều rất thú vị mà có thể bạn quan tâm, khi bạn làm việc với một mô hình đủ lâu, bạn có thể hình thành mối tương quan giữa số lượng tham số của mô hình và giá trị mất mát tối ưu.

Trong năm qua, đội ngũ ProtonX đã train rất nhiều mô hình cho Studio. sử dụng GPT2 - Medium với 345 triệu tham số với rất nhiều domain khác nhau, từ tuyển dụng cho đến công thức nấu ăn rồi viết bài marketing, chuẩn SEO, vv.

Với những domain cụ thể, team có những con số tương đối chính xác để dự đoán được hiệu suất của mô hình. Ví dụ như sau:

  • Với domain đơn giản như mô tả công việc (JD), chỉ cần khoảng 100.000 văn bản trở lên, bạn đã có thể tạo ra được một mô hình có khả năng sinh được ra miêu tả đủ dùng.

Đây là output cho vị trí phân tích dữ liệu:

Theo người dùng phản hồi thì mô hình hiện tại đang hỗ trợ người dùng 50% trong việc viết miêu tả, tức là 50% còn lại người dùng cần chỉnh sửa và nhập các thông tin cá nhân như quyền lợi ứng viên, địa chỉ công ty.

2) Ước lượng giá trị mất mát tối ưu dựa vào số lượng tham số của mô hình

Gần đây team có đọc nghiên cứu Scaling Laws for Neural Language Models thì đã liên hệ trực tiếp quá trình training của team thì có một số nhận định khá tương đồng.

Có 3 luật quan trọng trong bài báo này nhưng trong bài viết này mình sẽ chỉ nhắc đến quy luật đầu tiên mà họ rút ra.

Với mô hình giới hạn tham số, giá trị mất mát tối ưu (hội tụ tốt) với lượng dataset đủ lớn sẽ xấp xỉ theo công thức sau:

L(N)=(NcN)αNL(N) = (\frac{N_c}{N})^{\alpha_N}

Với αN0.076\alpha_N \sim 0.076Nc8.8×1013N_c \sim 8.8 \times 10^{13} là hai giá trị cố định

  • L(N)L(N) chính là giá trị mất mát tối ưu
  • NN: số lượng tham số của mô hình

Áp dụng vào bài toán của team:

Hiện tại team có hơn 200.000 miêu tả công việc, nếu áp dụng công thức này thì giá trị mất mát hợp lý sẽ là:

L(N)=(8.8×1013345×106)0.0762.375L(N) = (\frac{8.8 \times 10^{13}}{345 \times 10^6})^{0.076} \approx 2.375

Con số này khá thú vị, đó chính là con số mà team rất hay gặp trong khoảng training 7-10 epochs đầu tiên, vậy là nhận định này đã đúng với những gì thực tế diễn ra.

Ví dụ đây là epoch số 6 mà team đào tạo

'loss': 2.6251, 'learning_rate': 9.333333333333334e-06, 'epoch': 6.0}                                                               
 30%|████████████████████████▉                                                          | 37806/126020 [11:41:23<24:58:47,  1.02s/it]***** Running Evaluation *****
  Num examples = 378055
  Batch size = 8
{'eval_loss': 2.65189266204834, 'eval_runtime': 571.2631, 'eval_samples_per_second': 661.788, 'eval_steps_per_second': 20.682, 'epoch': 6.0}
 30%|████████████████████████▉                                                          | 37806/126020 [11:50:54<24:58:47,  1.02s/it]    

Giá trị rất sát với công thức trên.

Tất nhiêu theo đánh giá của team, công thức này sẽ đúng hơn nữa khi dataset lớn hơn khoảng 1 triệu bản ghi, tuy nhiên là một trong những thước đo rất quan trọng giúp bạn có thể ước lượng được điểm dừng sớm.

Team rất mong bạn có thể tham khảo công thức này để tiết kiệm thời gian và có những insight quan trong mà mình làm việc mỗi ngày.

Avatar
Ba
Làm việc với hàng tỷ điểm dữ liệu như thế nào?
Attachments

Làm việc với dữ liệu văn bản lớn


Nếu bạn cần phải làm việc 20GB dữ liệu văn bản mà máy tính của bạn chỉ có 4B RAM, chuyện gì sẽ xảy ra nếu bạn sử dụng trực tiếp Python để load file này? Câu trả lời rất đơn giản, máy tính của các bạn sẽ bị tràn RAM.

Một ví dụ về bộ dataset cỡ lớn: PILE, bộ dữ liệu này có 15518009 dòng, rất lớn đúng không?

Vậy giải quyết vấn đề này như thế nào?

Cùng làm quen với khái niệm Memory-mapped file.

Memory Mapping là cơ chế ánh xạ (map) một phần của file hoặc toàn bộ file trên ổ cứng (disk) thành một đoạn trên bộ nhớ. Việc này cho phép chúng ta có thể truy cập vào từng phần của một file lớn như trên thay vì phải load toàn bộ file lên RAM khiến tràn RAM.

1) Thực hành trải nghiệm Memory Mapped Files với pyarrow nhé.

Ví dụ bạn ghi dữ liệu ra một file

with pa.OSFile('example3.dat', 'wb') as f:
    f.write(b'some example data')

Sau đó bạn tiến hành đọc file này:

mmap = pa.memory_map('example3.dat')
mmap.read(4)

Bạn đã đọc một phần của file có nội dung:

b'some'

Với cách đọc từ memory map ở bên trên, thư viện sẽ đọc từng phần của file đã được ánh xạ trên RAM.

Nếu in tất cả ra thì các bạn thấy file đã được chia thành nhiều phần:

for i in range(1, 7):
    print(mmap.read(i))

Kết quả hiện ra

b's'
b'om'
b'e e'
b'xamp'
b'le da'
b'ta'

Rõ ràng trong AI cách thức này rất có lợi. Ví dụ khi bạn sử dụng Batch Gradient Descent, bạn sẽ không cần đọc toàn bộ dữ liệu một lúc, thay vào đó ta sẽ load từng phần, xử lý và training.

2) Ứng dụng trong các thư viện AI

Giả sử bạn tải một file dataset từ HuggingFace - Đây chính là một thư viện ứng dụng mạnh mẽ khái niệm bên trên. Xem thêm thư viện này.

from datasets import load_dataset

# This takes a few minutes to run, so go grab a tea or coffee while you wait :)
data_files = "https://the-eye.eu/public/AI/pile_preliminary_components/PUBMED_title_abstracts_2019_baseline.jsonl.zst"
pubmed_dataset = load_dataset("json", data_files=data_files, split="train")

File này dung lượng 19.54GB

print(f"Number of files in dataset : {pubmed_dataset.dataset_size}")
size_gb = pubmed_dataset.dataset_size / (1024**3)
print(f"Dataset size (cache file) : {size_gb:.2f} GB")
Number of files in dataset : 20979437051
Dataset size (cache file) : 19.54 GB

Sau đó bạn sử dụng thư viện psutil để kiểm tra xem biến pubmed_dataset thực sự đang chiếm bao nhiêu không gian trên RAM?

import psutil

# Process.memory_info is expressed in bytes, so convert to megabytes
print(f"RAM used: {psutil.Process().memory_info().rss / (1024 * 1024):.2f} MB")
RAM used: 5678.33 MB

Chỉ khoảng hơn 5GB được sử dụng bao gồm cả Python và các biến môi trường khác nên độ lớn biến của chúng ta nhỏ hơn con số này.

Rõ ràng ta nhận ra biến này đại diện cho việc mapping đã được nhắc ở bên trên, luôn luôn load một phần của file.

Avatar
Ba
Hướng dẫn sử dụng Dataset Streaming - Làm việc với 1.2 Terabytes dữ liệu mà không cần tải toàn bộ
Attachments

Dataset Streaming - Làm việc với 1.2 Terabytes dữ liệu mà không cần tải toàn bộ.


1) Giới thiệu về Streaming Dataset

Bộ dữ liệu OSCAR nặng 1.2 Terabytes, mình tin là rất ít người trong chúng ta có ổ cứng đủ để lưu và làm việc với bộ dữ liệu này. Vậy cách giải quyết như thế nào nhỉ?

Câu trả lời: Ta sẽ sử dụng/xây dựng một Streaming Dataset

Cơ chế tương tự Cursor trong MongoDB. Thay vì phải tải 10610^6 dòng một lúc thì khi bạn lặp Cursor đến vị trí dòng nào MongoDB mới tải dòng đó để ta xử lý.

Điều này cực kỳ hữu ích:

  • Bạn không phải tải toàn bộ tập dữ liệu về máy
  • Bạn muốn thử nghiệm vài samples nhanh

2) Trải nghiệm Streaming Dataset với HuggingFace

Cài đặt HuggingFace Dataset:

!pip install datasets

Sử dụng Dataset dưới dạng Streaming thay vì tải về toàn bộ:

Chú ý tham số streaming=True

from datasets import load_dataset
dataset = load_dataset('oscar', "unshuffled_deduplicated_en", split='train', streaming=True)
print(next(iter(dataset)))

Kết quả:



Biến dataaset thuộc lớp IterableDataset cho phép lặp tuần từ qua tất cả các phần tử.

Bạn chỉ thực sự tải dữ liệu khi viết:

for item in iter(dataset):
    print(item['id'])

3) Lấy một phần của dữ liệu thế nào

Mình đã làm rất nhiều video về Tensorflow Dataset và cách thức lấy một phần data của HuggingFace Dataset cũng tương tự. Đó chính là hàm take

Bạn lấy 3 phần tử khỏi dataset và chuyển thành mảng.

dataset_head = dataset.take(3)
list(dataset_head)

4) Xáo bộ dữ liệu thế nào?

Khi làm AI chắc chắn chúng ta cần phải quan tâm tới việc xáo dữ liệu đúng không? Vậy thì hàm shuffle sẽ giúp bạn làm điều này.

shuffled_dataset = dataset.shuffle(seed=42, buffer_size=1000)

Đây là tính năng tương tự ở bất kỳ một thư viện build dataset nào.

Chúng ta có đầy đủ công cụ hỗ trợ cho bạn tiền xử lý:

5) Nguồn tham khảo

Avatar
Ba
Tăng tốc truy vấn dữ liệu với Apache Parquet

Tăng tốc truy vấn dữ liệu với Apache Parquet


Apache Parquet là một định dạng file hỗ trợ việc xử lý data phức tạp với rất nhiều những đặc tính thú vị.

Trong một số trường hợp bạn có thể sử dụng định dạng Parquet thay vì sử dụng file CSV vì 2 lý do sau:

  • Khi bạn cần lưu trữ tiết kiệm
  • Bạn cần truy vấn nhanh theo cột trong bài toán cụ thể của mình

1) Hướng cột - Columnar


Không như những dạng hướng theo dòng như CSV, Parquet là dạng dữ liệu hướng theo cột, tức là các cột sẽ được lưu trữ liền kề nhau thay vì các dòng.



2) Lưu trữ hướng cột


Khi ổ đĩa quay, dữ liệu ghi trên đĩa sẽ được đọc bởi đầu đọc. Mỗi giá trị x ở dưới được biểu diễn bởi một cột của bảng.

Giả sử bạn chỉ muốn đọc cột Feature 3 thì với dữ liệu hướng dòng (row-oriented) bạn cần đọc tất cả các dòng, ở mỗi dòng bạn lại thu được một giá trị ở cột Feature 3.

Giả sử bạn có một bảng có 10610^6 dòng và 3 cột thì bạn cần duyệt qua toàn bộ số dòng này mới lấy được cột Feature 3.

Trong trường hợp, nếu ta sử dụng lưu trữ hướng cột sẽ cho tốc độ nhanh hơn nhiều.

Ngoài ra lưu trữ hướng cột cũng cho ta một số lợi thế về lưu trữ khi các giá trị trong cột có xu hướng giống nhau nên ta có thể sử dụng các thuật toán nén. Vì thế file Parquet sẽ nhẹ hơn các dạng lưu trữ khác. Ví dụ một file CSV 1TB khi chuyển sang dạng Parquet chỉ khoảng 100GB (còn 10% không gian lưu trữ).

3) Thực hiện tạo Parquet file với Pyarrow


Cài đặt thư viện:

!pip install pyarrow

Tạo mảng chứa 100 phần tử:

import numpy as np
import pyarrow as pa

arr = pa.array(np.arange(100))

print(f"{arr[0]} .. {arr[-1]}")

Định dạng Parquet là bảng chứa rất nhiều cột nên ta cần đặt tên cho cột này.

table = pa.Table.from_arrays([arr], names=["Feature 3"])

import pyarrow.parquet as pq

pq.write_table(table, "example.parquet", compression=None)

Kết quả ta đã được một file này:

4) Tiến hành đọc file Parquet


import pyarrow.parquet as pq

table = pq.read_table("example.parquet")

Kết quả hiện ra:

5) Kết luận

Hi vọng bạn đã có thêm lựa chọn khi xử lý dữ liệu lớn.

6) Nguồn tham khảo

Avatar
Ba
Convert bộ dữ liệu Coco thành TF Records để tăng tốc quá trình xử lý dữ liệu
Attachments

Convert bộ dữ liệu Coco thành TF Records để tăng tốc quá trình xử lý dữ liệu


1) Giới thiệu về TFRecord

Tensorflow là framework được thiết kế phù hợp với môi trường Production vì framework này có rất nhiều công cụ làm việc với dữ liệu lớn (Big Data).

Một trong những công cụ chúng ta rất cần thiết đó là TF Record giúp cải thiện tốc độ load dữ liệu và xử lý.

Định dạng TFRecord là dạng lưu trữ nhị phân của Tensorflow. Một số lợi điểm khi sử dụng kiểu lưu trữ này:

  • Tương tự như Apache Parquet, sử dụng TFRecord giúp tiết kiệm không gian lưu trữ.
  • Tốc độc đọc/ghi cao khi TF hỗ trợ đọc/ghi song song.

2) Khám phá bộ dữ liệu COCO

Bộ dữ liệu COCO có thể sử dụng cho bài toán nhận diện hình ảnh. Bộ dữ liệu bao gồm hai phần:

  • Phần 1) Ảnh được lưu dưới dạng JPG

Một ảnh trong bộ dữ liệu này.

Nguồn ảnh

  • Phần 2 ) Thông tin meta-data lưu dưới dạng JSON file bao gồm
    • id: mã metadata - dạng int
    • image_id: mã ảnh - dạng int
    • category_id: nhãn - dạng int
    • segmentation: đường bao quanh đối tượng - mảng các giá trị float
    • bbox: tọa độ các đỉnh hình vuông bao quanh đối tượng - mảng các giá trị float
    • area: diện tích của bounding box - mảng các giá trị float

Ví dụ

{
  "id": 1410165,
  "category_id": 1,
  "iscrowd": 0,
  "segmentation": [
    [
      486.34,
      239.01,
      495.95,
      ...
      244.39
    ]
  ],
  "image_id": 245915,
  "area": 1775.8932499999994,
  "bbox": [
    86.0,
    65.0,
    220.0,
    334.0
  ]

3) Hướng dẫn convert bộ dữ liệu COCO sang TFRecord

3.1) Hướng dẫn convert bộ dữ liệu COCO sang TFRecord

Tiến hành download ảnh:

root_dir = "datasets"
images_dir = os.path.join(root_dir, "val2017")
annotations_dir = os.path.join(root_dir, "annotations")
annotation_file = os.path.join(annotations_dir, "instances_val2017.json")
images_url = "http://images.cocodataset.org/zips/val2017.zip"
annotations_url = (
    "http://images.cocodataset.org/annotations/annotations_trainval2017.zip"
)

# Tải ảnh
if not os.path.exists(images_dir):
    image_zip = tf.keras.utils.get_file(
        "images.zip", cache_dir=os.path.abspath("."), origin=images_url, extract=True,
    )
    os.remove(image_zip)

Tiến hành download meta-data:


# Tải meta data
if not os.path.exists(annotations_dir):
    annotation_zip = tf.keras.utils.get_file(
        "captions.zip",
        cache_dir=os.path.abspath("."),
        origin=annotations_url,
        extract=True,
    )
    os.remove(annotation_zip)

print("The COCO dataset has been downloaded and extracted successfully.")

Kiểm tra số lượng mẫu:

import json
with open(annotation_file, "r") as f:
    annotations = json.load(f)["annotations"]

print(f"Number of images: {len(annotations)}")

Chúng ta có 36781 mẫu

Number of images: 36781

Ước tính số lượng file Tfrecord bằng việc tính toán như sau: nếu bạn muốn một file TFRecord chứa 4096 ảnh thì:

Soˆˊ lượng file=Soˆˊ lượng ảnhSoˆˊ lượng ảnh/File\text{Số lượng file} =\lfloor\frac{\text{Số lượng ảnh}}{\text{Số lượng ảnh/File}}\rfloor + 1 khi số lượng ảnh không chia hết cho số lượng file.

Ở đây mình sẽ có 367814096+1=9\lfloor\frac{36781}{4096}\rfloor + 1 = 9 file.

Code tính số file:

tfrecords_dir = "coco-tfrecords"
num_samples = 4096
num_tfrecods = len(annotations) // num_samples
if len(annotations) % num_samples:
    num_tfrecods += 1  # add one record if there are any remaining samples

if not os.path.exists(tfrecords_dir):
    os.makedirs(tfrecords_dir)  # creating TFRecords output folder
3.2) Hướng dẫn convert bộ dữ liệu COCO sang TFRecord

Với các dạng dữ liệu khác nhau ta sẽ sử dụng các cách convert khác nhau:

  • Ảnh ta sẽ chuyển thành dạng nhị phân với hàm sau
def image_feature(value):
    """Returns a bytes_list from a string / byte."""
    return tf.train.Feature(
        bytes_list=tf.train.BytesList(value=[tf.io.encode_jpeg(value).numpy()])
    )
  • Số nguyên, số thực hay mảng số thực được chuyển như sau:
def float_feature(value):
    """Returns a float_list from a float / double."""
    return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))


def int64_feature(value):
    """Returns an int64_list from a bool / enum / int / uint."""
    return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))


def float_feature_list(value):
    """Returns a list of float_list from a float / double."""
    return tf.train.Feature(float_list=tf.train.FloatList(value=value))

Sau đó bạn kết hợp tất cả các cách chuyển này vào trong một hàm thực hiện trên một mẫu, lưu ý một mẫu sẽ được lưu bằng hàm tf.train.Example

def create_example(image, path, example):
    feature = {
        "image": image_feature(image),
        "path": bytes_feature(path),
        "area": float_feature(example["area"]), # Số thực thì bạn dùng float_feature
        "bbox": float_feature_list(example["bbox"]), # Mảng số thực thì bạn dùng float_feature_list
        "category_id": int64_feature(example["category_id"]), # Số nguyên thì dùng int64_feature
        "id": int64_feature(example["id"]),
        "image_id": int64_feature(example["image_id"]),
    }
    return tf.train.Example(features=tf.train.Features(feature=feature))

Bước cuối cùng ta sẽ lặp qua tất cả ảnh và build ra từng file TF Record một:

for tfrec_num in range(num_tfrecods):
    # Cắt mẫu để chia ra file tương ứng
    samples = annotations[(tfrec_num * num_samples) : ((tfrec_num + 1) * num_samples)]
    # Tiến hành ghi ra file này
    with tf.io.TFRecordWriter(
        tfrecords_dir + "/file_%.2i-%i.tfrec" % (tfrec_num, len(samples))
    ) as writer:
        # Đọc từng ảnh và ghi vào file 
        for sample in samples:
            image_path = f"{images_dir}/{sample['image_id']:012d}.jpg"
            with open(image_path, "rb") as local_file:
              raw = local_file.read()
              image = tf.image.decode_jpeg(raw)
            example = create_example(image, image_path, sample)
            writer.write(example.SerializeToString())

Sau khi thực hiện xong kết quả sẽ thu được như sau:

Trong bài tiếp theo mình sẽ hướng dẫn bạn cách để đọc các file TFRecords đã được lưu.

Hi vọng bạn đã có thêm một lựa chọn tốt nữa để xây dựng được một hệ thống AI có khả năng nhân rộng cao.

Filter