1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

住所の表記ゆれを生成AIで何とかできないか(お試し編)

Last updated at Posted at 2023-09-13

きっかけ

転職後、徐々に生活が落ち着いてきたので、ここらでエンジニア的なところもペースを戻したいなと。

で、やりたいこと

例えば企業情報があって、会社名や郵便番号、電話番号などは一致しているんだけど、住所だけ一致しないとき、これは同じ会社の情報なのか判断できないだろうか?

前提条件

  • あくまでも「表記ゆれ」を対象とします

(ここでの)表記ゆれの定義

  • 半角-全角の違い
  • 漢数字-アラビア数字の違い
  • 丁目、番地、号の省略(「-」で記述)

とりあえず保留

  • 建物名の省略
  • 階数の省略

今回のデータ

デジタル庁のアドレス・ベース・レジストリを参考に正解を決め、それをベースに確認するデータを作成します。
image.png
※今回は、上の「住居表示を実施しているアドレス」を対象にして、下の「住居表示を実施していないアドレス」は見送ります

  • 正解
    • 「東京都港区海岸一丁目2番3号」
  • 表記ゆれ
    • 半角「東京都港区海岸一丁目2番3号」
    • 全角「東京都港区海岸一丁目2番3号」
    • アラビア数字「東京都港区海岸1丁目2番3号」「東京都港区海岸1丁目2番3号」
    • 丁目、番地、号の省略「東京都港区海岸1-2-3」「東京都港区海岸1-2-3」
  • 不正解
    • 正解「東京都港区海岸一丁目1番1号」
    • 半角「東京都港区海岸一丁目1番1号」
    • 漢数字「東京都港区海岸一丁目一番一号」
    • アラビア数字「東京都港区海岸1丁目1番1号」「東京都港区海岸1丁目1番1号」
    • 丁目、番地、号の省略「東京都港区海岸1-1-1」「東京都港区海岸1-1-1」

一応、不正解との比較もします。
なお、町名までは合っているもの(郵便番号があっている前提なので)としました。

環境構築

まずはベースモデルとして、日本語用Sentence-BERTモデル(バージョン2)を使用します。
ライセンスは「cc-by-sa-4.0」とのことですので、利用を明記しておけば商用利用も可能です。

インストール

以下をインストールします。(詳細は省略)

  • CUDA 11.8、cuDNN v8.9.4
  • PyTorch 2.0.1(とりあえずGPU版)
  • transformers 4.7.0
  • fugashi、ipadic

また、ローカル環境でJupyterNotebookを使いました。
(matplotlibも使用しました)

ソース

公式ページに従い、以下のコードを作成します。(途中まで)

from transformers import BertJapaneseTokenizer, BertModel
import torch


class SentenceBertJapanese:
    def __init__(self, model_name_or_path, device=None):
        self.tokenizer = BertJapaneseTokenizer.from_pretrained(model_name_or_path)
        self.model = BertModel.from_pretrained(model_name_or_path)
        self.model.eval()

        if device is None:
            device = "cuda" if torch.cuda.is_available() else "cpu"
        self.device = torch.device(device)
        self.model.to(device)

    def _mean_pooling(self, model_output, attention_mask):
        token_embeddings = model_output[0] #First element of model_output contains all token embeddings
        input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
        return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)


    def encode(self, sentences, batch_size=8):
        all_embeddings = []
        iterator = range(0, len(sentences), batch_size)
        for batch_idx in iterator:
            batch = sentences[batch_idx:batch_idx + batch_size]

            encoded_input = self.tokenizer.batch_encode_plus(batch, padding="longest", 
                                           truncation=True, return_tensors="pt").to(self.device)
            model_output = self.model(**encoded_input)
            sentence_embeddings = self._mean_pooling(model_output, encoded_input["attention_mask"]).to('cpu')

            all_embeddings.extend(sentence_embeddings)

        # return torch.stack(all_embeddings).numpy()
        return torch.stack(all_embeddings)


MODEL_NAME = "sonoisa/sentence-bert-base-ja-mean-tokens-v2"  # <- v2です。
model = SentenceBertJapanese(MODEL_NAME)

そのあとに、今回のデータを用意して、ベクトルを求めます。

sentences = [
    # 正解
    "東京都港区海岸一丁目2番3号",
    # 表記ゆれ
    "東京都港区海岸一丁目2番3号",
    "東京都港区海岸一丁目二番三号",
    "東京都港区海岸1丁目2番3号",
    "東京都港区海岸1丁目2番3号",
    "東京都港区海岸1-2-3",
    "東京都港区海岸1-2-3",
    # 不正解
    "東京都港区海岸一丁目1番1号",
    "東京都港区海岸一丁目1番1号",
    "東京都港区海岸一丁目一番一号",
    "東京都港区海岸1丁目1番1号",
    "東京都港区海岸1丁目1番1号",
    "東京都港区海岸1-1-1",
    "東京都港区海岸1-1-1"
]
sentence_vectors = model.encode(sentences)

ここでは768次元のベクトルが求まります。

最後に正解とのコサイン距離を求めます。

import scipy.spatial
distances = scipy.spatial.distance.cdist(sentence_vectors, sentence_vectors, metric="cosine")[0]

結果

何のチューニングもしない状態で、以下の結果になりました。

東京都港区海岸一丁目2番3号
1 東京都港区海岸一丁目2番3号 2.22044605e-16
2 東京都港区海岸一丁目二番三号 6.11741123e-02
3 東京都港区海岸1丁目2番3号 7.29590979e-03
4 東京都港区海岸1丁目2番3号 7.29590979e-03
5 東京都港区海岸1-2-3 5.00328437e-02
6 東京都港区海岸1-2-3 5.00328437e-02
7 東京都港区海岸一丁目1番1号 2.45641245e-01
8 東京都港区海岸一丁目1番1号 2.45641314e-01
9 東京都港区海岸一丁目一番一号 2.57492124e-01
10 東京都港区海岸1丁目1番1号 2.58257453e-01
11 東京都港区海岸1丁目1番1号 2.58257453e-01
12 東京都港区海岸1-1-1 2.06726289e-01
13 東京都港区海岸1-1-1 2.06726289e-01

image.png

一応、正解(表記ゆれ)/不正解はわかりそう。
なおアラビア数字・ハイフンの半角・全角は、どっちかにそろえてから処理していそうですね。

今後の予定

  • 今のモデルを住所の表記ゆれ用にチューニングしたいと思います
  • モデル自体をもっと性能の良いものに見直したいです

参考資料

こちらを参考にさせていただいております。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?