transformers_doc/ja/pytorch/preprocessing.ipynb (1,086 lines of code) (raw):

{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Preprocess" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "データセットでモデルをトレーニングする前に、それをモデルの期待する入力形式に前処理する必要があります。\n", "データがテキスト、画像、またはオーディオであるかどうかにかかわらず、それらはテンソルのバッチに変換して組み立てる必要があります。\n", "🤗 Transformersは、データをモデル用に準備するのに役立つ前処理クラスのセットを提供しています。\n", "このチュートリアルでは、次のことを学びます:\n", "\n", "* テキストの場合、[Tokenizer](https://huggingface.co/docs/transformers/main/ja/./main_classes/tokenizer)を使用してテキストをトークンのシーケンスに変換し、トークンの数値表現を作成し、それらをテンソルに組み立てる方法。\n", "* 音声とオーディオの場合、[Feature extractor](https://huggingface.co/docs/transformers/main/ja/./main_classes/feature_extractor)を使用してオーディオ波形から連続的な特徴を抽出し、それらをテンソルに変換する方法。\n", "* 画像入力の場合、[ImageProcessor](https://huggingface.co/docs/transformers/main/ja/./main_classes/image)を使用して画像をテンソルに変換する方法。\n", "* マルチモーダル入力の場合、[Processor](https://huggingface.co/docs/transformers/main/ja/./main_classes/processors)を使用してトークナイザと特徴抽出器または画像プロセッサを組み合わせる方法。\n", "\n", "<Tip>\n", "\n", "`AutoProcessor`は常に動作し、使用するモデルに適切なクラスを自動的に選択します。\n", "トークナイザ、画像プロセッサ、特徴抽出器、またはプロセッサを使用しているかにかかわらず、動作します。\n", "\n", "</Tip>\n", "\n", "始める前に、🤗 Datasetsをインストールして、いくつかのデータセットを試すことができるようにしてください:\n", "\n", "```bash\n", "pip install datasets\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Natural Language Processing" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "hide_input": true }, "outputs": [ { "data": { "text/html": [ "<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/Yffk5aydLzg?rel=0&amp;controls=0&amp;showinfo=0\" frameborder=\"0\" allowfullscreen></iframe>" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#@title\n", "from IPython.display import HTML\n", "\n", "HTML('<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/Yffk5aydLzg?rel=0&amp;controls=0&amp;showinfo=0\" frameborder=\"0\" allowfullscreen></iframe>')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "テキストデータの前処理に使用する主要なツールは、[トークナイザ](https://huggingface.co/docs/transformers/main/ja/main_classes/tokenizer)です。トークナイザは、一連のルールに従ってテキストを*トークン*に分割します。トークンは数値に変換され、その後テンソルに変換され、モデルの入力となります。モデルが必要とする追加の入力は、トークナイザによって追加されます。\n", "\n", "<Tip>\n", "\n", "事前学習済みモデルを使用する予定の場合、関連する事前学習済みトークナイザを使用することが重要です。これにより、テキストが事前学習コーパスと同じ方法で分割され、事前学習中に通常*ボキャブ*として参照される対応するトークンインデックスを使用します。\n", "\n", "</Tip>\n", "\n", "[AutoTokenizer.from_pretrained()](https://huggingface.co/docs/transformers/main/ja/model_doc/auto#transformers.AutoTokenizer.from_pretrained)メソッドを使用して事前学習済みトークナイザをロードして、開始しましょう。これにより、モデルが事前学習された*ボキャブ*がダウンロードされます:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from transformers import AutoTokenizer\n", "\n", "tokenizer = AutoTokenizer.from_pretrained(\"google-bert/bert-base-cased\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "次に、テキストをトークナイザに渡します:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'input_ids': [101, 2079, 2025, 19960, 10362, 1999, 1996, 3821, 1997, 16657, 1010, 2005, 2027, 2024, 11259, 1998, 4248, 2000, 4963, 1012, 102],\n", " 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", " 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "encoded_input = tokenizer(\"Do not meddle in the affairs of wizards, for they are subtle and quick to anger.\")\n", "print(encoded_input)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "トークナイザは、重要な3つの項目を持つ辞書を返します:\n", "\n", "* [input_ids](https://huggingface.co/docs/transformers/main/ja/glossary#input-ids) は文中の各トークンに対応するインデックスです。\n", "* [attention_mask](https://huggingface.co/docs/transformers/main/ja/glossary#attention-mask) はトークンがアテンションを受ける必要があるかどうかを示します。\n", "* [token_type_ids](https://huggingface.co/docs/transformers/main/ja/glossary#token-type-ids) は複数のシーケンスがある場合、トークンがどのシーケンスに属しているかを識別します。\n", "\n", "`input_ids` をデコードして入力を返します:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'[CLS] 魔法使いの事に干渉するな、彼らは微妙で怒りっぽい。 [SEP]'" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tokenizer.decode(encoded_input[\"input_ids\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "如何にお分かりいただけるかと思いますが、トークナイザはこの文章に2つの特別なトークン、`CLS`(クラシファイア)と`SEP`(セパレータ)を追加しました。\n", "すべてのモデルが特別なトークンを必要とするわけではありませんが、必要な場合、トークナイザは自動的にそれらを追加します。\n", "\n", "複数の文章を前処理する場合、トークナイザにリストとして渡してください:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'input_ids': [[101, 1252, 1184, 1164, 1248, 6462, 136, 102],\n", " [101, 1790, 112, 189, 1341, 1119, 3520, 1164, 1248, 6462, 117, 21902, 1643, 119, 102],\n", " [101, 1327, 1164, 5450, 23434, 136, 102]],\n", " 'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 0, 0, 0]],\n", " 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1],\n", " [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],\n", " [1, 1, 1, 1, 1, 1, 1]]}" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "batch_sentences = [\n", " \"But what about second breakfast?\",\n", " \"Don't think he knows about second breakfast, Pip.\",\n", " \"What about elevensies?\",\n", "]\n", "encoded_inputs = tokenizer(batch_sentences)\n", "print(encoded_inputs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Pad" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "文章は常に同じ長さではないことがあり、これはテンソル(モデルの入力)が均一な形状を持つ必要があるため問題となります。\n", "パディングは、短い文に特別な「パディングトークン」を追加して、テンソルを長いシーケンスに合わせるための戦略です。\n", "\n", "バッチ内の短いシーケンスを最長のシーケンスに合わせるために、`padding`パラメータを`True`に設定します:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'input_ids': [[101, 1252, 1184, 1164, 1248, 6462, 136, 102, 0, 0, 0, 0, 0, 0, 0],\n", " [101, 1790, 112, 189, 1341, 1119, 3520, 1164, 1248, 6462, 117, 21902, 1643, 119, 102],\n", " [101, 1327, 1164, 5450, 23434, 136, 102, 0, 0, 0, 0, 0, 0, 0, 0]],\n", " 'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],\n", " 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],\n", " [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],\n", " [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]]}" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "batch_sentences = [\n", " \"But what about second breakfast?\",\n", " \"Don't think he knows about second breakfast, Pip.\",\n", " \"What about elevensies?\",\n", "]\n", "encoded_input = tokenizer(batch_sentences, padding=True)\n", "print(encoded_input)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1番目と3番目の文は、短いために`0`でパディングされています。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Truncation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "逆のスペクトルでは、時折、モデルが処理するのに長すぎるシーケンスがあるかもしれません。この場合、シーケンスを短縮する必要があります。\n", "\n", "モデルが受け入れる最大の長さにシーケンスを切り詰めるには、`truncation`パラメータを`True`に設定します:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'input_ids': [[101, 1252, 1184, 1164, 1248, 6462, 136, 102, 0, 0, 0, 0, 0, 0, 0],\n", " [101, 1790, 112, 189, 1341, 1119, 3520, 1164, 1248, 6462, 117, 21902, 1643, 119, 102],\n", " [101, 1327, 1164, 5450, 23434, 136, 102, 0, 0, 0, 0, 0, 0, 0, 0]],\n", " 'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],\n", " 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],\n", " [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],\n", " [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]]}" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "batch_sentences = [\n", " \"But what about second breakfast?\",\n", " \"Don't think he knows about second breakfast, Pip.\",\n", " \"What about elevensies?\",\n", "]\n", "encoded_input = tokenizer(batch_sentences, padding=True, truncation=True)\n", "print(encoded_input)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "<Tip>\n", "\n", "異なるパディングと切り詰めの引数について詳しくは、[パディングと切り詰め](https://huggingface.co/docs/transformers/main/ja/./pad_truncation)のコンセプトガイドをご覧ください。\n", "\n", "</Tip>" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Build tensors" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "最後に、トークナイザがモデルに供給される実際のテンソルを返すように設定します。\n", "\n", "`return_tensors`パラメータを`pt`(PyTorch用)または`tf`(TensorFlow用)に設定します:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'input_ids': tensor([[101, 1252, 1184, 1164, 1248, 6462, 136, 102, 0, 0, 0, 0, 0, 0, 0],\n", " [101, 1790, 112, 189, 1341, 1119, 3520, 1164, 1248, 6462, 117, 21902, 1643, 119, 102],\n", " [101, 1327, 1164, 5450, 23434, 136, 102, 0, 0, 0, 0, 0, 0, 0, 0]]),\n", " 'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]),\n", " 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],\n", " [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],\n", " [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]])}" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "batch_sentences = [\n", " \"But what about second breakfast?\",\n", " \"Don't think he knows about second breakfast, Pip.\",\n", " \"What about elevensies?\",\n", "]\n", "encoded_input = tokenizer(batch_sentences, padding=True, truncation=True, return_tensors=\"pt\")\n", "print(encoded_input)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Audio" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "オーディオタスクの場合、データセットをモデル用に準備するために[特徴抽出器](https://huggingface.co/docs/transformers/main/ja/main_classes/feature_extractor)が必要です。\n", "特徴抽出器は生のオーディオデータから特徴を抽出し、それらをテンソルに変換するために設計されています。\n", "\n", "[PolyAI/minds14](https://huggingface.co/datasets/PolyAI/minds14)データセットをロードして(データセットのロード方法の詳細については🤗 [Datasetsチュートリアル](https://huggingface.co/docs/datasets/load_hub)を参照)、\n", "オーディオデータセットで特徴抽出器をどのように使用できるかを確認してみましょう:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from datasets import load_dataset, Audio\n", "\n", "dataset = load_dataset(\"PolyAI/minds14\", name=\"en-US\", split=\"train\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "アクセスして`audio`列の最初の要素を確認します。`audio`列を呼び出すと、自動的にオーディオファイルが読み込まれ、リサンプリングされます:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'array': array([ 0. , 0.00024414, -0.00024414, ..., -0.00024414,\n", " 0. , 0. ], dtype=float32),\n", " 'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~JOINT_ACCOUNT/602ba55abb1e6d0fbce92065.wav',\n", " 'sampling_rate': 8000}" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dataset[0][\"audio\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "これにより、3つのアイテムが返されます:\n", "\n", "* `array` は読み込まれた音声信号で、1Dの配列として読み込まれます。必要に応じてリサンプリングされることもあります。\n", "* `path` は音声ファイルの場所を指します。\n", "* `sampling_rate` は音声信号内のデータポイントが1秒間にいくつ測定されるかを示します。\n", "\n", "このチュートリアルでは、[Wav2Vec2](https://huggingface.co/facebook/wav2vec2-base)モデルを使用します。\n", "モデルカードを確認すると、Wav2Vec2が16kHzのサンプリングされた音声オーディオで事前学習されていることがわかります。\n", "モデルの事前学習に使用されたデータセットのサンプリングレートと、あなたのオーディオデータのサンプリングレートが一致することが重要です。\n", "データのサンプリングレートが異なる場合、データをリサンプリングする必要があります。\n", "\n", "1. 🤗 Datasetsの `cast_column` メソッドを使用して、サンプリングレートを16kHzにアップサンプリングします:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dataset = dataset.cast_column(\"audio\", Audio(sampling_rate=16_000))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "2. 再び `audio` 列を呼び出してオーディオファイルをリサンプルします:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'array': array([ 2.3443763e-05, 2.1729663e-04, 2.2145823e-04, ...,\n", " 3.8356509e-05, -7.3497440e-06, -2.1754686e-05], dtype=float32),\n", " 'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~JOINT_ACCOUNT/602ba55abb1e6d0fbce92065.wav',\n", " 'sampling_rate': 16000}" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dataset[0][\"audio\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "次に、入力を正規化しパディングするために特徴抽出器をロードします。テキストデータをパディングする場合、短いシーケンスには `0` が追加されます。同じ考え方がオーディオデータにも適用されます。特徴抽出器は `array` に `0` を追加します(これは無音として解釈されます)。\n", "\n", "[AutoFeatureExtractor.from_pretrained()](https://huggingface.co/docs/transformers/main/ja/model_doc/auto#transformers.AutoFeatureExtractor.from_pretrained)を使用して特徴抽出器をロードします:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from transformers import AutoFeatureExtractor\n", "\n", "feature_extractor = AutoFeatureExtractor.from_pretrained(\"facebook/wav2vec2-base\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "オーディオ `array` を特徴抽出器に渡します。特徴抽出器で発生する可能性のある無音エラーをより良くデバッグするために、特徴抽出器に `sampling_rate` 引数を追加することをお勧めします。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'input_values': [array([ 3.8106556e-04, 2.7506407e-03, 2.8015103e-03, ...,\n", " 5.6335266e-04, 4.6588284e-06, -1.7142107e-04], dtype=float32)]}" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "audio_input = [dataset[0][\"audio\"][\"array\"]]\n", "feature_extractor(audio_input, sampling_rate=16000)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "同様に、トークナイザと同様に、バッチ内の可変シーケンスを処理するためにパディングまたは切り詰めを適用できます。次に、これらの2つのオーディオサンプルのシーケンス長を確認してみましょう:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(173398,)" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dataset[0][\"audio\"][\"array\"].shape" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(106496,)" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dataset[1][\"audio\"][\"array\"].shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "この関数は、データセットを前処理してオーディオサンプルの長さを同じにするためのものです。最大サンプル長を指定し、特徴抽出器はシーケンスをそれに合わせてパディングまたは切り詰めます。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def preprocess_function(examples):\n", " audio_arrays = [x[\"array\"] for x in examples[\"audio\"]]\n", " inputs = feature_extractor(\n", " audio_arrays,\n", " sampling_rate=16000,\n", " padding=True,\n", " max_length=100000,\n", " truncation=True,\n", " )\n", " return inputs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`preprocess_function`をデータセットの最初の数例に適用します:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "processed_dataset = preprocess_function(dataset[:5])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "サンプルの長さは現在同じで、指定された最大長と一致しています。これで処理されたデータセットをモデルに渡すことができます!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(100000,)" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "processed_dataset[\"input_values\"][0].shape" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(100000,)" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "processed_dataset[\"input_values\"][1].shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Computer Vision" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "コンピュータビジョンタスクでは、モデル用にデータセットを準備するための[画像プロセッサ](https://huggingface.co/docs/transformers/main/ja/main_classes/image_processor)が必要です。\n", "画像の前処理には、画像をモデルが期待する入力形式に変換するためのいくつかのステップが含まれています。これらのステップには、リサイズ、正規化、カラーチャネルの補正、および画像をテンソルに変換するなどが含まれます。\n", "\n", "<Tip>\n", "\n", "画像の前処理は、通常、画像の増強の形式に従います。画像の前処理と画像の増強の両方は画像データを変換しますが、異なる目的があります:\n", "\n", "* 画像の増強は、過学習を防ぎ、モデルの堅牢性を向上させるのに役立つ方法で画像を変更します。データを増強する方法は無限で、明るさや色の調整、クロップ、回転、リサイズ、ズームなど、様々な方法があります。ただし、増強操作によって画像の意味が変わらないように注意する必要があります。\n", "* 画像の前処理は、画像がモデルの期待する入力形式と一致することを保証します。コンピュータビジョンモデルをファインチューニングする場合、画像はモデルが最初にトレーニングされたときとまったく同じ方法で前処理する必要があります。\n", "\n", "画像の増強には任意のライブラリを使用できます。画像の前処理には、モデルに関連付けられた`ImageProcessor`を使用します。\n", "\n", "</Tip>\n", "\n", "コンピュータビジョンのデータセットで画像プロセッサを使用する方法を示すために、[food101](https://huggingface.co/datasets/food101)データセットをロードします(データセットのロード方法の詳細については🤗[Datasetsチュートリアル](https://huggingface.co/docs/datasets/load_hub)を参照):\n", "\n", "<Tip>\n", "\n", "データセットがかなり大きいため、🤗 Datasetsの`split`パラメータを使用してトレーニングデータの小さなサンプルのみをロードします!\n", "\n", "</Tip>" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from datasets import load_dataset\n", "\n", "dataset = load_dataset(\"food101\", split=\"train[:100]\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "次に、🤗 Datasetsの [`Image`](https://huggingface.co/docs/datasets/package_reference/main_classes?highlight=image#datasets.Image) 機能で画像を見てみましょう:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dataset[0][\"image\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "<div class=\"flex justify-center\">\n", " <img src=\"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/vision-preprocess-tutorial.png\"/>\n", "</div>\n", "\n", "AutoImageProcessorを[AutoImageProcessor.from_pretrained()](https://huggingface.co/docs/transformers/main/ja/model_doc/auto#transformers.AutoImageProcessor.from_pretrained)を使用してロードします:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from transformers import AutoImageProcessor\n", "\n", "image_processor = AutoImageProcessor.from_pretrained(\"google/vit-base-patch16-224\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. まず、画像の拡張を追加しましょう。好きなライブラリを使用できますが、このチュートリアルではtorchvisionの[`transforms`](https://pytorch.org/vision/stable/transforms.html)モジュールを使用します。別のデータ拡張ライブラリを使用したい場合は、[Albumentations](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification_albumentations.ipynb)または[Kornia notebooks](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification_kornia.ipynb)で詳細を学ぶことができます。\n", "\n", " ここでは、[`Compose`](https://pytorch.org/vision/master/generated/torchvision.transforms.Compose.html)を使用していくつかの変換を連鎖させます - [`RandomResizedCrop`](https://pytorch.org/vision/main/generated/torchvision.transforms.RandomResizedCrop.html)と[`ColorJitter`](https://pytorch.org/vision/main/generated/torchvision.transforms.ColorJitter.html)。\n", " サイズの変更に関しては、`image_processor`から画像サイズの要件を取得できます。\n", " 一部のモデルでは、正確な高さと幅が必要ですが、他のモデルでは`shortest_edge`のみが定義されています。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from torchvision.transforms import RandomResizedCrop, ColorJitter, Compose\n", "\n", "size = (\n", " image_processor.size[\"shortest_edge\"]\n", " if \"shortest_edge\" in image_processor.size\n", " else (image_processor.size[\"height\"], image_processor.size[\"width\"])\n", ")\n", "\n", "_transforms = Compose([RandomResizedCrop(size), ColorJitter(brightness=0.5, hue=0.5)])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "2. モデルは[`pixel_values`](https://huggingface.co/docs/transformers/main/ja/model_doc/visionencoderdecoder#transformers.VisionEncoderDecoderModel.forward.pixel_values)を入力として受け取ります。\n", "`ImageProcessor`は画像の正規化と適切なテンソルの生成を処理できます。\n", "一連の画像に対する画像拡張と画像前処理を組み合わせ、`pixel_values`を生成する関数を作成します:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def transforms(examples):\n", " images = [_transforms(img.convert(\"RGB\")) for img in examples[\"image\"]]\n", " examples[\"pixel_values\"] = image_processor(images, do_resize=False, return_tensors=\"pt\")[\"pixel_values\"]\n", " return examples" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "<Tip>\n", "\n", "上記の例では、画像のサイズ変更を既に画像増強変換で行っているため、`do_resize=False`を設定しました。\n", "適切な `image_processor` からの `size` 属性を活用しています。画像増強中に画像のサイズ変更を行わない場合は、このパラメータを省略してください。\n", "デフォルトでは、`ImageProcessor` がサイズ変更を処理します。\n", "\n", "画像を増強変換の一部として正規化したい場合は、`image_processor.image_mean` と `image_processor.image_std` の値を使用してください。\n", "</Tip>\n", "\n", "3. 次に、🤗 Datasetsの[`set_transform`](https://huggingface.co/docs/datasets/process#format-transform)を使用して、変換をリアルタイムで適用します:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dataset.set_transform(transforms)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "4. 画像にアクセスすると、画像プロセッサが `pixel_values` を追加したことがわかります。これで処理済みのデータセットをモデルに渡すことができます!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dataset[0].keys()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "以下は、変換が適用された後の画像の外観です。 画像はランダムに切り抜かれ、その色の特性も異なります。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "img = dataset[0][\"pixel_values\"]\n", "plt.imshow(img.permute(1, 2, 0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "<div class=\"flex justify-center\">\n", " <img src=\"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/preprocessed_image.png\"/>\n", "</div>\n", "\n", "<Tip>\n", "\n", "オブジェクト検出、意味セグメンテーション、インスタンスセグメンテーション、およびパノプティックセグメンテーションなどのタスクの場合、`ImageProcessor`は\n", "ポスト処理メソッドを提供します。これらのメソッドは、モデルの生の出力を境界ボックスやセグメンテーションマップなどの意味のある予測に変換します。\n", "\n", "</Tip>" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Pad" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "一部の場合、たとえば、[DETR](https://huggingface.co/docs/transformers/main/ja/./model_doc/detr)をファインチューニングする場合、モデルはトレーニング時にスケールの変更を適用します。\n", "これにより、バッチ内の画像のサイズが異なる場合があります。[DetrImageProcessor](https://huggingface.co/docs/transformers/main/ja/model_doc/detr#transformers.DetrImageProcessor)から`DetrImageProcessor.pad()`を使用し、\n", "カスタムの`collate_fn`を定義して画像を一緒にバッチ処理できます。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def collate_fn(batch):\n", " pixel_values = [item[\"pixel_values\"] for item in batch]\n", " encoding = image_processor.pad(pixel_values, return_tensors=\"pt\")\n", " labels = [item[\"labels\"] for item in batch]\n", " batch = {}\n", " batch[\"pixel_values\"] = encoding[\"pixel_values\"]\n", " batch[\"pixel_mask\"] = encoding[\"pixel_mask\"]\n", " batch[\"labels\"] = labels\n", " return batch" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Multi Modal" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "マルチモーダル入力を使用するタスクの場合、モデル用にデータセットを準備するための[プロセッサ](https://huggingface.co/docs/transformers/main/ja/main_classes/processors)が必要です。プロセッサは、トークナイザや特徴量抽出器などの2つの処理オブジェクトを結合します。\n", "\n", "自動音声認識(ASR)のためのプロセッサの使用方法を示すために、[LJ Speech](https://huggingface.co/datasets/lj_speech)データセットをロードします(データセットのロード方法の詳細については🤗 [Datasets チュートリアル](https://huggingface.co/docs/datasets/load_hub)を参照):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from datasets import load_dataset\n", "\n", "lj_speech = load_dataset(\"lj_speech\", split=\"train\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ASR(自動音声認識)の場合、主に `audio` と `text` に焦点を当てているため、他の列を削除できます:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lj_speech = lj_speech.map(remove_columns=[\"file\", \"id\", \"normalized_text\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "次に、`audio`と`text`の列を見てみましょう:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'array': array([-7.3242188e-04, -7.6293945e-04, -6.4086914e-04, ...,\n", " 7.3242188e-04, 2.1362305e-04, 6.1035156e-05], dtype=float32),\n", " 'path': '/root/.cache/huggingface/datasets/downloads/extracted/917ece08c95cf0c4115e45294e3cd0dee724a1165b7fc11798369308a465bd26/LJSpeech-1.1/wavs/LJ001-0001.wav',\n", " 'sampling_rate': 22050}" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lj_speech[0][\"audio\"]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Printing, in the only sense with which we are at present concerned, differs from most if not from all the arts and crafts represented in the Exhibition'" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lj_speech[0][\"text\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "常に、オーディオデータセットのサンプリングレートを、モデルの事前学習に使用されたデータセットのサンプリングレートと一致させるように[リサンプル](https://huggingface.co/docs/transformers/main/ja/preprocessing#audio)する必要があります!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lj_speech = lj_speech.cast_column(\"audio\", Audio(sampling_rate=16_000))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "プロセッサを [AutoProcessor.from_pretrained()](https://huggingface.co/docs/transformers/main/ja/model_doc/auto#transformers.AutoProcessor.from_pretrained) を使用してロードします:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from transformers import AutoProcessor\n", "\n", "processor = AutoProcessor.from_pretrained(\"facebook/wav2vec2-base-960h\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. `array`内に含まれるオーディオデータを`input_values`に処理し、`text`を`labels`にトークン化する関数を作成します:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def prepare_dataset(example):\n", " audio = example[\"audio\"]\n", "\n", " example.update(processor(audio=audio[\"array\"], text=example[\"text\"], sampling_rate=16000))\n", "\n", " return example" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "2. サンプルに`prepare_dataset`関数を適用します:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "prepare_dataset(lj_speech[0])" ] } ], "metadata": {}, "nbformat": 4, "nbformat_minor": 4 }