[[390275]] 今日は、ディープラーニングを使用して顔認証アルゴリズムを作成します。 私たちのタスクを達成するには、主に 3 つの部分が必要です。 - 顔を見つけるアルゴリズム
- 顔をベクトル空間に埋め込む方法
- エンコードされた顔を比較する機能
顔検索と位置情報まず、画像内の顔を見つける方法が必要です。 MTCNN (マルチタスク カスケード畳み込みネットワーク) と呼ばれるエンドツーエンドのアプローチを使用できます。 少し技術的な背景を説明すると、これは複数のステージで構成され、各ステージにニューラル ネットワークがあるため、カスケードと呼ばれます。 次の図はフレームワークを示しています。 私たちは facenet-pytorch の MTCNN 実装に依存しています。 データ画像が必要です!レオナルド・ディカプリオとマット・デイモンの写真をいくつか集めました。 PyTorch のベスト プラクティスに従い、ImageFolder を使用してデータセットを読み込みます。 MTCNN インスタンスを作成し、transform パラメータを使用してデータセットを渡しました。 私のフォルダ構造は次のとおりです。 - ./顔
- ├── ディカプリオ
- │ ├── ....jpg
- ├── マット・デーモン
- │ ├── ....jpg
- └── 私
- │ ├── ....jpg
MTCNN は入力を自動的に切り抜いてサイズを変更します。モデルはそのサイズの画像でトレーニングされるため、image_size = 160 を使用します。 また、顔全体が確実に含まれるように、18 ピクセルの余白を追加します。 - 輸入トーチ
- torchvision.transforms をTとしてインポートします。
- matplotlib.pyplot をpltとしてインポートします。
-
- torch.utils.dataからDataset、DataLoader をインポートします
- torchvision.datasetsからImageFolder をインポートします
- facenet_pytorchからMTCNN、InceptionResnetV1 をインポートします
- pathlibからPathをインポート
- import Union , Callableと入力して
-
- data_root = パス( '.' )
- # MTCNNネットワークを作成する
- 変換 = MTCNN(画像サイズ=160、マージン=18)
-
- ds = ImageFolder(root=data_root / 'faces' 、transform=transform)
- # データセットが非常に小さいため、batch_size はその長さと同じになります
- dl = DataLoader(ds, バッチサイズ=len(ds))
-
- ds[1]
ds の構造は次のとおりです。 - (テンソル([[[ 0.9023, 0.9180, 0.9180, ..., 0.8398, 0.8242, 0.8242], [ 0.9023, 0.9414, 0.9492, ..., 0.8555, 0.8320, 0.8164], [ 0.9336, 0.9805, 0.9727, ..., 0.8555, 0.8320, 0.7930], ..., [-0.7070, -0.7383, -0.7305, ..., 0.4102, 0.3320, 0.3711], [-0.7539, -0.7383, -0.7305, ..., 9258, 0.9258], [ 0.9336, 0.9492, 0.9492, ..., 0.9336, 0.9258, 0.9258], [ 0.9414, 0.9648, 0.9414, ..., 0.9570, 0.9414, 0.9258], ..., [-0.3633, , 0.5352, 0.5820], [-0.3945, -0.3867, -0.3945, ..., 0.5820, 0.5742, 0.6211], [-0.3711, -0.3633, -0.4023, ..., 0.5273, 0.6055, 0.6211]], [[ 0.8867, 0.8867, 0.8945, ..., 0.8555, 0.8477, 0.8477], [ 0.8789, 0.8867, 0.8789, ..., 0.8789, 0.8633, 0.8477]、[ 0.8867、0.9023、0.8633、...、0.9023、0.8789、0.8555]、...、[-0.0352、-0.0586、-0.0977、...、0.7617、0.7070、0.7461]、[-0.0586、-0.0586、-0.0977、...、0.7617、0.7617、0.8086]、[-0.0352、-0.0352、-0.1211、...、0.7227、0.8086、0.8086]]])、0)
データセットはテンソルとして返されます。 すべての入力を視覚化してみましょう。 これらは MTCNN 画像によって正規化されており、最後の行の最後の 3 つの画像は私自身の自撮りです :) 埋め込みベクトル空間データは準備完了です。 顔を比較して 2 つの顔が類似しているかどうかを確認するには、それらをベクトル空間にエンコードする必要があります。2 つの顔が類似している場合は、それらに関連付けられた両方のベクトルも類似しています (近い)。 よく知られた顔データセット (例: vgg_face2) でトレーニングされたモデルを使用し、分類ヘッドの前の最後のレイヤーの出力 (潜在空間) をエンコーダーとして使用することができます。 これらのデータセットのいずれかでトレーニングされたモデルは、入力に関する重要な特徴を学習する必要があります。 最後のレイヤー (完全に接続されたレイヤーの前) は、高レベルの機能をエンコードします。 したがって、これを使用して入力をベクトル空間に埋め込み、類似した画像が互いに近くなることを期待できます。 具体的には、vggface2 データセットでトレーニングされた Inception Resnet を使用します。 埋め込み空間の次元は 512 です。 - resnet = InceptionResnetV1(事前トレーニング済み = 'vggface2' ).eval()
-
- torch.no_grad()の場合:
- (画像、ラベル)をdlに挿入:
- embs = resnet(画像)
- 壊す
-
- embs.shape
-
- トーチ.サイズ([8, 512])
完璧です。8枚の画像があり、8つのベクトルが得られます。 類似度の計算ベクトルを比較するには、cosine_similarity を使用して、ベクトルが互いにどれだけ近いかを確認します。 コサイン類似度は [-1, 1] の間の値を出力します。 単純なケースでは、比較される 2 つのベクトルは同じであり、それらの類似度は 1 です。したがって、類似度は 1 に最も近くなります。 これで、データセット内のすべてのペア間の距離をすべて見つけることができます。 - Seaborn をSNSとしてインポートする
- numpyをnpとしてインポートする
-
- 類似度マトリックス = torch.zeros(embs.shape[0], embs.shape[0])
-
- iが範囲内(embs.shape[0])の場合:
- jが範囲内(embs.shape[0])の場合:
- similarity_matrix[i,j] = torch.cosine_similarity(embs[i] .view (1,-1), embs[j].view ( 1,-1))の類似度行列を求める。
-
-
- 図 = plt.figure(図サイズ=(15, 15))
-
- sns.heatmap(類似性マトリックス.numpy(), annot = True ,)
-
- ヌミコン = 8
- i が範囲内(numicons)の場合:
- アキシコン = fig.add_axes([0.12+0.082*i,0.01,0.05,0.05])
- axicon.imshow(un_normalize(ds[i][0]).permute(1,2,0).numpy())
- axicon.set_xticks([])
- axicon.set_yticks([])
-
- アキシコン = fig.add_axes([0, 0.15 + 0.092 * i, .05, 0.05])
- axicon.imshow(un_normalize(ds[len(ds) - 1 - i][0]).permute(1,2,0).numpy())
- axicon.set_xticks([])
- axicon.set_yticks([])
もちろん、私はマットやレオとあまり似ていませんが、共通点がいくつかあります。 さらに一歩進んで、埋め込みベクトルに対して PCA を実行し、画像を 2D 平面に投影することもできます。 - matplotlib.offsetboxからOffsetImage、AnnotationBbox をインポートします
-
- pca(x: torch.Tensor, k: int = 2) を定義します。-> torch.Tensor:
- 「」 「 」
- http://agnesmustar.com/2017/11/01/principal-component-analysis-pca-implemented-pytorch/より
- 「」 「 」
- # データを前処理する
- X_mean = torch.mean(x, 0)
- x = x - X_mean.expand_as(x)
- #svd
- U、S、V = torch.svd(torch.t(x))
- torch.mm(x, U[:, :k])を返す
-
- ポイント = pca(embs, k=2)
- plt.rcParams[ "figure.figsize" ] = (12,12)
-
- 図、ax = plt.figure()、plt.subplot(111)
- plt.scatter(ポイント[:,0], ポイント[:,1])
- i, pをenumerate(ポイント)に代入する場合:
- x, y = p[0], p[1]
- img = un_normalize(ds[i][0])
- img_np = img.permute(1, 2, 0).numpy().squeeze()
- ab = AnnotationBbox(OffsetImage(img_np, zoom=0.6), (x, y), frameon= False )
- ax.add_artist(ab)
-
- plt.plot()
512 次元を 2 次元に圧縮したため、大量のデータが失われました。 さて、顔を見つけて、それらが互いに似ているかどうかを確認する方法ができたので、顔認証アルゴリズムを作成できます。 私のアイデアは、人物の許容される画像を n 枚取得し、埋め込み空間の中心を見つけ、しきい値を選択して、中心と新しい画像間のコサイン類似度がそのしきい値より小さいか大きいかを確認することです。 - データクラスからデータクラスをインポートし、フィールド
- import List, Callable と入力して
- PIL インポート画像から
-
- @データクラス
- クラス FaceUnlock:
-
- 画像: List[Image.Image] = フィールド(default_factory = list)
- th:浮動小数点数= 0.8
- 変換: Callable = MTCNN(image_size=160, margin=18)
- 埋め込み: torch.nn.Module = InceptionResnetV1(事前トレーニング済み = 'vggface2' ).eval()
- 中心: torch.Tensor = None
-
- __post_init__(self)を定義します。
- 顔 = torch.stack(リスト(map(self.transform, self.images)))
- embds = self.embedder(faces)
-
- 自己中心 = embds.sum (0) / embds.shape[0]
-
- def __call__(self, x: Image.Image) -> bool:
- 顔 = 自己.transform(x)
- emb = self.embedder(face.unsqueeze(0))
-
- 類似度 = torch.cosine_similarity( emb.view (1,-1), self.center.view (1 , -1))
- is_me = 類似性 > self.th
-
- is_me、類似度を返す
-
- #自分の写真を読み込む
- me = データルート / 'faces' / 'me'
- 画像 = list(map( Image.open 、 me.glob( '*' )))
- #自分の画像で顔認証を初期化する
- face_unlock = FaceUnlock(画像)
-
- ipywidgetsから、interact、interactive、fixed、interact_manual をインポートします
-
- def unlock_with_filepath(パス):
- img = Image.open (パス)
-
- is_me、類似度 = face_unlock(img)
- print(f "{'' if is_me else ''} similarity={similarity.item():.3f}" )
-
- 図 = plt.figure()
- plt.imshow(画像)
- plt.plot()
-
- test_root = data_root / 'faces_test'
-
- 対話(unlock_with_filepath、パス=リスト(test_root.glob( '*' )))
類似度スコアは前の画像よりも高いので本物だと思います! 新しい自撮りを試してみましょう 要約する2D データ (画像) のみを使用して顔認証アルゴリズムを作成する魅力的なアプローチを見てきました。 これは、類似した顔が互いに近接している高次元ベクトル空間で切り取られた顔をエンコードするためにニューラル ネットワークに依存しています。 しかし、モデルがどのようにトレーニングされたかはわかりませんし、簡単に混乱する可能性があります (私の実験ではアルゴリズムがうまく機能したにもかかわらず)。 モデルがデータ拡張なしでトレーニングされた場合はどうなるでしょうか? その場合、同じ人物を反転するだけで潜在的な表現が破壊される可能性があります。 より堅牢なトレーニング ルーチンは、データ拡張に大きく依存する教師なし (BYOL に類似) になります。 |