YutaroOgawa / pytorch_advanced

書籍「つくりながら学ぶ! PyTorchによる発展ディープラーニング」の実装コードを配置したリポジトリです
MIT License
837 stars 336 forks source link

【第4章2節:cm.jetについて(P.201)】 #141

Open kawase621 opened 3 years ago

kawase621 commented 3 years ago

p.201でheat_mapを表示させる時に使っているcm.jetの詳細を教えてもらえませんか?

調べ方が悪いのか、インターネットで検索しても欲しい情報が出てこず、以下の2点で悩んでいます。

Q.jet関数実行の前と後で、何がどう変わるのでしょうか(カラーマップが設定される?)。 Q.jet関数に引数として与えているのはndarrayでなくTensorだと思うのですが、問題なく動くのでしょうか?

YutaroOgawa commented 3 years ago

@kawase621 さま

ご質問ありがとうございます。

質問箇所は


# 左肘
heat_map = heatmaps[:, :, 6]  # 6は左肘
heat_map = Image.fromarray(np.uint8(cm.jet(heat_map)*255))
heat_map = np.asarray(heat_map.convert('RGB'))

などの、cm.jetですね。

このcm(color maps)について、紙面で丁寧な解説がなく申し訳ございません。

詳細には、

Notebook https://github.com/YutaroOgawa/pytorch_advanced/blob/master/4_pose_estimation/4-2_DataLoader.ipynb

のセル1でimport している、

from matplotlib import cm

になります。

cm.jetは、使用するcolor mapをjetに指定せよ、という意味になります。

cmのさらなる詳細は、MatPlotlibの該当をご参照くださいませ。

https://matplotlib.org/3.1.0/tutorials/colors/colormaps.html

kawase621 commented 3 years ago

ご回答ありがとうございます。

cm.jetについて、以下のようにplt.imshowの引数として使われているのはよく見かけます。 plt.imshow(a,camp=plt.cm.jet)など

ただ、勉強不足なことに、今回のようにTensorを引数に、関数として実行されているcm.jetを初めて見ました(添付頂いたリンクでも詳細を見つけることが出来ませんでした)。

今回、cm.jetの引数となっているTensorは、torch.size([46,46])で、各値はピクセル座標を中心としたガウス分布になっているとの理解ですが、ここでは「描画時に使用される、各値に対応するcolor mapがjetとして設定される」と考えて良いのでしょうか?その場合、なぜplt.imshow実行時にcolor mapを設定するやり方を取らないのでしょうか? それとも、今回のcm.jetはTensor自体に何らかの変化を及ぼすものなのでしょうか?

また、この処理がheatmapのみに対して実行されている(pafはそのまま)のはなぜでしょうか?

本論とはあまり関係ないところかも知れませんが、ご回答頂けると幸いです。

YutaroOgawa commented 3 years ago

@kawase621 さま

ここでは「描画時に使用される、各値に対応するcolor mapがjetとして設定される」と考えて良いのでしょうか?

はい、その通りです。 heat_mapは、各関節位置である可能性を示し、各座標値につきスカラ値となっています。 この0-255のスカラ値を、RGBのカラーにして、255に近く、関節である確率が高いと赤色に 0に近い場合は青色にしたいので、jetでテンソル自体を置き換えています。

なぜplt.imshow実行時にcolor mapを設定するやり方を取らないのでしょうか?それとも、今回のcm.jetはTensor自体に何らかの変化を及ぼすものなのでしょうか?

これはplt.imshow()でのcolormapsの使い方と基本は同じですが、今回は画像を2つマージしているので、 先にカラーマップを適用しています。 Tensor自体をRGBに変え、変化させている(はずです)

また、この処理がheatmapのみに対して実行されている(pafはそのまま)のはなぜでしょうか?

確かに、ここでPAFもカラーマップにするのもありですね。

ただ、PAFが出てくる初めての部分なので、PAFの概念の第一段階(関節と関節をつなぐピクセルかどうかを示す) を理解していただくため

そして、関節のheatmapと同じ表示で、混乱しないように、PAFは白黒のグレイスケールにした(気がします)。

最後の

https://github.com/YutaroOgawa/pytorch_advanced/blob/master/4_pose_estimation/4-7_OpenPose_inference.ipynb

ではPAFもカラーマップにしています。 この時点ではPAFの計算の仕方を説明し終えているからです。

逆に混乱を招いてしまい、大変申し訳ございません。

非常に丁寧に本書を活用いただけていることが伝わり、非常に嬉しいです。 ありがとうございます。

kawase621 commented 3 years ago

本件、私の拙い質問に丁寧に回答下さりありがとうございます。とてもよく分かりました。

一点だけ、回答の中に 「heat_mapは、各関節位置である可能性を示し、各座標値につきスカラ値となっています。 この0-255のスカラ値を...」とありますが、heat_mapは0-1の間に正規化されているということはありませんか?

YutaroOgawa commented 3 years ago

@kawase621 さん

「heat_mapは、各関節位置である可能性を示し、各座標値につきスカラ値となっています。 この0-255のスカラ値を...」とありますが、heat_mapは0-1の間に正規化されているということはありませんか?

Tensorにする際に正規化しているので0-1の間ですね。失礼しました。 ありがとうございます!

kawase621 commented 3 years ago

こちらこそありがとうございました!

kawase621 commented 3 years ago

何度もすみません。 P.201のtorch.Tensorに対してcm.jet()を実行する場合の動きについて確認するため、 以下のような実験を行いました。

内容;10×10のndarray配列(0〜1の範囲の一様分布)をtorch.Tensorに変換し、cm.jet()を実行

import numpy as np
import torch
from matplotlib import cm
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')

a = np.random.rand(10,10)

heatmaps = torch.from_numpy(a)

heatmaps = cm.jet(heatmaps)

すると、以下のようなエラーが発生します。 本書の実装では、matplotlibでtorch.Tensorを扱えるように特別な処理をしているのでしょうか? それとも、torch.Tensor自体は何の変換もせずmatplotlibで使えるようになっていて、 私が今回の実験でcm.jet()に与えたデータがまずかったのでしょうか?

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-dac50ff05f4e> in <module>
      9 heatmaps = torch.from_numpy(a)
     10 
---> 11 heatmaps = cm.jet(heatmaps)

~/opt/anaconda3/lib/python3.8/site-packages/matplotlib/colors.py in __call__(self, X, alpha, bytes)
    559         if np.ma.is_masked(X):
    560             mask_bad = X.mask
--> 561         elif np.any(np.isnan(X)):
    562             # mask nan's
    563             mask_bad = np.isnan(X)

<__array_function__ internals> in any(*args, **kwargs)

~/opt/anaconda3/lib/python3.8/site-packages/numpy/core/fromnumeric.py in any(a, axis, out, keepdims)
   2315 
   2316     """
-> 2317     return _wrapreduction(a, np.logical_or, 'any', axis, None, out, keepdims=keepdims)
   2318 
   2319 

~/opt/anaconda3/lib/python3.8/site-packages/numpy/core/fromnumeric.py in _wrapreduction(obj, ufunc, method, axis, dtype, out, **kwargs)
     86                 return reduction(axis=axis, dtype=dtype, out=out, **passkwargs)
     87             else:
---> 88                 return reduction(axis=axis, out=out, **passkwargs)
     89 
     90     return ufunc.reduce(obj, axis, dtype, out, **passkwargs)

TypeError: any() received an invalid combination of arguments - got (out=NoneType, axis=NoneType, ), but expected one of:
 * ()
 * (name dim, bool keepdim)
      didn't match because some of the keywords were incorrect: out, axis
 * (int dim, bool keepdim)
      didn't match because some of the keywords were incorrect: out, axis
YutaroOgawa commented 3 years ago

@kawase621 さま

ありがとうございます。 いま、ぱっと動かせる環境がないのでご確認いただきたいのですが、 本書での、

heatmaps

のTensorのsize、型

と、

上記の変数aから作成したTensor(heatmaps)のTesorのsize、型は何になっていますか?

一致していますでしょうか?

kawase621 commented 3 years ago

早速ありがとうございます。

変数aから作ったTensorのsizeは適当に作った(10×10の配列)ので、本書のheatmapsと一致していませんが、配列の形状(shape)は2次元で一致させたつもりです。 また、本書のheatmapsも、私が作ったheatmapsも型はTorch.tensorとの理解です。

YutaroOgawa commented 3 years ago

@kawase621 さま

ありがとうございます。

おかげさまで、重要なエラーを理解しました。

こちら、結論としては、Matplotlibのバージョンの問題です。

本書が出版された頃、そしてそれ以降当分の、MatplotlibのVearsion3.1では問題なく動作するのですが、 現在のGoogle Colab等でも採用されているVersion3.2からエラー になっています。

Google Colabでの試したファイルを添付します。

またいただいた内容に従い、誤植修正Issueとプログラムに注意を記載します。

非常に重要なご指摘をありがとうございます!

以下、Google Coabのノートブックです。 Issue欄にipynbファイルを貼れないので、zipにしています。 cm_check_210131.zip

kawase621 commented 3 years ago

なるほど、バージョンの問題だったんですね! ご対応頂きありがとうございました。

YutaroOgawa commented 3 years ago

@kawase621 さま

こちらこそ、誠にありがとうございます。

kawaseさまのおかげで問題と解決が判明しました。 今後ともどうぞ宜しくお願い致します