Sep 16, 2019

一点集中の攻めの受け損ねを反省してみる

昨日は毎年参加している、地域の将棋大会だった。
今年も家庭が忙しくて準備不足で、特に今年は直前になっても実戦練習をほとんどやらなかったので、予選突破は完全に諦めていて、予選落ちして指導対局を受ける覚悟で行ったが、意外にも2連勝で予選突破した。決勝トーナメント1回戦敗退はいつも通りだが、予選突破がストレートの分、例年より少し良い結果だった。

決勝Tの1回戦は、悪いと思ってなかった局面から、一方的に攻められて受け方がわからず、そのままボロ負けするという、私にはよくある、指していて全く面白くない将棋になってしまったので、激指14を用いて少し研究してみる。


筆者は後手である。先手が3手目角交換から振り飛車にして、このように▲6六銀△6五歩▲5五銀とぶつけられた。△6三銀と引けば5五の銀が立ち往生して先手が困るのではないか、▲4五歩からの桂馬攻めが見えてるが大したことないだろうと思って引いたら、数分の長考の後、▲7七角とされた。

これを見ても、△4三金右で受かるだろうと思った。
相手は4年前の優勝者で、その年に私も当たって負けたのだが、圧倒的に強い感じではなかったし、長考してる時に意表を突かれて悩んでいる感じだったので、苦し紛れの手だろうと思った。
△4三金右▲4五歩

△同歩▲同桂△4四歩▲3三桂成△同金上▲4五歩△同歩▲4四銀打

となってこの局面になったが、まだ受け切れそうに思っていた。
そこから△4二飛▲4三銀成△同飛▲4四金△4二飛▲3三金△同桂▲4四銀

となって崩壊し、この後△6四角▲3七金△3二金▲5五金から角を取られて▲5一角とされて終了した。

何が悪かったのだろうと激指14で解析してみたら、42手目の△4三金右から58手目の△3三同桂までの間の悪手は56手目の△4二飛だけで、評価値は42手目の△4三金右で+380(Pro+3, 先手有利)、52手目くらいまで後手だけ最善を尽くしても+560、本譜の手順でも56手目の△4二飛の悪手が無くて代わりに△4一飛▲3三金△同桂▲4四銀△3二銀

とすれば+589なので54手目まで評価値がほぼ最善手順と変わらないという感じなので、42手目の△4三金右の時点でどうしようもなかったようだ。
しかし、上の△3二銀の局面の評価値が最善手順と大差ないといっても、52手目に△4二飛とするとこの局面まで一本道なのであり、51手目の段階でこの局面を想像できたとしても、筆者には危なっかしくてこの局面を選択することはできない。▲4四の銀が動くと△4六歩があるので、先手が悩みそうで、勝負手としては良さそうだが、後手がこれで耐えていると判断するのが、筆者には難しそうだ。

局後の感想戦では、相手の人がどこかで△6六歩とされるのが嫌だったと言っていた。▲同角に銀があれば△6五銀ということだろうか。筆者としては先手に1歩渡すリスクが大き過ぎてまず考えられないし、激指14の検討手順には出て来なかったが、先手としては角を狙われるのが一番嫌だったのだろうか。
また、52手目の△4二飛がまずく、△3一桂なら良かったのではないか、という話になった。激指14の検討手順には出て来なかった(52手目の候補手の上位は△5四銀、△4二金、△3二玉)が、進めてみると、△3一桂▲3三銀成△同桂▲4四銀△3二銀

▲3三銀成△同銀▲2五桂△4四銀打▲3三桂成△同銀

で激指14の評価値は+500〜+700くらいで極端に悪くはないし、あくまでも筆者の感性では、後手の手順がわかりやすいし、後手が受け切っている。後手からの攻め味が無いが、先手が焦っていればミスを誘発しやすい。上の手順中、先手には4三の金を取る機会が2回あるが、4三の金を取ると△同桂で先手の攻めが切れやすいと思う(局後の検討では△4三同桂で後手良し)。このようにしたかったと思った。

他に、激指14の候補手の中に、46手目から△5四歩▲3三桂成△同桂▲4四銀△6四角▲4六歩

というのが出てきた。46手目に△4四歩としないと先手から▲4四歩とされて困ると思ったので、ここで△5四歩は選ばなかったのだが、もしこの局面のように▲4六歩を強要できるなら、これを選択したい。ただ、この手順で▲4六歩を強要できるかどうかを考えるのは、筆者には難しすぎる。

See more ...

Posted at 23:52 in 将棋 | WriteBacks (0)
WriteBacks

Sep 08, 2019

TensorFlowのofficialな学習済みResNetを動かしてみる

少し前に画像認識できるTensorFlowの学習済みモデルを探していると、https://github.com/tensorflow/modelsのofficialの下に、ImageNetデータセットで学習済みの、ResNetのPre-trained modelというのを見つけた。
ResNet以外のモデルやPre-trained modelがほとんど無いので、"official"といってもあまり注目されていないサイトなのかな、TensorFlow Hubがメインストリームなのかなと思いつつも、"official"なので信頼できそうだし、メンテナンスされているだろうからクオリティが高いだろう、難なく動かせるだろうと思って、とりあえず動かしてみようと思った。

しかし、TensorFlowのofficialなものなので、サンプルコードがすぐに見つかるだろうと思ったが、直接的なものを全く見つけることができなかった。その時点でこれは興味を持つ人が少ない、あまり良いものではないのだろうなと確信したが、何せTensorFlowのofficialなものなので、一応動かしておこうと思った。筆者は"official"という言葉に弱いのである。
しかし、TensorFlowの使い方をほとんど知らないまま、巷のサンプルコードをつぎはぎしながらでは予想以上に難しく、見ても何が悪いのかがわからない同じエラーメッセージを何時間も見続けて嫌になったが、それでもofficialなものを動かせなくては敗北と思って、さらに何時間も費やしてしまった。
最終的にはよくわからない所があるまま何らか動いたので、一応そのコードを記録する。

使用したモデルは、"ResNet in TensorFlow"のPre-trained modelの"ResNet-50 v2 (fp32, ...)"のSavedModelの所にある、"(NHWC)"と"(NHWC, JPG)"というリンクの先の、以下の2つのファイルである。
[1] resnet_v2_fp32_savedmodel_NHWC.tar.gz
[2] resnet_v2_fp32_savedmodel_NHWC_jpg.tar.gz
これらを、カレントディレクトリに展開したものとする。 すると、それぞれ
resnet_v2_fp32_savedmodel_NHWC/1538687283/
resnet_v2_fp32_savedmodel_NHWC_jpg/1538687457/
の下に、
saved_model.pb
variables/
が展開される。

それぞれ、saved_model_cliコマンドを使って、入力テンソルと出力テンソルの情報を表示してみる。

$ saved_model_cli show --dir resnet_v2_fp32_savedmodel_NHWC/1538687283/ --all
MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:

signature_def['predict']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['input'] tensor_info:
        dtype: DT_FLOAT
        shape: (64, 224, 224, 3)
        name: input_tensor:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['classes'] tensor_info:
        dtype: DT_INT64
        shape: (64)
        name: ArgMax:0
    outputs['probabilities'] tensor_info:
        dtype: DT_FLOAT
        shape: (64, 1001)
        name: softmax_tensor:0
  Method name is: tensorflow/serving/predict
$ saved_model_cli show --dir resnet_v2_fp32_savedmodel_NHWC_jpg/1538687457/ --all
MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:

signature_def['predict']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['image_bytes'] tensor_info:
        dtype: DT_STRING
        shape: (-1)
        name: input_tensor:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['classes'] tensor_info:
        dtype: DT_INT64
        shape: (-1)
        name: ArgMax:0
    outputs['probabilities'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 1001)
        name: softmax_tensor:0
  Method name is: tensorflow/serving/predict

まず、tf.contrib.predictorを使って、"(NHWC, JPG)"[2]についてやってみた。
これは割と簡単に動いた。

●コード例1
import tensorflow as tf
from tensorflow.contrib import predictor

img_path = 'elephant.jpg'
with open(img_path, 'rb') as F:
    jpeg_bytes = F.read()

predict_fn = predictor.from_saved_model("./resnet_v2_fp32_savedmodel_NHWC_jpg/1538687457/")
result = predict_fn({'image_bytes': [jpeg_bytes]})

cls = result['classes'][0]
prob = result['probabilities'][0, cls]
print('class={} probability={:.3f}'.format(cls, prob))
●出力例1
class=386 probability=0.988

動作確認した環境は、macOS 10.13.6 + TensorFlow 1.13.1である。Raspberry Pi 2 v1.2(Cortex A53) + TensorFlow 1.13.1では、import行で後述のエラーが出て動かなかった。
コード中の'image_bytes'というのは、上記のsaved_model_cliの出力にある。
'elephant.jpg'はhttps://keras.io/ja/applications/の"Classify ImageNet classes with ResNet50"のコード例に合わせたものだが、officialなelephant.jpgが見つからなかったので、All-free-download.comの中から選んだ、次の画像を使った。
elephant_in_kobe_zoo_514337_resized.jpg
class=386は、別途調べた(後述)所では"Indian_elephant"なので、正解である。

次に、同じくtf.contrib.predictorを使って、"(NHWC)"[1]についてやってみた。
これはかなり苦労した。

●コード例2
import numpy as np
from PIL import Image
import tensorflow as tf
from tensorflow.contrib import predictor

img_path = 'elephant.jpg'
img = Image.open(img_path).resize((224,224))
x = np.array(img)
x = x.astype(np.float32)

predict_fn = predictor.from_saved_model("./resnet_v2_fp32_savedmodel_NHWC/1538687283/")
result = predict_fn({'input': np.array([x] * 64)})

cls = result['classes'][0]
prob = result['probabilities'][0, cls]
print('class={} probability={:.3f}'.format(cls, prob))
●出力例2
class=386 probability=0.821

上記のsaved_model_cliの出力にあるように、入力テンソルのshapeが(64, 224, 224, 3)なので、1枚の画像だけを認識したくても、必ず64枚分渡す必要がある(認識処理も64枚分まとめてなされる)のである。そのことになかなか気付かなかったので、同じエラーメッセージを嫌になるほど目にする羽目になってしまった。一体そういう仕様にすることにどういう意味があるのだろうか。これでは使い勝手が悪すぎる。
さらに、同じ形状のニューラルネットワークと同じ入力画像を使ってるのに、probabilityの値が"(NHWC, JPG)"[2]よりも悪くなっている。これについて少し調べたことを後述する。

次に、predictorを使わず、TensorFlow APIだけを使って、"(NHWC, JPG)"[2]についてやってみた。

●コード例3
import tensorflow as tf

img_path = 'elephant.jpg'
with open(img_path, 'rb') as F:
    jpeg_bytes = F.read()

with tf.Session(graph=tf.Graph()) as sess:
    tf.saved_model.loader.load(sess, [tf.saved_model.tag_constants.SERVING], "./resnet_v2_fp32_savedmodel_NHWC_jpg/1538687457/")
    class_tensor = sess.graph.get_tensor_by_name('ArgMax:0')
    prob_tensor = sess.graph.get_tensor_by_name('softmax_tensor:0')
    classes, probabilities = sess.run([class_tensor, prob_tensor], {'input_tensor:0': [jpeg_bytes]})

cls = classes[0]
prob = probabilities[0, cls]
print('class={} probability={:.3f}'.format(cls, prob))
●出力例3
class=386 probability=0.988

これはRaspberry Pi 2 v1.2 + TensorFlow 1.13.1でも動いた。
コード中の'ArgMax:0', 'softmax_tensor:0', 'input_tensor:0'は、上記のsaved_model_cliの出力から拾って試行錯誤して見つけた。

最後に、同じくpredictorを使わず、TensorFlow APIだけを使って、"(NHWC)"[1]についてやってみた。

●コード例4
import numpy as np
from PIL import Image
import tensorflow as tf

img_path = 'elephant.jpg'
img = Image.open(img_path).resize((224,224))
x = np.array(img)
x = x.astype(np.float32)

with tf.Session(graph=tf.Graph()) as sess:
    tf.saved_model.loader.load(sess, [tf.saved_model.tag_constants.SERVING], "./resnet_v2_fp32_savedmodel_NHWC/1538687283/")
    class_tensor = sess.graph.get_tensor_by_name('ArgMax:0')
    prob_tensor = sess.graph.get_tensor_by_name('softmax_tensor:0')
    classess, probabilities = sess.run([class_tensor, prob_tensor], {'input_tensor:0': np.array([x] * 64)})

cls = classes[0]
prob = probabilities[0, cls]
print('class={} probability={:.3f}'.format(cls, prob))
●出力例4
class=386 probability=0.821

See more ...

Posted at 18:35 in PC一般 | WriteBacks (0)
WriteBacks