LoginSignup
0
0

More than 1 year has passed since last update.

言語処理100本ノック(2020)-71: 単層ニューラルネットワークによる予測(TensorFlow)

Last updated at Posted at 2021-10-04

言語処理100本ノック 2020 (Rev2)「第8章: ニューラルネット」71本目「単層ニューラルネットワークによる予測」記録です。前回、TFRecord形式で保存したファイルを読み込み、ニューラルネットワークに流し込みます。やはりTFRecord形式ファイルの扱いに手間取りました。この時点では訓練なしで流し込むのですが、そんな処理は初めて書きました。本当はSoftmaxとか解説すべきなのでしょうが、ググればいい記事がすぐに見つかるので解説しません。
記事「まとめ: 言語処理100本ノックで学べることと成果」言語処理100本ノック 2015についてはまとめていますが、追加で差分の言語処理100本ノック 2020 (Rev2)についても更新します。

参考リンク

リンク 備考
71_単層ニューラルネットワークによる予測.ipynb 回答プログラムのGitHubリンク
言語処理100本ノック 2020 第8章: ニューラルネット (PyTorchだけど)解き方の参考
【言語処理100本ノック 2020】第8章: ニューラルネット (PyTorchだけど)解き方の参考
まとめ: 言語処理100本ノックで学べることと成果 言語処理100本ノックまとめ記事
TFRecords と tf.Example の使用法 今回の課題メイン

環境

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

種類 バージョン 内容
Python 3.7.12 Google Colaboratoryのバージョン
google 2.0.3 Google Driveのマウントに使用
tensorflow 2.6.0 ディープラーニングの主要処理

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

学習内容

深層学習フレームワークの使い方を学び,ニューラルネットワークに基づくカテゴリ分類を実装します.

ノック内容

第6章で取り組んだニュース記事のカテゴリ分類を題材として,ニューラルネットワークでカテゴリ分類モデルを実装する.なお,この章ではPyTorch, TensorFlow, Chainerなどの機械学習プラットフォームを活用せよ.

71. 単層ニューラルネットワークによる予測

問題70で保存した行列を読み込み,学習データについて以下の計算を実行せよ.

\hat{\boldsymbol y_1} = {\rm softmax}(\boldsymbol x_1 W), \\
\hat{Y} = {\rm softmax}(X_{[1:4]} W)

ただし,${\rm softmax}$はソフトマックス関数,$X_{[1:4]} \in \mathbb{R}^{4 \times d}$は特徴ベクトル$\boldsymbol x_1, \boldsymbol x_2, \boldsymbol x_3, \boldsymbol x_4$を縦に並べた行列である.

X_{[1:4]} = \begin{pmatrix} 
  \boldsymbol x_1 \\ 
  \boldsymbol x_2 \\ 
  \boldsymbol x_3 \\ 
  \boldsymbol x_4 \\ 
\end{pmatrix}

行列$W \in \mathbb{R}^{d \times L}$は単層ニューラルネットワークの重み行列で,ここではランダムな値で初期化すればよい(問題73以降で学習して求める).なお,$\hat{\boldsymbol y_1} \in \mathbb{N}^L$は未学習の行列$W$で事例$x_1$を分類したときに,各カテゴリに属する確率を表すベクトルである.
同様に,$\hat{Y} \in \mathbb{N}^{n \times L}$は,学習データの事例$x_1, x_2, x_3, x_4$について,各カテゴリに属する確率を行列として表現している.

回答

回答結果

結果(事例1件)
[[0.23627585 0.25216544 0.25520897 0.25634965]]
結果(事例集合4件)
[[0.23627585 0.25216544 0.25520897 0.25634965]
 [0.24906628 0.2570258  0.2513765  0.24253134]
 [0.2553226  0.24705489 0.24583162 0.25179094]
 [0.24834852 0.25343078 0.24328355 0.2549371 ]]

回答プログラム 71_単層ニューラルネットワークによる予測.ipynb

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

import tensorflow as tf
from google.colab import drive

drive.mount('/content/drive')

BASE_PATH = '/content/drive/MyDrive/ColabNotebooks/ML/NLP100_2020/08.NeuralNetworks/'
train_raw = tf.data.TFRecordDataset(BASE_PATH+'train.tfrecord')

def _parse_function(example_proto):
    # 特徴の記述
    feature_description = {
        'title': tf.io.FixedLenFeature([], tf.string),
        'category': tf.io.FixedLenFeature([], tf.string)}

  # 上記の記述を使って入力の tf.Example を処理
    features = tf.io.parse_single_example(example_proto, feature_description)
    X = tf.io.decode_raw(features['title'], tf.float32)
    y = tf.io.decode_raw(features['category'], tf.int32)
    return X, y

dense_layer = tf.keras.layers.Dense(4, activation='softmax', use_bias=False, input_dim=300, kernel_initializer='random_uniform')

def output_result(batch_size):
    for X, y in train_raw.map(_parse_function).batch(batch_size).take(1):

        # 入力データ
        print('---入力データ---')
        print(X.numpy().shape) 
        print(y.numpy())  # 使わないけど確認だけする

        print('---出力データ---')
        print(dense_layer(X).numpy())


output_result(1)
output_result(4)

回答解説

TFRecord形式ファイル読込

TFRecord形式ファイルの読込は以下のコード。

BASE_PATH = '/content/drive/MyDrive/ColabNotebooks/ML/NLP100_2020/08.NeuralNetworks/'
train_raw = tf.data.TFRecordDataset(BASE_PATH+'train.tfrecord')
print(train_raw)

このままだと、データとして使えないので形式変更にする必要あり。

結果
<TFRecordDatasetV2 shapes: (), types: tf.string>

parseするための関数を作ります。正直、面倒なのでデータ量が機械学習のボトルネックにならないのであれば、pickleやnumpy形式でファイルI/Oすべきです。

def _parse_function(example_proto):
    # 特徴の記述
    feature_description = {
        'title': tf.io.FixedLenFeature([], tf.string),
        'category': tf.io.FixedLenFeature([], tf.string)}

  # 上記の記述を使って入力の tf.Example を処理
    features = tf.io.parse_single_example(example_proto, feature_description)
    X = tf.io.decode_raw(features['title'], tf.float32)
    y = tf.io.decode_raw(features['category'], tf.int32)
    return X, y

で、map関数を使って先程定義した関数_parse_functionを呼んで、batchとtakeでデータ取得の調整をします。

def output_result(batch_size):
    for X, y in train_raw.map(_parse_function).batch(batch_size).take(1):

        # 入力データ
        print('---入力データ---')
        print(X.numpy().shape) 
        print(y.numpy())  # 使わないけど確認だけする

        print('---出力データ---')
        print(dense_layer(X).numpy())

あとは、バッチサイズを渡して先に定義した関数を実行。

output_result(1)
output_result(4)

訓練などをしていない状態なので、1/4に近い数値がSoftmax結果として返ってきます。

結果
---入力データ---
(1, 300)
[[1 0 0 0]]
---出力データ---
[[0.23627585 0.25216544 0.25520897 0.25634965]]
---入力データ---
(4, 300)
[[1 0 0 0]
 [0 1 0 0]
 [0 0 0 1]
 [0 0 1 0]]
---出力データ---
[[0.23627585 0.25216544 0.25520897 0.25634965]
 [0.24906628 0.2570258  0.2513765  0.24253134]
 [0.2553226  0.24705489 0.24583162 0.25179094]
 [0.24834852 0.25343078 0.24328355 0.2549371 ]]

softmax計算

以下のノック内容部分です。活性化関数activationをsoftmaxに、入力input_dimを300次元にしています。
kernel_initializerランダムな値で初期化をして、use_biasFalseにすることでバイアス項をなくしています。バイアス項をなくしている理由は、ノック79本目に「バイアス項の導入や多層化など,ニューラルネットワークの形状を変更しながら,高性能なカテゴリ分類器を構築せよ」と書かれていて、ここではまだ入れてはいけないことに気づきました。

行列$W \in \mathbb{R}^{d \times L}$は単層ニューラルネットワークの重み行列で,ここではランダムな値で初期化すればよい

dense_layer = tf.keras.layers.Dense(
    4, activation='softmax', 
    use_bias=False, 
    input_dim=300, 
    kernel_initializer='random_uniform')
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