PyTorchについて概要を把握したいと思ってましたが。。。

今後必要になりそうなので、やっと調べ始めました。
公式ドキュメントを読んでも、まぁ頭に入らないので、pytorchを使用しているプログラムから学んで行くことにしよう。

と思っていましたが、結論いうと、
中途半端な知識ではほとんどわからない、ということがわかりました。。


これ以降はだたの駄文、汚物じゃ!!
今年かけてpytorchならびにDeeplearningについて学習し、
年末にこの汚物を修正し、神へと昇華させる所存でございます。


お勉強用プログラム

Deep learning で一番ホットな企業であるNVIDIAのサンプルをお勉強用としてます。

そのNVIDIAのデバイスを使用した、JetBotというものがあり、それ用に提供されているCollision Avoidanceのデモプログラムを見ています。

コードは、↓Githubから取ってきてます。


さっそくレッツ&ゴー!!

[1] import torch
[2] import torchvision

[1][2] importしている"torch" と "torchvision"は何者ぞ?

公式ドキュメントによると、

  • torch: Tensorデータやその算術とかのパッケージ
  • torchvision: Computer Visionのためのパッケージ。具体的には下記のようなもの
  • popular datasets
  • model architectures
  • common image transformations

torchvisionの"vision"は、computer visionvisionか、なるほど。

"torch"単品のほうは、computer visionに限らず、汎用的なものが詰まっているのか、なるほど。


[3] model = torchvision.models.alexnet(pretrained=False)
[4] model.classifier[6] = torch.nn.Linear(model.classifier[6].in_features, 2)

[3] torchvisionパッケージで、かの有名なalexnetを召喚している。(torchvisionドキュメント箇所)

[4] よくわからん。。一つずつみていこうか。

  • model.classifier[6] :
    • マジックナンバー6ってなんだ?
    • ?今のところよくわかっていないけど、最終レイヤーを弄っているっぽい。
  • torch.nn.Linear:
    • torch.nn:
      • グラフのためのベーシックなブロックとのこと。
      • ところで、torch.nnの”nn”って何の略なんだ?よくわからん。
    • torch.nn.Linear
      • 入力データを線形変換(Linear transformation)するもの。全然わかんね。。

[5] model.load_state_dict(torch.load('best_model.pth'))

[5] モデルの重みデータを読み込んでいる


[6] device = torch.device('cuda')
[7] model = model.to(device)

[6] torch.device: cuda使います。と宣言。

[7] 調べてないけど、modelをdevice(cuda,,というかGPU?)へロードします宣言。


[8]
import torch.nn.functional as F
import time

def update(change):
    global robot
    x = change['new'] # <--- camera input 
    x = preprocess(x) # <--- cmera input preprocessed
    y = model(x) # <--- Alextnetにかけた結果がy
    y = F.softmax(y, dim=1) # <--- yをsoftmax関数にかけて、0〜100%の値に変換する。
    prob_blocked = float(y.flatten()[0]) #<---flatten後の最初の要素が、blocked状態かどうかを示すものらしい。
    if prob_blocked < 0.5: <--- 50%より小さいと直進
        robot.forward(speed_slider.value)
    else: <--- 50%以上だと、Blockedとみなし、左へ曲がる。
    robot.left(speed_slider.value)
    time.sleep(0.001)

update({'new': camera.value})  # we call the function once to initialize"

[8] プログラム中にコメントとして記載。

C++ std::accumulateについてざっくり調べてみた

これまでstd::accumulate()を使用する場面に遭遇すると、
その都度なんとなく調べて使ってました。
そして今日もstd::accumulate()を使う場面があり、コロナで暇なので、少しアウトプットしてみた。
アウトプットすることで思考の整理ができ、記憶に定着するのだ!!と、誰かが言ってました。


自分的に信頼できるcpprefjp - C++日本語リファレンスに記載があったひとことが端的に表してらっしゃる。

- accumulate()は、範囲を集計する関数である。

なるほど。


フル定義は下記↓↓

#include <numeric>

template <class InputIterator, class T, class BinaryOperation>
std::accumulate(
    InputIterator first,
    InputIterator last,
    T init,    // 省略可能。デフォルト:1
    BinaryOperation binary_op); // 省略可能。デフォルト:Add
  • "init" で初期値を変更することができる。
  • "binary_op"で、算術を指定することができる。

自分がわかりにくかった点は、binary_opの引数が、毎回何が代入されているのかとしっくりこなかった✕

例えば、(※これも冒頭のcpprefjp - C++日本語リファレンスに記載の例)

std::vector<int> v = {1, 2, 3, 4, 5};
product = std::accumulate(v.begin(), v.end(), 1, [](int acc, int i) {
    return acc * i;
  });

lambda関数の引数"acc""i"ってどこからくるんじゃい!!
何が代入されるんじゃい!!と。

結論は、↓↓であります。

- init(accumulateの第3引数) = binary_op(init, *iter)

初期値をどんどん再帰的にアップデートしていく感じになります。
なるほど。 上記の例で具体的にいうと、

初期値"init=1"が
- (((init*iter)*iter)*iter)*iter)
とこんな感じで雪だるま式に増えていきます。
んー、なんか借金の利子みたいな。。


やっぱり、アウトプットすると自分が理解できていなかったことが浮き彫りになりますな。

cmakeにて使用するコンパイラを指定したい場合はどうする?

CMAKE公式ドキュメントに記載あり。

ひと事で言うと、下記のように書けばよろし。

set(CMAKE_C_COMPILER "hogehoge")
set(CMAKE_CXX_COMPILER "hogehoge")


苦労してこそ意味がある... そんな価値観で、makefileを直書きを選択していないでしょうか?
(自戒の念)

時代に逆境せずに、便利なものがでてきたのであれば、なるべくそれを使うべし。
ただ、実際の現場では色んなしがらみあることは存じておりますが。。

変化に対応するものだけが生き残る?
なんかそんなことをダーウィンが言ったとか言わないとか。

うまい、はやい、やすい、そんな吉野家的なのがCMAKEだと思ってます。

「ひとつ上の思考力」を読んで

Amazon Kindle Unlimitedで、あなたのおすすめに出てきた「ひとつ上の思考力」を読んでみた。

ひとつ上の思考力。。。
私のような凡人が本題から想像できるのは、

  • 木を見て森を見ずはあかんで
  • 自分が平社員なら、2つ上の視座、つまり部長になったつもりで考える

みたいな。 この予想を超えて見よ!!(鷹の目のミホーク)


ざっくりまとめると。。。

  • PDCAサイクルをきっちり回しましょう。(Plan, Doのやりっぱなしはあかんで)
  • 仕事の精度と生産性を高めるため、物事を抽象化して考え、その他の事象に転用せよ


PDCAダブルループと読んでいたり、抽象化思考や仮説思考を何か別の言葉で表していたりと、
全体を通して、ビビッとくるものはなく、テンション高くなるようなこともなく終わりました。。。



ただ、この本で心に残ったフレーズがあり、それは下記

- 人と課題(問題)を分けて考える。
- 「期待するのではなく、応援する」というスタンスでいる。


子育てに大切な言葉だな〜...としみじみ感じて、本をそっと閉じました。

C++ 最大値と最小値を同時に求める中級魔法 "std::minmax_element()"

最大値と最小値を同時に求める関数である

ドラクエでいうと、"std::minmax_element()"ってメラミくらいの威力でしょうか。


さて、こちらはCodewarにて問題を解く過程で使用しました。

メモ:

  • vector限定ではなく、イテレータであればOK。
  • minmaxを求める時の比較関数の指定も可能。
  • 戻り値の覚え方: min, maxの順。関数名"minmax_XXX"の記載順そのままと覚えるがよろし。

詳しくは、Google先生で検索する or ↓公式ドキュメントを参照するがよろし。


Example Code:

#include <algorithm>
#include <iostream>
 
int main() {
    const auto v = { 3, 9, 1, 4, 2, 5, 9 };
    const auto [min, max] = std::minmax_element(begin(v), end(v));
 
    std::cout << "min = " << *min << ", max = " << *max << '\n';
}

Output:

min = 1, max = 9


ホントは、std::min_element()とstd::max_element()を使って解きました、はい。。

他の人がこの関数を使って、スマートに解いていたので紹介しているだけです、はい。。


パフォーマンス(計算量とかメモリ使用量)については、
Google先生で、そのことに言及している記事があったが、めんどくさくて読んでない✕
今のところパフォーマンスはどうでもいいので、めんどくさくなってしょうがないよ、自分。
セルフコンパッションが高まってきたな、よし。

rect, polar, degrees, radians...まとめて覚えよ!!!

Pythonモジュールの話です。


cmath.rect

公式ドキュメントの記載

cmath.rect(r, phi)¶ 極座標 r, phi を持つ複素数 x を返します。値は r * (math.cos(phi) + math.sin(phi)*1j) に等しいです。

(例)

>>> cmath.rect(2**.5, math.pi/4) # phiを孤度法で指定
(1.0000000000000002+1j)

>>> cmath.rect(2**.5, math.radians(45)) #phiを度数法の45°から孤度法のラジアンに変換して指定
(1.0000000000000002+1j)

[注意] phiは、ラジアンで指定する必要があるので注意。 つまり、60°みたいな度数法じゃくて、π/4みたいな孤度法や。 後述のmath.radiansとの合わせ技で使うシーンがあるかも。

cmath.polar

[公式ドキュメント]https://docs.python.org/ja/3/library/cmath.html?highlight=polar#cmath.polar)の記載

cmath.polar(x)¶

x の極座標表現を返します。x の半径 r と x の位相 phi の組 (r, phi) を返します。polar(x) は (abs(x), phase(x)) に等しいです。

(例)

>>> cmath.polar(1+1j)
(1.4142135623730951, 0.7853981633974483)

直交座標から、距離と角度をパッと出すのに便利かも。

math.degrees

公式ドキュメントの記載

math.degrees(x)¶ 角 x をラジアンから度に変換します。

(例)

>>> math.degrees(math.pi)
180.0

ま、これはそのままだよね。
ラジアン-->度? 度-->ラジアン?どっちだっけ、あ〜〜〜〜!となりそうなので
モジュール名のdegreesは、変換後単位と覚えるとよろし。
Google先生に聞いたり、簡単に試すとすぐわかるけどね。

math.redians

公式ドキュメントの記載

math.radians(x)¶ ラジアンから度に変換します。

(例)

>>> math.radians(180)
3.141592653589793 # 180°はπなので、3.14XXXとなる。


問題

これらモジュールをマスターすると下記問題が簡単に解けるようになるのである。

f:id:atti_itta:20201222234836p:plain

Input: func(OA, AB, BC, alpha, beta, gamma)
Output: OCの長さ、OCの角度(OC辺<-->X軸マイナス方向)

Python 初期値を無限大にしたく

Codewarにて、初期値を無限大にしたい場面に遭遇。

無限大定義について、google先生ヒアリング。。

  • float型でのみ無限大を定義できる
  • int型は、桁数に制限がないという違う意味での無限大。

なので、今回はfloatで無限大を定義した。

(例) floatでの無限大

>>> f = float('inf') # infiniteのinf。たぶん。負の無限大は'-inf'で指定
>>> f > 100000000 # 適当な大きな数と比較
True
>>> f < 100000000
False
>>> 



そもそも、こんなinf使わなくても効率良く解けたというのは別の話。。。