このチュートリアルの最後の項目です。意外とテンソルの操作が複雑です。
テンソルがどんな風になっているのか追うのが大変だね。
チュートリアルをやりながら、色々と横にそれてしまいましたが、このチュートリアルの最後の項目をやっていきます。やはり、テンソルを色々と操作すると今データがどんな形なのか、という点が非常に複雑です。出来るだけどんなデータになっているのか追いつつ、見ていきたいと思います。
今やっているチュートリアルはこちらの「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で実行する用のプログラムを配置します。