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)-72: 損失と勾配の計算(TensorFlow)

Last updated at Posted at 2021-10-06

言語処理100本ノック 2020 (Rev2)「第8章: ニューラルネット」72本目「損失と勾配の計算」記録です。勾配計算はいつもkerasに任せていたので、勾配の取得などしようと思ったこともなく、調べるのに時間がかかりました。本当は**kerasを使わずに、自分でコーディングすることこそが良い学習なのでしょうが、取り急ぎkerasを使い続けます**。
記事「まとめ: 言語処理100本ノックで学べることと成果」言語処理100本ノック 2015についてはまとめていますが、追加で差分の言語処理100本ノック 2020 (Rev2)についても更新します。

参考リンク

リンク 備考
72_損失と勾配の計算.ipynb 回答プログラムのGitHubリンク
言語処理100本ノック 2020 第8章: ニューラルネット (PyTorchだけど)解き方の参考
【言語処理100本ノック 2020】第8章: ニューラルネット (PyTorchだけど)解き方の参考
まとめ: 言語処理100本ノックで学べることと成果 言語処理100本ノックまとめ記事
公式ガイド: モデルに関する勾配 勾配取得の公式ガイド

環境

後々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などの機械学習プラットフォームを活用せよ.

72. 損失と勾配の計算

学習データの事例$x_1$と事例集合$x_1$,$x_2$,$x_3$,$x_4$に対して,クロスエントロピー損失と,行列$W$に対する勾配を計算せよ.なお,ある事例$x_i$に対して損失は次式で計算される.

$$l_i=−log[事例x_iがy_iに分類される確率]$$

ただし,事例集合に対するクロスエントロピー損失は,その集合に含まれる各事例の損失の平均とする.

回答

回答結果

これ見ても何も判断できないですが、一応回答結果です。1行目がLossで、行列部分が勾配。

結果(事例1件)
1.3719598
dense_1/kernel:0, shape: (300, 4)
[[-0.06244335  0.02067989  0.02176488  0.01999857]
 [-0.00420518  0.00139266  0.00146573  0.00134678]
 [-0.00508651  0.00168454  0.00177292  0.00162904]
 ...
 [-0.05607251  0.01857001  0.0195443   0.0179582 ]
 [-0.03232378  0.01070494  0.01126659  0.01035225]
 [ 0.06478423 -0.02145514 -0.02258081 -0.02074828]]
結果(事例集合4件)
1.3873249
dense_1/kernel:0, shape: (300, 4)
[[-0.05536687  0.00082223  0.08464365 -0.03009901]
 [ 0.01126796 -0.01080388 -0.03230093  0.03183684]
 [-0.03271427  0.06947812 -0.0883422   0.05157837]
 ...
 [-0.09661584  0.08457799 -0.00822031  0.02025817]
 [-0.00410734  0.08742411  0.00315564 -0.08647241]
 [ 0.07903252  0.00211453  0.01354344 -0.09469048]]

回答プログラム 72_損失と勾配の計算.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', 
    input_dim=300, 
    use_bias=False, 
    kernel_initializer='random_uniform')

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

        print('---y_true---')
        print(y_true.numpy())

        with tf.GradientTape() as tape:
            y_pred = dense_layer(X)
            print('---y_pred---')
            print(y_pred.numpy())
            loss = tf.keras.losses.categorical_crossentropy(y_true, y_pred)
            print('---loss---')
            print(tf.math.reduce_sum((loss.numpy()/batch_size)).numpy())

        grad = tape.gradient(loss, dense_layer.trainable_variables)
        for var, g in zip(dense_layer.trainable_variables, grad):
            print(f'{var.name}, shape: {g.shape}')
            print(g.numpy())

print_loss_gradients(1)
print_loss_gradients(4)

回答解説

勾配の記録

GradientTapeを使って勾配を記録します。with内で記録するための計算を書きます。

with tf.GradientTape() as tape:
    y_pred = dense_layer(X)
    print('---y_pred---')
    print(y_pred.numpy())
    loss = tf.keras.losses.categorical_crossentropy(y_true, y_pred)
    print('---loss---')
    print(tf.math.reduce_sum((loss.numpy()/batch_size)).numpy())

gradient関数で勾配を入出力を渡して取得します。

grad = tape.gradient(loss, dense_layer.trainable_variables)

今回はバイアス項がないのでforでまわしても1件しか取得出来ませんが、バイアス項があると複数回ループして取得できます。

        for var, g in zip(dense_layer.trainable_variables, grad):
            print(f'{var.name}, shape: {g.shape}')
            print(g.numpy())

1件のみ取得するとこんな出力です。

結果(事例1件)
---y_true---
[[1 0 0 0]]
---y_pred---
[[0.25360948 0.24718848 0.2601575  0.23904456]]
---loss---
1.3719598
dense_1/kernel:0, shape: (300, 4)
[[-0.06244335  0.02067989  0.02176488  0.01999857]
 [-0.00420518  0.00139266  0.00146573  0.00134678]
 [-0.00508651  0.00168454  0.00177292  0.00162904]
 ...
 [-0.05607251  0.01857001  0.0195443   0.0179582 ]
 [-0.03232378  0.01070494  0.01126659  0.01035225]
 [ 0.06478423 -0.02145514 -0.02258081 -0.02074828]]
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?