大模型-应用-加载数据

在我们进行大模型的训练或微调的过程中,第一步就是要准备自己的训练数据集并导入到代码中。
而 datasets 是huggingface开发的一个数据集python库,可以很方便的从Hugging Face Hub里下载数据,也可很方便的从本地加载数据集,本文主要对load_dataset方法的使用进行详细说明。

load_dataset的参数说明如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def load_dataset(
path: str,
name: Optional[str] = None,
data_dir: Optional[str] = None,
data_files: Union[Dict, List] = None,
split: Optional[Union[str, Split]] = None,
cache_dir: Optional[str] = None,
features: Optional[Features] = None,
download_config: Optional[DownloadConfig] = None,
download_mode: Optional[GenerateMode] = None,
ignore_verifications: bool = False,
save_infos: bool = False,
script_version: Optional[Union[str, Version]] = None,
**config_kwargs,
) -> Union[DatasetDict, Dataset]:

常用且比较重要的参数如下:

  • path
    参数path表示数据集的名字或者路径。可以是如下几种形式(每种形式的使用方式后面会详细说明)
    数据集的名字,比如imdb、glue
    数据集文件格式,比如json、csv、parquet、txt
    数据集目录中的处理数据集的脚本(.py)文件,比如“glue/glue.py”

  • name:参数name表示数据集中的子数据集,当一个数据集包含多个数据集时,就需要这个参数,比如glue数据集下就包含”sst2”、“cola”、”qqp”等多个子数据集,此时就需要指定name来表示加载哪一个子数据集

  • data_dir:数据集所在的目录
  • data_files:数据集文件
  • cache_dir:构建的数据集缓存目录,方便下次快速加载

示例

查看数据集

1
2
3
4
5
from datasets import list_datasets

datasets_list = list_datasets()
print( len(datasets_list))
print(datasets_list[:10])

我们就可以得到 hugging Face上的所有数据集列表

1
2
47660
['acronym_identification', 'ade_corpus_v2', 'adversarial_qa', 'aeslc', 'afrikaans_ner_corpus', 'ag_news', 'ai2_arc', 'air_dialogue', 'ajgt_twitter_ar', 'allegro_reviews']

下载数据集

官方下载

后面通过直接指定 path 等于相关数据集的名字就能下载并加载相关数据集

1
2
from datasets import load_dataset
dataset = load_dataset(path='squad', split='train')

本地加载数据集

加载指定格式的文件

用path参数指定数据集格式
- son格式,path="json"
- csv格式, path="csv"
- 纯文本格式, path="text"
- dataframe格式, path="panda"
- 图片,path="imagefolder"

然后用data_files指定文件名称,data_files可以是字符串,列表或者字典,data_dir指定数据集目录。如下case
1
2
3
4
5
from datasets import load_dataset
dataset = load_dataset('csv', data_files='my_file.csv') #加载一个文件,默认数据集名称为 train
dataset = load_dataset('csv', data_files=['my_file_1.csv', 'my_file_2.csv', 'my_file_3.csv']) # 所有数据都会汇集到 train 数据集中
dataset = load_dataset('csv', data_files={'train':['my_train_file_1.csv','my_train_file_2.csv'],'test': 'my_test_file.csv'}) # 加载多个文件并指定数据集名称
dataset = load_dataset("csv",data_dir="path/2/data/") # 加载目录下的所有csv类型文件,文件名前缀作为数据集名称

加载图片

如下我们通过打开指定图片目录进行加载图片数据集

1
2
3
4
dataset = load_dataset(path="imagefolder",
data_dir="D:\Desktop\workspace\code\loaddataset\data\images")
print(dataset)
print(dataset["train"][0])

很多情况下加载图片并非只要图片,还会有对应的文本,比如在图片分类的时候,每张图片都对应一个类别。这种情况我们需要在图片所在文件夹中加入一个metadata.jsonl的文件,来指定每个图片对应的类别,格式如下,注意file_name字段必须要有,其他字段可自行命名

1
2
3
4
5
6
7
8
{
"file_name": "1.jpg",
"class": 1
}
{
"file_name": "2.png",
"class": 0
}

复杂数据加载

一些情况下加载数据集的逻辑较为复杂,需要自定义加载方式。比如训练ControlNet时,输入有原始图片,边缘图,以及prompt,这时候我们就需要通过在图片所在的目录下写一个python脚本来处理数据加载方式。
如下所示,我们数据处理需要是,每条数据包括两张图片,一个文本。
step1: 首先我们先创建一个json文件train.jsonl,把图片和文本对应起来,json文件的格式如下所示

1
2
3
{"text": "pale golden rod circle with old lace background", "image": "images/0.png", "conditioning_image": "conditioning_images/0.png"}
{"text": "light coral circle with white background", "image": "images/1.png", "conditioning_image": "conditioning_images/1.png"}
{"text": "aqua circle with light pink background", "image": "images/2.png", "conditioning_image": "conditioning_images/2.png"}

step2:创建一个python脚本fill50k.py根据json文件中的对应关系加载图片,python脚本如下所示,这个脚本中定义一个 Fill50k类,并继承datasets.GeneratorBasedBuilder,在类中重写_info(self): _split_generators(self, dl_manager)和_split_generators(self, dl_manager)这三个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import pandas as pd
import datasets
import os
import logging

# 数据集路径设置
META_DATA_PATH = "D:\Desktop\workspace\code\loaddataset\\fill50k\\train.jsonl"
IMAGE_DIR = "D:\Desktop\workspace\code\loaddataset\\fill50k"
CONDITION_IMAGE_DIR = "D:\Desktop\workspace\code\loaddataset\\fill50k"


# 定义数据集中有哪些特征,及其类型
_FEATURES = datasets.Features(
{
"image": datasets.Image(),
"conditioning_image": datasets.Image(),
"text": datasets.Value("string"),
},
)


# 定义数据集
class Fill50k(datasets.GeneratorBasedBuilder):
BUILDER_CONFIGS = [datasets.BuilderConfig(name="default", version=datasets.Version("0.0.2"))]
DEFAULT_CONFIG_NAME = "default"

def _info(self):
return datasets.DatasetInfo(
description="None",
features=_FEATURES,
supervised_keys=None,
homepage="None",
license="None",
citation="None",
)

def _split_generators(self, dl_manager):

return [
datasets.SplitGenerator(
name=datasets.Split.TRAIN,
# These kwargs will be passed to _generate_examples
gen_kwargs={
"metadata_path": META_DATA_PATH,
"images_dir": IMAGE_DIR,
"conditioning_images_dir": CONDITION_IMAGE_DIR,
},
),
]

def _generate_examples(self, metadata_path, images_dir, conditioning_images_dir):
metadata = pd.read_json(metadata_path, lines=True)

for _, row in metadata.iterrows():
text = row["text"]

image_path = row["image"]
image_path = os.path.join(images_dir, image_path)

# 打开文件错误时直接跳过
try:
image = open(image_path, "rb").read()
except Exception as e:
logging.error(e)
continue

conditioning_image_path = os.path.join(
conditioning_images_dir, row["conditioning_image"]
)

# 打开文件错误直接跳过
try:
conditioning_image = open(conditioning_image_path, "rb").read()
except Exception as e:
logging.error(e)
continue

yield row["image"], {
"text": text,
"image": {
"path": image_path,
"bytes": image,
},
"conditioning_image": {
"path": conditioning_image_path,
"bytes": conditioning_image,
},
}

step3: 通过load_dataset加载数据集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
dataset = load_dataset(path="D:\Desktop\workspace\code\loaddataset\\fill50k\\fill50k.py",
cache_dir="D:\Desktop\workspace\code\loaddataset\\fill50k\cache")
print(dataset)
print(dataset["train"][0])


# 历史问题及相关处理记录
## datasets-2.11.0 本地文件系统不支持
```python
>>> dataset = load_dataset("csv",data_dir=data_dir,data_files=data_files)
Downloading and preparing dataset csv/default to file:///home/phoenix/.cache/huggingface/datasets/csv/default-df2512f4672b5719/0.0.0/6954658bab30a358235fa864b05cf819af0e179325c740e4bc853bcc7ec513e1...
Downloading data files: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 7839.82it/s]
Extracting data files: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1653.91it/s]
Dataset csv downloaded and prepared to file:///home/phoenix/.cache/huggingface/datasets/csv/default-df2512f4672b5719/0.0.0/6954658bab30a358235fa864b05cf819af0e179325c740e4bc853bcc7ec513e1. Subsequent calls will reuse this data.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/phoenix/anaconda3/envs/liubo_llm/lib/python3.8/site-packages/datasets/load.py", line 1804, in load_dataset
ds = builder_instance.as_dataset(split=split, verification_mode=verification_mode, in_memory=keep_in_memory)
File "/home/phoenix/anaconda3/envs/liubo_llm/lib/python3.8/site-packages/datasets/builder.py", line 1108, in as_dataset
raise NotImplementedError(f"Loading a dataset cached in a {type(self._fs).__name__} is not supported.")
NotImplementedError: Loading a dataset cached in a LocalFileSystem is not supported.

datasets 新版本已解决,安装旧版本datasets导致,进行版本升级即可 pip install -U datasets 。测试升级至 datasets-2.20.0 问题解决。

-------------本文结束感谢您的阅读-------------