【PyTorchチュートリアル】VISUALIZING MODELS, DATA, AND TRAINING WITH TENSORBOARD-7

1_プログラミング

このチュートリアルの最後の項目です。意外とテンソルの操作が複雑です。

テンソルがどんな風になっているのか追うのが大変だね。

チュートリアルをやりながら、色々と横にそれてしまいましたが、このチュートリアルの最後の項目をやっていきます。やはり、テンソルを色々と操作すると今データがどんな形なのか、という点が非常に複雑です。出来るだけどんなデータになっているのか追いつつ、見ていきたいと思います。

今やっているチュートリアルはこちらの「6.」の項目です。

こんな人の役に立つかも

・機械学習プログラミングを勉強している人

・PyTorchのチュートリアルをやっている人

・PyTorchでTensorBoardを利用したい人

スポンサーリンク

7.モデルの検証

最後の項目では、モデルの検証ということで、「PRカーブ」というものをTensorBordで作成するようです。

PRカーブは、PrecisionとRecall(過去にやったような・・・)を縦軸と横軸にとり、モデルの評価を行うものです。この線の下の部分の面積が大きいほど良いそうです。今やっているチュートリアルのモデルでは、ラベルが0〜9(答えの値)ありますので、これらのラベルに対するカーブをそれぞれ作成していくことになります。

利用する関数

softmaxの挙動

softmaxは、他クラス分類の答えの確率を全て足して1の値になるようにするものです。10個の答えがある場合、モデルは10個の出力を持ちますが、10個の出力の合計を1に揃えるものです。次のサンプルで感覚を掴みました。

#Softmaxを行う(2階のテンソル、行列の場合、dim1で行の方向に処理を行う設定)
m = nn.Softmax(dim=1)
print(m)
#2行3列のテンソルをランダムな値で初期化
input = torch.randn(2, 3)
print(input)
#テンソルにSoftMaxの処理を行う
output = m(input)
print(output)
Softmax(dim=1)
tensor([[ 0.1624,  0.9412, -0.2218],
        [ 0.3319, -0.8020, -0.4833]])
tensor([[0.2591, 0.5645, 0.1764],
        [0.5668, 0.1824, 0.2508]])
#行方向にテンソルを合計する
print(torch.sum(output, dim=1))
tensor([1.0000, 1.0000])

PyTorchの公式ドキュメントはこちらです。

torch.catとstackの挙動

catとstackはテンソルを結合するときに利用するらしいのですが、次のサンプルで理解できると思います。

#2×3のテンソル(行列)を準備
x = torch.randn(2, 3)
x
tensor([[ 1.2377,  0.0331,  1.4176],
        [ 0.6362, -0.5774,  1.7173]])

テンソルをリストに3個追加します。(同じテンソルを3回追加)

#リストを作成します。
x_list = []
x_list.append(x)
x_list.append(x)
x_list.append(x)

まずはstackをしてみます。リストに3個のテンソルが入っていますので、それらのテンソルが結合されるはずです。

print(torch.stack(x_list))
torch.stack(x_list).size()

[3×2×3]のサイズのテンソルとなりました。

tensor([[[ 1.2377,  0.0331,  1.4176],
         [ 0.6362, -0.5774,  1.7173]],

        [[ 1.2377,  0.0331,  1.4176],
         [ 0.6362, -0.5774,  1.7173]],

        [[ 1.2377,  0.0331,  1.4176],
         [ 0.6362, -0.5774,  1.7173]]])
torch.Size([3, 2, 3])

stackの公式ドキュメントはこちらです。

次に、catを試してみます。

print(torch.cat(x_list))
torch.cat(x_list).size()

今度は[6×3]のテンソルとなりました。

tensor([[ 1.2377,  0.0331,  1.4176],
        [ 0.6362, -0.5774,  1.7173],
        [ 1.2377,  0.0331,  1.4176],
        [ 0.6362, -0.5774,  1.7173],
        [ 1.2377,  0.0331,  1.4176],
        [ 0.6362, -0.5774,  1.7173]])
torch.Size([6, 3])

catのドキュメントはこちらです。

実際には、catとstackはどの軸を指定するかでもっと色々な結合方法があるのですが、今回チュートリアルで利用されているのは、上で見た結合の方法でした。

stackは、2×3のテンソルを3個、3×[2×3]というような結合を行いましたが、catでは、6行3列のテンソル(行列)を作成する、というような違いがありました。

チュートリアルのプログラムを見ていきます

前置きが長くなりましたが、チュートリアルのプログラムを見ていきます。

ちなみに、今回のGPUにするところは、1行だけですが、【GPU】としました。

#1. テストデータの「probability」の値を求めます(モデルが出力する確率の値です)
#2. テストデータのモデルの予測値を求めます。
#この処理には10秒程度かかります。
class_probs = []
class_preds = []
with torch.no_grad():
    for data in testloader:
        #【GPU】
        #images, labels = data[0].to(device) , data[1].to(device)
        #【CPU】
        images, labels = data

        output = net(images)
        #テンソルの行(画像1枚当たりの出力)をソフトマックス関数に通す
        #class_probs_batchはリスト。
        class_probs_batch = [F.softmax(el, dim=0) for el in output]
        #一番値が大きいクラスをMax関数で選択して予測回答とする(第二引数が1で行の中の最大値を取る)
        _, class_preds_batch = torch.max(output, 1)

    #Pythonのリストに「probability」と「予測回答」を追加していきます
        #class_probsはリスト。
        class_probs.append(class_probs_batch)
        class_preds.append(class_preds_batch)

#[torch.stack(batch) for batch in class_probs]
#テンソルを要素に持つリストをテンソルに変換
test_probs = torch.cat([torch.stack(batch) for batch in class_probs])
#print(test_probs.size())#ここで、[10000,10]の行列となる。
test_preds = torch.cat(class_preds)
#print(test_preds.size())#ここで、[10000]のベクトルとなる。

テンソルの流れが複雑なので、ピックアップして、「class_probs_batch」から「class_probs」のテンソルの変換を図にしてみました。

作っているときは、とてもいいアイデアだと思ったのですが、改めて見ると、わかりにくいかもしれません・・・すいません。

次に、「class_probs」からPythonのリスト内包表記により、stackで結合され、catでさらに結合されます。

このような流れで、「test_probs」が単純な行列の形になります。「test_probs」は、画像一枚一枚に対するモデルの予測確率になります。一方で、「test_preds」は画像一枚一枚に対する予測結果なので、1枚の画像に対して、0~9のどれか一つの数値だけが予測値として存在します。そのため、「test_preds」は10000個のベクトルになっています。

次にヘルパー関数で、TensorBoardに書き込みます。add_pr_curveというメソッドで書き込みができるようです。

probsとpredsはややこしい・・・

次のヘルパー関数でPRカーブをTensorBoardに書き込みます。

# ヘルパー関数
def add_pr_curve_tensorboard(class_index, test_probs, test_preds, global_step=0):
    '''
    Takes in a "class_index" from 0 to 9 and plots the corresponding
    precision-recall curve
    '''
    #ラベル(class_index)と等しいtest_predsの値がtensorboard_predsとなる。
    tensorboard_preds = test_preds == class_index
    #ラベルの列のみを取得してtensorboard_probsとする。
    tensorboard_probs = test_probs[:, class_index]

    writer.add_pr_curve(classes[class_index],
                        tensorboard_preds,
                        tensorboard_probs,
                        global_step=global_step)
    writer.close()

# PRカーブを作成する。0~9までのラベルで作成するのでループする。
for i in range(len(classes)):
    add_pr_curve_tensorboard(i, test_probs, test_preds)

add_pr_curve関数はこちらのドキュメントもご参照ください。

TensorBoaardをブラウザで立ち上げて、次のようにPRカーブが確認できるはずです。(画像は、Shirtの場合のPRカーブです。

GitHubにJupyterで実行する用のプログラムを配置します。

 

タイトルとURLをコピーしました