ハードウェア技術者のスキルアップ日誌

某家電メーカーの技術者がスキルアップのために勉強したことを記録するブログです

【読書記録】- PLAY WORK

今回は「PLAY WORK」という本を読みましたので、要点をまとめます。

PLAY WORK プレイ・ワーク 仕事の生産性がグングン高まる「遊びながら働く」方法

PLAY WORK プレイ・ワーク 仕事の生産性がグングン高まる「遊びながら働く」方法

 

 著者のピョートルさんは元Googleの方で働き方や組織に関する本を多数出されています。以前「NEW ELITE」を読ませてもらって、働く上での考え方で大いに刺激をもらったので、今作も期待して読みました。

ニューエリート グーグル流・新しい価値を生み出し世界を変える人たち

ニューエリート グーグル流・新しい価値を生み出し世界を変える人たち

 

それでは、早速まとめていきたいと思います。

PLAY WORKとは?

遊ぶように働く、仕事と遊びの境があいまいな働き方

落合陽一さんが著書の中で言われていましたが、「ワークアズライフ」(寝ている時間以外はすべて仕事でありその仕事が趣味である)に通ずる考え方だと思います。

 

PLAY WORKに必要な4つのステップ

①自己認識

問いを通して自分に向き合い、自分を掘り下げる
 ・自分とは何?何をしたい?どうなりたい?
 ・自分が本当にやりたいことは?
 ・子供の頃、何に一番興味があった?
 ・学生の頃、どんなふうに活躍したいと思ってた?
 ・この一週間楽しかったタスクは?それはなぜ?

「メモの魔力」でも言われていましたが、これから自分が何をしたいか、自己分析の重要性は高まっていくと思います。自己分析1000問はぴったりのツールですね。

②自己開示

自分がやりたいことを周りに伝える
 ⇒周りの人がやりたいことを手助けしてくれる

被害者意識はNG 「上司が○○してくれないからできない」
当事者意識に変える!

自己開示をするには考えを整理しないといけない
他者視点のフィードバックをもらえる
 ⇒自己開示をすると自己認識がますます深まる

③自己表現

自分がやりたいことを自分らしく実現すること =「仕事」
自分が提供できる価値は何かを考え、仕事の幅を広げていく

アクションはすぐ起こすことが大事 直感で動く
仕事は楽しんだもの勝ち! 楽しく仕事する!

自己実現

他人から言われた仕事を嫌々やるといった他人のための人生ではなく、
自分がやりたいことをやる「自分の人生」を生きる
 ”THIS IS YOUR LIFE. (これはあなたの人生です)”

自分にしかできないことで社会や周りの人に貢献していく
そうすれば楽しんで、前向きに仕事ができるようになる

まとめ

ここまでの内容をスライド1枚にすると以下のようになります。


f:id:masashi_k:20190824234913p:plain

この本で紹介されているPLAY WORKという働き方は自分の中では理想の働き方です。
仲間とワイワイ議論して、面白いことを実現するために素早く行動していく。
今は職場環境含めて理想とは差がありますが、そんな働き方に近づけながら自己実現を目指していきたいです。

Tensorflow ー 複数の学習済みモデルを同時に実行する

GITHUBで公開されているディープラーニングの学習済みモデルを流用し、
USBカメラ映像を入力して推論するというプログラムをいくつか作ってきました。
今まで動かしたプログラムは全てモデル1つだけを動かしていましたが、
複数の学習済みモデルを組み合わせて機能を作れないか試してみました。
動かし方を調べたのでまとめておきます。

 

モデルが一つの場合

以下のような構成でプログラムを書いていました。
USBカメラの映像をWhileループ内で取得するため、ループの外でセッションを作成し、学習済みモデルの復元までを行います。ループ内ではsess.run()のみを行います。

import tensorflow as tf
import cv2

video_capture = cv2.VideoCapture(0)

with tf.Session() as sess:
    saver = tf.train.Saver()
    saver.restore(sess, model_path)

    while True:
        ret, frame = video_capture.read()
        sess.run()

        if cv2.waitKey(10) & 0xFF == ord('q'):
            break
video_capture.release() cv2.destroyAllwindows()

 

 

ネットワークが二つの場合

2つの異なるグラフを作成し、それぞれのグラフのセッションを構築してモデルを復元します。そして、whileループ内でそれぞれのセッションを実行しています。

従来の処理ではwith tf.Session() as sess:の中にwhileループを置いていましたが、
withを使わずにSessionを作成するように少し変更しました。

import tensorflow as tf
import cv2

video_capture = cv2.VideoCapture(0)

with tf.Graph().as_default() as graph_1:
     saver1 = tf.train.Saver()
sess1 = tf.Session(graph = graph_1)
saver1.restore(sess1, model_path1)

with tf.Graph().as_default() as graph_2:
     saver2 = tf.train.Saver()
sess2 = tf.Session(graph = graph_2)
saver2.restore(sess2, model_path2)

     while True:
            ret, frame = video_capture.read()
            sess1.run()
            sess2.run()

            if cv2.waitKey(10) & 0xFF == ord('q'):
                 break

    video_capture.release()
cv2.destroyAllwindows()

 

参考サイト

事前に訓練された複数のTensorflowネットを同時に実行する - コードログ

 

Tensorflow - ckptからpbへの変換方法

PC上で学習したモデルを動かす際にはckptファイルで問題ないですが、iOS, Android上や組み込み機器上で動かしたい場合、pb(protocol buffer)形式のファイルが必要となります。ckptからpbへの変換方法を調べたのでメモしておきたいと思います。

ckpt, pbとは?

変換方法に行く前にckpt, pbのおさらいです。

Tensorflowで重み、ネットワーク構造を保存するデータのファイルが.ckptです。
check pointの略(?)です。

ckptファイルは3種類あります。
  ckpt.meta : モデルの構造を記述 重み情報はない
  ckpt.data : 実際の重みが入ったバイナリ
       ckpt.data-00000-of-00001のようなファイル名となる
  ckpt.index : どのファイルがどのstepのものかを一意に特定するためのバイナリ

 

一方、protocol bufferは元はGoogleが開発したシリアライズフォーマットとのことで、Tensorflowのグラフ(モデル構造と重み)をこのprotocol buffer形式で記述できます。

Protocol Buffers - Wikipedia

 

変換方法

以下の参考サイトでいろいろなやり方が紹介されていますが、私の環境でうまくいったサンプルコードです。

import tensorflow as tf
import models

graph = tf.get_default_graph()

sess = tf.Session()

saver = tf.train.import_meta_graph('test.ckpt.meta')
saver.restore(sess, 'test.ckpt')

tf.train.write_graph(sess.graph_def, '.', 'graph.pb', as_text=False)

まず前提として、学習は完了しており、そのネットワークや重みデータはckpt形式で保存されています。(test.ckpt) このckptファイルを用いてグラフを復元し、pb形式で保存しなおします。

tf.train.import_meta_graphを使って.metaからモデルをロードします。これを使えば新たにモデルのインスタンスを作る必要がありません。
そして、saver.restoreでckptを読み込み、学習済みモデルを復元します。
pb形式への変換にはtf.train.write_graphを使用します。 

こちらのサイトには、通常のモデルでは学習済みのWeightやBiasを保持するためのtf.Variableの変数を持つが、これをpbファイルに保存できないため、 
graph_util.convert_variables_to_constants() を使ってConstに変換する必要があると記載されています。
しかし、私の環境ではこれをやるとうまくいかなかったです。
もし、上記のやり方でNGであればこちらをお試しください。

 

参考サイト

https://codeday.me/jp/qa/20190407/569692.html

https://tyfkda.github.io/blog/2016/09/14/tensorflow-protobuf.html

http://workpiles.com/2016/07/tensorflow-protobuf-dump/

https://gist.github.com/funwarioisii/68ed46d8ccfcbc31a456b7c4166b8d0e

Tensorflowで作成したグラフのノード名、型を表示する方法

Tensorflowの学習済みモデル、重みデータのcheckpointファイルをProtocolbuf形式(pbファイル)に変換する際にグラフのノード名を指定する必要があったのですが、ノード名を知る方法がわからなかったので調べてみました。

結論から記載すると、以下の記述ですべてのネットワーク構成を可視化できます。

graph = tf.Graph()
with graph.as_default():

    for op in graph.get_operations():
        print(op.type)  # type
        print(op.name) # name
        print(op.op_def) # protocol buf

関数graph.get_operations()でグラフのOperations一覧を取得します。
各ノードごとに型と名前とprotocol bufを表示していきます。

ネットワークの層数が多いと見ていくのが大変なので、typeがReLUのみのノード名を表示するなど、if文で条件を絞ると確認がしやすくなります。

 

参考サイト

http://docs.fabo.io/tensorflow/building_graph/tensorflow_graph_part1.html

 

Tensorflow, CUDA, CuDNN バージョン確認方法

Tensorflow GPU環境を作る際に何度も調べなおしているので備忘録です。

対応表

Tensorflow-GPU, CUDA, CuDNNのバージョンは正しい組み合わせでないと正常に動かないため、以下のリンク先で確認します。

https://www.tensorflow.org/install/source#tested_build_configurations

GPUで対応するCUDAのバージョンが決まると思うので、それに合わせてTensorflow-GPUをインストールします。

 

Tensorflow-GPUのバージョン確認方法

$ pip list

 anacondaを使用している場合はconda listでOKです。

 

CUDAのバージョン確認方法

$ nvcc -V

 

CuDNNのバージョン確認方法

$ cat /usr/include/cudnn.h | grep CUDNN_MAJOR -A 2

 

Tensorflow-GPUが動作しない場合、以上3つのコマンドでバージョンを確認し、対応している組み合わせかを確認してみてください。

シェルスクリプト - フォルダ内の全ファイルに対して処理

シェルスクリプトを作るときにフォルダ内の各ファイルに対して同じ処理を繰り返す場合が多いのですが、よく書き方が分からなくなるので、備忘録として記録しておきます。

シェルスクリプトのサンプル

以下はフォルダ内の各mp4ファイルを引数にしてsample.pyを実行するものです。
シェルスクリプトの引数に対象フォルダのパスを指定して実行します。

#!/bin/bash
[ "x$1" = "x" ] && exit 1
#引数にファイルパスを代入
DIR=$1

for file in `\find $DIR -name '*.mp4'`; do
  #echo $file
 python sample.py $file
done

各行の解説

[ "x$1" = "x" ] && exit 1

"x$1"と"x"が等しい、即ち$1(スクリプトの第一引数)が指定されてないときに
エラーで終了する。

DIR=$1

$1(スクリプトの第一引数)を変数DIRに代入する。

for file in `\find $DIR -name '*.mp4'`; do

` `内の条件を満たすものを変数fileに代入し、条件に満足するものがなくなるまで
do - done内の処理を繰り返す。
` `は内側の処理を行った結果で置換する記述で$()でも同じ。
findコマンドでDIRで指定したディレクトリ内のファイル名がmp4で終わるものを検索。
この検索結果をひとつずつ変数findに代入する。
ディレクトリの階層が深くてもすべて抽出して実行可能。
逆にサブディレクトリは処理したくない場合は-maxdepthオプションで1を指定する。

#echo $file

対象ファイルが正しく取れているかの確認のため、ファイル名を表示。
デバッグ用のため、コメントアウト

python sample.py $file

抽出したファイル名を引数にしてsample.pyを実行する。

応用

find文の検索条件を変えたり、forループの中を変えることでいろいろな処理に応用できると思います。自動でたくさんのファイルを処理したい場合に活用したいと思います。

フォルダ内のファイルを連番でリネーム

仕事で作業している中で手こずった内容を備忘録としてメモしておきたいと思います。
今回はLinuxOSでフォルダ内のファイルを連番でリネームする方法です。

 

コマンドの一例はこちら。

$ ls *.png | sort -t - -k 2 -n | awk '{ printf "mv %s %04d.png\n", $0, NR }' | sh

 pngファイルをソート後、若い順に0001から連番で番号を振ります。

 

今後応用できるように各コマンドの意味を残しておきます。

①ls *.png
拡張子pngファイルのみを表示します。jpgだけ抽出したかったらls *.jpg

②sort -t - -k 2 -n
区切り文字'-'で区切り、2番目の項目で数値として昇順に並べ替え

awk '{ printf "mv %s %04d.png\n", $0, NR}'
awkコマンドはawk 'パターン {アクション}' ファイル名」で、テキストファイルを
1行ずつ読み、パターンに合致した行に対して、アクションで指定された内容を実行します。
このコマンドは全行に対し、{ printf "mv %s %04d.png\n", $0, NR}を実行します。
$0は②の出力、NRは行番号を示すので、
 「mv (元のファイル名) (0パディングした4桁の数字.png)」
を表示します。NRは1から始まるので100番から始めたい場合はNR+99とします。

④sh
③の出力をシェルに渡します。

 

いろいろなケースにこれを応用して活用していきたいと思います。