ぶつりやAI

物理屋の視点から、原理原則を大事に、ディープラーニングのわかり易い説明を心がけています。

自己紹介

あいさつ

このブログでは、ディープラーニングについて、自ら学んだ内容や業務を通じて得た知識を発信していきます(ブログの引越し先はこちら)。

私はもともと物理学を専門としており、大学院卒業後、日本にて医療機器メーカーで開発に携わっていました。ちょうどその頃、E ラーニング大手の Coursera で機械学習とディープラーニングを学び、その後、本を読んだり、会社の GPU を活用しながら学習を進めました。この時に学んだ知識が役に立つことになり、現在ではディープラーニングを使った研究開発に従事しています。

現在はディープラーニングの基礎的な内容が中心ですが、2025 年中には、より実践的な技術を解説する実践者編、医療画像(CT・MRI)の原理やディープラーニングの活用にも着手する予定です。

略歴

  • 2013年 京都大学 理学部 卒業
  • 2015年 東京大学 理学系研究科 物理学専攻 修士課程 修了
  • 2018年 東京大学 理学系研究科 物理学専攻 博士課程 修了
  • 2018年 GEヘルスケアジャパン・CT開発

SNS等

私の研究・開発経験の詳細は LinkedIn でご覧いただけます。

AIやディープラーニングに関する最新情報は X(旧Twitter) でも発信しています!

このサイトで学べること

このサイトでは、ディープラーニングの基礎から応用、実践までを体系的に学べるように整理しています。興味のあるカテゴリからご覧ください。

以下、一部抜粋して紹介します。

📘 理論基礎(概念)

ディープラーニングを学ぶ前に、AI・機械学習・ディープラーニングの違いを理解し、基本的な理論を固めることが重要です。

🔬理論基礎( 数学・最適化)

ディープラーニングの学習プロセスを理解するには、損失関数、勾配降下法、逆誤差伝搬法の概念が重要です。

🛠️ 実践理論理論基礎

実際の学習プロセスを理解するために、過学習、バリデーション、ミニバッチ学習などの概念を解説します。

💻 実践実装基礎

実際にコードを書いて動かすことで、より深い理解を得ることができます。Google Colabを使って実装を試してみましょう。

🔎 サイエンスコラム

ディープラーニングだけでなく、物理や数学の視点からAIを考えるコラムも執筆しています。

📚 おすすめディープラーニング教材

ディープラーニングを効率的に学ぶための書籍やオンライン教材を紹介しています。

ChatGPT マイGPT×プロジェクト×メモリの使い方【独自検証つき】


ChatGPT をチャットベースで利用する際、マイGPT(MyGPTs)・プロジェクト・メモリの3つの機能が重要な役割を果たします。これらを活用することで、ChatGPT を自分専属のコンサルタントに近づけ、幅広いニーズに合わせた使い方が可能になります。

マイGPT(MyGPTs)とは?〜自分専属のコンサルタント

基本機能

マイGPTには大きく分けて3つの特徴があります。手入力による設定は至ってシンプル。設定自体をChatGPTに依頼することもでき、方向性を入力するだけで必要に応じた質問を返しながら調整してくれます。

指示(人格・役割の設定)

テキストでGPTに期待する役割を書きます。

例: 「あなたは英語と日本語を母国語とする英会話教室のベテラン英語教師です。TOEIC500点の日本人を想定し...」

知識(ファイルのアップロード)

ユーザー独自の情報をファイルとして与えることができます。例えば、統計データ、方針やガイドラインをまとめたテキスト、自分の文章やイラストのサンプルデータなどです。

アップロードされたデータは必要に応じて参照されます。チャットでの質問などでファイルを参照する確度、頻度を上げたい場合、指示でそのように書くなどの工夫が必要です。

対応するファイル形式は公式ドキュメント (Supported files) を参照してください。

  • PDF
  • Word (.doc, .docx)
  • Excel (.xls, .xlsx)
  • PowerPoint (.ppt, .pptx)
  • テキスト (.txt, .csv)
  • コード等(.c, .json, .html など)

@による呼び出し

チャットで最初に“@”とマイGPTの名前を入力することで、作成済みのマイGPTを呼び出せます。

マイGPTの使い方(活用例)

  • 語学学習:自分の国籍、学習言語、レベル、使用言語を指定。
  • 論文要約:要約の長さ、新規性、根拠の信頼性などを指定。
  • 校閲:自分の文章、契約書等をレビュー、間違いなどの確認。

設定方法

  1. ChatGPTを開き、左サイドバーの「GPT」をクリック。
  2. 右上の「+作成する」で新規作成。
  3. 左側が設定画面、右側で試験的に会話が可能。

マイGPT作成画面。

左サイドバーの「GPT」をクリックし、右上の「+作成する」でマイGPTを作成。

「作成する」を選べばChatGPTに設定を任せることもできますが、「構成」タブで以下を設定することも可能です:

  • 名前:わかりやすく簡潔に。
  • 説明:多数作る場合のメモや公開時の説明文。
  • 指示:性格・専門性・ルールを設定。
  • 会話のきっかけ:最初に投げかける文を設定。「最新の◯◯を教えて」などとしてテンプレ化が可能。
  • 知識:前述のファイルをアップロード。
  • 推奨モデル:特定モデルを指定可能。指定しない場合は通常のチャットモデルを利用。
  • 機能:ウェブ検索、Canvas、画像生成などを有効化。初期状態はユーザー環境によって異なる場合があります。

マイGPTの設定画面。

左側のタブ「作成する」で「ブログ作成のアドバイザーが欲しいです...」「はい」「okです。」とすることで、「構成」の設定が作成された。

プロジェクトとは?〜自分専用の作業環境

基本機能

プロジェクトは複数のチャットやファイルをまとめる作業環境です。用途ごとに整理することで、一貫した作業がしやすくなります。

  • フォルダ機能:「旅行計画」「仕事」「語学」などテーマごとにプロジェクトとして分けられる。
  • 指示の追加:プロジェクト内のチャットでは、ここで設定した指示が優先されます(公式ドキュメント)。
  • 知識の追加:アップロードしたファイルをプロジェクト全体で利用可能。
  • 専用メモリ:プロジェクト単位で記憶を保持。設定で「プロジェクトのみ」とすることで、プロジェクト内に閉じた記憶となり、外部とは共有されません(公式ドキュメント)。

メモリとチャット参照の利用とその範囲

メモリを利用するためには、サブスクリプションの場合、ChatGPTの設定>パーソナライズで「保存されたメモリを参照する」と「チャット履歴を参照する」をオンにする必要があります。

プロジェクトが参照、保存できるメモリの範囲は、プロジェクト作成時の設定で変わります。「デフォルト」を選んだ場合、ChatGPT全体のメモリに相互にアクセスできるようになります。一方で、「プロジェクトのみ」を選ぶと、メモリの参照、保存はプロジェクト内部で閉じることになります。いずれの場合も、プロジェクト内のチャットは相互に参照でき、外部と内部の参照はできません

プロジェクト内部のメモリに保存された内容は、ユーザーが見ることはできません。

プロジェクトのメモリとチャット参照の範囲。

プロジェクトのメモリとチャット参照の範囲(公式ドキュメント)。

プロジェクトの使い方(活用例)

  • 「夏の旅行計画」と「冬の旅行計画」を別チャットに分けつつ、同じプロジェクトで管理。
  • 語学学習プロジェクトで、文法、会話、リーディングにチャットを分け、全体の進捗はメモリで共有。
  • 記事作成プロジェクトで、記事ごとにチャットを分け、校正・HTML変換を行う。あるいは役割ごとにチャットを分ける。

マイGPT × プロジェクトの併用 (2025.09.16現在)

マイGPTとプロジェクトは別機能ですが、同時に利用することも可能です。執筆時点の仕様では、新規チャット開始時に“@”でマイGPTを呼び出すと、チャットがプロジェクト外に作成されてしまいます。ただし、プロジェク ト内で会話を始め、途中からマイGPTを呼び出すことは可能です。

  • マイGPT:特定の人格・専門家を設定し、任意のタイミングで呼び出し可能。
  • プロジェクト:共通の指示・知識をもとに進める閉じた作業環境。

メモリ、知識の活用と適用範囲

公式情報では、マイGPTとプロジェクトのメモリや知識の適用範囲を明確に確認できなかったため、簡単な実験を行いました。結論としては、プロジェクト内でマイGPTを使用した場合、以下の通りとなります。

  • マイGPTで設定した「知識」と「指示 」の両方が適用される
  • プロジェクトの「知識」にも技術的にはアクセス可能
  • プロジェクトメモリに内容は保存される

メモリと知識の範囲(検証)

実験条件:

  • プロジェクト:
    • 名前:お天気情報まとめ
    • 指示:「だ」「である」と硬い表現で答えてください
    • 知識:weather_project.txt
  • マイGPT:
    • 名前:お天気情報
    • 指示:小さい子供に話しかけるように、優しく答えてください
    • 知識:weather_GPT.txt 

結果:

プロジェクト内でマイGPTを使った時の、知識とメモリの適応範囲の実験結果。

プロジェクト内でマイGPTを使った時の、知識とメモリの適応範囲。

まず、プロジェクト内でマイGPTを使用し、マイGPTの知識について聞くと、自然にマイGPTの知識を参照しました(図左)。次に、プロジェクトの知識について聞くと(図中央上)参照されませんでしたが、明示的にプロジェクトの知識(ファイル)の内容を聞くと(図中央下)アクセスできました。最後に、プロジェクト内の他のチャットで会話した内容について聞くと、マイGPTを使用した場合、使用してない場合、両方の内容とも記憶していました。

まとめ

  • マイGPT(MyGPTs)は役割や知識を持たせた「専属の専門家」。
  • プロジェクトはファイル・チャット・指示・メモリをまとめる「作業環境」。
  • 両者を併用することで柔軟かつ効率的に活用可能。
  • ただし挙動は今後変更される可能性があるため、常に最新の公式情報をご確認ください。

🔗 本記事の最新版は こちら 

ChatGPT マイGPT×プロジェクト×メモリの使い方【独自検証つき】


ChatGPT をチャットベースで利用する際、マイGPT(MyGPTs)・プロジェクト・メモリの3つの機能が重要な役割を果たします。これらを活用することで、ChatGPT を自分専属のコンサルタントに近づけ、幅広いニーズに合わせた使い方が可能になります。

マイGPT(MyGPTs)とは?〜自分専属のコンサルタント

基本機能

マイGPTには大きく分けて3つの特徴があります。手入力による設定は至ってシンプル。設定自体をChatGPTに依頼することもでき、方向性を入力するだけで必要に応じた質問を返しながら調整してくれます。

指示(人格・役割の設定)

テキストでGPTに期待する役割を書きます。

例: 「あなたは英語と日本語を母国語とする英会話教室のベテラン英語教師です。TOEIC500点の日本人を想定し...」

知識(ファイルのアップロード)

ユーザー独自の情報をファイルとして与えることができます。例えば、統計データ、方針やガイドラインをまとめたテキスト、自分の文章やイラストのサンプルデータなどです。

アップロードされたデータは必要に応じて参照されます。チャットでの質問などでファイルを参照する確度、頻度を上げたい場合、指示でそのように書くなどの工夫が必要です。

対応するファイル形式は公式ドキュメント (Supported files) を参照してください。

  • PDF
  • Word (.doc, .docx)
  • Excel (.xls, .xlsx)
  • PowerPoint (.ppt, .pptx)
  • テキスト (.txt, .csv)
  • コード等(.c, .json, .html など)

@による呼び出し

チャットで最初に“@”とマイGPTの名前を入力することで、作成済みのマイGPTを呼び出せます。

マイGPTの使い方(活用例)

  • 語学学習:自分の国籍、学習言語、レベル、使用言語を指定。
  • 論文要約:要約の長さ、新規性、根拠の信頼性などを指定。
  • 校閲:自分の文章、契約書等をレビュー、間違いなどの確認。

設定方法

  1. ChatGPTを開き、左サイドバーの「GPT」をクリック。
  2. 右上の「+作成する」で新規作成。
  3. 左側が設定画面、右側で試験的に会話が可能。

マイGPT作成画面。

左サイドバーの「GPT」をクリックし、右上の「+作成する」でマイGPTを作成。

「作成する」を選べばChatGPTに設定を任せることもできますが、「構成」タブで以下を設定することも可能です:

  • 名前:わかりやすく簡潔に。
  • 説明:多数作る場合のメモや公開時の説明文。
  • 指示:性格・専門性・ルールを設定。
  • 会話のきっかけ:最初に投げかける文を設定。「最新の◯◯を教えて」などとしてテンプレ化が可能。
  • 知識:前述のファイルをアップロード。
  • 推奨モデル:特定モデルを指定可能。指定しない場合は通常のチャットモデルを利用。
  • 機能:ウェブ検索、Canvas、画像生成などを有効化。初期状態はユーザー環境によって異なる場合があります。

マイGPTの設定画面。

左側のタブ「作成する」で「ブログ作成のアドバイザーが欲しいです...」「はい」「okです。」とすることで、「構成」の設定が作成された。

プロジェクトとは?〜自分専用の作業環境

基本機能

プロジェクトは複数のチャットやファイルをまとめる作業環境です。用途ごとに整理することで、一貫した作業がしやすくなります。

  • フォルダ機能:「旅行計画」「仕事」「語学」などテーマごとにプロジェクトとして分けられる。
  • 指示の追加:プロジェクト内のチャットでは、ここで設定した指示が優先されます(公式ドキュメント)。
  • 知識の追加:アップロードしたファイルをプロジェクト全体で利用可能。
  • 専用メモリ:プロジェクト単位で記憶を保持。設定で「プロジェクトのみ」とすることで、プロジェクト内に閉じた記憶となり、外部とは共有されません(公式ドキュメント)。

メモリとチャット参照の利用とその範囲

メモリを利用するためには、サブスクリプションの場合、ChatGPTの設定>パーソナライズで「保存されたメモリを参照する」と「チャット履歴を参照する」をオンにする必要があります。

プロジェクトが参照、保存できるメモリの範囲は、プロジェクト作成時の設定で変わります。「デフォルト」を選んだ場合、ChatGPT全体のメモリに相互にアクセスできるようになります。一方で、「プロジェクトのみ」を選ぶと、メモリの参照、保存はプロジェクト内部で閉じることになります。いずれの場合も、プロジェクト内のチャットは相互に参照でき、外部と内部の参照はできません

プロジェクト内部のメモリに保存された内容は、ユーザーが見ることはできません。

プロジェクトのメモリとチャット参照の範囲。

プロジェクトのメモリとチャット参照の範囲(公式ドキュメント)。

プロジェクトの使い方(活用例)

  • 「夏の旅行計画」と「冬の旅行計画」を別チャットに分けつつ、同じプロジェクトで管理。
  • 語学学習プロジェクトで、文法、会話、リーディングにチャットを分け、全体の進捗はメモリで共有。
  • 記事作成プロジェクトで、記事ごとにチャットを分け、校正・HTML変換を行う。あるいは役割ごとにチャットを分ける。

マイGPT × プロジェクトの併用 (2025.09.16現在)

マイGPTとプロジェクトは別機能ですが、同時に利用することも可能です。執筆時点の仕様では、新規チャット開始時に“@”でマイGPTを呼び出すと、チャットがプロジェクト外に作成されてしまいます。ただし、プロジェク ト内で会話を始め、途中からマイGPTを呼び出すことは可能です。

  • マイGPT:特定の人格・専門家を設定し、任意のタイミングで呼び出し可能。
  • プロジェクト:共通の指示・知識をもとに進める閉じた作業環境。

メモリ、知識の活用と適用範囲

公式情報では、マイGPTとプロジェクトのメモリや知識の適用範囲を明確に確認できなかったため、簡単な実験を行いました。結論としては、プロジェクト内でマイGPTを使用した場合、以下の通りとなります。

  • マイGPTで設定した「知識」と「指示 」の両方が適用される
  • プロジェクトの「知識」にも技術的にはアクセス可能
  • プロジェクトメモリに内容は保存される

メモリと知識の範囲(検証)

実験条件:

  • プロジェクト:
    • 名前:お天気情報まとめ
    • 指示:「だ」「である」と硬い表現で答えてください
    • 知識:weather_project.txt
  • マイGPT:
    • 名前:お天気情報
    • 指示:小さい子供に話しかけるように、優しく答えてください
    • 知識:weather_GPT.txt 

結果:

プロジェクト内でマイGPTを使った時の、知識とメモリの適応範囲の実験結果。

プロジェクト内でマイGPTを使った時の、知識とメモリの適応範囲。

まず、プロジェクト内でマイGPTを使用し、マイGPTの知識について聞くと、自然にマイGPTの知識を参照しました(図左)。次に、プロジェクトの知識について聞くと(図中央上)参照されませんでしたが、明示的にプロジェクトの知識(ファイル)の内容を聞くと(図中央下)アクセスできました。最後に、プロジェクト内の他のチャットで会話した内容について聞くと、マイGPTを使用した場合、使用してない場合、両方の内容とも記憶していました。

まとめ

  • マイGPT(MyGPTs)は役割や知識を持たせた「専属の専門家」。
  • プロジェクトはファイル・チャット・指示・メモリをまとめる「作業環境」。
  • 両者を併用することで柔軟かつ効率的に活用可能。
  • ただし挙動は今後変更される可能性があるため、常に最新の公式情報をご確認ください。

ChatGPT マイGPT×プロジェクト×メモリの使い方【独自検証つき】


ChatGPT をチャットベースで利用する際、マイGPT(MyGPTs)・プロジェクト・メモリの3つの機能が重要な役割を果たします。これらを活用することで、ChatGPT を自分専属のコンサルタントに近づけ、幅広いニーズに合わせた使い方が可能になります。

マイGPT(MyGPTs)とは?〜自分専属のコンサルタント

基本機能

マイGPTには大きく分けて3つの特徴があります。手入力による設定は至ってシンプル。設定自体をChatGPTに依頼することもでき、方向性を入力するだけで必要に応じた質問を返しながら調整してくれます。

指示(人格・役割の設定)

テキストでGPTに期待する役割を書きます。

例: 「あなたは英語と日本語を母国語とする英会話教室のベテラン英語教師です。TOEIC500点の日本人を想定し...」

知識(ファイルのアップロード)

ユーザー独自の情報をファイルとして与えることができます。例えば、統計データ、方針やガイドラインをまとめたテキスト、自分の文章やイラストのサンプルデータなどです。

アップロードされたデータは必要に応じて参照されます。チャットでの質問などでファイルを参照する確度、頻度を上げたい場合、指示でそのように書くなどの工夫が必要です。

対応するファイル形式は公式ドキュメント (Supported files) を参照してください。

  • PDF
  • Word (.doc, .docx)
  • Excel (.xls, .xlsx)
  • PowerPoint (.ppt, .pptx)
  • テキスト (.txt, .csv)
  • コード等(.c, .json, .html など)

@による呼び出し

チャットで最初に“@”とマイGPTの名前を入力することで、作成済みのマイGPTを呼び出せます。

マイGPTの使い方(活用例)

  • 語学学習:自分の国籍、学習言語、レベル、使用言語を指定。
  • 論文要約:要約の長さ、新規性、根拠の信頼性などを指定。
  • 校閲:自分の文章、契約書等をレビュー、間違いなどの確認。

設定方法

  1. ChatGPTを開き、左サイドバーの「GPT」をクリック。
  2. 右上の「+作成する」で新規作成。
  3. 左側が設定画面、右側で試験的に会話が可能。

マイGPT作成画面。

左サイドバーの「GPT」をクリックし、右上の「+作成する」でマイGPTを作成。

「作成する」を選べばChatGPTに設定を任せることもできますが、「構成」タブで以下を設定することも可能です:

  • 名前:わかりやすく簡潔に。
  • 説明:多数作る場合のメモや公開時の説明文。
  • 指示:性格・専門性・ルールを設定。
  • 会話のきっかけ:最初に投げかける文を設定。「最新の◯◯を教えて」などとしてテンプレ化が可能。
  • 知識:前述のファイルをアップロード。
  • 推奨モデル:特定モデルを指定可能。指定しない場合は通常のチャットモデルを利用。
  • 機能:ウェブ検索、Canvas、画像生成などを有効化。初期状態はユーザー環境によって異なる場合があります。

マイGPTの設定画面。

左側のタブ「作成する」で「ブログ作成のアドバイザーが欲しいです...」「はい」「okです。」とすることで、「構成」の設定が作成された。

プロジェクトとは?〜自分専用の作業環境

基本機能

プロジェクトは複数のチャットやファイルをまとめる作業環境です。用途ごとに整理することで、一貫した作業がしやすくなります。

  • フォルダ機能:「旅行計画」「仕事」「語学」などテーマごとにプロジェクトとして分けられる。
  • 指示の追加:プロジェクト内のチャットでは、ここで設定した指示が優先されます(公式ドキュメント)。
  • 知識の追加:アップロードしたファイルをプロジェクト全体で利用可能。
  • 専用メモリ:プロジェクト単位で記憶を保持。設定で「プロジェクトのみ」とすることで、プロジェクト内に閉じた記憶となり、外部とは共有されません(公式ドキュメント)。

メモリとチャット参照の利用とその範囲

メモリを利用するためには、サブスクリプションの場合、ChatGPTの設定>パーソナライズで「保存されたメモリを参照する」と「チャット履歴を参照する」をオンにする必要があります。

プロジェクトが参照、保存できるメモリの範囲は、プロジェクト作成時の設定で変わります。「デフォルト」を選んだ場合、ChatGPT全体のメモリに相互にアクセスできるようになります。一方で、「プロジェクトのみ」を選ぶと、メモリの参照、保存はプロジェクト内部で閉じることになります。いずれの場合も、プロジェクト内のチャットは相互に参照でき、外部と内部の参照はできません

プロジェクト内部のメモリに保存された内容は、ユーザーが見ることはできません。

プロジェクトのメモリとチャット参照の範囲。

プロジェクトのメモリとチャット参照の範囲(公式ドキュメント)。

プロジェクトの使い方(活用例)

  • 「夏の旅行計画」と「冬の旅行計画」を別チャットに分けつつ、同じプロジェクトで管理。
  • 語学学習プロジェクトで、文法、会話、リーディングにチャットを分け、全体の進捗はメモリで共有。
  • 記事作成プロジェクトで、記事ごとにチャットを分け、校正・HTML変換を行う。あるいは役割ごとにチャットを分ける。

マイGPT × プロジェクトの併用 (2025.09.16現在)

マイGPTとプロジェクトは別機能ですが、同時に利用することも可能です。執筆時点の仕様では、新規チャット開始時に“@”でマイGPTを呼び出すと、チャットがプロジェクト外に作成されてしまいます。ただし、プロジェク ト内で会話を始め、途中からマイGPTを呼び出すことは可能です。

  • マイGPT:特定の人格・専門家を設定し、任意のタイミングで呼び出し可能。
  • プロジェクト:共通の指示・知識をもとに進める閉じた作業環境。

メモリ、知識の活用と適用範囲

公式情報では、マイGPTとプロジェクトのメモリや知識の適用範囲を明確に確認できなかったため、簡単な実験を行いました。結論としては、プロジェクト内でマイGPTを使用した場合、以下の通りとなります。

  • マイGPTで設定した「知識」と「指示 」の両方が適用される
  • プロジェクトの「知識」にも技術的にはアクセス可能
  • プロジェクトメモリに内容は保存される

メモリと知識の範囲(検証)

実験条件:

  • プロジェクト:
    • 名前:お天気情報まとめ
    • 指示:「だ」「である」と硬い表現で答えてください
    • 知識:weather_project.txt
  • マイGPT:
    • 名前:お天気情報
    • 指示:小さい子供に話しかけるように、優しく答えてください
    • 知識:weather_GPT.txt 

結果:

プロジェクト内でマイGPTを使った時の、知識とメモリの適応範囲の実験結果。

プロジェクト内でマイGPTを使った時の、知識とメモリの適応範囲。

まず、プロジェクト内でマイGPTを使用し、マイGPTの知識について聞くと、自然にマイGPTの知識を参照しました(図左)。次に、プロジェクトの知識について聞くと(図中央上)参照されませんでしたが、明示的にプロジェクトの知識(ファイル)の内容を聞くと(図中央下)アクセスできました。最後に、プロジェクト内の他のチャットで会話した内容について聞くと、マイGPTを使用した場合、使用してない場合、両方の内容とも記憶していました。

まとめ

  • マイGPT(MyGPTs)は役割や知識を持たせた「専属の専門家」。
  • プロジェクトはファイル・チャット・指示・メモリをまとめる「作業環境」。
  • 両者を併用することで柔軟かつ効率的に活用可能。
  • ただし挙動は今後変更される可能性があるため、常に最新の公式情報をご確認ください。

この記事の最新バージョンは新ブログで公開しています:
👉 https://ai-physics-lab.com/ja/chatgpt-custom-guide-mygpt-project-memory/

Perceptual Loss

GitHub リポジトリ(コード全体はこちら)


<概要>

Perceptual Lossはノイズ除去などにおいて、人間が認識する、画像に含まれる構造に着目して、より現実的に意味のある学習を可能にします。

本記事では、Perceptual Lossの大まかな原理、中間層から得られる feature map(特徴マップ)の様子、VGG16を用いた実装から応用例より効果を上げるための Tips まで説明します。

Perceptual Loss に至る背景

従来の画像比較の定量化

教師あり学習で画像処理を行う場合、入力画像からターゲットとなる画像を出力するように訓練するのが一般的です。その際、出力画像がターゲットと等しくなることを目的に、ピクセルごとの誤差を足し上げた値、MSE(Mean Square Error)が損失関数としてよく用いられます。

AIの現実的な限界

MSEがテストデータで限りなく0に近づくことが理想ですが、ノイズ除去や超解像などの応用では、完全に期待通りの画像を出力するのは原理的に不可能です。つまり、学習結果が不完全なりに、どのように正解に近づけるかが重要になります。

直感的な画像比較の定量化

MSEによる訓練では、数値的な誤差が小さくても、人間が見て「不自然」と感じる構造の誤差が残ることが多くあります。それはMSEが画素単位の誤差に着目するのみで、構造的類似度を反映しないためです。これを補うために構造の類似度に着目したものに、 SSIM があります。これは各ピクセル近傍の値のばらつき方の類似を定量化する指標で、構造の類似度をより捉えやすくします。

とはいえ、SSIM も固定的な計算式によるため、人間の知覚と完全に一致するわけではありません。そこで、さらに「人間が感じる画像間の類似性」を定量化できる手法として期待されるのが、Perceptual Lossです。

Perceptual Loss の原理

AI (VGG) による「直感」の定量化

人間の直感的な画像認識を数式化するのは困難ですが、Perceptual Loss は、画像認識に優れた訓練済みのニューラルネットワーク(VGG: ソースコード)を活用することで、これを実現しています。VGGは、オックスフォード大学の Visual Geometry Group が2015年に開発したモデルで、層の深さに応じて VGG11 / VGG16 などがあります。

VGG16の模式図。Convolution、ReLU、Fully Connected, softmaxからなる。

VGG16の模式図。前半はCNNベース、max poolingで徐々に特徴マップが小さくなり、最後にfully connected layer、softmax (活性化関数) につながり、1000 クラスに画像を分類する。

Perceptual Lossで使われる、VGG16の特徴マップ

VGG は RGB 入力画像から豊富な特徴量を抽出し、1000クラスに分類できます。したがって、画像の構造やテクスチャーを抽出する能力に長けていると考えられます。実際、訓練済みモデルに犬の画像を入力し中間層の特徴マップを可視化すると、浅い層ではザラつきや質感といった局所的特徴が、深層に進むにつれて輪郭や意味的構造が抽象的に表現されていく様子がわかります。

VGG16の中間層からとりだした特徴マップ。

VGG16の特徴マップ。各ブロックごとに、全特徴マップの下に、抽象度が上がる順番に代表例を3つ表示した。第一ブロックでは前景、背景、そして細かいテクスチャーが、第二ブロックでは太陽光のあたっている部分、犬の目と鼻、微分フィルタを通したような特徴、第3ブロックでは背景のテクスチャーや輪郭、犬の各部位(目、鼻、手など)、そして意味が明確ではない特徴が観察できる。

特徴マップを利用した損失の計算

各特徴マップの意味を解釈するのは難しいですが、モデルが画像認識のために学習した構造が反映されているのは明らかです。そこで、比較したい2つの画像を訓練済みのVGGモデルにそれぞれ入力し、中間層の特徴マップ間の絶対誤差を積算することで、人間が直感的に感じる構造・テクスチャーの差異を定量化できます。これをPerceptual(知覚的)Loss(損失)と呼びます。

Perceptual Loss の実装

以下では、VGG16 を用いた Perceptual Loss のクラスを PyTorch で実装した例を紹介します。訓練済みの VGG16 モデルをダウンロードして vgg16.pth という名前で保存し、クラスのインスタンスを作成する際に path 引数として指定します。

コードは大きく次のブロックに分かれています:

  • VGG16 モデルのロードとブロック分割
  • 標準化および画像サイズの調整
  • 特徴マップおよびスタイルマップに基づく損失計算

次のセクションでは、これらの詳細なコードブロックとその役割を順に説明していきます。

PyTorch に不安のある方は、以下の記事を御覧ください。

PyTorchモデルの全体構造と作り方|nn.Module・Sequential・ModuleListを図解で理解 - ぶつりやAI

import torch
import torchvision
import torchvision.models as models

class VGGPerceptualLoss(torch.nn.Module):
    def __init__(self, path='/content/drive/MyDrive/VGGPerceptualLoss/vgg16.pth', resize=True):
        super(VGGPerceptualLoss, self).__init__()
        # load trained model
        # load vgg into cuda if available, load into cpu if cuda not available
        if torch.cuda.is_available():
            self.vgg = models.vgg16().to('cuda')
        else:
            self.vgg = models.vgg16().to('cpu')
        self.vgg.load_state_dict((torch.load(path)))
        self.vgg.eval() # モデルを評価モードにする。
        # preparation to get feature maps from the middle of the model
        blocks = [
            self.vgg.features[:4],
            self.vgg.features[4:9],
            self.vgg.features[9:16],
            self.vgg.features[16:23]
        ]
        # No grad to prevent back propagation
        for bl in blocks:
            for p in bl.parameters():
                p.requires_grad = False
        # Combine the blocks into ModuleList
        self.blocks = torch.nn.ModuleList(blocks)
        self.transform = torch.nn.functional.interpolate
        self.resize = resize
        self.register_buffer("mean", torch.tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1))
        self.register_buffer("std", torch.tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1))

    def forward(self, input, target, feature_layers=[0, 1, 2, 3], style_layers=[]):
        # shape の調整
        if input.shape[1] != 3:
            input = input.repeat(1, 3, 1, 1) # model output
            target = target.repeat(1, 3, 1, 1) # ground truth
        # ピクセル値の標準化
        input = (input-self.mean) / self.std
        target = (target-self.mean) / self.std
        # 画像サイズの調整
        if self.resize:
            input = self.transform(input, mode='bilinear', size=(224, 224), align_corners=False)
            target = self.transform(target, mode='bilinear', size=(224, 224), align_corners=False)
        loss = 0.0
        x = input
        y = target
        # 順伝搬 (forward propagation)
        for i, block in enumerate(self.blocks):
            x = block(x)
            y = block(y)
            if i in feature_layers:
                # add loss by using the feature map in the middle of the model
                loss += torch.nn.functional.l1_loss(x, y)
            if i in style_layers:
                # add loss by using the "style layer" calculated from the feature maps
                act_x = x.reshape(x.shape[0], x.shape[1], -1)
                act_y = y.reshape(y.shape[0], y.shape[1], -1)
                gram_x = act_x @ act_x.permute(0, 2, 1)
                gram_y = act_y @ act_y.permute(0, 2, 1)
                loss += torch.nn.functional.l1_loss(gram_x, gram_y)
        return loss

中間層の準備

モデルそのものは torchvision.models にすでに用意されている VGG16 を使用し、保存しておいた訓練済みのパラメータを load_state_dict で読み込みます。モデルを評価モード(.eval())に切り替えた後、VGG16 を複数のブロック(blocks)に分割してリストとして保存しておきます。これにより、後ほど特徴マップを個別に取り出すことができます。

VGG16 の中間層(Conv2D や ReLU の繰り返し)は、features という名前で定義されており、以下のドキュメントでも確認できます:

torchvision.models.vgg — PyTorch Docs

Perceptual Loss の計算中に VGG16 の重みが更新されないように、分割した各ブロックのすべてのパラメータについて requires_grad = False を設定して、勾配計算が行われないようにします。

最後に、これらのブロックを torch.nn.ModuleList にまとめて self.blocks に格納し、順番に特徴マップを計算できるようにします。

import torchvision.models as models
# モデルをロード
if torch.cuda.is_available():
    self.vgg = models.vgg16().to('cuda')
else:
    self.vgg = models.vgg16().to('cpu')
    
# パラメータをロード
self.vgg.load_state_dict((torch.load(path)))
self.vgg.eval() # モデルを評価モードにする。
blocks = [
    self.vgg.features[:4],
    self.vgg.features[4:9],
    self.vgg.features[9:16],
    self.vgg.features[16:23]
]

# No grad to prevent back propagation
for bl in blocks:
    for p in bl.parameters():
        p.requires_grad = False
        
# Combine the blocks into ModuleList
self.blocks = torch.nn.ModuleList(blocks)

Forwardで順伝搬

ここで、x および y はそれぞれモデルの出力画像と正解画像(前処理済)です。これらを self.blocks に格納された VGG16 の各ブロックに順番に通し、特徴マップを抽出します。

x = block(x)y = block(y) によって得られるのが特徴マップであり、これらの差を L1損失として加算し、Perceptual Loss を構成します。

# 順伝搬 (forward propagation)
for i, block in enumerate(self.blocks):
    x = block(x)
    y = block(y)
    if i in feature_layers:
        # add loss by using the feature map in the middle of the model
        loss += torch.nn.functional.l1_loss(x, y)

この処理により、画像の高次特徴がどれだけ似ているかを損失として捉えることができます。

Style Transfer

Perceptual Loss の原論文では、Style Transfer(スタイル変換) という応用技術も提案されています。これは、出力画像の「内容」は保持しつつ、「スタイル(画風)」だけを別の画像に似せるというもので、例として写真をアニメ風や油絵風に変換することができます。

具体的には、各ブロックから得られた特徴マップ同士の「スタイル(相関構造)」を Gram行列として定義し、その差を L1損失として計算します。これにより、「スタイルの違い」を損失として表現することができます。

if i in style_layers:
    # add loss by using the "style layer" calculated from the feature maps
    act_x = x.reshape(x.shape[0], x.shape[1], -1)
    act_y = y.reshape(y.shape[0], y.shape[1], -1)
    gram_x = act_x @ act_x.permute(0, 2, 1)
    gram_y = act_y @ act_y.permute(0, 2, 1)
    loss += torch.nn.functional.l1_loss(gram_x, gram_y)

この処理により、スタイルだけを揃えることも、Perceptual Loss(内容)と組み合わせて両方を揃えることも可能になります。

Perceptual Loss の実用例

超解像(Super Resolution)

超解像とは、低解像度の入力画像から高解像度の出力画像を生成する技術です。たとえば、256×256 の画像から 512×512 の画像を再構成するような問題で、ディープラーニングによる画像処理の代表的な応用の一つです。

このような問題は ill-posed(解が一意に定まらない) であり、細部の再現性が不十分となる場合があります。

こうした状況でも、Perceptual Loss は、人間が「自然」と感じる構造が一致するように学習させることができます。特に、ESRGAN では、GAN(敵対的ネットワーク)と Perceptual Loss を組み合わせることで、細かな構造を再現する性能が大きく向上することが報告されています。

さらに、VGG の中間層出力から特徴を得る際には ReLU 直前(Conv2Dの出力) を使うことで、画像の明暗やエッジがより忠実に再現されると報告されています。

ノイズ除去

ノイズ除去は、日常の写真だけでなく、CT や MRI などの医療画像にも広く応用されています。

例えば、CT画像への応用例では、Perceptual Loss のみを使用した場合にはグリッド状のアーティファクトが残ることがあり、MSE + Perceptual Loss を併用することで、自然で高品質な画像が得られることが報告されています。

Style Transfer

Style Transfer(スタイル変換)は、出力画像の「内容」を保持しつつ、「スタイル」(色使いや質感)を別の画像から学習させる技術です。Perceptual Loss の代表的な応用として知られています。

例えば、写真をジブリ風や印象派風に変換したり、アニメの作風を模倣することが可能です。これは、画像の構造とスタイルの類似性を特徴マップから定量化できる Perceptual Loss の強みを活かした例です。

まとめ

本記事では、Perceptual Loss の背景、原理、実装方法、そして応用例を詳しく解説しました。ピクセル単位での誤差評価にとどまらず、「人間の知覚に基づく類似性」を損失関数として導入することで、より高品質な画像処理が可能になります。

特に、VGG の中間層から得られる特徴マップを用いることで、画像の 構造的・意味的特徴 を活かした訓練ができる点が重要です。

また、Style Transfer をはじめとする様々な応用により、Perceptual Loss は単なる損失関数ではなく、画像理解と生成の鍵となる技術として注目されています。

ディープラーニングを用いた画像処理において、表現力を一段階引き上げたいと考えるすべての実践者にとって、Perceptual Loss は極めて有用なツールと言えます。

引用

Perceptual Loss:

 arxiv.org 

VGG:

 arxiv.org 

超解像:

 arxiv.org 

デノイズ:

pmc.ncbi.nlm.nih.gov

Perceptual Loss

GitHub リポジトリ(コード全体はこちら)


<概要>

Perceptual Lossはノイズ除去などにおいて、人間が認識する、画像に含まれる構造に着目して、より現実的に意味のある学習を可能にします。

本記事では、Perceptual Lossの大まかな原理、中間層から得られる feature map(特徴マップ)の様子、VGG16を用いた実装から応用例より効果を上げるための Tips まで説明します。

Perceptual Loss に至る背景

従来の画像比較の定量化

教師あり学習で画像処理を行う場合、入力画像からターゲットとなる画像を出力するように訓練するのが一般的です。その際、出力画像がターゲットと等しくなることを目的に、ピクセルごとの誤差を足し上げた値、MSE(Mean Square Error)が損失関数としてよく用いられます。

AIの現実的な限界

MSEがテストデータで限りなく0に近づくことが理想ですが、ノイズ除去や超解像などの応用では、完全に期待通りの画像を出力するのは原理的に不可能です。つまり、学習結果が不完全なりに、どのように正解に近づけるかが重要になります。

直感的な画像比較の定量化

MSEによる訓練では、数値的な誤差が小さくても、人間が見て「不自然」と感じる構造の誤差が残ることが多くあります。それはMSEが画素単位の誤差に着目するのみで、構造的類似度を反映しないためです。これを補うために構造の類似度に着目したものに、 SSIM があります。これは各ピクセル近傍の値のばらつき方の類似を定量化する指標で、構造の類似度をより捉えやすくします。

とはいえ、SSIM も固定的な計算式によるため、人間の知覚と完全に一致するわけではありません。そこで、さらに「人間が感じる画像間の類似性」を定量化できる手法として期待されるのが、Perceptual Lossです。

Perceptual Loss の原理

AI (VGG) による「直感」の定量化

人間の直感的な画像認識を数式化するのは困難ですが、Perceptual Loss は、画像認識に優れた訓練済みのニューラルネットワーク(VGG: ソースコード)を活用することで、これを実現しています。VGGは、オックスフォード大学の Visual Geometry Group が2015年に開発したモデルで、層の深さに応じて VGG11 / VGG16 などがあります。

VGG16の模式図。Convolution、ReLU、Fully Connected, softmaxからなる。

VGG16の模式図。前半はCNNベース、max poolingで徐々に特徴マップが小さくなり、最後にfully connected layer、softmax (活性化関数) につながり、1000 クラスに画像を分類する。

Perceptual Lossで使われる、VGG16の特徴マップ

VGG は RGB 入力画像から豊富な特徴量を抽出し、1000クラスに分類できます。したがって、画像の構造やテクスチャーを抽出する能力に長けていると考えられます。実際、訓練済みモデルに犬の画像を入力し中間層の特徴マップを可視化すると、浅い層ではザラつきや質感といった局所的特徴が、深層に進むにつれて輪郭や意味的構造が抽象的に表現されていく様子がわかります。

VGG16の中間層からとりだした特徴マップ。

VGG16の特徴マップ。各ブロックごとに、全特徴マップの下に、抽象度が上がる順番に代表例を3つ表示した。第一ブロックでは前景、背景、そして細かいテクスチャーが、第二ブロックでは太陽光のあたっている部分、犬の目と鼻、微分フィルタを通したような特徴、第3ブロックでは背景のテクスチャーや輪郭、犬の各部位(目、鼻、手など)、そして意味が明確ではない特徴が観察できる。

特徴マップを利用した損失の計算

各特徴マップの意味を解釈するのは難しいですが、モデルが画像認識のために学習した構造が反映されているのは明らかです。そこで、比較したい2つの画像を訓練済みのVGGモデルにそれぞれ入力し、中間層の特徴マップ間の絶対誤差を積算することで、人間が直感的に感じる構造・テクスチャーの差異を定量化できます。これをPerceptual(知覚的)Loss(損失)と呼びます。

Perceptual Loss の実装

以下では、VGG16 を用いた Perceptual Loss のクラスを PyTorch で実装した例を紹介します。訓練済みの VGG16 モデルをダウンロードして vgg16.pth という名前で保存し、クラスのインスタンスを作成する際に path 引数として指定します。

コードは大きく次のブロックに分かれています:

  • VGG16 モデルのロードとブロック分割
  • 標準化および画像サイズの調整
  • 特徴マップおよびスタイルマップに基づく損失計算

次のセクションでは、これらの詳細なコードブロックとその役割を順に説明していきます。

PyTorch に不安のある方は、以下の記事を御覧ください。

PyTorchモデルの全体構造と作り方|nn.Module・Sequential・ModuleListを図解で理解 - ぶつりやAI

import torch
import torchvision
import torchvision.models as models

class VGGPerceptualLoss(torch.nn.Module):
    def __init__(self, path='/content/drive/MyDrive/VGGPerceptualLoss/vgg16.pth', resize=True):
        super(VGGPerceptualLoss, self).__init__()
        # load trained model
        # load vgg into cuda if available, load into cpu if cuda not available
        if torch.cuda.is_available():
            self.vgg = models.vgg16().to('cuda')
        else:
            self.vgg = models.vgg16().to('cpu')
        self.vgg.load_state_dict((torch.load(path)))
        self.vgg.eval() # モデルを評価モードにする。
        # preparation to get feature maps from the middle of the model
        blocks = [
            self.vgg.features[:4],
            self.vgg.features[4:9],
            self.vgg.features[9:16],
            self.vgg.features[16:23]
        ]
        # No grad to prevent back propagation
        for bl in blocks:
            for p in bl.parameters():
                p.requires_grad = False
        # Combine the blocks into ModuleList
        self.blocks = torch.nn.ModuleList(blocks)
        self.transform = torch.nn.functional.interpolate
        self.resize = resize
        self.register_buffer("mean", torch.tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1))
        self.register_buffer("std", torch.tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1))

    def forward(self, input, target, feature_layers=[0, 1, 2, 3], style_layers=[]):
        # shape の調整
        if input.shape[1] != 3:
            input = input.repeat(1, 3, 1, 1) # model output
            target = target.repeat(1, 3, 1, 1) # ground truth
        # ピクセル値の標準化
        input = (input-self.mean) / self.std
        target = (target-self.mean) / self.std
        # 画像サイズの調整
        if self.resize:
            input = self.transform(input, mode='bilinear', size=(224, 224), align_corners=False)
            target = self.transform(target, mode='bilinear', size=(224, 224), align_corners=False)
        loss = 0.0
        x = input
        y = target
        # 順伝搬 (forward propagation)
        for i, block in enumerate(self.blocks):
            x = block(x)
            y = block(y)
            if i in feature_layers:
                # add loss by using the feature map in the middle of the model
                loss += torch.nn.functional.l1_loss(x, y)
            if i in style_layers:
                # add loss by using the "style layer" calculated from the feature maps
                act_x = x.reshape(x.shape[0], x.shape[1], -1)
                act_y = y.reshape(y.shape[0], y.shape[1], -1)
                gram_x = act_x @ act_x.permute(0, 2, 1)
                gram_y = act_y @ act_y.permute(0, 2, 1)
                loss += torch.nn.functional.l1_loss(gram_x, gram_y)
        return loss

中間層の準備

モデルそのものは torchvision.models にすでに用意されている VGG16 を使用し、保存しておいた訓練済みのパラメータを load_state_dict で読み込みます。モデルを評価モード(.eval())に切り替えた後、VGG16 を複数のブロック(blocks)に分割してリストとして保存しておきます。これにより、後ほど特徴マップを個別に取り出すことができます。

VGG16 の中間層(Conv2D や ReLU の繰り返し)は、features という名前で定義されており、以下のドキュメントでも確認できます:

torchvision.models.vgg — PyTorch Docs

Perceptual Loss の計算中に VGG16 の重みが更新されないように、分割した各ブロックのすべてのパラメータについて requires_grad = False を設定して、勾配計算が行われないようにします。

最後に、これらのブロックを torch.nn.ModuleList にまとめて self.blocks に格納し、順番に特徴マップを計算できるようにします。

import torchvision.models as models
# モデルをロード
if torch.cuda.is_available():
    self.vgg = models.vgg16().to('cuda')
else:
    self.vgg = models.vgg16().to('cpu')
    
# パラメータをロード
self.vgg.load_state_dict((torch.load(path)))
self.vgg.eval() # モデルを評価モードにする。
blocks = [
    self.vgg.features[:4],
    self.vgg.features[4:9],
    self.vgg.features[9:16],
    self.vgg.features[16:23]
]

# No grad to prevent back propagation
for bl in blocks:
    for p in bl.parameters():
        p.requires_grad = False
        
# Combine the blocks into ModuleList
self.blocks = torch.nn.ModuleList(blocks)

Forwardで順伝搬

ここで、x および y はそれぞれモデルの出力画像と正解画像(前処理済)です。これらを self.blocks に格納された VGG16 の各ブロックに順番に通し、特徴マップを抽出します。

x = block(x)y = block(y) によって得られるのが特徴マップであり、これらの差を L1損失として加算し、Perceptual Loss を構成します。

# 順伝搬 (forward propagation)
for i, block in enumerate(self.blocks):
    x = block(x)
    y = block(y)
    if i in feature_layers:
        # add loss by using the feature map in the middle of the model
        loss += torch.nn.functional.l1_loss(x, y)

この処理により、画像の高次特徴がどれだけ似ているかを損失として捉えることができます。

Style Transfer

Perceptual Loss の原論文では、Style Transfer(スタイル変換) という応用技術も提案されています。これは、出力画像の「内容」は保持しつつ、「スタイル(画風)」だけを別の画像に似せるというもので、例として写真をアニメ風や油絵風に変換することができます。

具体的には、各ブロックから得られた特徴マップ同士の「スタイル(相関構造)」を Gram行列として定義し、その差を L1損失として計算します。これにより、「スタイルの違い」を損失として表現することができます。

if i in style_layers:
    # add loss by using the "style layer" calculated from the feature maps
    act_x = x.reshape(x.shape[0], x.shape[1], -1)
    act_y = y.reshape(y.shape[0], y.shape[1], -1)
    gram_x = act_x @ act_x.permute(0, 2, 1)
    gram_y = act_y @ act_y.permute(0, 2, 1)
    loss += torch.nn.functional.l1_loss(gram_x, gram_y)

この処理により、スタイルだけを揃えることも、Perceptual Loss(内容)と組み合わせて両方を揃えることも可能になります。

Perceptual Loss の実用例

超解像(Super Resolution)

超解像とは、低解像度の入力画像から高解像度の出力画像を生成する技術です。たとえば、256×256 の画像から 512×512 の画像を再構成するような問題で、ディープラーニングによる画像処理の代表的な応用の一つです。

このような問題は ill-posed(解が一意に定まらない) であり、細部の再現性が不十分となる場合があります。

こうした状況でも、Perceptual Loss は、人間が「自然」と感じる構造が一致するように学習させることができます。特に、ESRGAN では、GAN(敵対的ネットワーク)と Perceptual Loss を組み合わせることで、細かな構造を再現する性能が大きく向上することが報告されています。

さらに、VGG の中間層出力から特徴を得る際には ReLU 直前(Conv2Dの出力) を使うことで、画像の明暗やエッジがより忠実に再現されると報告されています。

ノイズ除去

ノイズ除去は、日常の写真だけでなく、CT や MRI などの医療画像にも広く応用されています。

例えば、CT画像への応用例では、Perceptual Loss のみを使用した場合にはグリッド状のアーティファクトが残ることがあり、MSE + Perceptual Loss を併用することで、自然で高品質な画像が得られることが報告されています。

Style Transfer

Style Transfer(スタイル変換)は、出力画像の「内容」を保持しつつ、「スタイル」(色使いや質感)を別の画像から学習させる技術です。Perceptual Loss の代表的な応用として知られています。

例えば、写真をジブリ風や印象派風に変換したり、アニメの作風を模倣することが可能です。これは、画像の構造とスタイルの類似性を特徴マップから定量化できる Perceptual Loss の強みを活かした例です。

まとめ

本記事では、Perceptual Loss の背景、原理、実装方法、そして応用例を詳しく解説しました。ピクセル単位での誤差評価にとどまらず、「人間の知覚に基づく類似性」を損失関数として導入することで、より高品質な画像処理が可能になります。

特に、VGG の中間層から得られる特徴マップを用いることで、画像の 構造的・意味的特徴 を活かした訓練ができる点が重要です。

また、Style Transfer をはじめとする様々な応用により、Perceptual Loss は単なる損失関数ではなく、画像理解と生成の鍵となる技術として注目されています。

ディープラーニングを用いた画像処理において、表現力を一段階引き上げたいと考えるすべての実践者にとって、Perceptual Loss は極めて有用なツールと言えます。

引用

Perceptual Loss:

 arxiv.org 

VGG:

 arxiv.org 

超解像:

 arxiv.org 

デノイズ:

pmc.ncbi.nlm.nih.gov

Perceptual Loss

GitHub リポジトリ(コード全体はこちら)


<概要>

Perceptual Lossはノイズ除去などにおいて、人間が認識する、画像に含まれる構造に着目して、より現実的に意味のある学習を可能にします。

本記事では、Perceptual Lossの大まかな原理、中間層から得られる feature map(特徴マップ)の様子、VGG16を用いた実装から応用例より効果を上げるための Tips まで説明します。

Perceptual Loss に至る背景

従来の画像比較の定量化

教師あり学習で画像処理を行う場合、入力画像からターゲットとなる画像を出力するように訓練するのが一般的です。その際、出力画像がターゲットと等しくなることを目的に、ピクセルごとの誤差を足し上げた値、MSE(Mean Square Error)が損失関数としてよく用いられます。

AIの現実的な限界

MSEがテストデータで限りなく0に近づくことが理想ですが、ノイズ除去や超解像などの応用では、完全に期待通りの画像を出力するのは原理的に不可能です。つまり、学習結果が不完全なりに、どのように正解に近づけるかが重要になります。

直感的な画像比較の定量化

MSEによる訓練では、数値的な誤差が小さくても、人間が見て「不自然」と感じる構造の誤差が残ることが多くあります。それはMSEが画素単位の誤差に着目するのみで、構造的類似度を反映しないためです。これを補うために構造の類似度に着目したものに、 SSIM があります。これは各ピクセル近傍の値のばらつき方の類似を定量化する指標で、構造の類似度をより捉えやすくします。

とはいえ、SSIM も固定的な計算式によるため、人間の知覚と完全に一致するわけではありません。そこで、さらに「人間が感じる画像間の類似性」を定量化できる手法として期待されるのが、Perceptual Lossです。

Perceptual Loss の原理

AI (VGG) による「直感」の定量化

人間の直感的な画像認識を数式化するのは困難ですが、Perceptual Loss は、画像認識に優れた訓練済みのニューラルネットワーク(VGG: ソースコード)を活用することで、これを実現しています。VGGは、オックスフォード大学の Visual Geometry Group が2015年に開発したモデルで、層の深さに応じて VGG11 / VGG16 などがあります。

VGG16の模式図。Convolution、ReLU、Fully Connected, softmaxからなる。

VGG16の模式図。前半はCNNベース、max poolingで徐々に特徴マップが小さくなり、最後にfully connected layer、softmax (活性化関数) につながり、1000 クラスに画像を分類する。

Perceptual Lossで使われる、VGG16の特徴マップ

VGG は RGB 入力画像から豊富な特徴量を抽出し、1000クラスに分類できます。したがって、画像の構造やテクスチャーを抽出する能力に長けていると考えられます。実際、訓練済みモデルに犬の画像を入力し中間層の特徴マップを可視化すると、浅い層ではザラつきや質感といった局所的特徴が、深層に進むにつれて輪郭や意味的構造が抽象的に表現されていく様子がわかります。

VGG16の中間層からとりだした特徴マップ。

VGG16の特徴マップ。各ブロックごとに、全特徴マップの下に、抽象度が上がる順番に代表例を3つ表示した。第一ブロックでは前景、背景、そして細かいテクスチャーが、第二ブロックでは太陽光のあたっている部分、犬の目と鼻、微分フィルタを通したような特徴、第3ブロックでは背景のテクスチャーや輪郭、犬の各部位(目、鼻、手など)、そして意味が明確ではない特徴が観察できる。

特徴マップを利用した損失の計算

各特徴マップの意味を解釈するのは難しいですが、モデルが画像認識のために学習した構造が反映されているのは明らかです。そこで、比較したい2つの画像を訓練済みのVGGモデルにそれぞれ入力し、中間層の特徴マップ間の絶対誤差を積算することで、人間が直感的に感じる構造・テクスチャーの差異を定量化できます。これをPerceptual(知覚的)Loss(損失)と呼びます。

Perceptual Loss の実装

以下では、VGG16 を用いた Perceptual Loss のクラスを PyTorch で実装した例を紹介します。訓練済みの VGG16 モデルをダウンロードして vgg16.pth という名前で保存し、クラスのインスタンスを作成する際に path 引数として指定します。

コードは大きく次のブロックに分かれています:

  • VGG16 モデルのロードとブロック分割
  • 標準化および画像サイズの調整
  • 特徴マップおよびスタイルマップに基づく損失計算

次のセクションでは、これらの詳細なコードブロックとその役割を順に説明していきます。

PyTorch に不安のある方は、以下の記事を御覧ください。

PyTorchモデルの全体構造と作り方|nn.Module・Sequential・ModuleListを図解で理解 - ぶつりやAI

import torch
import torchvision
import torchvision.models as models

class VGGPerceptualLoss(torch.nn.Module):
    def __init__(self, path='/content/drive/MyDrive/VGGPerceptualLoss/vgg16.pth', resize=True):
        super(VGGPerceptualLoss, self).__init__()
        # load trained model
        # load vgg into cuda if available, load into cpu if cuda not available
        if torch.cuda.is_available():
            self.vgg = models.vgg16().to('cuda')
        else:
            self.vgg = models.vgg16().to('cpu')
        self.vgg.load_state_dict((torch.load(path)))
        self.vgg.eval() # モデルを評価モードにする。
        # preparation to get feature maps from the middle of the model
        blocks = [
            self.vgg.features[:4],
            self.vgg.features[4:9],
            self.vgg.features[9:16],
            self.vgg.features[16:23]
        ]
        # No grad to prevent back propagation
        for bl in blocks:
            for p in bl.parameters():
                p.requires_grad = False
        # Combine the blocks into ModuleList
        self.blocks = torch.nn.ModuleList(blocks)
        self.transform = torch.nn.functional.interpolate
        self.resize = resize
        self.register_buffer("mean", torch.tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1))
        self.register_buffer("std", torch.tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1))

    def forward(self, input, target, feature_layers=[0, 1, 2, 3], style_layers=[]):
        # shape の調整
        if input.shape[1] != 3:
            input = input.repeat(1, 3, 1, 1) # model output
            target = target.repeat(1, 3, 1, 1) # ground truth
        # ピクセル値の標準化
        input = (input-self.mean) / self.std
        target = (target-self.mean) / self.std
        # 画像サイズの調整
        if self.resize:
            input = self.transform(input, mode='bilinear', size=(224, 224), align_corners=False)
            target = self.transform(target, mode='bilinear', size=(224, 224), align_corners=False)
        loss = 0.0
        x = input
        y = target
        # 順伝搬 (forward propagation)
        for i, block in enumerate(self.blocks):
            x = block(x)
            y = block(y)
            if i in feature_layers:
                # add loss by using the feature map in the middle of the model
                loss += torch.nn.functional.l1_loss(x, y)
            if i in style_layers:
                # add loss by using the "style layer" calculated from the feature maps
                act_x = x.reshape(x.shape[0], x.shape[1], -1)
                act_y = y.reshape(y.shape[0], y.shape[1], -1)
                gram_x = act_x @ act_x.permute(0, 2, 1)
                gram_y = act_y @ act_y.permute(0, 2, 1)
                loss += torch.nn.functional.l1_loss(gram_x, gram_y)
        return loss

中間層の準備

モデルそのものは torchvision.models にすでに用意されている VGG16 を使用し、保存しておいた訓練済みのパラメータを load_state_dict で読み込みます。モデルを評価モード(.eval())に切り替えた後、VGG16 を複数のブロック(blocks)に分割してリストとして保存しておきます。これにより、後ほど特徴マップを個別に取り出すことができます。

VGG16 の中間層(Conv2D や ReLU の繰り返し)は、features という名前で定義されており、以下のドキュメントでも確認できます:

torchvision.models.vgg — PyTorch Docs

Perceptual Loss の計算中に VGG16 の重みが更新されないように、分割した各ブロックのすべてのパラメータについて requires_grad = False を設定して、勾配計算が行われないようにします。

最後に、これらのブロックを torch.nn.ModuleList にまとめて self.blocks に格納し、順番に特徴マップを計算できるようにします。

import torchvision.models as models
# モデルをロード
if torch.cuda.is_available():
    self.vgg = models.vgg16().to('cuda')
else:
    self.vgg = models.vgg16().to('cpu')
    
# パラメータをロード
self.vgg.load_state_dict((torch.load(path)))
self.vgg.eval() # モデルを評価モードにする。
blocks = [
    self.vgg.features[:4],
    self.vgg.features[4:9],
    self.vgg.features[9:16],
    self.vgg.features[16:23]
]

# No grad to prevent back propagation
for bl in blocks:
    for p in bl.parameters():
        p.requires_grad = False
        
# Combine the blocks into ModuleList
self.blocks = torch.nn.ModuleList(blocks)

Forwardで順伝搬

ここで、x および y はそれぞれモデルの出力画像と正解画像(前処理済)です。これらを self.blocks に格納された VGG16 の各ブロックに順番に通し、特徴マップを抽出します。

x = block(x)y = block(y) によって得られるのが特徴マップであり、これらの差を L1損失として加算し、Perceptual Loss を構成します。

# 順伝搬 (forward propagation)
for i, block in enumerate(self.blocks):
    x = block(x)
    y = block(y)
    if i in feature_layers:
        # add loss by using the feature map in the middle of the model
        loss += torch.nn.functional.l1_loss(x, y)

この処理により、画像の高次特徴がどれだけ似ているかを損失として捉えることができます。

Style Transfer

Perceptual Loss の原論文では、Style Transfer(スタイル変換) という応用技術も提案されています。これは、出力画像の「内容」は保持しつつ、「スタイル(画風)」だけを別の画像に似せるというもので、例として写真をアニメ風や油絵風に変換することができます。

具体的には、各ブロックから得られた特徴マップ同士の「スタイル(相関構造)」を Gram行列として定義し、その差を L1損失として計算します。これにより、「スタイルの違い」を損失として表現することができます。

if i in style_layers:
    # add loss by using the "style layer" calculated from the feature maps
    act_x = x.reshape(x.shape[0], x.shape[1], -1)
    act_y = y.reshape(y.shape[0], y.shape[1], -1)
    gram_x = act_x @ act_x.permute(0, 2, 1)
    gram_y = act_y @ act_y.permute(0, 2, 1)
    loss += torch.nn.functional.l1_loss(gram_x, gram_y)

この処理により、スタイルだけを揃えることも、Perceptual Loss(内容)と組み合わせて両方を揃えることも可能になります。

Perceptual Loss の実用例

超解像(Super Resolution)

超解像とは、低解像度の入力画像から高解像度の出力画像を生成する技術です。たとえば、256×256 の画像から 512×512 の画像を再構成するような問題で、ディープラーニングによる画像処理の代表的な応用の一つです。

このような問題は ill-posed(解が一意に定まらない) であり、細部の再現性が不十分となる場合があります。

こうした状況でも、Perceptual Loss は、人間が「自然」と感じる構造が一致するように学習させることができます。特に、ESRGAN では、GAN(敵対的ネットワーク)と Perceptual Loss を組み合わせることで、細かな構造を再現する性能が大きく向上することが報告されています。

さらに、VGG の中間層出力から特徴を得る際には ReLU 直前(Conv2Dの出力) を使うことで、画像の明暗やエッジがより忠実に再現されると報告されています。

ノイズ除去

ノイズ除去は、日常の写真だけでなく、CT や MRI などの医療画像にも広く応用されています。

例えば、CT画像への応用例では、Perceptual Loss のみを使用した場合にはグリッド状のアーティファクトが残ることがあり、MSE + Perceptual Loss を併用することで、自然で高品質な画像が得られることが報告されています。

Style Transfer

Style Transfer(スタイル変換)は、出力画像の「内容」を保持しつつ、「スタイル」(色使いや質感)を別の画像から学習させる技術です。Perceptual Loss の代表的な応用として知られています。

例えば、写真をジブリ風や印象派風に変換したり、アニメの作風を模倣することが可能です。これは、画像の構造とスタイルの類似性を特徴マップから定量化できる Perceptual Loss の強みを活かした例です。

まとめ

本記事では、Perceptual Loss の背景、原理、実装方法、そして応用例を詳しく解説しました。ピクセル単位での誤差評価にとどまらず、「人間の知覚に基づく類似性」を損失関数として導入することで、より高品質な画像処理が可能になります。

特に、VGG の中間層から得られる特徴マップを用いることで、画像の 構造的・意味的特徴 を活かした訓練ができる点が重要です。

また、Style Transfer をはじめとする様々な応用により、Perceptual Loss は単なる損失関数ではなく、画像理解と生成の鍵となる技術として注目されています。

ディープラーニングを用いた画像処理において、表現力を一段階引き上げたいと考えるすべての実践者にとって、Perceptual Loss は極めて有用なツールと言えます。

この記事の最新バージョンは新ブログで公開しています:
👉 https://ai-physics-lab.com/ja/perceptual-loss/

引用

Perceptual Loss:

 arxiv.org 

VGG:

 arxiv.org 

超解像:

 arxiv.org 

デノイズ:

pmc.ncbi.nlm.nih.gov

【実践基礎10】PyTorchでモデルを訓練する方法|GPU・DataLoader・訓練ループを体系的に理解

前の記事  


<概要>

GPU + PyTorchを使った教師ありのミニバッチ学習の仕方を説明します。

全体の構造についてフォーカスし、モデルの本体のモジュールクラスやDataLoader等の各論については<関連記事>を参照してください。

細かい設定、例えば torch.optim.lr_scheduler による学習率の管理などは触れません。

<関連記事>

<インポート>

import os
import torch
import torch.nn as nn

ディレクトリ構成

実際のプロジェクトでは、「モデルの定義」や「データの読み込み処理」を別ファイルに分けることで、コードの見通しが良くなり、再利用もしやすくなります。

本記事ではこれらが model.pydataloader.py に記述されているものと仮定し、訓練ループに重点を置きます。

学習を行う本体のコードは以下の train.py にかかれているものとします。

project/
│
├── train.py           # 訓練のメインスクリプト
├── model.py           # MyModelの定義 (モジュールクラス)
└── dataloader.py      # train_loader, val_loader の定義

訓練コードと全体像

本記事のメインである、ディープラーニングで教師ありミニバッチ学習を行う最小限のコードは以下の通り、30 行ほど(コメント除く)になります。コードの下に、コードと対応する形で訓練全体をまとめたフローチャートがあります。

# train.py
import os
import torch

from model import MyModel
from dataloader import train_loader, val_loader

##############
# 1. 初期設定 #
##############
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# 1-1 モデルのロード・GPUへの以降
model = MyModel().to(device)
model.train()

# 1-2 データローダー
train_loader = get_dataloader(cfg, train)
val_loader = get_dataloader(cfg, val)

# 1- 3 損失関数と最適化手法(optimizer)
criterion =
optimizer = torch.optim.Adam

#############
# 2 学習開始 #
#############
for epoch in range(num_epochs):
    # 2-1 訓練のループ(バッチ)
    for inputs, targets in train_loader:
        # 2-1-0 勾配を初期化
        optimizer.zero_grad()

        # 2-1-1 データをGPUへ
        inputs = inputs.to(device)
        targets = targets.to(device)

        # 2-1-2 順伝播と損失計算
        outputs = model(inputs)
        loss = criterion(outputs, targets)

        # 2-1-3 勾配計算と誤差逆伝播
        loss.backward()
        optimizer.step()

    # 2-2 検証
    model.eval()
    val_loss = 0.0
    # 勾配計算を無効化(メモリの節約・事故防止)
    with torch.no_grad():
        for inputs, targets in val_loader:
            # 2-2-1 データをGPUへ
            inputs = inputs.to(device)
            targets = targets.to(device)

            # 2-2-2 順伝搬と損失計算
            outputs = model(inputs)
            val_loss += criterion(outputs, targets)
    print(f'val loss: {val_loss}')

def get_dataloader(cfg, train=True):
    dataset = MyDataset(cfg.data_path, train=train)
    return DataLoader(dataset, batch_size=cfg.batch_size, shuffle=train)

ディープラーニングのトレーニングプロセスを示すフローチャート。データベースから入力データを処理し、モデルを用いて出力データを生成。その後、損失関数を通じて誤差を計算し、勾配計算とパラメータ更新を行う流れを視覚的に解説。dataloderからモデル (net)、criterion、loss.backward、optimizerまでの流れがわかる(出典:筆者作成)。

【実践基礎3】PyTorch による学習アルゴリズムとプロセスの全体像より

初期設定

GPU設定

PyTorchでは、GPUが使用可能であればGPUを使い、そうでなければCPUを使うように設定するのが一般的です。

os.environ["CUDA_VISIBLE_DEVICES"] = "0"
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

ここでは、複数GPUがある場合に「使いたいGPUを番号で指定」するために環境変数 CUDA_VISIBLE_DEVICES を設定しています。詳細なGPUの扱いについては、PyTorchによるGPU環境設定を参照してください。

モデル

model.py に定義されている MyModel クラスを読み込み、GPUに転送します。

model = MyModel().to(device)
model.train()

.train() はモデルを「訓練モード」に設定するためのものです(例えば Dropout や BatchNorm の挙動が異なります)。推論時は .eval() に切り替えます(後述)。

モデル定義の詳細は 実践基礎9 PyTorchモデルの全体構造と作り方を理解しよう を参照。

DataLoader

訓練データと検証データの読み込みは、dataloader.py に定義されている関数 get_dataloader() を通じて行います。

train_loader = get_dataloader(cfg, train=True)
val_loader = get_dataloader(cfg, train=False)

get_dataloader はコードの最後に定義されています。cfg はDataLoader や Dataset に渡す引数を含み、argparse 等で作ることを想定しています。

引数の渡し方はDataset の設計次第で、例えば辞書形式でも構いません。また、引数 train を元に Dataset が訓練・検証データを適切に準備すると仮定しています。

DataLoaderの基本は 実践基礎6 PyTorchのDatasetとDataLoaderを理解しよう を参照。

損失関数と最適化手法

criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

ここでは、回帰タスクを想定して MSELoss(平均二乗誤差)を使用し、Adamオプティマイザを選択しています。

    • criterion: 「正解とのズレを数値で表す」役割。分類なら CrossEntropyLoss など。
    • optimizer: 「どうやってパラメータを更新するか」の方法を定める。

自分で損失関数を定義することも可能ですが、PyTorchの組み込み関数は安定性・高速性の点で優れており、特に複雑な損失関数では自前実装はおすすめしません。

損失関数の自動微分の仕組みは 実践基礎8 Tensorの自動微分を理解しよう を参照。

訓練ループの実装

訓練処理は for epoch in range(num_epochs) のループで構成されており、各エポックにおいて全てのミニバッチに対して以下の手順が実行されます。

  1. 勾配の初期化: optimizer.zero_grad() で前のバッチの勾配情報をクリアします。これをしないと勾配が蓄積されてしまいます。
  2. データの転送: 各バッチの inputstargets をGPUに移します。DataLoaderでは転送せず、GPUが必要になる直前のこのタイミングで転送するのが一般的です。
  3. 順伝播と損失計算: モデルに入力を通して出力を得た後、criterion を使って損失を計算します。
  4. 誤差逆伝播とパラメータ更新: loss.backward() で勾配を計算し、optimizer.step() によりモデルのパラメータを更新します。
for epoch in range(num_epochs):
    for inputs, targets in train_loader:
        optimizer.zero_grad()
        inputs = inputs.to(device)
        targets = targets.to(device)
        outputs = model(inputs)
        loss = criterion(outputs, targets)
        loss.backward()
        optimizer.step()

この一連の処理をエポック(データセット全体を一巡する単位)ごとに繰り返します。

PyTorchではこのようなミニバッチ単位の訓練ループを明示的に記述することで、学習の挙動を柔軟にカスタマイズできます。

検証

検証のバッチループは「2-1 訓練のループ」とだいたい同じですが、勾配の初期化と計算、誤差逆伝播は行いません。あくまで検証データでの loss 等の計算と出力だけが目的です。with torch.no_grad()でインデントした塊の中では勾配計算を禁止することができます。

まとめ

本記事では、PyTorch + GPU を用いた教師あり学習の最小構成を通して、モデルの訓練全体の流れを解説しました。

ここで取り扱ったポイントは以下の通りです:

    • GPUの設定と活用方法
    • モデルを訓練モードに設定し、GPUに転送する方法
    • 訓練用および検証用のデータローダーの利用
    • 損失関数(criterion)と最適化手法(optimizer)の定義
    • 学習ループと検証ループの実装

このコードをベースにすれば、基本的なモデル訓練はすぐに始められます。複雑なモデルや特殊な訓練条件に進む前に、まずはこの「訓練の全体像」をしっかり体感しておくことが重要です。

次のステップ

本記事は、「理論基礎編」から続く「実践基礎編」の最後の記事であり、初心者向けカテゴリの締めくくりでもあります。ここまで読んできた方は、PyTorchを使った基礎的なモデルの訓練が一通り理解できているはずです。

ここから次に進むおすすめの方向性は:

    • 応用編(CNN、転移学習など)へ進む
    • 実データを用いたプロジェクト構築に挑戦
    • モデルの性能改善(学習率調整、正則化、Early Stoppingなど)

それぞれのステップに対応した記事やチュートリアルは、ブログのカテゴリ「ディープラーニング実践編」にて順次公開していきます。