Frqux’s AI laboratory

AIの技術が進化する今日

自然言語処理AI学習時の前処理について

1.自然言語処理の前処理

自然言語処理では、文章データの前処理の有無や品質によって結果が大きく変わってくるんですよね。

文章データを使ったAIの学習や、テキストデータを扱ったお仕事をする場合に参考になるよう要点をまとめて説明します。


正規化

テキストデータの前処理には正規化があります。

ここでいう正規化とは、簡単に言うと正しい形に文字をそろえることです。

例えば、以下のような英文があったとします。

  • I am a cat.
  • i am a cat.
  • I AM A CAT.

これらはすべて「私は猫です。」という意味の英文ですが、これらをそのままAIの学習に使ってしまうと精度が下がる可能性があります。

なぜなら、翻訳のAIなどを見てもわかる通り、大文字と小文字の使い分けができているものがほとんどだと思うのですが、この大文字と小文字の区別も学習しています。

なので、正規化を行い文字の形をそろえる必要があるんですね。
次に、文字正規化の種類を4つ紹介します。

NFD

Normalization Form Canonical Decomposition(NFD)です。

正準等価性によって文字を分解する方法です。


NFC

Normalization Form Canonical Composition(NFC)です。

正準等価性によって文字を分解し、その後合成する方法です。


NFKD

Normalization Form Compatibility Decomposition(NFKD)です。

互換等価性によって文字を分解する方法です。


NFKC

Normalization Form Compatibility Composition(NFKC)です。

互換等価性によって文字を分解し、その後正準等価性によって合成する方法です。


2.Pythonで正規化を行う方法

「正準等価性って何?」「互換等価性ってなんだよ」という方でも簡単にテキストデータを正規化することができるライブラリがあるのでそれを使いましょう。

unicodedataモジュール

unicodedataというモジュールを使えば、簡単に正規化ができます。

使い方は簡単で、Python標準モジュールのためインストールする必要がありません。
Pythonでインポートして使うだけです。

import unicodedata

text = "日曜日を英語でいうとSunday"

# NFDを使いたい場合。
unicodedata.normalize("NFD", text)

# NFCを使いたい場合。
unicodedata.normalize("NFC", text)

# NFKDを使いたい場合。
unicodedata.normalize("NFKD", text)

# NFKCを使いたい場合。
unicodedata.normalize("NFKC", text)

unicodedata.normalize(form, unistr)のような形で記述すれば正規化が可能です。

公式Docmentは以下です。
unicodedata --- Unicode データベース — Python 3.11.4 ドキュメント


3.終わりに

近年開発が盛んになっている自然言語系のAIを学習する際に、学習データの正規化は欠かせません。

ご自分で簡単なAIを作ってみる場合でも、簡単にできますので正規化をやってみましょう。

では。


ps.久々の投稿で、はてな記法忘れてて焦った。

Docker入門: コンテナ化技術の基礎

お久しぶりです。

今回は、開発でお世話になっているDockerについて解説していきます。

誰でもわかるよう簡単に書くことを目指していますので、初学者の方でも気軽に閲覧していってください。

Dockerとは

Dockerとは、コンテナ仮想化技術を提供するプラットフォームです。
OSやパッケージ、ライブラリなどをコンテナ内に展開・構築し環境を整えることができます。

簡単に言うと、皆さんが自分のPCにwslのubuntuなどを入れて、そこにnumpyやpandasやpytorchを入れて一生懸命環境構築していたものを、まとめて管理してくれるものです。

また、Dockerはバージョンを統一して環境を構築することもできるので、チームでの開発では、開発メンバー全員で環境を統一して進められる点も魅力です。


Dockerイメージ

Dockerについて説明する際に、Dockerイメージについて解説しなければいけません。

Dockerイメージとは、コンテナの設計図のようなもののことです。Dockerイメージを作成して、それに沿ってDockerコンテナが作成されます。

このDockerイメージは、読み取り専用で、変更することはできません。イメージを作成してしまえば、それ以降は全く同じ環境でコンテナを構築できるようになります。

また、Dockerfileというものもあり、これはDockerイメージを作るための設計図です。


設計図を作るための設計図?!


となるかと思いますが、そういうものなのです。

詳しく説明すると、Dockerfileには、使用するOSや使用するライブラリやパッケージをインストールするためのコマンドが書かれています。

プログラミング経験がある方ならわかるかもしれませんが、「pip install numpy」や「apt get ~~」とコマンドを打ってライブラリやパッケージをインストールしていたと思います。

これを必要数記述してあるのがDockerfileです。

Dockerfileの例を下に示します。

# ベースイメージの指定
FROM python:3.9

# 必要なパッケージのインストール
RUN pip install torch torchvision

# 作業ディレクトリの指定
WORKDIR /app

# コンテナ内にファイルをコピー
COPY pytorch_program.py /app/pytorch_program.py

# コンテナ実行時に実行するコマンド
CMD ["python", "/app/pytorch_program.py"]

- FROM python:3.9 ... pythonのバージョン3.9を使用
- RUN pip install torch torchvision ... torchとtorchvisionをインストール
- WORKDIR /app ... 作業ディレクトリをappとする。もしコンテナ内にappディレクトリがなかった場合、自動でappディレクトリが作成されます。
- COPY pytorch_program.py /app/pytorch_program.py ... 実際に実行するpytorchプログラムを、コンテナ内にコピーする。コンテナに入って作ってもいいが、vimやnanoなどのエディタがない場合が多いので、こうするほうがいい。
- CMD ["python", "/app/pytorch_program.py"] ... コンテナ起動時に実行されるコマンドです。この場合、
[ python /app/pytorch_program.py ]が実行されます。


このように、Dockerfile内に、使用するベースイメージと一連のコマンドを記しておくことで、自分の思い通りの環境を立ち上げることができるようになります。

あとはこれをイメージ化して、いつでもコンテナとして起動できるようにするだけです。


Docker Hub

Docker Hubは、コンテナイメージを共有しているプラットフォームです。
ここには、数々のDockerイメージが共有されており、自分で環境構築しなくとも必要な環境をダウンロードして使うことができます。

ここには、大手の会社が配布するイメージや、公式のイメージが多数あるので安心して使えるだけでなく、実際の開発環境と近い状態で自分自身も開発を進められるというメリットがあります。


Docker主要コマンド一覧

以下にDockerコマンドを記します。

コマンド 説明
docker build -t イメージ名 Dockerfileのパス
Dockerfileをビルドしてイメージにする
docker run -d --name コンテナ名 イメージ名
イメージからコンテナを作成・実行する
docker images
Dockerイメージの一覧を見る
docker ps
Dockerコンテナの一覧を見る
docker stop コンテナ名またはID
Dockerコンテナを停止する
docker rm コンテナ名またはID
Dockerコンテナの削除
docker rmi イメージ名またはID
Dockerイメージの削除
docker exec コンテナ名またはID コマンド
起動中のコンテナ内でコマンドを実行する
docker exec -it コンテナ名またはID bash
起動中のコンテナ内でbashシェルを使用する
docker logs コンテナ名またはID
Dockerコンテナのログを見ることができる
docker cp ローカルファイルのパス コンテナ名またはID:コンテナ内のパス
ローカル環境にあるファイルをコンテナ内のディレクトリにコピーする
docker push イメージ名
作成したDockerをDocker Hubなどにプッシュする
docker pull イメージ名
Docker Hubなどからイメージをプルする
docker network create ネットワーク名
Docker networkを作成する
docker network ls
Docker networkの一覧を見る


今回は主要なコマンドのみを紹介をしましたが、ほかにも様々なコマンドがありますので、気になる方は各自調べてください。


まとめ

今回はDockerについて簡単に説明してみました。

Dockerを使えば他記事で紹介している環境でも、簡単に作れてしまうのでぜひ習得することをおすすめします。

ではまた。

最後まで閲覧いただきありがとうございます!

2023/05/11「忙しい」

 現在行っている研究が忙しく時間との勝負になっているため、更新が少なくなります。

 しかし、新しい技術の勉強や技術力向上のための勉強をしていますので、今後時間ができれば学んだことをどんどん記事としてアウトプットして、情報共有したいと思います!
 主にwebアプリ開発やサーバー・ネットワーク構築などです。

 また、stable diffusionのモデル紹介などは、ちまちま更新しているので良ければ覗いて行ってください!

 取り急ぎ報告だけで終わります。
 今後ともよろしくお願いします(´・ω・)

 AIを楽しもう!!!

現代の革新的技術!transformerモデルを解説(Encoder編)

 本記事では、近年話題になっているGPTなどのモデルの基礎にもなっているtransformerモデルの解説を行います。

 今回はEncoder編で、Decoder部分は別記事で紹介します。

 私も学習段階で、記事の信ぴょう性としては薄いですが参考程度に読んでいただけますと幸いです。


transformerモデルのEncoder構造

 オリジナルのtransformerモデルのEncoder部分は以下のような構造になっています。

transformer Encoder

 Attention層・Normalization層・Linear層・Activation層が組み合わさったものがtransformer Encoderです。

 この各層の役割について次に解説していきます。


入力

 transformer Encoderに入力されるデータは、数値の時系列データです。

 例えば、「1, 13, 4, 76, 2」などです。

 主にこれはトークンIDと言って、単語それぞれに割り振られたIDを入力とすることが多いです。上記の例ですと、何らかの5つのトークンが入力されることになります。


入力からAttention層への間の処理

 入力からAttention層にデータが入る際、トークンIDをそれに対応したベクトルに変換する処理が入ります。

 詳しく言うと、単語埋め込み情報と言って、単語それぞれにベクトルが割り振られており、Attention層に入る前にトークンIDがそのベクトルに変換されます。
 例えば、語彙数ぶんの次元があるone-hotベクトルに変換されるなどです。


Attention層

 ここがtransformerモデルの一番重要な部分です。

 Attentionとは、そのままの意味で注意する機構のことです。文章のどの位置にどれくらい注意を向けて読み解くかを計算する層なのです。

 Attentionは大きく分けて以下の2種類があります。

  • 外部からどこを注意するか指示される普通のAttention
  • 自分自身でどこに注意を向けるか計算するself-Attention

 中でも主にself-Attentionが採用されていますので、こちらを説明します。
 更にself-Attentionの中にもいろいろ種類がありますが、transformerモデルで採用されたキーバリューストアという機構を使ったself-Attentionを説明します。

 このキーバリューストアとは、文章を、クエリ(query)・キー(key)・バリュー(value)の3つに分けることで、文章内の注意するべき箇所を見つけ出す手法です。

 まず、文章の数値情報をそのままクエリとキーとバリューにコピーします。そのうちのクエリとキーの2つの数値の行列積をとり、単語間の関係性の行列情報を得ます。そしてそれをsoftmax関数に通すことで、数値の正規化を行います。
 行列積をとることによって、各次元に対応するベクトルを合わせた情報が得られます。

 その後、この注意次元ベクトルとバリューのベクトルを掛け合わせると、最終的な出力が得られます。

 これがSelf-Attentionです。


Normalization層

 ここでは、ベクトルデータの正規化を行います。

 ベクトルの正規化には以下の式を使います。


\displaystyle
hi = f(\frac{gi}{σi}(ai-μi)+bi)

  • σ ... 二乗誤差の平方根
  • a ... 入力ベクトル
  • μ ... 平均値
  • f ... 活性化関数
  • g, b ... 学習可能パラメータ

ここで記号の後についているiはトークンの位置を表します。


Linear層

 ここでは、演算処理および次元圧縮・次元拡張を行います。

 主に、入力されたベクトルを全結合層と同じような方法(入力*重み+バイアス)で演算処理したり、入力された2次元及び3次元のベクトルを1次元に圧縮、もしくはそれを2次元、3次元に戻してあげる役割を果たします。

 この次元変更がなぜ必要なのかというと、オリジナルのモデルでは、全結合層としての演算を行う際に1次元データのみ処理できる形となっていたため、このような処理が入ります。
 後に出た改良型では、複数次元でも処理できるようになったとかなってないとか...。


Activation層

 ここでは、活性化関数を定義してデータを通します。

 活性化関数とは、ニューロンの発火を制御するための関数です。

 上でAttention層を通してどの次元に注意すべきかが決まっているので、それを活性化関数に通してフラットにします。
 
 活性化関数には様々な種類があり、それぞれにメリット・デメリットがあります。
 より詳しく実例を知りたい方は、以下のリンクより飛んでください。詳しく説明してくださっているサイトに飛びます。

活性化関数(activation function) [ディープラーニング向け] | CVMLエキスパートガイド


 これですべての層の説明が終わりました。


終わりに

 今回はtransformerモデルを解説しました。
 意外と簡単に見えますが、時代を変えた革新的な技術です。

 このAttention部分がなかなかの曲者で、これが性能の向上を助けています。
 「Attention Is All You Need」という論文で世に広まるきっかけを作り、一世を風靡しました。論文のリンクを以下に貼っておきます。

[1706.03762] Attention Is All You Need

 では、今回はこれで終わります。

 このtransformerモデルは、今後解説する予定のBERTやGPTに使われているモデル構造なので、理解しておくことが必要です。

 では、最後まで閲覧いただきありがとうございました!

Wikipediaデータで実践する文書解析!SentencePieceを使った自然言語処理の基礎

 こんにちは。ふらうです。

 今回は、SentencePieceの解説です。

 自然言語処理では重要な内容となっていますので、初学者の方は必見です。

 それでは、解説していきましょう。

はじめに

まず、SentencePieceとは何なのか、なぜ必要なのかについて解説します。


SentencePieceとは何か

 SentencePieceは、Googleが開発した自然言語処理のためのオープンソースのライブラリです。


なぜSentencePieceが必要なのか

 SentencePieceは、文章を解析して分割するために必要なライブラリです。

 文章を単語に分割するライブラリ・ツールは、主に以下の2つだと思います。

  • SentencePiece
  • BPE(Byte Pair Encoding)

 今回は、SentencePieceの解説なのでBPEのアルゴリズムについては解説しません。

 「なぜこのようなものが必要なのか。」「文章をそのままAIに理解してもらえればいいのではないか。」と考える人もいると思います。
 ではなぜ必要なのかというと、AIは文章を理解するために文章中の単語間の係り受けを学習するように作られているからです。その単語に分割する役割を担っているのがSentencePieceなのです。


単語分割とサブワード分割の違い

 文章を細かく分割する方法には、単語分割とサブワード分割があります。

 これから各分割のアルゴリズムと問題点について解説していきます。


単語分割

 単語分割について解説します。


単語分割とは

 単語分割は、文字通り文章を単語に分割します。

 例えば、「私は猫です。」という文章があった場合、「私」「は」「猫」「です」「。」の5つの単語に分割されます。これが単語分割です。

単語分割の問題点

 単語分割の問題点としては、語彙数が多くなるということです。

 SentencePieceでは、分割された単語を記憶して、一つ一つの単語を語彙辞書として保存しています。この語彙数が多ければ多いほど細かく分割できるのですが、多すぎると容量が圧迫されますし推奨されていません。
 有名な日本語大規模言語モデルでも最大で32000語程度です。その他、大学などの研究機関や企業が開発している大規模言語モデルで使用されている語彙辞書でも24000および12000がほとんどです。


サブワード分割

 サブワード分割について解説します。


サブワード分割とは

 サブワード分割とは、頻繁に使われる文字列を一つの単語としてとらえて分割する手法です。

 先ほどの単語分割では、「東京大学」と「京都大学」と「東京」と「京都」は全て別々の単語として語彙辞書に保存されます。

 サブワード分割では、「東京」と「京都」と「##大学」の3つに分割されます。
 これは、「~大学」という単語が多く出てくるため、「大学」という単語をサブワードとして分割することで、語彙数を少なく抑えることができるメリットがあります。


SentencePieceの概要

ここからは、SentencePieceの概要について触れていきます。


SentencePieceのアルゴリズム

 SentencePieceはテキストのサブワード分割を行うアルゴリズムです。

 SentencePieceは以下の手順で構成・実行されます。


1.学習データの準備

 まず、SentencePieceを学習させるためにデータを用意する必要があります。このデータは、主に文章になっているテキストファイルです。公式のSentencePieceTrainerで学習するためには、一行一文になっているテキストファイルが必要です。


2.トークンの初期化

 SentencePieceでは初めに、出てくる文字一つ一つをトークンとして認識します。単語ではなく文字です。はじめは、単語が全く分からない状態からスタートするのでこのようになります。


3.トークンペアをマージ

 先ほどのトークンのペアを、頻繁に出現する順で取り出していき、新しいトークンを作ります。

 例えば、「斎藤家の夕飯はラーメン」と「田中さんの夕飯はお好み焼き」という2つの文があった場合、どちらの文にも出現している「夕飯」という単語が新しいトークンとして登録されます。

 このように、トークンのペアを出現頻度順にマージしていき、単語を作成していきます。


4.サブワード分割

 さっきも説明した通り、できた単語を使用してサブワードに分割し語彙辞書を調整していきます。


SentencePieceを使ってみる

 ここからは、実際にSentencePieceで学習を行い、語彙辞書とモデルを構築、そして実際に文章をそれに基づいて分割してみたいと思います。

 では、さっそくやっていきましょう。


学習データの準備

 今回は、日本語wikipediaデータを利用させていただきます。

 以前の私の記事で、一行一文になるよう学習データを作成したことがありますので、そちらから引用します。データのダウンロードや作成方法は以下のリンクより、私の記事を参考にしてください。
frqux.hatenablog.com

 上の記事で作成した"wiki.txt"は一行一文のデータになっていないので、調整していきます。しかし、そのままSentencePieceの学習に入れても一応学習はできます。
 また、フルのデータで学習しようとすると、高スペックPCでないと途中でメモリ不足で終了してしまい、学習が失敗するので、データを削ることも行います。
 今回は、1/100に縮小して実行します。


データの前処理

 まず、入出力ファイルの指定を行います。

input_file = "data/wiki.txt"
output_file = "data/wiki_split.txt"

 ここでは、作業ディレクトリの中にdataというフォルダを作成して、その中にwiki.txtを入れている場合を想定しています。完成したテキストファイルも、このdataフォルダに保存されます。

 次に、wiki.txtを開き、「。」で文章を分割します。

with open(input_file, "r", encoding="utf-8") as f:
    lines = f.readlines()

sentences = []
for line in lines:
    line = line.rstrip("\n")
    sentences.extend(line.split("。"))

 ここで、念のため空の行を削除するコードを実行します。

sentences = list(filter(lambda s: s.strip() != "", sentences))

 最後にテキストファイルとして保存します。

with open(output_file, "w", encoding="utf-8") as f:
    f.write("\n".join(sentences))

 これで、一行に一文となっている"wiki_split.txt"というテキストファイルが完成します。

 これをこのままSentecePieceの学習に入れてもいいのですが、私のPCではスペック不足でエラーが発生するので、1/100に削ります。

 皆さんのPCではできる可能性がありますので、一度そのまま入れてみて、「killed」という表示とともに学習が終了してしまうようなら以下のプログラムでデータを削ってください。

input_file_path = "data/wiki_split.txt"
output_file_path = "data/wiki_split_001.txt"

with open(input_file_path, "r", encoding="utf-8") as f:
    lines = f.readlines()

num_lines = len(lines)
print(num_lines)

num_output_lines = num_lines // 100
print(num_output_lines)

output_lines = lines[:num_output_lines]

with open(output_file_path, "w", encoding="utf-8") as f:
    f.write("".join(output_lines))

 これで、新しくwiki_split_001.txtというファイルが作成されますので、これを使いましょう。


学習の実行

 次に学習を開始します。

 まず、必要なライブラリをインポートします。

import sentencepiece as spm

 sentencepieceは以下のコマンドで環境にインストールすることができます。

pip install sentencepiece

 anaconda環境の方は以下でもインストールできます。

conda install sentencepiece

 次に、引数の指定を行います。

input_file="data/wiki_split.txt"
model_prefix="wiki"
vocab_size=32000
character_coverage=0.9995
model_type="unigram"

input_file ... 学習するために読み込むテキストファイル
model_prefix ... 生成されるモデルファイルの名前
vocab_size ... 語彙数
character_coverage ... モデルがカバーする文字の量。公式では0.9995がおすすめらしい。
model_type ... 学習方法。unigramがデフォルトで、ほかにもbpe、char、wordがある。

 そして、学習を実行します。

spm.SentencePieceTrainer.train(input=input_file, model_prefix=model_prefix, vocab_size=vocab_size, model_type=model_type)

 学習が終了すると、「wiki.vocab」と「wiki.model」の2つのファイルが生成されます。.vocabが語彙ファイルで.modelがモデルファイルです。


文章を分割してみる。

 できたモデルファイルをもとに、文章を分割してみたいと思います。

import sentencepiece as spm

model_path = "wiki.model"
text = "明日は雨が降るだろう。"

sp = spm.SentencePieceProcessor(model_file=model_path)

enc = sp.encode(text)
enc_str = sp.encode(text, out_type=str)
dec = sp.decode(enc)

print(enc)
print(enc_str)
print(dec)

まず、encには、分割された文章のトークンIDが入ります。なので、私の環境では以下のようになります。

[4, 19748, 6, 27527, 53, 2291, 29763]

 次に、enc_strには、トークンIDではなく単語が入りますので、以下のような出力になりました。

['▁', '明日', 'は', '雨が降', 'る', 'だろう', '。']

 うーん。まあ学習データが少ないせいかうまく単語で分割できてないですね。

 最後に、decには、トークンIDを対応する単語に戻してあげたものが入りますので、出力は以下のように元の文章に戻るはずです。

明日は雨が降るだろう。


終わりに

 今回はSentencePieceについて解説しました。

 途中、学習したモデルを使って文章の分割を行ったのですが、うまく単語に分割できてなかったですね。少ないデータで学習する場合は、事前にMeCabなどを使って分かち書きしておいたほうがよさそうです。

 実際、日本語の文書解析って難しいです。英語ですと、もともと単語間に半角スペース入れるのが普通ですよね。「Thisisadog」ではなくて「This is a dog」と書きますよね。
 でも日本語は単語間に区切りがないですし、書き方も人によって異なります。「これは犬です。」「これ犬だよ。」「これは犬よ。」「これ犬。」などたくさんありますので、自然言語処理の世界でも問題になっている点です。

 では、これで終わります。最後まで閲覧いただきありがとうございました。



参考文献

GitHub - google/sentencepiece: Unsupervised text tokenizer for Neural Network-based text generation.

PythonでWebスクレイピングを始めよう!BeautifulSoupの基礎とスクレイピングの注意点を簡単に解説!

 こんにちは。ふらうです。

 今回は、Webスクレイピングについて解説していきます。

 AIを学習する際も、何か情報を解析する際も、多くのデータが必要になります。その際に、自力で収集するのは結構大変だと思います。そこでPythonを使い、データ収集を自動化することで効率的にデータを集めることができるようになります。

 もちろんデータには著作権が存在しますし、頻繁なアクセスはサーバー負荷につながり、最悪サーバーがダウンして業務妨害等に当たる可能性もあるので、ある程度の知識が必要になってきます。

 そのあたりの基本的なことを今回は説明していけたらと考えております。


Webスクレイピングとは

 Webスクレイピングとは、Web上のデータを解析・分析できる状態で収集することです。主にツールを使っての収集が基本です。


Webスクレイピングの注意点

 Webスクレイピングをする際にはいくつか注意点があります。主に以下の5つです。


 これらの注意点を一つずつ説明していきます。

利用規約の確認

 真っ先に確認しましょう。
 とりあえずスクレイピングしたいサイトに入ったら、利用規約のページに行き、"ctrl+F"でweb内検索を起動して「スクレイピング」「スクレイパー」「クローラー」などで検索して記載の有無を確認しましょう。

 ダメと書かれていたらそれに従ってください。また、後述しますが、スクレイピングが禁止な代わりにAPIが提供されている場合がありますので、それも併せて確認してください。


著作権を侵害しない範囲での収集

 どんなデータにも必ず著作者がいるものです。ここで、その著作者がデータの提供を許可しているかの確認はしておかなければ、最悪裁判になる可能性があります。
 日本では、未成年であれば別ですが「知らなかった」では済まされないので一番気を付けることでしょう。

 基本的に、商用利用・研究利用・個人的利用の3つに分かれると思いますが、規約をしっかり確認しそれぞれの使用用途に合った対応をするべきです。


サーバー負荷を極力抑えたスクレイピングを行う

 Webサーバーに、あまりに頻繁な接続を繰り返すとサーバーがダウンしたり、接続困難になったりする可能性があります。そうなれば、ほかの利用者の迷惑になるほか、最悪の場合に訴えられる可能性があります。
 
 では、どの程度サーバーにアクセスすると危険なのでしょうか。結論としては、サーバーや接続方法によって違います。

 サーバーは1つではなく、数多くの企業がサーバー事業を展開しており、大規模なサーバーは大量のアクセスにも耐えられるサーバーを使っており、小規模であればすぐに重くなってしまいます。このようにサーバーによって耐久性が違います。
 また、トップページへのアクセスからその他の接続とでは負荷が違います。こういったことから決められた制限はないです。しかし、一般の共通認識はあるようで、1秒間に1回のアクセスに抑えるべきだという認識が大多数の意見です。


robots.txtの確認および robots metaタグに従ってデータを収集する

 robots.txtは、クローラーでデータを収集されるときにそれを制御するためのものです。クローラーとはWebサイトを巡回してデータを集めてくるbot(ロボット)のことです。Webスクレイピングは、データを収集する技術のことを呼ぶということに対して、クローラーはデータ収集を行うbotのことを呼ぶので注意してください。

 robots.txtは、クローラーに町(Webサイト)の総合案内を行う窓口のようなものです。「あそこのデータは持ってっていいよー!」、「あそこのデータは持っていったら駄目だよー!」などとデータ収集の案内をしてくれるテキストファイル君です。クローラー君が総合案内所に行って案内を受けたうえで町を観光すると思ってもらえればわかりやすいです。
 これの確認方法としてはWebサイトのURLに「/robots.txt」を付け加えると確認できます。例えば、はてなブログであれば、「https://hatenablog.com/robots.txt」とアドレスバーに入力して検索すれば、はてなブログrobots.txtを見ることができます。

 robots.txtの記載内容については以下の表を参考にしてください。

robots.txt内の項目 説明
User-agent
制御するクローラーの種類を制御する項目。
Disallow
クロールを禁止する部分を指定している。
Allow
クロールが可能である部分を指定している。
基本的に、Disallowで指定した以外の部分が自動的にクロール可能となるため記載してないところが多い。
Sitemap
sitemap.xmlの場所を記載している。
これがあるとクローラーがWebサイトを巡回しやすくなる。

 robots metaタグ、クローラーの動作を制御するものになります。これはテキストファイルではなくhtml内等のmetaタグとして記載されてありますので、詳細に制御が可能です。しかし権限はrobots.txtのほうが強いので、robots.txtで制御しているページはmetaタグは無意味になりますので、確認は不要です。


APIの有無の確認

 スクレイピングについて言及されていないサイトでも、APIの有無を確認しましょう。
 もしAPIにてデータの提供を行っているのであれば、そちらを利用するようにしましょう。

 APIを使ったほうが、面倒な処理をしなくてもいいですし、サーバー側の負荷も抑えられます。また、APIでの情報提供のみしていてスクレイピングは不可なサイトがありますので、確認しましょう。



BeautifulSoupとは

 BeautifulSoupはスクレイピングするためのPythonライブラリです。htmlおよびxmlファイルからデータを引き出します。

 今回使用しているバージョンは、執筆当時の最新バージョンの2023年3月20日にリリースされた、4.12.0です。

BeautifulSoupのインストール

 以下のコマンドでインストールできます。

pip install beautifulsoup4

 Beautiful Soupのパーサーは自分で選択することができ、種類が複数あるので紹介します。

パーサー 使用方法 特徴
Python’s html.parser
BeautifulSoup(markup, "html.parser")
Pythonの標準ライブラリとして入っているので追加のインストールが不要
lxml’s HTML parser
BeautifulSoup(markup, "lxml")
・とても速い
・外部C依存
lxml’s XML parser
BeautifulSoup(markup, "lxml-xml")
BeautifulSoup(markup, "xml")
・とても速い
・現在サポートされている唯一のxmlパーサー
html5lib
BeautifulSoup(markup, "html5lib")
webブラウザと同じ方法で解析
・有効なhtml5を作成
・とても遅い

 特徴に記した通り、標準搭載のhtmlパーサー以外は各自インストールが必要です。以下にインストール用のコマンドを記しておきますので必要に応じてインストールしてください。

パーサー インストール方法
lxml’s HTML・XML parser
以下のいずれかのコマンド
・apt-get install python-lxml
・easy_install lxml
・pip install lxml
html5lib
以下のいずれかのコマンド
・apt-get install python-html5lib
・easy_install html5lib
・pip install html5lib


BeautifulSoupでスクレイピングする

 では、実際にスクレイピングを実行していきましょう。

各種ライブラリのインポート

import requests
import re
from bs4 import BeautifulSoup

 各ライブラリの説明を簡単にしておきます。

  • requests ... HTTP向けのPythonライブラリで、webの情報を取得したりできる。
  • re ... 正規表現を扱うライブラリ。


 次にデータを取得しましょう。今回は食べログを使わせていただきます。
 規約には特に何も書かれていなかったので大丈夫でしょう。

URL = "https://tabelog.com/"
doc = requests.get(URL)

 これで、食べログのデータがdoc変数に入りました。これをBeautifukSoupにかけてオブジェクトを得ます。パーサーは標準のhtml.parserを使います。

soup = BeautifulSoup(doc.text, "html.parser")

 ここまでできたのでsoupを見てみましょう。

soup

 なんかめちゃくちゃ出てくると思いますが、これがwebページを構成しているhtmlです。ここから必要な情報を各自抽出していくことになります。

 例えば以下の関数があります。

soup.title

 これはtitleタグで囲まれているwebサイトのタイトルを取得しています。また以下のようにすると、titleタグを外して要素だけ取得できます。

soup.title.string

 まあ正直、タグを外したりするのは別途Pythonプログラムで外せるので覚えなくていいかもしれません。大体でいいので、ランキングの部分を抽出する方法であったり、タイトルを抽出したりする方法が分かれば大丈夫だと思います。

 ほかにもBeautifulSoupにはいろんな機能があるのですが、別のブログ様が紹介してくださっているものが優秀すぎることや、公式が日本語でドキュメントを書いてくれていることもあるので説明しません。

 ブログの一番最後にリンクをまとめて貼っておきますので活用してください。


終わりに

 今回はスクレイピングの注意点や方法について簡単に解説しました。

 私的には、requestsでデータを取得してBeautifulSoupで細かく抽出、その後にPythonのプログラムを自分で書いてタグを外したり文章を正規化していく方法がおすすめです。

 大手のサイトはスクレイピングが禁止されていることが多いので、訴えられないように気を付けましょう。自分は中学生の時に著作権で揉めた経験があるので、これからも注意していきたいですね...。

 では。最後まで閲覧いただきありがとうございました!

以下、おすすめな参考サイト様です。

日本語訳のドキュメント
kondou.com - Beautiful Soup 4.2.0 Doc. 日本語訳 (2013-11-19最終更新)

図解!Python BeautifulSoupの使い方を徹底解説!
図解!Python BeautifulSoupの使い方を徹底解説!(select、find、find_all、インストール、スクレイピングなど) - AI-interのPython3入門

Stable Diffusionモデルを利用して画像生成する方法を圧倒的に詳しく徹底解説!!(AUTOMATIC1111)

 こんにちは。ふらうです。

 今回はAUTOMATIC1111上で、Stable Diffusionモデルを利用して画像生成を行うまでを解説します。
 「Hugging Faceからどのモデルをダウンロードすればいいか分からない...」
 「どこに保存すればいいかわからない...」
など、疑問を抱えていれば参考になる内容になると思いますので、ぜひ見ていってください。

 また、AUTOMATIC1111をインストールする方法は以下の記事で解説してますので、こちらもよろしくお願いします。

frqux.hatenablog.com

各拡張子のファイルの役割について

 各プラットフォームで配布されているファイルには、主に以下の拡張子のものです。

  • .ckpt
  • .safetensors
  • .yaml
  • .vae.pt

 まずは、これらのファイルの役割を解説します。

.ckpt

 この拡張子のファイルは、モデルのチェックポイントファイルです。チェックポイント(check point)の各単語の頭文字と終わりの文字をくっつけて「ckpt」です。
 ckptファイルは、学習されたモデルデータを「pickle」というライブラリを用いて保存しています。これをまたpickleなどで復元して元のモデルの形に戻し、使用することができます。

 ckptファイルは性質上、割と危険であったりもします。悪意のあるckptファイルだった場合、復元したと同時に最悪、不正なコードが実行されてPCが汚染されたりします。

 

.safetensors

 この拡張子のファイルも、モデルのチェックポイントファイルです。
 先ほどのckptの違いとしては、安全が保障されているか、されていないかの違いです。
 safetensorsファイルは、不正なコードが実行されないという認識で間違ってないと思います。なので、ckptファイルとsafetensorsの2種類が配布されていた場合、safetensorsを選んだほうが安心ということです。


.yaml

 この拡張子のファイルには、モデルの構成データが記されています。
 モデルの構成データは、ほかにも「.json」や「.py」で記されることがありますが、「.yaml」で記したほうが単純で分かりやすいのだそうです。

 こちらは、もし配布サイトにモデルファイルと一緒においてあれば一緒にダウンロードして、モデルファイルと同じフォルダに入れたほうがいいです。
 でも、正直理由はよくわかりませんでした。申し訳ございません。だいたいのモデルは、yamlファイルがなくても使用できましたので謎です。詳しい方、コメントなどで教えてくださると幸いです。


.vae.pt

 この拡張子のファイルは、vaeデータです。
 vaeとは変分オートエンコーダーのことで、画像生成に使われる用途としては、画質向上です。
 画像生成モデルで画像が生成された後、vaeを用いてもう一度作り直すことでクオリティが向上します。
 vaeはモデルごとに作られていることが多いです。
 vaeの性質上、モデルの学習データと同じデータセットを使って学習したほうが性能が上がるからです。
 しかし、どのモデルにも使えるような汎用的なvaeもありますので、vaeが一緒に配布されていないモデルがあっても心配ご無用です。

 基本的にこれもモデルファイルと同時にダウンロードされることが多いです。
 保存する場合は、

  • ある特定のモデルに特化したvaeは以下のstable diffusionのモデルファイルに入れる。

\\wsl.localhost\Ubuntu-20.04\home\[UNIX user name]\stable-diffusion-webui\models\Stable-diffusion

  • 様々なモデルに使うことを想定したvaeは以下のVAE専用のフォルダに入れる。

\\wsl.localhost\Ubuntu-20.04\home\[UNIX user name]\stable-diffusion-webui\models\VAE

という風に保存しましょう。


prunedとfp16・fp32の違い

 モデルファイルには、ファイル名の中に「pruned」という名前が入っているものがあります。
 これは、簡単に言うとモデルから不要な部分を取り除いたものになります。なので、通常のモデルと比べるとかなり小さいファイルサイズになっていることが多く、性能も大差ない結果になります。

 しかし、「不要な部分ってどんな部分?」、「性能は本当にあまり変わらないの?」って思いますよね。そういったところまで書いているサイトが見る限りなかったので調べてみました。
 以下に解説を載せますが、専門的な内容なので、わからない方はスキップしてください。

 tensorflowの公式リファレンスで調べてみると、以下のような記事が見つかりました。

www.tensorflow.org

 簡単に言うと重要度に基づいて重みを変えていき、不要なものを取っ払う方法らしいです。

 詳しく説明します。
 ニューラルネットワークの中の重みを学習していく段階で、複数の重みを徐々にゼロに近づけていきます。すると、ほかのゼロに近づいていない部分の重みで出力を正そうとします。この流れで、最終時に複数の重みをゼロに限りなく近くしてから、その部分を削除することで重みデータの削減につながります。
 公式リファレンスでは、性能の低下はほぼないまま、普通にファイルサイズを小さくした(モデルを小さくした)場合と比較して6倍の改善があったらしいです。

 わかりやすく具体例を挙げて説明します。まず、バナナが何か分類するために以下の三択を与えます。

  • 果物
  • 野菜

 もちろん正解は「果物」なので、「野菜」と「肉」の重要度は下がります。その後さらに選択肢を与えます。

  • 木の上にできるもの
  • 木の下にできるもの
  • 土の中にできるもの

 これは「木の上にできるもの」が正解なので、それ以外の重要度は下がります。こういった学習の過程でランダムに各選択肢の重要度をゼロに近づけていって、最終的に指標を下回った重要度の選択肢は削除される形になります。

 機械学習では、重み(例の中での重要度)一つ一つがファイルサイズを大きくする要因なので、それが削減されることでファイルサイズが小さくなります。さらに、重要度が指標を下回ったものを消すので、性能も高めたままにすることができるのです。

 実際はランダムにゼロに近づけるらしいので正解の選択肢も、もしかしたらゼロに近くなってしまうかもしれません。でも学習は基本的に何千回・何万回とループさせるのが基本なので、最終的に重要であれば指標を下回る事はないといえます。多分。

 なので、結果から言うと性能はprunedのほうが若干下がります。

 さらにその中でもfp16とfp32の2種類がありますが、fp16が基本的に選択されています。
 なぜなら、AUTOMATIC1111は基本的にfp16で計算が行われるからです。

 fp32は、単精度浮動小数点と呼ばれているものです。これは、10^38桁の数値を有効桁数7〜9桁で表せます。精度をあまり重視しない場合に使われるみたいです。

 また、fp16は半精度浮動小数点と呼ばれているもので、これは、〜10^-8から〜65504の間で、有効桁数4桁の範囲で表現可能なものです。fp32と比べて半分ほどのメモリ量で使用されるため、更にファイルサイズが小さくなります。fp32よりも精度を重視しない深層学習などで使われるみたいです。

 ちなみに、Dreamboothなどで追加学習したい方はfp16はお勧めできません。prunedモデルか、素のモデルを利用するようにしましょう。

 なので最終的な結論としては、「容量を食いたくないし、少しの性能差ならどうでもいい!」という方は"prunedのfp16モデル"を、「容量は気にしてないから性能が一番いいものを使いたい!」という方は通常のprunedと書かれていない素のモデルをダウンロードしましょう。


emaとnon emaの違い

 これもモデルファイルの違いです。
 emaは”exponential moving average”の略で加重移動平均のことです。
 加重移動平均とは、直近のデータを重要視した平均です。
 例えば、中学生の頃は偏差値が30くらいだったとして、高校生で一気に偏差値が70近くになった場合、加重移動平均は70に近い値をとることになります。

 なので、emaモデルは直近の性能の重みを採用しているものであると言えます。
 non emaについては特に書かれていなかったのですが、逆に考えるとnon emaは過去のデータすべてを平均して近似値をとっているものだと考えられます。

 正直、初心者目線だと違いがいまいちわからないし、ファイルサイズも一切変わらないのでどっちでもいいと思います。ただ、基本的に推論モデルにはemaを使うことになっているらしい(reddit情報)なので、emaモデルを使うのが無難といえます。


実際にモデルとvaeを選んで画像生成する

 ここまでの説明を見ればだいたい、どのファイルがどんな役割を果たすのか分かったと思います。
 早速ですが画像生成に移っていきましょう。


AUTOMATIC1111の起動

 まずAUTOMATIC1111を起動させましょう。

 ubuntuを起動して、stable-diffusion-webuiフォルダの中に入って以下のコマンドで起動できます。

./webui.sh

 すると以下の画像のような画面がブラウザを介して開かれると思います。

メイン画面

これで起動は完了です。


モデルファイルとvaeファイルのセット

 左上の「Stable Diffusion checkpoint」にモデルファイル
 右上の「SD VAE」にVAEを設定しましょう。
 VAEに関しては設定しないことも可能ですのでダウンロードが面倒な方や、別に多少のクオリティ向上はいらないという方は「None」を選びましょう。

 設定するとファイル名が表示されるようになり、セット完了になります。
 もし、errorと表示されて、左上に"connection error"などが出れば、AUTOMATIC1111が落ちていますので、もう一度起動して設定しなおしましょう。
 おそらくですが、PCの性能に見合わない大きいモデルを読み込もうとしたり、複数のモデルを入れ替え入れ替え使用したりするとErrorが出て落ちます。


プロンプト(呪文)の設定

 次にプロンプトを入力します。

 "prompt(press Ctrl+Enter or Alt+Enter to generate)"と書かれている欄に生成したい画像の特徴を入力していきます。
 文章でもいいのですが、単語ごとにカンマ(,)で区切って入力することが、基本のやり方でおすすめです。例えば以下のように"1girl"(一人の女の子)と"smile"(笑顔)と入力します。

 次にネガティブプロンプトを入力します。
 簡単に言うと、「こうなってほしくない!」というような特徴を入力します。

 ここでネット上からかき集めてきたネガティブプロンプトを以下に記しますので、以下の内容をコピペして貼り付けましょう。

lowres, ((bad anatomy)), ((bad hands)), text, missing finger, extra digits, fewer digits, blurry, ((mutated hands and fingers)), (poorly drawn face), ((mutation)), ((deformed face)), (ugly), ((bad proportions)), ((extra limbs)), extra face, (double head), (extra head), ((extra feet)), monster, logo, cropped, worst quality, jpeg, humpbacked, long body, long neck, ((jpeg artifacts)), deleted, old, oldest, ((censored)), ((bad aesthetic)), (mosaic censoring, bar censor, blur censor), multiple angle, blurry, longbody, lowres, bad anatomy, bad hands, missing fingers, pubic hair,extra digit, fewer digits, cropped, worst quality, low quality, text, error, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, missing fingers, bad hands, missing arms, large breasts, head_out_of_frame, 2koma, panel layout,

 中身は、monster(化け物)やworst quality(最低品質)などが入ってます。

 もっといい方法で、Embeddingファイルを利用する方法があるのですが、以下の記事で紹介してますので参考にしてください。

frqux.hatenablog.com

 ここまで行うと以下のようになります。

 必要最低限の設定をしたので、右の「Generate」ボタンを押してください。すると、画面右側に画像が生成されます。

 この状態では以下のような画像が生成されました。

モデル:Anything v4.5

 これで画像生成ができました。
 あとはおまけ程度に画面下部のオプションの解説をします。

  • Sampling method ... サンプラーの設定。サンプラーによって、生成される速さや品質を変えることができる。処理速度なら「Euler a」、クオリティなら「DPM++」から始まるサンプラーを選ぶとよい。
  • Sampling steps ... サンプリングするステップ数。数が多ければ多いほど多くのステップを踏んで画像が生成されていくのでクオリティが高くなりやすい。だがもちろんステップ数が多いほど時間がかかる。おすすめはデフォルトの「20」。
  • Width・Height ... 出力される画像を縦横のサイズ。少し変えるだけで生成時間が大きく変わるほか、縦横のサイズを大きくしすぎるとVRAM不足になって、CUDA out of memoryのエラーが出て生成できない場合がある。おすすめは、縦横合わせて1000近くなるよう数値を調整するといいでしょう。
  • Batch count ... 画像が生成される回数。
  • Batch size ... 一度に生成される画像の数。
  • CFG Scale ... 生成画像の内容をAIの感覚に任せるか、プロンプトを重視するかの割合。数値を小さくすればするほどプロンプトとは違った絵になりやすいが、自然な仕上がりになる。逆に数値を大きくすればするほど、プロンプトの内容に近い内容の絵になるが、無理やり近づけていくため絵が崩れてしまいやすい。おすすめは4~8の間。また、LoRAやLyCORISを使っている場合、おすすめのCFG Scaleがダウンロード元のページに記載されている場合があるのでそれを参考にするといいです。
  • Seed ... 初期値(シード値)。これを指定すると、同じシーンを生成できるようになる。例えば、シード値を「1000」に設定して画像生成したときに自分好みの絵が生成されたとします。そして、また別の機会に同じ絵を生成したい場合、また同じプロンプトを入力して、シード値に「1000」と入れて画像生成するとまったく同じ画像が生成されるようになる。初期値は「-1」となってますが、これはシード値を完全ランダムにするという意味です。特別なことがない限り「-1」のままのほうがいいです。


 以上を細かく設定して、自分好みの絵を生成しましょう。


終わりに

 今回は、AUTOMATIC1111での画像生成を行う方法を解説しました。

 また、このプロンプトから新しい絵を生成することをtxt2img(text to image : テキストから画像に)というものになります。

 これのほかにも、img2img(image to image : 画像から画像に)というものもあります。
 これは、既存の画像をもとに新たな画像を生成するものです。例えば、既存の画像のポージングを真似た画像を作りたい場合や、既存の画像を微調整(画質向上やサイズ変更など)したいときに使います。

 また、AUTOMATIC1111には、txt2imgで生成した画像をimg2imgにそのまま直接送ることができる("Send to img2img"を押す)ので、使用用途は結構あります。

 また時間があれば解説したいと思っています。

 それでは、最後まで閲覧いただきありがとうございました!
 今後もよろしくお願いいたします。