動かざることバグの如し

近づきたいよ 君の理想に

runtime=nvidiaを有効してdocker buildする

環境

  • docker
  • nvidia/cuda:10.0-runtime-ubuntu18.04

やりたいこと

docker build時にも --runtime=nvidiaしたい!!!!!!!

周知の通り、nvidiaはDockerに対してランタイムという形でCUDA環境を提供している。つまり、nvidia-dockerをインストールすると、Dockerのランタイム機能であたかもそのDocker Image内にCUDAがインストールされているかのように扱うことができる。

例えば以下の例

docker run --runtime=nvidia --rm nvidia/cuda:10.0-base nvidia-smi

--runtime=nvidiaをつけるだけ つよい

が、build時には何故かruntimeを指定することができない

なんでや

方法

現在のところ、デフォルトランタイムというオプションがあって、それをnvidia指定にするしかない

指定する方法は以下

/etc/docker/daemon.json にてdefault-runtimeを追記するだけ

{
    "default-runtime": "nvidia",
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}

でDockerサービスを再起動

# systemctl restart docker

確認

Default RuntimeがnvidiaになっていればOK

docker info 2> /dev/null | grep -i runtime
Runtimes: nvidia runc
Default Runtime: nvidia

これでruntime=nvidiaを指定しなくても自動的にnvidiaが有効になる。

# 以下も叩けるはず
docker run --rm nvidia/cuda:10.0-base nvidia-smi

当然全Dockerに対して有効になってしまうので、諸刃の剣な気がする。やっぱりdocker build時に指定できるようになってほしい。。。

TensorFlowでTensorBoardを使う MNIST版

環境

  • Python 3.6
  • TensorFlow 1.13
    • 今年中にはTensorFlow2.xが出るのだろうか、、、

やりたいこと

TensorBoardを試してみたかった。が、Qiitaをかいつまんで実行してもうまくいかない。。。

そこでMNISTの最小のコードを使ってサンプルを作る。

TensorBoardなしのMNISTコード

公式サイトのチュートリアルTOPページに載ってたやつそのまんま

import tensorflow as tf
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)

とくにコケる要素はないと思う

TensorBoardありのMNISTコード

import tensorflow as tf
import datetime
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

#### ここから追記
log_dir="logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M")
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)
#### ここまで追記

model.fit(x=x_train, 
          y=y_train, 
          epochs=5, 
          validation_data=(x_test, y_test), 
          callbacks=[tensorboard_callback]) ## 追記

model.evaluate(x_test, y_test)

変更点をいくつか

後述用のコールバック関数を定義 kerasがコールバック関数を持ってるのでそれを使う histogram_freq=1は必須 log_dirは日付とかにしといたほうがあとでごちゃごちゃにならないので吉

log_dir="logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M")
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)

ここで先のコールバックを渡す。配列なのが注意。

model.fit(x=x_train, 
          y=y_train, 
          epochs=5, 
          validation_data=(x_test, y_test), 
          callbacks=[tensorboard_callback])

あとこのコードではkerasもtensorboardも別途インストールはいらなかった

実行

TensorBoardを実行する

tensorboard --logdir logs

ローカルホスト以外のサーバーから実行した場合は--host 0.0.0.0 を付ける必要がある。

次はkerasと組み合わせて、、

インストールされたOpenCVのバージョンを確認するコマンド

環境

OpenCVバージョン確認する!

自分が入れたサーバーなら流石にどのOpenCVを入れたか分かるが、プリインストールされていたり、他人がインストールしてた場合はバージョンがわからない。そこでコマンドで確認する方法をいくつかまとめておく

多分一番確実な方法

pkg-config --modversion opencv

Debian/Ubuntuでapt経由でインストールしている場合

dpkg -l | grep libopencv

Python経由 あまりメリットが感じないが

$python
Python 3.6.5 (default, Jul  8 2018, 20:13:17)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> cv2.__version__

参考リンク

Puppeteerで位置情報取得を有効化して現在地を偽造する

環境

  • Nodejs 12
  • puppeteer 1.17

概要

puppeteerは本当に便利で、やろうと思えば(大抵のことは)なんでもできる。今回は現在位置をうまく偽装してみる。

コード

今回は東京駅にセットしてみる。ただしデフォルトではブラウザの左上の確認プロンプトが出てしまって一生JavascriptGPSにアクセスできないので、overridePermissions()を使って現在地取得を許可しておく

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  const url = 'https://map.ultra-zone.net/g/';

  // geolocationを有効化
  const context = browser.defaultBrowserContext();
  await context.overridePermissions(url, ['geolocation']);
  // 現在位置を東京駅にセット
  const client = await page.target().createCDPSession();
  await client.send('Emulation.setGeolocationOverride', {
    latitude: 35.681236,
    longitude: 139.767125,
    accuracy: 100
  });

  await page.goto(url);
  await page.screenshot({
    path: 'example.png'
  });

  const result = await page.evaluate(() => {
    return new Promise(resolve => {
      navigator.geolocation.getCurrentPosition(position => {
        resolve({lat: position.coords.latitude, lng: position.coords.longitude});
      });
    });
  });
  console.log(result);

  await browser.close();
})();

実行して以下のように表示されればおk

 $node index.js
{ lat: 35.681236, lng: 139.767125 }

f:id:thr3a:20190525145732p:plain

まぁ悪用厳禁ってことでね(

Rubyで外部コマンドを実行するならopen3が1番よさそう

環境

やりたいこと

Rubyでは様々な方法でコマンドを実行できるが、1番シンプルなのはバッククオートを使う方法だと思う

p `date` # dateコマンドを実行

これは本当に楽なのだが、欠点が一つあって標準出力は取れるが、標準エラー出力、さらに結果のstatusが取れない。したがってそのコマンドが正常に終了したかどうかはバッククオートのやり方ではわからない

そこでsystemuのライブラリ入れたりなんやかんややってたが、実は標準ライブラリで実現できた

やりかた

open3という標準ライブラリを使う。

require 'open3'
cmd = "mkdir /tmp/hoge"
stdout, stderr, status = Open3.capture3(cmd)
p stdout
p stderr
p status

これで

が入る

以下は正常に終了した例

""
""
#<Process::Status: pid 30477 exit 0>

以下は失敗した例

""
"mkdir: /tmp/hoge: File exists\n"
#<Process::Status: pid 30540 exit 1>

蛇足

ちなみにruby2.6以降だが、system()で外部コマンドを実行する際にexception:trueを渡すとプロセス終了ステータスが異常だった場合に例外が投げられる

cmd = "mkdir /tmp/hoge"
system(cmd, exception: true)

結果

$ruby a.rb 
mkdir: /tmp/hoge: File exists
Traceback (most recent call last):
        1: from a.rb:6:in `<main>'
a.rb:6:in `system': Command failed with exit 1: mkdir (RuntimeError)

もちろんcatchすることも可能。が、標準エラー出力を取得することはできないっぽい?

cmd = "mkdir /tmp/hoge"
begin
  system(cmd, exception: true)
rescue => e
  puts e.class
  puts e.message
end

結果

$ ruby a.rb 
mkdir: /tmp/hoge: File exists
RuntimeError
Command failed with exit 1: mkdir