اتبع هذا الدليل لإنشاء مجموعة بيانات جديدة (إما في TFDS أو في المستودع الخاص بك).
تحقق من قائمة مجموعات البيانات لدينا لمعرفة ما إذا كانت مجموعة البيانات التي تريدها موجودة بالفعل.
ليرة تركية؛ د
أسهل طريقة لكتابة مجموعة بيانات جديدة هي استخدام TFDS CLI :
cd path/to/my/project/datasets/
tfds new my_dataset # Create `my_dataset/my_dataset.py` template files
# [...] Manually modify `my_dataset/my_dataset_dataset_builder.py` to implement your dataset.
cd my_dataset/
tfds build # Download and prepare the dataset to `~/tensorflow_datasets/`
لاستخدام مجموعة البيانات الجديدة مع tfds.load('my_dataset')
:
- سوف يقوم
tfds.load
تلقائيًا باكتشاف وتحميل مجموعة البيانات التي تم إنشاؤها في~/tensorflow_datasets/my_dataset/
(على سبيل المثال بواسطةtfds build
). - وبدلاً من ذلك، يمكنك
import my.project.datasets.my_dataset
بشكل صريح لتسجيل مجموعة البيانات الخاصة بك:
import my.project.datasets.my_dataset # Register `my_dataset`
ds = tfds.load('my_dataset') # `my_dataset` registered
ملخص
يتم توزيع مجموعات البيانات بجميع أنواع التنسيقات وفي جميع أنواع الأماكن، ولا يتم تخزينها دائمًا بتنسيق جاهز للتغذية في مسار التعلم الآلي. أدخل تي اف دي اس.
تقوم TFDS بمعالجة مجموعات البيانات هذه في تنسيق قياسي (بيانات خارجية -> ملفات متسلسلة)، والتي يمكن بعد ذلك تحميلها كخط أنابيب للتعلم الآلي (ملفات متسلسلة -> tf.data.Dataset
). يتم إجراء التسلسل مرة واحدة فقط. سيتم قراءة الوصول اللاحق من تلك الملفات التي تمت معالجتها مسبقًا مباشرة.
تتم معظم عمليات المعالجة المسبقة تلقائيًا. تطبق كل مجموعة بيانات فئة فرعية من tfds.core.DatasetBuilder
، والتي تحدد:
- من أين تأتي البيانات (أي عناوين URL الخاصة بها)؛
- كيف تبدو مجموعة البيانات (أي ميزاتها)؛
- كيف ينبغي تقسيم البيانات (على سبيل المثال،
TRAIN
TEST
)؛ - والأمثلة الفردية في مجموعة البيانات.
اكتب مجموعة البيانات الخاصة بك
القالب الافتراضي: tfds new
استخدم TFDS CLI لإنشاء ملفات بايثون القالب المطلوبة.
cd path/to/project/datasets/ # Or use `--dir=path/to/project/datasets/` below
tfds new my_dataset
سيقوم هذا الأمر بإنشاء مجلد my_dataset/
جديد بالبنية التالية:
my_dataset/
__init__.py
README.md # Markdown description of the dataset.
CITATIONS.bib # Bibtex citation for the dataset.
TAGS.txt # List of tags describing the dataset.
my_dataset_dataset_builder.py # Dataset definition
my_dataset_dataset_builder_test.py # Test
dummy_data/ # (optional) Fake data (used for testing)
checksum.tsv # (optional) URL checksums (see `checksums` section).
ابحث عن TODO(my_dataset)
هنا وقم بالتعديل وفقًا لذلك.
مثال على مجموعة البيانات
يتم تنفيذ جميع مجموعات البيانات ضمن فئات فرعية من tfds.core.DatasetBuilder
، الذي يعتني بمعظم البيانات المعيارية. وهو يدعم:
- مجموعات البيانات الصغيرة والمتوسطة التي يمكن إنشاؤها على جهاز واحد (هذا البرنامج التعليمي).
- مجموعات بيانات كبيرة جدًا تتطلب إنشاءًا موزعًا (باستخدام Apache Beam ، راجع دليل مجموعة البيانات الضخمة الخاص بنا)
فيما يلي مثال بسيط لمنشئ مجموعة البيانات الذي يعتمد على tfds.core.GeneratorBasedBuilder
:
class Builder(tfds.core.GeneratorBasedBuilder):
"""DatasetBuilder for my_dataset dataset."""
VERSION = tfds.core.Version('1.0.0')
RELEASE_NOTES = {
'1.0.0': 'Initial release.',
}
def _info(self) -> tfds.core.DatasetInfo:
"""Dataset metadata (homepage, citation,...)."""
return self.dataset_info_from_configs(
features=tfds.features.FeaturesDict({
'image': tfds.features.Image(shape=(256, 256, 3)),
'label': tfds.features.ClassLabel(
names=['no', 'yes'],
doc='Whether this is a picture of a cat'),
}),
)
def _split_generators(self, dl_manager: tfds.download.DownloadManager):
"""Download the data and define splits."""
extracted_path = dl_manager.download_and_extract('http://data.org/data.zip')
# dl_manager returns pathlib-like objects with `path.read_text()`,
# `path.iterdir()`,...
return {
'train': self._generate_examples(path=extracted_path / 'train_images'),
'test': self._generate_examples(path=extracted_path / 'test_images'),
}
def _generate_examples(self, path) -> Iterator[Tuple[Key, Example]]:
"""Generator of examples for each split."""
for img_path in path.glob('*.jpeg'):
# Yields (key, example)
yield img_path.name, {
'image': img_path,
'label': 'yes' if img_path.name.startswith('yes_') else 'no',
}
لاحظ أنه بالنسبة لبعض تنسيقات البيانات المحددة، فإننا نوفر أدوات إنشاء مجموعات بيانات جاهزة للاستخدام للاهتمام بمعظم عمليات معالجة البيانات.
دعونا نرى بالتفصيل الطرق الثلاثة المجردة للكتابة فوق.
_info
: البيانات الوصفية لمجموعة البيانات
تقوم _info
بإرجاع tfds.core.DatasetInfo
الذي يحتوي على البيانات التعريفية لمجموعة البيانات .
def _info(self):
# The `dataset_info_from_configs` base method will construct the
# `tfds.core.DatasetInfo` object using the passed-in parameters and
# adding: builder (self), description/citations/tags from the config
# files located in the same package.
return self.dataset_info_from_configs(
homepage='https://dataset-homepage.org',
features=tfds.features.FeaturesDict({
'image_description': tfds.features.Text(),
'image': tfds.features.Image(),
# Here, 'label' can be 0-4.
'label': tfds.features.ClassLabel(num_classes=5),
}),
# If there's a common `(input, target)` tuple from the features,
# specify them here. They'll be used if as_supervised=True in
# builder.as_dataset.
supervised_keys=('image', 'label'),
# Specify whether to disable shuffling on the examples. Set to False by default.
disable_shuffling=False,
)
يجب أن تكون معظم الحقول واضحة بذاتها. بعض الدقة:
-
features
: يحدد هذا بنية مجموعة البيانات وشكلها... دعم أنواع البيانات المعقدة (الصوت والفيديو والتسلسلات المتداخلة،...). راجع الميزات المتوفرة أو دليل موصل الميزات لمزيد من المعلومات. -
disable_shuffling
: راجع القسم الحفاظ على ترتيب مجموعة البيانات .
كتابة ملف BibText
CITATIONS.bib
:
- ابحث في موقع مجموعة البيانات عن تعليمات الاقتباس (استخدم ذلك بتنسيق BibTex).
- بالنسبة لأوراق arXiv : ابحث عن الورقة وانقر فوق رابط
BibText
الموجود على الجانب الأيمن. - ابحث عن الورقة البحثية في Google Scholar وانقر على علامة الاقتباس المزدوجة الموجودة أسفل العنوان وفي النافذة المنبثقة، انقر على
BibTeX
. - إذا لم يكن هناك ورق مرتبط (على سبيل المثال، يوجد موقع ويب فقط)، يمكنك استخدام محرر BibTeX عبر الإنترنت لإنشاء إدخال BibTeX مخصص (تحتوي القائمة المنسدلة على نوع إدخال
Online
).
تحديث ملف TAGS.txt
:
- تتم تعبئة جميع العلامات المسموح بها مسبقًا في الملف الذي تم إنشاؤه.
- قم بإزالة كافة العلامات التي لا تنطبق على مجموعة البيانات.
- يتم إدراج العلامات الصالحة في Tensorflow_datasets/core/valid_tags.txt .
- لإضافة علامة إلى تلك القائمة، يرجى إرسال PR.
الحفاظ على ترتيب مجموعة البيانات
افتراضيًا، يتم خلط سجلات مجموعات البيانات عند تخزينها من أجل جعل توزيع الفئات أكثر اتساقًا عبر مجموعة البيانات، نظرًا لأن السجلات التي تنتمي إلى نفس الفئة غالبًا ما تكون متجاورة. من أجل تحديد أنه يجب فرز مجموعة البيانات حسب المفتاح الذي تم إنشاؤه بواسطة _generate_examples
يجب تعيين الحقل disable_shuffling
على True
. افتراضيًا، يتم تعيينه على False
.
def _info(self):
return self.dataset_info_from_configs(
# [...]
disable_shuffling=True,
# [...]
)
ضع في اعتبارك أن تعطيل التبديل العشوائي له تأثير على الأداء حيث لا يمكن قراءة الأجزاء بشكل متوازٍ بعد الآن.
_split_generators
: تنزيل البيانات وتقسيمها
تحميل واستخراج البيانات المصدر
تحتاج معظم مجموعات البيانات إلى تنزيل البيانات من الويب. ويتم ذلك باستخدام وسيطة الإدخال tfds.download.DownloadManager
الخاصة بـ _split_generators
. لدى dl_manager
الطرق التالية:
-
download
: يدعمhttp(s)://
،ftp(s)://
-
extract
: يدعم حاليًا ملفات.zip
و.gz
و.tar
. -
download_and_extract
: مثلdl_manager.extract(dl_manager.download(urls))
تقوم جميع هذه الأساليب بإرجاع tfds.core.Path
(الأسماء المستعارة لـ epath.Path
)، وهي كائنات تشبه pathlib.Path .
تدعم هذه التوابع بنية متداخلة اعتباطية ( list
، dict
)، مثل:
extracted_paths = dl_manager.download_and_extract({
'foo': 'https://example.com/foo.zip',
'bar': 'https://example.com/bar.zip',
})
# This returns:
assert extracted_paths == {
'foo': Path('/path/to/extracted_foo/'),
'bar': Path('/path/extracted_bar/'),
}
التحميل والاستخراج يدويا
لا يمكن تنزيل بعض البيانات تلقائيًا (على سبيل المثال، يتطلب تسجيل الدخول)، وفي هذه الحالة، سيقوم المستخدم بتنزيل البيانات المصدر يدويًا ووضعها في manual_dir/
(الإعداد الافتراضي هو ~/tensorflow_datasets/downloads/manual/
).
يمكن بعد ذلك الوصول إلى الملفات من خلال dl_manager.manual_dir
:
class MyDataset(tfds.core.GeneratorBasedBuilder):
MANUAL_DOWNLOAD_INSTRUCTIONS = """
Register into https://example.org/login to get the data. Place the `data.zip`
file in the `manual_dir/`.
"""
def _split_generators(self, dl_manager):
# data_path is a pathlib-like `Path('<manual_dir>/data.zip')`
archive_path = dl_manager.manual_dir / 'data.zip'
# Extract the manually downloaded `data.zip`
extracted_path = dl_manager.extract(archive_path)
...
يمكن تخصيص موقع manual_dir
باستخدام tfds build --manual_dir=
أو باستخدام tfds.download.DownloadConfig
.
قراءة الأرشيف مباشرة
يقوم dl_manager.iter_archive
بقراءة الأرشيفات بشكل تسلسلي دون استخراجها. يمكن أن يؤدي ذلك إلى توفير مساحة التخزين وتحسين الأداء في بعض أنظمة الملفات.
for filename, fobj in dl_manager.iter_archive('path/to/archive.zip'):
...
يمتلك fobj
نفس الأساليب المستخدمة with open('rb') as fobj:
(على سبيل المثال fobj.read()
)
تحديد تقسيمات مجموعة البيانات
إذا كانت مجموعة البيانات تأتي مع تقسيمات محددة مسبقًا (على سبيل المثال، تحتوي MNIST
على تقسيمات train
test
)، فاحتفظ بها. بخلاف ذلك، قم بتحديد تقسيم all
فقط. يمكن للمستخدمين إنشاء تقسيماتهم الفرعية ديناميكيًا باستخدام واجهة برمجة التطبيقات الخاصة بالتقسيم الفرعي (على سبيل المثال، split='train[80%:]'
). لاحظ أنه يمكن استخدام أي سلسلة أبجدية كاسم مقسم، بصرف النظر عن all
المذكور أعلاه.
def _split_generators(self, dl_manager):
# Download source data
extracted_path = dl_manager.download_and_extract(...)
# Specify the splits
return {
'train': self._generate_examples(
images_path=extracted_path / 'train_imgs',
label_path=extracted_path / 'train_labels.csv',
),
'test': self._generate_examples(
images_path=extracted_path / 'test_imgs',
label_path=extracted_path / 'test_labels.csv',
),
}
_generate_examples
: مثال للمولد
_generate_examples
ينشئ الأمثلة لكل تقسيم من البيانات المصدر.
ستقوم هذه الطريقة عادةً بقراءة عناصر مجموعة البيانات المصدر (مثل ملف CSV) وتنتج مجموعات (key, feature_dict)
:
-
key
: معرف المثال. يُستخدم لخلط الأمثلة بشكل حتمي باستخدامhash(key)
أو للفرز حسب المفتاح عند تعطيل الخلط (راجع القسم الحفاظ على ترتيب مجموعة البيانات ). ينبغي أن يكون:- فريد : إذا استخدم مثالان نفس المفتاح، فسيتم ظهور استثناء.
- حتمية : لا ينبغي أن تعتمد على
download_dir
، ترتيبos.path.listdir
،... توليد البيانات مرتين يجب أن يؤدي إلى نفس المفتاح. - قابل للمقارنة : إذا تم تعطيل الخلط، فسيتم استخدام المفتاح لفرز مجموعة البيانات.
-
feature_dict
:dict
يحتوي على قيم المثال.- يجب أن تتطابق البنية مع
features=
البنية المحددة فيtfds.core.DatasetInfo
. - سيتم تشفير أنواع البيانات المعقدة (الصورة، الفيديو، الصوت،...) تلقائيًا.
- غالبًا ما تقبل كل ميزة أنواعًا متعددة من الإدخال (مثل قبول الفيديو
/path/to/vid.mp4
,np.array(shape=(l, h, w, c))
,List[paths]
,List[np.array(shape=(h, w, c)]
,List[img_bytes]
,...) - راجع دليل موصل الميزات لمزيد من المعلومات.
- يجب أن تتطابق البنية مع
def _generate_examples(self, images_path, label_path):
# Read the input data out of the source files
with label_path.open() as f:
for row in csv.DictReader(f):
image_id = row['image_id']
# And yield (key, feature_dict)
yield image_id, {
'image_description': row['description'],
'image': images_path / f'{image_id}.jpeg',
'label': row['label'],
}
الوصول إلى الملفات و tf.io.gfile
من أجل دعم أنظمة التخزين السحابية، تجنب استخدام عمليات الإدخال/الإخراج المضمنة في Python.
بدلاً من ذلك، يقوم dl_manager
بإرجاع كائنات تشبه pathlib المتوافقة مباشرة مع تخزين Google Cloud:
path = dl_manager.download_and_extract('http://some-website/my_data.zip')
json_path = path / 'data/file.json'
json.loads(json_path.read_text())
وبدلاً من ذلك، استخدم tf.io.gfile
API بدلاً من المدمج في عمليات الملفات:
-
open
->tf.io.gfile.GFile
-
os.rename
->tf.io.gfile.rename
- ...
يجب تفضيل Pathlib على tf.io.gfile
(راجع ملف عقلاني .
تبعيات اضافية
تتطلب بعض مجموعات البيانات تبعيات Python إضافية فقط أثناء الإنشاء. على سبيل المثال، تستخدم مجموعة بيانات SVHN scipy
لتحميل بعض البيانات.
إذا كنت تضيف مجموعة بيانات إلى مستودع TFDS، فيرجى استخدام tfds.core.lazy_imports
لإبقاء حزمة tensorflow-datasets
صغيرة. سيقوم المستخدمون بتثبيت تبعيات إضافية حسب الحاجة فقط.
لاستخدام lazy_imports
:
- أضف إدخالاً لمجموعة البيانات الخاصة بك إلى
DATASET_EXTRAS
فيsetup.py
. وهذا يجعل من الممكن للمستخدمين القيام، على سبيل المثال،pip install 'tensorflow-datasets[svhn]'
لتثبيت التبعيات الإضافية. - قم بإضافة إدخال للاستيراد الخاص بك إلى
LazyImporter
وإلىLazyImportsTest
. - استخدم
tfds.core.lazy_imports
للوصول إلى التبعية (على سبيل المثال،tfds.core.lazy_imports.scipy
) فيDatasetBuilder
الخاص بك.
بيانات تالفة
بعض مجموعات البيانات ليست نظيفة تمامًا وتحتوي على بعض البيانات الفاسدة (على سبيل المثال، الصور موجودة في ملفات JPEG ولكن بعضها JPEG غير صالح). يجب تخطي هذه الأمثلة، ولكن اترك ملاحظة في وصف مجموعة البيانات حول عدد الأمثلة التي تم إسقاطها ولماذا.
تكوين/متغيرات مجموعة البيانات (tfds.core.BuilderConfig)
قد تحتوي بعض مجموعات البيانات على متغيرات متعددة، أو خيارات لكيفية معالجة البيانات مسبقًا وكتابتها على القرص. على سبيل المثال، يحتوي Cycle_gan على تكوين واحد لكل زوج من الكائنات ( cycle_gan/horse2zebra
، cycle_gan/monet2photo
،...).
ويتم ذلك من خلال tfds.core.BuilderConfig
s:
قم بتعريف كائن التكوين الخاص بك كفئة فرعية من
tfds.core.BuilderConfig
. على سبيل المثال،MyDatasetConfig
.@dataclasses.dataclass class MyDatasetConfig(tfds.core.BuilderConfig): img_size: Tuple[int, int] = (0, 0)
حدد
BUILDER_CONFIGS = []
عضو الفئة فيMyDataset
الذي يسردMyDatasetConfig
s التي تكشفها مجموعة البيانات.class MyDataset(tfds.core.GeneratorBasedBuilder): VERSION = tfds.core.Version('1.0.0') # pytype: disable=wrong-keyword-args BUILDER_CONFIGS = [ # `name` (and optionally `description`) are required for each config MyDatasetConfig(name='small', description='Small ...', img_size=(8, 8)), MyDatasetConfig(name='big', description='Big ...', img_size=(32, 32)), ] # pytype: enable=wrong-keyword-args
استخدم
self.builder_config
فيMyDataset
لتكوين إنشاء البيانات (على سبيل المثال،shape=self.builder_config.img_size
). قد يتضمن ذلك تعيين قيم مختلفة في_info()
أو تغيير الوصول إلى بيانات التنزيل.
ملحوظات:
- كل تكوين له اسم فريد. الاسم المؤهل بالكامل للتكوين هو
dataset_name/config_name
(على سبيل المثالcoco/2017
). - إذا لم يتم تحديده، فسيتم استخدام التكوين الأول في
BUILDER_CONFIGS
(على سبيل المثال،tfds.load('c4')
الافتراضي هوc4/en
)
راجع anli
للحصول على مثال لمجموعة بيانات تستخدم BuilderConfig
s.
إصدار
يمكن أن يشير الإصدار إلى معنيين مختلفين:
- إصدار البيانات الأصلية "الخارجية": على سبيل المثال COCO v2019، v2017،...
- إصدار كود TFDS "الداخلي": على سبيل المثال، إعادة تسمية ميزة في
tfds.features.FeaturesDict
، وإصلاح الخلل في_generate_examples
لتحديث مجموعة بيانات:
- بالنسبة لتحديث البيانات "الخارجية": قد يرغب عدة مستخدمين في الوصول إلى سنة/إصدار محدد في وقت واحد. يتم ذلك عن طريق استخدام
tfds.core.BuilderConfig
واحد لكل إصدار (على سبيل المثالcoco/2017
,coco/2019
) أو فئة واحدة لكل إصدار (على سبيل المثالVoc2007
,Voc2012
). - بالنسبة لتحديث الكود "الداخلي": يقوم المستخدمون بتنزيل الإصدار الأحدث فقط. يجب أن يؤدي أي تحديث للتعليمات البرمجية إلى زيادة سمة فئة
VERSION
(على سبيل المثال، من1.0.0
إلىVERSION = tfds.core.Version('2.0.0')
) بعد الإصدار الدلالي .
إضافة استيراد للتسجيل
لا تنس استيراد وحدة مجموعة البيانات إلى مشروعك __init__
ليتم تسجيلها تلقائيًا في tfds.load
, tfds.builder
.
import my_project.datasets.my_dataset # Register MyDataset
ds = tfds.load('my_dataset') # MyDataset available
على سبيل المثال، إذا كنت تساهم في tensorflow/datasets
، فأضف استيراد الوحدة النمطية إلى دليلها الفرعي __init__.py
(على سبيل المثال image/__init__.py
.
تحقق من وجود أخطاء التنفيذ الشائعة
يرجى التحقق من الأخطاء الشائعة في التنفيذ .
اختبر مجموعة البيانات الخاصة بك
التنزيل والتحضير: tfds build
لإنشاء مجموعة البيانات، قم بتشغيل tfds build
من الدليل my_dataset/
:
cd path/to/datasets/my_dataset/
tfds build --register_checksums
بعض العلامات المفيدة للتنمية:
-
--pdb
: أدخل في وضع التصحيح في حالة ظهور استثناء. -
--overwrite
: احذف الملفات الموجودة إذا تم إنشاء مجموعة البيانات بالفعل. -
--max_examples_per_split
: قم بإنشاء أمثلة X الأولى فقط (الافتراضي هو 1)، بدلاً من مجموعة البيانات الكاملة. -
--register_checksums
: سجل المجموع الاختباري لعناوين url التي تم تنزيلها. يجب استخدامه فقط أثناء التطوير.
راجع وثائق CLI للحصول على القائمة الكاملة للأعلام.
المجاميع الاختبارية
يوصى بتسجيل المجموع الاختباري لمجموعات البيانات الخاصة بك لضمان الحتمية والمساعدة في التوثيق... ويتم ذلك عن طريق إنشاء مجموعة البيانات باستخدام --register_checksums
(راجع القسم السابق).
إذا كنت تقوم بإصدار مجموعات البيانات الخاصة بك من خلال PyPI، فلا تنس تصدير ملفات checksums.tsv
(على سبيل المثال، في package_data
الخاص بـ setup.py
).
وحدة اختبار مجموعة البيانات الخاصة بك
tfds.testing.DatasetBuilderTestCase
عبارة عن TestCase
أساسي لممارسة مجموعة البيانات بشكل كامل. ويستخدم "بيانات وهمية" كبيانات اختبار تحاكي بنية مجموعة البيانات المصدر.
- يجب وضع بيانات الاختبار في الدليل
my_dataset/dummy_data/
ويجب أن تحاكي عناصر مجموعة البيانات المصدر كما تم تنزيلها واستخراجها. يمكن إنشاؤه يدويًا أو تلقائيًا باستخدام برنامج نصي ( مثال للبرنامج النصي ). - تأكد من استخدام بيانات مختلفة في تقسيمات بيانات الاختبار، حيث سيفشل الاختبار إذا تداخلت تقسيمات مجموعة البيانات.
- يجب ألا تحتوي بيانات الاختبار على أي مواد محمية بحقوق الطبع والنشر . إذا كان لديك شك، فلا تقم بإنشاء البيانات باستخدام مواد من مجموعة البيانات الأصلية.
import tensorflow_datasets as tfds
from . import my_dataset_dataset_builder
class MyDatasetTest(tfds.testing.DatasetBuilderTestCase):
"""Tests for my_dataset dataset."""
DATASET_CLASS = my_dataset_dataset_builder.Builder
SPLITS = {
'train': 3, # Number of fake train example
'test': 1, # Number of fake test example
}
# If you are calling `download/download_and_extract` with a dict, like:
# dl_manager.download({'some_key': 'http://a.org/out.txt', ...})
# then the tests needs to provide the fake output paths relative to the
# fake data directory
DL_EXTRACT_RESULT = {
'name1': 'path/to/file1', # Relative to my_dataset/dummy_data dir.
'name2': 'file2',
}
if __name__ == '__main__':
tfds.testing.test_main()
قم بتشغيل الأمر التالي لاختبار مجموعة البيانات.
python my_dataset_test.py
أرسل لنا ردود الفعل
نحن نحاول باستمرار تحسين سير عمل إنشاء مجموعة البيانات، ولكن لا يمكننا القيام بذلك إلا إذا كنا على دراية بالمشكلات. ما المشكلات أو الأخطاء التي واجهتها أثناء إنشاء مجموعة البيانات؟ هل كان هناك جزء مربك، أو لم يكن يعمل في المرة الأولى؟
يرجى مشاركة ملاحظاتك على جيثب .