llm load_datasetからdata_collatorまで
概要
llmを学習する際にデータをロードしてmodelにデータを渡すまでの流れをまとめました。
今までなんとなくの雰囲気でやっていたので、整理するためのメモです。
load_dataset
Hugging Face Hubまたはローカルファイルから学習データをロードする。
実行例
from datasets import load_dataset
Hugging Face Hubからロード。
DatasetDictが返る。
dataset_dict = load_dataset('kunishou/databricks-dolly-15k-ja')
print(dataset_dict)
print(dataset_dict['train'])
DatasetDict({
train: Dataset({
features: ['index', 'category', 'instruction', 'input', 'output'],
num_rows: 15015
})
})
Dataset({
features: ['index', 'category', 'instruction', 'input', 'output'],
num_rows: 15015
})
splitを指定した場合、Datasetが返る。
dataset = load_dataset('kunishou/databricks-dolly-15k-ja', split='train')
print(dataset)
Dataset({
features: ['index', 'category', 'instruction', 'input', 'output'],
num_rows: 15015
})
データ抽出。
for data in dataset.select(range(5)):
print(data)
{'index': '0', 'category': 'closed_qa', 'instruction': 'ヴァージン・オーストラリア航空はいつから運航を開始したのですか?', 'input': 'ヴァージン・オーストラリア航空(Virgin Australia Airlines Pty Ltd)はオーストラリアを拠点とするヴァージン・ブランドを冠する最大の船団規模を持つ航空会社です。2000年8月31日に、ヴァージン・ブルー空港として、2機の航空機、1つの空路を運行してサービスを開始しました。2001年9月のアンセット・オーストラリア空港の崩壊後、オーストラリアの国内市場で急速に地位を確立しました。その後はブリスベン、メルボルン、シドニーをハブとして、オーストラリア国内の32都市に直接乗り入れるまでに成長しました。', 'output': 'ヴァージン・オーストラリア航空は、2000年8月31日にヴァージン・ブルー航空として、2機の航空機で単一路線の運航を開始しました。'}
{'index': '1', 'category': 'classification', 'instruction': '魚の種類はどっち?イコクエイラクブカとロープ', 'input': '', 'output': 'イコクエイラクブカ'}
{'index': '2', 'category': 'open_qa', 'instruction': 'ラクダはなぜ水なしで長く生きられるのか?', 'input': '', 'output': 'ラクダは、長時間にわたってエネルギーと水分で満たされた状態を保つために、腰の脂肪を利用しています。'}
{'index': '3', 'category': 'open_qa', 'instruction': 'アリスの両親には3人の娘がいる:エイミー、ジェシー、そして三女の名前は?', 'input': '', 'output': '三女の名前はアリス'}
{'index': '4', 'category': 'closed_qa', 'instruction': '小森田友明はいつ生まれたの?', 'input': '小森田は1981年7月10日、熊本県に生まれる。高校卒業後、2000年にJ1リーグのアビスパ福岡に入団。2001年にMFとしてデビューするも、出番は少なく、2001年シーズン終了後にJ2リーグに降格する。2002年、J2の大分トリニータに移籍。守備的MFとしてレギュラーに定着し、2002年に優勝、2003年に昇格を果たす。2005年まで多くの試合に出場した。2005年9月、J2のモンテディオ山形に移籍。2006年、J2のヴィッセル神戸へ移籍。守備的ミッドフィルダーとしてレギュラーになったものの、夏には徐々に出番が少なくなっていった。2007年、地元に本拠地を置く日本フットボールリーグのロッソ熊本(後のロアッソ熊本)へ移籍。レギュラーとして活躍し、2008年にはクラブはJ2に昇格した。その後は出場機会は限られたものの、多くの試合に出場した。2010年、インドネシアに渡り、ペルセラ・ラモンガンに移籍。2010年7月、日本に戻り、J2のギラヴァンツ北九州に入団。2012年に引退するまで、守備的ミッドフィルダーやセンターバックとして多くの試合に出場した。', 'output': '小森田友明は1981年7月10日に生まれました。'}
ローカルファイルからのロード。
# ロードするためのファイルを設置する
%%writefile sample.csv
名前,年齢,都市
山田太郎,25,東京
鈴木一郎,30,大阪
佐藤花子,22,福岡
dataset_dict = load_dataset('csv', data_files='./sample.csv')
dataset_dict
DatasetDict({
train: Dataset({
features: ['名前', '年齢', '都市'],
num_rows: 3
})
})
プログラマブルに作成。
こういうデータセットを過学習させて、訓練がうまくいくことを確認すると良い。
from datasets import Dataset
def gen():
yield {"prompt": "何がコラじゃコラ?", "response": "何コラタココラ!"}
train_dataset = Dataset.from_generator(gen)
データセットのフィルタ
from datasets import Dataset
def gen():
yield {"prompt": "prefix prompt1", "response": "test"}
yield {"prompt": "prefix prompt2", "response": "test"}
yield {"prompt": "prompt3", "response": "test"}
train_dataset = Dataset.from_generator(gen)
def filter_method(example):
return example['prompt'].startswith('prefix')
train_dataset = train_dataset.filter(filter_method)
streaming=True
streaming=True
を指定するとデータのロードは行わず、IterableDatasetが返る。
iterable_dataset = load_dataset('kunishou/databricks-dolly-15k-ja', split='train', streaming=True)
print(iterable_dataset)
IterableDataset({
features: ['index', 'category', 'instruction', 'input', 'output'],
n_shards: 1
})
for data in iterable_dataset.take(5):
print(data)
{'index': '0', 'category': 'closed_qa', 'instruction': 'ヴァージン・オーストラリア航空はいつから運航を開始したのですか?', 'input': 'ヴァージン・オーストラリア航空(Virgin Australia Airlines Pty Ltd)はオーストラリアを拠点とするヴァージン・ブランドを冠する最大の船団規模を持つ航空会社です。2000年8月31日に、ヴァージン・ブルー空港として、2機の航空機、1つの空路を運行してサービスを開始しました。2001年9月のアンセット・オーストラリア空港の崩壊後、オーストラリアの国内市場で急速に地位を確立しました。その後はブリスベン、メルボルン、シドニーをハブとして、オーストラリア国内の32都市に直接乗り入れるまでに成長しました。', 'output': 'ヴァージン・オーストラリア航空は、2000年8月31日にヴァージン・ブルー航空として、2機の航空機で単一路線の運航を開始しました。'}
{'index': '1', 'category': 'classification', 'instruction': '魚の種類はどっち?イコクエイラクブカとロープ', 'input': '', 'output': 'イコクエイラクブカ'}
{'index': '2', 'category': 'open_qa', 'instruction': 'ラクダはなぜ水なしで長く生きられるのか?', 'input': '', 'output': 'ラクダは、長時間にわたってエネルギーと水分で満たされた状態を保つために、腰の脂肪を利用しています。'}
{'index': '3', 'category': 'open_qa', 'instruction': 'アリスの両親には3人の娘がいる:エイミー、ジェシー、そして三女の名前は?', 'input': '', 'output': '三女の名前はアリス'}
{'index': '4', 'category': 'closed_qa', 'instruction': '小森田友明はいつ生まれたの?', 'input': '小森田は1981年7月10日、熊本県に生まれる。高校卒業後、2000年にJ1リーグのアビスパ福岡に入団。2001年にMFとしてデビューするも、出番は少なく、2001年シーズン終了後にJ2リーグに降格する。2002年、J2の大分トリニータに移籍。守備的MFとしてレギュラーに定着し、2002年に優勝、2003年に昇格を果たす。2005年まで多くの試合に出場した。2005年9月、J2のモンテディオ山形に移籍。2006年、J2のヴィッセル神戸へ移籍。守備的ミッドフィルダーとしてレギュラーになったものの、夏には徐々に出番が少なくなっていった。2007年、地元に本拠地を置く日本フットボールリーグのロッソ熊本(後のロアッソ熊本)へ移籍。レギュラーとして活躍し、2008年にはクラブはJ2に昇格した。その後は出場機会は限られたものの、多くの試合に出場した。2010年、インドネシアに渡り、ペルセラ・ラモンガンに移籍。2010年7月、日本に戻り、J2のギラヴァンツ北九州に入団。2012年に引退するまで、守備的ミッドフィルダーやセンターバックとして多くの試合に出場した。', 'output': '小森田友明は1981年7月10日に生まれました。'}
dataset.map
Datasetを加工して新たなDatasetを返す。
実行例
渡した関数の戻り値(dictionary)で、元のデータセットのレコードに属性を追加する。
元々存在する属性の場合は上書きになる。
def f(example):
return {'add_column': f"add_culumn {example['index']}"}
mapped_dataset = dataset.map(f)
print(mapped_dataset)
print('mapped_dataset')
for data in mapped_dataset.select(range(5)):
print(data)
# 元のデータセットは変わらない
print('dataset')
for data in dataset.select(range(5)):
print(data)
Dataset({
features: ['index', 'category', 'instruction', 'input', 'output', 'add_column'],
num_rows: 15015
})
mapped_dataset
{'index': '0', 'category': 'closed_qa', 'instruction': 'ヴァージン・オーストラリア航空はいつから運航を開始したのですか?', 'input': 'ヴァージン・オーストラリア航空(Virgin Australia Airlines Pty Ltd)はオーストラリアを拠点とするヴァージン・ブランドを冠する最大の船団規模を持つ航空会社です。2000年8月31日に、ヴァージン・ブルー空港として、2機の航空機、1つの空路を運行してサービスを開始しました。2001年9月のアンセット・オーストラリア空港の崩壊後、オーストラリアの国内市場で急速に地位を確立しました。その後はブリスベン、メルボルン、シドニーをハブとして、オーストラリア国内の32都市に直接乗り入れるまでに成長しました。', 'output': 'ヴァージン・オーストラリア航空は、2000年8月31日にヴァージン・ブルー航空として、2機の航空機で単一路線の運航を開始しました。', 'add_column': 'add_culumn 0'}
{'index': '1', 'category': 'classification', 'instruction': '魚の種類はどっち?イコクエイラクブカとロープ', 'input': '', 'output': 'イコクエイラクブカ', 'add_column': 'add_culumn 1'}
{'index': '2', 'category': 'open_qa', 'instruction': 'ラクダはなぜ水なしで長く生きられるのか?', 'input': '', 'output': 'ラクダは、長時間にわたってエネルギーと水分で満たされた状態を保つために、腰の脂肪を利用しています。', 'add_column': 'add_culumn 2'}
{'index': '3', 'category': 'open_qa', 'instruction': 'アリスの両親には3人の娘がいる:エイミー、ジェシー、そして三女の名前は?', 'input': '', 'output': '三女の名前はアリス', 'add_column': 'add_culumn 3'}
{'index': '4', 'category': 'closed_qa', 'instruction': '小森田友明はいつ生まれたの?', 'input': '小森田は1981年7月10日、熊本県に生まれる。高校卒業後、2000年にJ1リーグのアビスパ福岡に入団。2001年にMFとしてデビューするも、出番は少なく、2001年シーズン終了後にJ2リーグに降格する。2002年、J2の大分トリニータに移籍。守備的MFとしてレギュラーに定着し、2002年に優勝、2003年に昇格を果たす。2005年まで多くの試合に出場した。2005年9月、J2のモンテディオ山形に移籍。2006年、J2のヴィッセル神戸へ移籍。守備的ミッドフィルダーとしてレギュラーになったものの、夏には徐々に出番が少なくなっていった。2007年、地元に本拠地を置く日本フットボールリーグのロッソ熊本(後のロアッソ熊本)へ移籍。レギュラーとして活躍し、2008年にはクラブはJ2に昇格した。その後は出場機会は限られたものの、多くの試合に出場した。2010年、インドネシアに渡り、ペルセラ・ラモンガンに移籍。2010年7月、日本に戻り、J2のギラヴァンツ北九州に入団。2012年に引退するまで、守備的ミッドフィルダーやセンターバックとして多くの試合に出場した。', 'output': '小森田友明は1981年7月10日に生まれました。', 'add_column': 'add_culumn 4'}
dataset
{'index': '0', 'category': 'closed_qa', 'instruction': 'ヴァージン・オーストラリア航空はいつから運航を開始したのですか?', 'input': 'ヴァージン・オーストラリア航空(Virgin Australia Airlines Pty Ltd)はオーストラリアを拠点とするヴァージン・ブランドを冠する最大の船団規模を持つ航空会社です。2000年8月31日に、ヴァージン・ブルー空港として、2機の航空機、1つの空路を運行してサービスを開始しました。2001年9月のアンセット・オーストラリア空港の崩壊後、オーストラリアの国内市場で急速に地位を確立しました。その後はブリスベン、メルボルン、シドニーをハブとして、オーストラリア国内の32都市に直接乗り入れるまでに成長しました。', 'output': 'ヴァージン・オーストラリア航空は、2000年8月31日にヴァージン・ブルー航空として、2機の航空機で単一路線の運航を開始しました。'}
{'index': '1', 'category': 'classification', 'instruction': '魚の種類はどっち?イコクエイラクブカとロープ', 'input': '', 'output': 'イコクエイラクブカ'}
{'index': '2', 'category': 'open_qa', 'instruction': 'ラクダはなぜ水なしで長く生きられるのか?', 'input': '', 'output': 'ラクダは、長時間にわたってエネルギーと水分で満たされた状態を保つために、腰の脂肪を利用しています。'}
{'index': '3', 'category': 'open_qa', 'instruction': 'アリスの両親には3人の娘がいる:エイミー、ジェシー、そして三女の名前は?', 'input': '', 'output': '三女の名前はアリス'}
{'index': '4', 'category': 'closed_qa', 'instruction': '小森田友明はいつ生まれたの?', 'input': '小森田は1981年7月10日、熊本県に生まれる。高校卒業後、2000年にJ1リーグのアビスパ福岡に入団。2001年にMFとしてデビューするも、出番は少なく、2001年シーズン終了後にJ2リーグに降格する。2002年、J2の大分トリニータに移籍。守備的MFとしてレギュラーに定着し、2002年に優勝、2003年に昇格を果たす。2005年まで多くの試合に出場した。2005年9月、J2のモンテディオ山形に移籍。2006年、J2のヴィッセル神戸へ移籍。守備的ミッドフィルダーとしてレギュラーになったものの、夏には徐々に出番が少なくなっていった。2007年、地元に本拠地を置く日本フットボールリーグのロッソ熊本(後のロアッソ熊本)へ移籍。レギュラーとして活躍し、2008年にはクラブはJ2に昇格した。その後は出場機会は限られたものの、多くの試合に出場した。2010年、インドネシアに渡り、ペルセラ・ラモンガンに移籍。2010年7月、日本に戻り、J2のギラヴァンツ北九州に入団。2012年に引退するまで、守備的ミッドフィルダーやセンターバックとして多くの試合に出場した。', 'output': '小森田友明は1981年7月10日に生まれました。'}
input_columns
渡した関数の引数(positional arguments)として渡す属性を指定する。
def f2(index, category):
return {'add_column': f"add_culumn {index} {category}"}
dataset_with_input_columns = dataset.map(f2, input_columns=['index', 'category'])
print(dataset_with_input_columns)
print('dataset_with_input_columns')
for data in dataset_with_input_columns.select(range(5)):
print(data)
Dataset({
features: ['index', 'category', 'instruction', 'input', 'output', 'add_column'],
num_rows: 15015
})
dataset_with_input_columns
{'index': '0', 'category': 'closed_qa', 'instruction': 'ヴァージン・オーストラリア航空はいつから運航を開始したのですか?', 'input': 'ヴァージン・オーストラリア航空(Virgin Australia Airlines Pty Ltd)はオーストラリアを拠点とするヴァージン・ブランドを冠する最大の船団規模を持つ航空会社です。2000年8月31日に、ヴァージン・ブルー空港として、2機の航空機、1つの空路を運行してサービスを開始しました。2001年9月のアンセット・オーストラリア空港の崩壊後、オーストラリアの国内市場で急速に地位を確立しました。その後はブリスベン、メルボルン、シドニーをハブとして、オーストラリア国内の32都市に直接乗り入れるまでに成長しました。', 'output': 'ヴァージン・オーストラリア航空は、2000年8月31日にヴァージン・ブルー航空として、2機の航空機で単一路線の運航を開始しました。', 'add_column': 'add_culumn 0 closed_qa'}
{'index': '1', 'category': 'classification', 'instruction': '魚の種類はどっち?イコクエイラクブカとロープ', 'input': '', 'output': 'イコクエイラクブカ', 'add_column': 'add_culumn 1 classification'}
{'index': '2', 'category': 'open_qa', 'instruction': 'ラクダはなぜ水なしで長く生きられるのか?', 'input': '', 'output': 'ラクダは、長時間にわたってエネルギーと水分で満たされた状態を保つために、腰の脂肪を利用しています。', 'add_column': 'add_culumn 2 open_qa'}
{'index': '3', 'category': 'open_qa', 'instruction': 'アリスの両親には3人の娘がいる:エイミー、ジェシー、そして三女の名前は?', 'input': '', 'output': '三女の名前はアリス', 'add_column': 'add_culumn 3 open_qa'}
{'index': '4', 'category': 'closed_qa', 'instruction': '小森田友明はいつ生まれたの?', 'input': '小森田は1981年7月10日、熊本県に生まれる。高校卒業後、2000年にJ1リーグのアビスパ福岡に入団。2001年にMFとしてデビューするも、出番は少なく、2001年シーズン終了後にJ2リーグに降格する。2002年、J2の大分トリニータに移籍。守備的MFとしてレギュラーに定着し、2002年に優勝、2003年に昇格を果たす。2005年まで多くの試合に出場した。2005年9月、J2のモンテディオ山形に移籍。2006年、J2のヴィッセル神戸へ移籍。守備的ミッドフィルダーとしてレギュラーになったものの、夏には徐々に出番が少なくなっていった。2007年、地元に本拠地を置く日本フットボールリーグのロッソ熊本(後のロアッソ熊本)へ移籍。レギュラーとして活躍し、2008年にはクラブはJ2に昇格した。その後は出場機会は限られたものの、多くの試合に出場した。2010年、インドネシアに渡り、ペルセラ・ラモンガンに移籍。2010年7月、日本に戻り、J2のギラヴァンツ北九州に入団。2012年に引退するまで、守備的ミッドフィルダーやセンターバックとして多くの試合に出場した。', 'output': '小森田友明は1981年7月10日に生まれました。', 'add_column': 'add_culumn 4 closed_qa'}
remove_columns
削除する属性を指定する。
def f3(example):
return {'add_column': f"add_culumn {example['index']}"}
dataset_with_remove_columns = dataset.map(f3, remove_columns=['category', 'instruction'])
print(dataset_with_remove_columns)
print('dataset_with_remove_columns')
for data in dataset_with_remove_columns.select(range(5)):
print(data)
Dataset({
features: ['index', 'input', 'output', 'add_column'],
num_rows: 15015
})
dataset_with_remove_columns
{'index': '0', 'input': 'ヴァージン・オーストラリア航空(Virgin Australia Airlines Pty Ltd)はオーストラリアを拠点とするヴァージン・ブランドを冠する最大の船団規模を持つ航空会社です。2000年8月31日に、ヴァージン・ブルー空港として、2機の航空機、1つの空路を運行してサービスを開始しました。2001年9月のアンセット・オーストラリア空港の崩壊後、オーストラリアの国内市場で急速に地位を確立しました。その後はブリスベン、メルボルン、シドニーをハブとして、オーストラリア国内の32都市に直接乗り入れるまでに成長しました。', 'output': 'ヴァージン・オーストラリア航空は、2000年8月31日にヴァージン・ブルー航空として、2機の航空機で単一路線の運航を開始しました。', 'add_column': 'add_culumn 0'}
{'index': '1', 'input': '', 'output': 'イコクエイラクブカ', 'add_column': 'add_culumn 1'}
{'index': '2', 'input': '', 'output': 'ラクダは、長時間にわたってエネルギーと水分で満たされた状態を保つために、腰の脂肪を利用しています。', 'add_column': 'add_culumn 2'}
{'index': '3', 'input': '', 'output': '三女の名前はアリス', 'add_column': 'add_culumn 3'}
{'index': '4', 'input': '小森田は1981年7月10日、熊本県に生まれる。高校卒業後、2000年にJ1リーグのアビスパ福岡に入団。2001年にMFとしてデビューするも、出番は少なく、2001年シーズン終了後にJ2リーグに降格する。2002年、J2の大分トリニータに移籍。守備的MFとしてレギュラーに定着し、2002年に優勝、2003年に昇格を果たす。2005年まで多くの試合に出場した。2005年9月、J2のモンテディオ山形に移籍。2006年、J2のヴィッセル神戸へ移籍。守備的ミッドフィルダーとしてレギュラーになったものの、夏には徐々に出番が少なくなっていった。2007年、地元に本拠地を置く日本フットボールリーグのロッソ熊本(後のロアッソ熊本)へ移籍。レギュラーとして活躍し、2008年にはクラブはJ2に昇格した。その後は出場機会は限られたものの、多くの試合に出場した。2010年、インドネシアに渡り、ペルセラ・ラモンガンに移籍。2010年7月、日本に戻り、J2のギラヴァンツ北九州に入団。2012年に引退するまで、守備的ミッドフィルダーやセンターバックとして多くの試合に出場した。', 'output': '小森田友明は1981年7月10日に生まれました。', 'add_column': 'add_culumn 4'}
batched=True
渡した関数に複数のデータが渡される様になる。
引数のデータ形式が変わるので注意。
戻り値のデータ形式は変わらない。
def f4(batched_example):
print('batched_example')
print(batched_example)
return {'add_column': [ f"add_culumn {index}" for index in batched_example['index'] ]}
mapped_dataset = dataset.select(range(5)).map(f4, batched=True, batch_size=2)
print(mapped_dataset)
print('mapped_dataset')
for data in mapped_dataset:
print(data)
Dataset({
features: ['index', 'category', 'input', 'instruction', 'output', 'add_column'],
num_rows: 5
})
mapped_dataset
{'index': '0', 'category': 'closed_qa', 'input': 'ヴァージン・オーストラリア航空(Virgin Australia Airlines Pty Ltd)はオーストラリアを拠点とするヴァージン・ブランドを冠する最大の船団規模を持つ航空会社です。2000年8月31日に、ヴァージン・ブルー空港として、2機の航空機、1つの空路を運行してサービスを開始しました。2001年9月のアンセット・オーストラリア空港の崩壊後、オーストラリアの国内市場で急速に地位を確立しました。その後はブリスベン、メルボルン、シドニーをハブとして、オーストラリア国内の32都市に直接乗り入れるまでに成長しました。', 'instruction': 'ヴァージン・オーストラリア航空はいつから運航を開始したのですか?', 'output': 'ヴァージン・オーストラリア航空は、2000年8月31日にヴァージン・ブルー航空として、2機の航空機で単一路線の運航を開始しました。', 'add_column': 'add_culumn 0'}
{'index': '1', 'category': 'classification', 'input': '', 'instruction': '魚の種類はどっち?イコクエイラクブカとロープ', 'output': 'イコクエイラクブカ', 'add_column': 'add_culumn 1'}
{'index': '2', 'category': 'open_qa', 'input': '', 'instruction': 'ラクダはなぜ水なしで長く生きられるのか?', 'output': 'ラクダは、長時間にわたってエネルギーと水分で満たされた状態を保つために、腰の脂肪を利用しています。', 'add_column': 'add_culumn 2'}
{'index': '3', 'category': 'open_qa', 'input': '', 'instruction': 'アリスの両親には3人の娘がいる:エイミー、ジェシー、そして三女の名前は?', 'output': '三女の名前はアリス', 'add_column': 'add_culumn 3'}
{'index': '4', 'category': 'closed_qa', 'input': '小森田は1981年7月10日、熊本県に生まれる。高校卒業後、2000年にJ1リーグのアビスパ福岡に入団。2001年にMFとしてデビューするも、出番は少なく、2001年シーズン終了後にJ2リーグに降格する。2002年、J2の大分トリニータに移籍。守備的MFとしてレギュラーに定着し、2002年に優勝、2003年に昇格を果たす。2005年まで多くの試合に出場した。2005年9月、J2のモンテディオ山形に移籍。2006年、J2のヴィッセル神戸へ移籍。守備的ミッドフィルダーとしてレギュラーになったものの、夏には徐々に出番が少なくなっていった。2007年、地元に本拠地を置く日本フットボールリーグのロッソ熊本(後のロアッソ熊本)へ移籍。レギュラーとして活躍し、2008年にはクラブはJ2に昇格した。その後は出場機会は限られたものの、多くの試合に出場した。2010年、インドネシアに渡り、ペルセラ・ラモンガンに移籍。2010年7月、日本に戻り、J2のギラヴァンツ北九州に入団。2012年に引退するまで、守備的ミッドフィルダーやセンターバックとして多くの試合に出場した。', 'instruction': '小森田友明はいつ生まれたの?', 'output': '小森田友明は1981年7月10日に生まれました。', 'add_column': 'add_culumn 4'}
tokenizer.init
トーカナイザの初期化。
実際には以下のようなtokenizer_config.jsonを使って初期化が行われる。
実行例
import torch
from transformers import AutoTokenizer
model_name = "tokyotech-llm/Swallow-7b-instruct-hf"
tokenizer = AutoTokenizer.from_pretrained(model_name)
# ValueError: Asking to pad but the tokenizer does not have a padding token. Please select a token to use as `pad_token` `(tokenizer.pad_token = tokenizer.eos_token e.g.)` or add a new pad token via `tokenizer.add_special_tokens({'pad_token': '[PAD]'})`.
# に対応
tokenizer.pad_token = tokenizer.eos_token
tokenizerの属性
一般的な属性
print('is_fast')
print(tokenizer.is_fast)
print('padding_side')
print(tokenizer.padding_side)
print('truncation_side')
print(tokenizer.truncation_side)
is_fast
True
padding_side
right
truncation_side
right
スペシャルトークン関連
bos_token: beginning of a sentence
eos_token: end of a sentence
unk_token: out-of-vocabulary token
sep_token: separating two different sentences in the same input
pad_token: make arrays of tokens the same size for batching purpose
cls_token: class of the input (used by BERT for instance)
mask_token: masked token (used by masked-language modeling pretraining objectives, like BERT)
print('all_special_tokens')
print(tokenizer.all_special_tokens)
print('all_special_ids')
print(tokenizer.all_special_ids)
print('special_tokens_map')
print(tokenizer.special_tokens_map)
print('additional_special_tokens')
print(tokenizer.additional_special_tokens)
all_special_tokens
['<s>', '</s>', '<unk>']
all_special_ids
[1, 2, 0]
special_tokens_map
{'bos_token': '<s>', 'eos_token': '</s>', 'unk_token': '<unk>'}
additional_special_tokens
[]
tokenizer.call
テキストをトークンIDに変換する。
実行例
batch_encoding = tokenizer('あいうえおかきくけこ')
print(type(batch_encoding))
print(batch_encoding)
decoded_str = tokenizer.decode(batch_encoding["input_ids"])
print(decoded_str)
<class 'transformers.tokenization_utils_base.BatchEncoding'>
{'input_ids': [1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
<s> あいうえおかきくけこ
複数文字列にも対応。
batch_encoding = tokenizer(['あいうえおかきくけこ', 'さしすせそ'])
print(batch_encoding)
decoded_str = tokenizer.decode(batch_encoding["input_ids"][0])
print(decoded_str)
decoded_str = tokenizer.decode(batch_encoding["input_ids"][1])
print(decoded_str)
{'input_ids': [[1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589], [1, 29871, 41059, 30427, 31095, 31110]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1]]}
<s> あいうえおかきくけこ
<s> さしすせそ
padding
最長のトークン長でパディング
padding=True
でも同じ挙動になる。
batch_encoding = tokenizer(['あいうえおかきくけこ', 'さしすせそ'], padding='longest')
print(batch_encoding)
print(len(batch_encoding["input_ids"][0]))
decoded_str = tokenizer.decode(batch_encoding["input_ids"][0])
print(decoded_str)
print(len(batch_encoding["input_ids"][1]))
decoded_str = tokenizer.decode(batch_encoding["input_ids"][1])
print(decoded_str)
{'input_ids': [[1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589], [1, 29871, 41059, 30427, 31095, 31110, 2, 2, 2, 2]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 0, 0, 0, 0]]}
10
<s> あいうえおかきくけこ
10
<s> さしすせそ</s></s></s></s>
max_lengthでパディング
batch_encoding = tokenizer(['あいうえおかきくけこ', 'さしすせそ'], padding='max_length', max_length=24)
print(batch_encoding)
print(len(batch_encoding["input_ids"][0]))
decoded_str = tokenizer.decode(batch_encoding["input_ids"][0])
print(decoded_str)
print(len(batch_encoding["input_ids"][1]))
decoded_str = tokenizer.decode(batch_encoding["input_ids"][1])
print(decoded_str)
{'input_ids': [[1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [1, 29871, 41059, 30427, 31095, 31110, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]}
24
<s> あいうえおかきくけこ</s></s></s></s></s></s></s></s></s></s></s></s></s></s>
24
<s> さしすせそ</s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s>
truncation
max_lengthで切り捨て
max_lengthの指定がない場合、モデルが受け付ける最大長で切り捨てられる。
# ValueError: Asking to pad but the tokenizer does not have a padding token. Please select a token to use as `pad_token` `(tokenizer.pad_token = tokenizer.eos_token e.g.)` or add a new pad token via `tokenizer.add_special_tokens({'pad_token': '[PAD]'})`.
# に対応
tokenizer.pad_token = tokenizer.eos_token
batch_encoding = tokenizer(['あいうえおかきくけこ', 'さしすせそ'], truncation='longest_first', max_length=8)
print(batch_encoding)
print(len(batch_encoding["input_ids"][0]))
decoded_str = tokenizer.decode(batch_encoding["input_ids"][0])
print(decoded_str)
print(len(batch_encoding["input_ids"][1]))
decoded_str = tokenizer.decode(batch_encoding["input_ids"][1])
print(decoded_str)
{'input_ids': [[1, 29871, 30641, 32010, 30914, 33242, 30538, 30568], [1, 29871, 41059, 30427, 31095, 31110]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1]]}
8
<s> あいうえおかきく
6
<s> さしすせそ
質問と回答のような形式の場合に質問の方を切り捨てる。
batch_encoding = tokenizer(['あいうえおかきくけこ', 'さしすせそ'], ['アイウエオカキクケコ', 'サシスセソ'], truncation='only_first', max_length=15)
print(batch_encoding)
print(len(batch_encoding["input_ids"][0]))
decoded_str = tokenizer.decode(batch_encoding["input_ids"][0])
print(decoded_str)
print(len(batch_encoding["input_ids"][1]))
decoded_str = tokenizer.decode(batch_encoding["input_ids"][1])
print(decoded_str)
{'input_ids': [[1, 29871, 30641, 32010, 30914, 33242, 1, 29871, 32230, 37288, 41717, 30454, 30305, 30978, 30459], [1, 29871, 41059, 30427, 31095, 31110, 1, 29871, 30615, 37096, 30885, 31051]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]}
15
<s> あいうえおか<s> アイウエオカキクケコ
12
<s> さしすせそ<s> サシスセソ
質問と回答のような形式の場合に回答の方を切り捨てる。
batch_encoding = tokenizer(['あいうえおかきくけこ', 'さしすせそ'], ['アイウエオカキクケコ', 'サシスセソ'], truncation='only_second', max_length=15)
print(batch_encoding)
print(len(batch_encoding["input_ids"][0]))
decoded_str = tokenizer.decode(batch_encoding["input_ids"][0])
print(decoded_str)
print(len(batch_encoding["input_ids"][1]))
decoded_str = tokenizer.decode(batch_encoding["input_ids"][1])
print(decoded_str)
{'input_ids': [[1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589, 1, 29871, 32230, 37288, 41717], [1, 29871, 41059, 30427, 31095, 31110, 1, 29871, 30615, 37096, 30885, 31051]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]}
15
<s> あいうえおかきくけこ<s> アイウエオカ
12
<s> さしすせそ<s> サシスセソ
return_overflowing_tokens=True
truncation=True
時にmax_lengthから溢れたトークンを分割して返す。
batch_encoding = tokenizer(['あいうえおかきくけこ', 'さしすせそ'], truncation=True, max_length=8, return_overflowing_tokens=True)
print(batch_encoding)
print(len(batch_encoding["input_ids"][0]))
decoded_str = tokenizer.decode(batch_encoding["input_ids"][0])
print(decoded_str)
print(len(batch_encoding["input_ids"][1]))
decoded_str = tokenizer.decode(batch_encoding["input_ids"][1])
print(decoded_str)
print(len(batch_encoding["input_ids"][2]))
decoded_str = tokenizer.decode(batch_encoding["input_ids"][2])
print(decoded_str)
{'input_ids': [[1, 29871, 30641, 32010, 30914, 33242, 30538, 30568], [1, 30807, 30589], [1, 29871, 41059, 30427, 31095, 31110]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1], [1, 1, 1, 1, 1, 1]], 'overflow_to_sample_mapping': [0, 0, 1]}
8
<s> あいうえおかきく
3
<s>けこ
6
<s> さしすせそ
return_tensors
tensors形式で返す。
padding等でトークン長を揃える必要がある。
batch_encoding = tokenizer(['あいうえおかきくけこ', 'さしすせそ'], padding='max_length', max_length=24, return_tensors='pt')
import pprint
pprint.pprint(batch_encoding)
decoded_str = tokenizer.decode(batch_encoding["input_ids"][0])
print(decoded_str)
decoded_str = tokenizer.decode(batch_encoding["input_ids"][1])
print(decoded_str)
{'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]),
'input_ids': tensor([[ 1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2],
[ 1, 29871, 41059, 30427, 31095, 31110, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2]])}
<s> あいうえおかきくけこ</s></s></s></s></s></s></s></s></s></s></s></s></s></s>
<s> さしすせそ</s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s>
DataCollator
1バッチ分のdatasetsを加工してモデルに対するinputsを返す。
実行方法(DefaultDataCollator)
from transformers import DefaultDataCollator
max_length = 24
batch_encoding = tokenizer('あいうえおかきくけこ', padding='max_length', max_length=max_length)
print(batch_encoding)
batch_encoding2 = tokenizer('さしすせそ', padding='max_length', max_length=max_length)
print(batch_encoding2)
data_collator = DefaultDataCollator()
batch = data_collator([batch_encoding, batch_encoding2])
print(batch)
{'input_ids': [1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}
{'input_ids': [1, 29871, 41059, 30427, 31095, 31110, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], 'attention_mask': [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}
{'input_ids': tensor([[ 1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2],
[ 1, 29871, 41059, 30427, 31095, 31110, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])}
以下のように、複数文字列を渡したときに返されるbatch_encodingをdata_collatorに渡す方法がちょっとわかりませんでした。
tensorのネストが1つ深くなってしまっています。
batch_encoding = tokenizer(['あいうえおかきくけこ', 'さしすせそ'], padding='max_length', max_length=24)
print(batch_encoding)
data_collator = DefaultDataCollator()
batch = data_collator([batch_encoding])
print(batch)
{'input_ids': [[1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [1, 29871, 41059, 30427, 31095, 31110, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]}
{'input_ids': tensor([[[ 1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2],
[ 1, 29871, 41059, 30427, 31095, 31110, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2]]]), 'attention_mask': tensor([[[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0],
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0]]])}
DataCollatorWithPadding
データのpaddingを行う。
tokenizerでも同様の処理を行えますが、出来ればこちらでやったほうが良いように思えました。
from transformers import DataCollatorWithPadding
batch_encoding = tokenizer('あいうえおかきくけこ')
print(batch_encoding)
batch_encoding2 = tokenizer('さしすせそ')
print(batch_encoding2)
max_length = 24
data_collator = DataCollatorWithPadding(tokenizer, padding='max_length', max_length=max_length)
batch = data_collator([batch_encoding, batch_encoding2])
print(batch)
decoded_str = tokenizer.decode(batch["input_ids"][0])
print(decoded_str)
decoded_str2 = tokenizer.decode(batch["input_ids"][1])
print(decoded_str2)
{'input_ids': [1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
{'input_ids': [1, 29871, 41059, 30427, 31095, 31110], 'attention_mask': [1, 1, 1, 1, 1, 1]}
{'input_ids': tensor([[ 1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2],
[ 1, 29871, 41059, 30427, 31095, 31110, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])}
<s> あいうえおかきくけこ</s></s></s></s></s></s></s></s></s></s></s></s></s></s>
<s> さしすせそ</s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s>
DataCollatorForSeq2Seq
input_idsだけでなくlabelsに対してもパディングを行う。
と書いてあるが、結果はlabelsの方にパディングは入っていない。(tokenizerするフェーズで対応する必要がありそう)
from transformers import DataCollatorForSeq2Seq
from datasets import Dataset
def f(example):
tokenized = tokenizer(example['text'])
tokenized['labels'] = tokenized['input_ids'].copy()
return tokenized
dataset = Dataset.from_dict({"text": ["あいうえおかきくけこ", "さしすせそ"]})
mapped_dataset = dataset.map(f, remove_columns=['text'])
print(mapped_dataset)
max_length = 24
data_collator = DataCollatorForSeq2Seq(tokenizer, padding='max_length', max_length=max_length)
batch = data_collator(list(mapped_dataset))
print(batch)
decoded_str = tokenizer.decode(batch["input_ids"][0])
print(decoded_str)
decoded_str2 = tokenizer.decode(batch["input_ids"][1])
print(decoded_str2)
Dataset({
features: ['input_ids', 'attention_mask', 'labels'],
num_rows: 2
})
{'input_ids': tensor([[ 1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2],
[ 1, 29871, 41059, 30427, 31095, 31110, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]), 'labels': tensor([[ 1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589],
[ 1, 29871, 41059, 30427, 31095, 31110, -100, -100, -100, -100]])}
<s> あいうえおかきくけこ</s></s></s></s></s></s></s></s></s></s></s></s></s></s>
<s> さしすせそ</s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s>
DataCollatorForLanguageModeling
mlm=Trueにすると単語の一部をマスクすることができる。
labelsの設定が自動で行われる。
最大長でパディングされる。padding_lengthは指定できない。
from transformers import DataCollatorForLanguageModeling
from datasets import Dataset
def f(example):
tokenized = tokenizer(example['text'])
return tokenized
dataset = Dataset.from_dict({"text": ["あいうえおかきくけこ", "さしすせそ"]})
mapped_dataset = dataset.map(f, remove_columns=['text'])
print(mapped_dataset)
data_collator = DataCollatorForLanguageModeling(tokenizer, mlm=False)
batch = data_collator(list(mapped_dataset))
print(batch)
decoded_str = tokenizer.decode(batch["input_ids"][0])
print(decoded_str)
decoded_str2 = tokenizer.decode(batch["input_ids"][1])
print(decoded_str2)
Dataset({
features: ['input_ids', 'attention_mask'],
num_rows: 2
})
{'input_ids': tensor([[ 1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589],
[ 1, 29871, 41059, 30427, 31095, 31110, 2, 2, 2, 2]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0]]), 'labels': tensor([[ 1, 29871, 30641, 32010, 30914, 33242, 30538, 30568, 30807, 30589],
[ 1, 29871, 41059, 30427, 31095, 31110, -100, -100, -100, -100]])}
<s> あいうえおかきくけこ
<s> さしすせそ</s></s></s></s>
その他
何か試したい場合は、こちらのリンクからnotebookをコピーして使ってください。
Discussion