0
0

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 3 years have passed since last update.

言語処理100本ノック(2020)-80: ID番号への変換(keras)

Last updated at Posted at 2021-11-23

言語処理100本ノック 2020 (Rev2)「第9章: RNN, CNN」80本目「ID番号への変換」記録です。
Pythonあるあるですが、横着しようとしてすごく簡単にできるパッケージがないか調べた結果、逆に時間かかってしまった系です。多分4時間くらい解くのに時間かけてしまいました。また、少し思うところがあってノック内容に反することもしています。
記事「まとめ: 言語処理100本ノックで学べることと成果」言語処理100本ノック 2015についてはまとめていますが、追加で差分の言語処理100本ノック 2020 (Rev2)についても更新します。

参考リンク

リンク 備考
80_ID番号への変換.ipynb 回答プログラムのGitHubリンク
言語処理100本ノック 2020 第9章: RNN, CNN (PyTorchだけど)解き方の参考
【言語処理100本ノック 2020】第9章: RNN, CNN (PyTorchだけど)解き方の参考
まとめ: 言語処理100本ノックで学べることと成果 言語処理100本ノックまとめ記事
TextVectorization ID化のkeras関数
FreqDist 辞書作成のnltk関数

環境

後々GPUを使わないと厳しいので、Google Colaboratory使いました。Pythonやそのパッケージでより新しいバージョンありますが、新機能使っていないので、プリインストールされているものをそのまま使っています。TensorFlowはいつの間にか2.6から2.7に上がっています。

種類 バージョン 内容
Python 3.7.12 Google Colaboratoryのバージョン
google 2.0.3 Google Driveのマウントに使用
tensorflow 2.7.0 ディープラーニングの主要処理
nltk 3.2.5 Tokenの辞書作成に使用
pandas 1.1.5 行列に関する処理に使用

第8章: ニューラルネット

学習内容

深層学習フレームワークを用い,再帰型ニューラルネットワーク(RNN)や畳み込みニューラルネットワーク(CNN)を実装します.

80. ID番号への変換

問題51で構築した学習データ中の単語にユニークなID番号を付与したい.学習データ中で最も頻出する単語に1,2番目に頻出する単語に2,……といった方法で,学習データ中で2回以上出現する単語にID番号を付与せよ.そして,与えられた単語列に対して,ID番号の列を返す関数を実装せよ.ただし,出現頻度が2回未満の単語のID番号はすべて0とせよ.

回答

回答結果

適当なサンプル文を入力します。

print(vectorize_layer([["bar unknown_word(1)"]]).numpy)

辞書化されて、Numpy配列が返ってきます。これ見ただけでは意味わからないですね。

結果
<bound method _EagerTensorBase.numpy of <tf.Tensor: shape=(1, 18), dtype=int64, numpy=
array([[2081,    1,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0]])>>

今回は以下の2点について違反をしています。

  1. 学習データ中で最も頻出する単語に1,2番目に頻出する単語に2,……といった方法で,学習データ中で2回以上出現する単語にID番号を付与せよ.
  2. 出現頻度が2回未満の単語のID番号はすべて0とせよ.

1に関しては、特に頻出順位とID番号は関連付けていません。特に関連付けるメリットを見いだせず、逆に使っている関数にその機能がなかったためです。
2. に関しては0はmask用にしています。これが一般的なのではないでしょうか(kerasだけ?)。代わりに1をUnkownとして使っています。

回答プログラム 80_ID番号への変換.ipynb

GitHubには確認用コードも含めていますが、ここには必要なものだけ載せています。

import nltk
import pandas as pd
import tensorflow as tf
from google.colab import drive

drive.mount('/content/drive')

BASE_PATH = '/content/drive/MyDrive/ColabNotebooks/ML/NLP100_2020/06.MachineLearning/'
max_len = 0


def get_vocabulary(type_):
    global max_len
    df = pd.read_table(BASE_PATH+type_+'.feature.txt')
    df.info()
    sr_title = df['title'].str.split().explode()
    max_len_ = df['title'].map(lambda x: len(x.split())).max()
    if max_len < max_len_:
        max_len = max_len_
    fdist = nltk.FreqDist(sr_title)
    print(f'Top 3 tokens: {fdist.most_common(3)}')
    return [k for k, v in fdist.items() if v > 1]


vocabulary = get_vocabulary('train')
vocabulary.extend(get_vocabulary('valid'))
vocabulary.extend(get_vocabulary('test')) # あまりこだわらずにテストデータセットも追加

# setで重複削除し、タプル形式に設定
tup_voc = tuple(set(vocabulary))

print(f'vocabulary size before removing duplicates: {len(vocabulary)}')
print(f'vocabulary size after removing duplicates: {len(tup_voc)}')
print(f'sample vocabulary: {tup_voc[:10]}')
print(f'max length is {max_len}')

vectorize_layer = tf.keras.layers.TextVectorization(
 output_mode='int',
 vocabulary=tup_voc,
 output_sequence_length=max_len)

print(f'sample vocabulary: {vectorize_layer.get_vocabulary()[:10]}')

model = tf.keras.models.Sequential()
model.add(tf.keras.Input(shape=(1,), dtype=tf.string))
model.add(vectorize_layer)

# いまいち仕様を調べていないが、一度modelに追加すると下記が有効になる
print(vectorize_layer([["bar unknown_word(1)"]]).numpy)

回答解説

辞書作成

今回の肝となるコードです。
df['title'].str.split().explode()で単語分割をして1列のSeriesを作り、nltk.FreqDist(sr_title)で辞書を作成しています。ifの条件文で*「学習データ中で2回以上出現する単語にID番号を付与」*を実現しています。
また、max_len_ = df['title'].map(lambda x: len(x.split())).max()で1文の最大Token数を求めています。最大Token数はTextVectorization関数に渡すために求めています。

def get_vocabulary(type_):
    global max_len
    df = pd.read_table(BASE_PATH+type_+'.feature.txt')
    df.info()
    sr_title = df['title'].str.split().explode()
    max_len_ = df['title'].map(lambda x: len(x.split())).max()
    if max_len < max_len_:
        max_len = max_len_
    fdist = nltk.FreqDist(sr_title)
    print(f'Top 3 tokens: {fdist.most_common(3)}')
    return [k for k, v in fdist.items() if v > 1]

テストデータセットも辞書化しています。実運用を考えると辞書化から除外すべきかとも思いますが、こだわらずにやっています。

vocabulary = get_vocabulary('train')
vocabulary.extend(get_vocabulary('valid'))
vocabulary.extend(get_vocabulary('test')) # あまりこだわらずにテストデータセットも追加

辞書のモデル組込み

KerasのTextVectorization関数を使っています。今回、ノックの学習データ中で2回以上出現する単語にID番号を付与せよがなければ、本当にただテキストを渡すだけでした。しかし、1回以下の単語を除去するために事前に辞書を作ってパラメータvocabularyに渡しています。パラメータmax_tokensを使えば、覚え込む単語数の上限は指定できるのですが、頻度での指定はできないです。

vectorize_layer = tf.keras.layers.TextVectorization(
 output_mode='int',
 vocabulary=tup_voc,
 output_sequence_length=max_len)

print(f'sample vocabulary: {vectorize_layer.get_vocabulary()[:10]}')

model = tf.keras.models.Sequential()
model.add(tf.keras.Input(shape=(1,), dtype=tf.string))
model.add(vectorize_layer)

# いまいち仕様を調べていないが、一度modelに追加すると下記が有効になる
print(vectorize_layer([["bar unknown_word(1)"]]).numpy)

以下の出力をします。1行目の[UNK]は未知語です。小さい息子の影響で「う○こ」に見えてしまいます。

結果
sample vocabulary: ['', '[UNK]', 'Changes', 'rampage', 'Politics', 'Gawker', 'mood', 'Quiznos', 'friendless', 'end']
<bound method _EagerTensorBase.numpy of <tf.Tensor: shape=(1, 18), dtype=int64, numpy=
array([[2081,    1,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0]])>>

こぼれ話

今回、ノックの学習データ中で2回以上出現する単語にID番号を付与せよに非常に苦しみました。
普通にPythonで組めばそんなに手間がかからないのですが、関数を色々探してしまいました。

没関数1: Tokenizer

Keras の Tokenizer関数を調べました。パラメータdocument_countを使えばできるかも、と思いましたがそんなことは無かった。

没関数2: corpora.dictionary

Gensim の corpora.dictionary関数を調べました。もう忘れましたが、パラメータか関数を使ってできるかも、と思いましたがそんなことは無かった。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?