動かざることバグの如し

近づきたいよ 君の理想に

2019年上半期 買ってよかったモノまとめ

もう何日もすれば6月も終わる。つまり2019年の半分が過ぎてしまう。

半年を上半期/下半期と釘付け、買ってよかったものを備忘録としてまとめてみる。

基準としては「その期間中に初めて買って個人的によかったもの」とする。

目薬 サンテビオ

シミないタイプの目薬 めっちゃパッケージが地味なのでドラッグストアで探しづらい

【第2類医薬品】サンテビオ 15mL

【第2類医薬品】サンテビオ 15mL

仕事上どうしても目がつかれるので頻繁に目薬を買ってるのだが、いつも買ってるのが無かったのでたまには別と思って買った。(ロートは飽きたので別のメーカーにしようと思った

で、買ったのがこれ。他の目薬よりドライアイに効くし、ピントが合いやすくなる(個人の感想

ただし液体が赤みかかってるので服につかないように差すときに注意しないといけない

ルックプラス バスタブクレンジング

風呂洗うのに使うやつ

駅の広告で見て気になって買った。宣伝文句は「バスタブをこすらなくもきれいになる」 結論から言うと流石にコスり不要は言いすぎと思いつつ、確かに今まで使ってた洗剤よりコスらなくても落ちる。

ので自分みたいに風呂掃除ダルいマンにはおすすめ

MacbookSSD TS960GJDM850

今個人で使ってるMacbookPro 2015のSSDの増設用に買った。もともと128GBだったのでかなりキチキチだったのと、ここ最近のMacbookの出来をみて当分買い換えることがなさそうだったので買った。

自分のときで50000円いかないぐらいだった。

ポイントは「TS960JDM820」ではなく「TS960GJDM850」であること。JDM820の後継バージョンとしてJDM850シリーズがリリースされ、インターフェイスAHCIからNVMeに変更されたので速くなったとのこと(公式サイト

結果的に快適に使えるようになったので満足 どれ位早くなったかのベンチマーク撮ったはずだが消えてた(

(ちなみに日本にあまり流通されてないのでAmazon.comから個人輸入したほうが絶対安い

エーザイ チョコラBBハイパー

口内炎に効く(個人の感想です

口内炎がひどかったときに勧められて試してみたら効果てきめんだったのでリピートしてる。

ポイントはチョコラBB「ハイパー」である点。他にも無印、ライト、ローヤル等々同じブランドでもいくつも種類があるが、効果&味ともにハイパーが一番最強な気がする。

もちろんその分値段もするが、ドラッグストアだけじゃなくてコンビニでも変えるので口内炎f**kのときにはぜひ

cheero Power Plus モバイルバッテリー(CHE-096)

軽さは正義 ダンボーは好み

今まで使ってきたやつがヘタってきたので買い替え。そうそう買い替えないのでType-C対応&PD充電対応で調べてたらcheeroから発売されてたので買った。

ポイントは「軽さ」 普段リュックとか手提げに入れて使ってるのでなるべく軽いほうが助かる。(とはいえ5000mAhだと若干不安なので10000mAhはほしい。)

これは約185gだが、Amazonでタイムセールしているやつは結構重かったりする。。cheeroは比較的軽めのモバイルバッテリーが多いのですき

マイナス点は機能としてケーブルを挿すだけで充電が始まる(ボタンを押す必要がない)のだが、ごく稀に充電されずにあ〜ってなったことがあった。ちゃんと確認しておけって話だが。

価格だがAmazonだとクッソ高いのでおすすめしない 秋葉原で税込み4000円でお釣り来たので現地で買ったほうがよさげ

ダンボーくんあんまり好きじゃないって場合はこれとか同機能なのでいいかも(何故かダンボーくんより20g重いが

Amazon | cheero Power Plus 5 10000mAh with Power Delivery 18W (Metallic) 大容量 モバイルバッテリー (パワーデリバリー対応) 2ポート出力 Type-A Type-C 対応機種へ超高速充電 iPhone, Android, Galaxy, AUTO-IC搭載 PSEマーク付 Power Delivery 3.0 対応 CtoCケーブル付 CHE-101 | モバイルバッテリー 通販


他にもあったかもしれないが忘れた

リアルタイムに手を検出できるJavascriptライブラリ「handtrack.js」

TensorFlow.jsというのがあって、これはTensorflowで作成したモデルをブラウザで使えるようにできるライブラリなのだが、これを利用して手の検出をリアルタイムにブラウザ上で行えるライブラリを使う機会があったのでメモ。

その名もhandtrack.js

サンプルコード

必要最低限の動くコード。HTMLにcanvasとvideoタグがあるが、WEBカメラで取得した映像をvideoタグに反映させて、そこから手を検出した画像がcanvasに反映されていく。試したほうが速い

<div id="message">loading model...</div>
<canvas id="mycanvas" width="640" height="480"></canvas>
<video id="myvideo" width="640" height="480"></video>

<script src="https://cdn.jsdelivr.net/npm/handtrackjs@0.0.13/dist/handtrack.min.js"></script>
<script>
const canvas = document.getElementById('mycanvas');
const context = canvas.getContext('2d');
const video = document.getElementById('myvideo');
let model;
const options = {
  flipHorizontal: true,   // flip e.g for video  
  maxNumBoxes: 3,        // maximum number of boxes to detect
  iouThreshold: 0.5,      // ioU threshold for non-max suppression
  scoreThreshold: 0.7,    // confidence threshold for predictions.
};
handTrack.load(options).then(l_model => {
  model = l_model;
  document.getElementById('message').innerText = 'loaded!';
  handTrack.startVideo(video).then(function (status) {
    if (status) {
      console.log("video started", status);
      runDetection();
    } else {
      console.log("video error", status);
    }
  });
});

function runDetection() {
  model.detect(video).then(predictions => {
      console.log("Predictions: ", predictions);
      model.renderPredictions(predictions, canvas, context, video);
      requestAnimationFrame(runDetection);
  });
}
</script>

ポイントはいくつかって

オプションの

  • flipHorizontal WEBカメラ経由とかだと鏡になるので左右逆になる これを補正するかどうか
  • maxNumBoxes: 3 一度に最大どれだけの手を検出するか
  • iouThreshold: 0.5 うーんわからん
  • scoreThreshold: 0.7 手とみなすしきい値 1に近ければ近いほど確からしくないと手として認めてくれなくなる

で、

  • handTrack.load()
  • handTrack.startVideo()
  • model.detect()
  • model.renderPredictions()
  • model.renderPredictions()

の順番に実行していく

細かいところは公式のREADME見たほうがいい というかそれしかないが

脳死でCNNによる画像分類 on TensorFlowするメモ

Ver 2

from keras.models import Sequential
from keras.layers import Conv2D, Dense, MaxPool2D, Flatten, Dropout
from tensorflow.keras import optimizers
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import datetime

# バッチサイズ
batch_size = 32
# 画像分類したい数
num_classes = 3
# エポック数
epochs = 30
train_dir = 'images/train'
validation_dir = 'images/test'

# 画像の解像度
# image_height, image_weight = 1280, 720
image_height, image_weight = 384, 216

# CNN
model = Sequential()
model.add(Conv2D(32, (3, 3), activation='relu',
                        input_shape=(image_height, image_weight, 3)))
model.add(MaxPool2D((2, 2)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPool2D((2, 2)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPool2D((2, 2)))
model.add(Conv2D(128, (3, 3), activation='relu'))
model.add(MaxPool2D((2, 2)))
model.add(Flatten())
model.add(Dropout(0.5))
model.add(Dense(512, activation='relu')) # 値が多いほうが精度はいいが計算量は増える
model.add(Dense(num_classes, activation='softmax')) # 多分類の場合softmax

model.compile(loss='categorical_crossentropy',
              optimizer='adam',
              metrics=['acc'])

# 画像のRGBの値域が0-255であるのを0-1に正規化
train_datagen = ImageDataGenerator(
    rescale=1./255,
    rotation_range=20,
    width_shift_range=10,
    height_shift_range=10,
    brightness_range=[0.7, 2]
)
validation_datagen = ImageDataGenerator(
    rescale=1./255,
    rotation_range=20,
    width_shift_range=10,
    height_shift_range=10,
    brightness_range=[0.7, 2]    
)
train_generator = train_datagen.flow_from_directory(
    train_dir,
    target_size=(image_height, image_weight),
    batch_size=batch_size,
    class_mode='categorical'
)

validation_generator = validation_datagen.flow_from_directory(
    validation_dir,
    target_size=(image_height, image_weight),
    batch_size=batch_size,
    class_mode='categorical'
)

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

from keras.callbacks import ModelCheckpoint
mc = ModelCheckpoint(
    filepath='best.h5',
    monitor="val_loss",
    verbose=1,
    save_weights_only=False,
    mode='min',
    save_best_only=True,
    period=1
)

train_step_size = train_generator.n // train_generator.batch_size
validation_step_size = validation_generator.n // validation_generator.batch_size

model.fit_generator(
      train_generator,
      steps_per_epoch=train_step_size,
      epochs=epochs,
      validation_data=validation_generator,
      validation_steps=validation_step_size,
      verbose=1,
      callbacks=[mc]
)

Ver 1

データは Fruits 360 dataset | Kaggle

# kerasでやろうとしていたがどうもtensorflowに吸収されたっぽい
# 参考: https://book.mynavi.jp/manatee/detail/id=79420
# よって tensorflow.keras と奇妙に見えるがこれで正しい
import tensorflow as tf
from tensorflow.keras import layers
from tensorflow.keras import models
from tensorflow.keras import optimizers
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import datetime

# GPUのメモリを使い切らないようにするおまじない
# ちなみにTF2.xではエラーになるので注意
from keras.backend.tensorflow_backend import set_session
config = tf.ConfigProto(
    gpu_options=tf.GPUOptions(
        visible_device_list="0",
        allow_growth=True
    )
)
set_session(tf.Session(config=config))
# バッチサイズ
batch_size = 32
# 画像分類したい数
num_classes = 103
# エポック数
epochs = 20

# 画像の解像度 100x100pxとなる
img_rows, img_cols = 100, 100

# CNN
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu',
                        input_shape=(img_rows, img_cols, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Flatten())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(512, activation='relu'))
# 最後のsoftmaxは多分類の場合
model.add(layers.Dense(num_classes, activation='softmax'))

model.compile(loss='categorical_crossentropy',
              optimizer='adam',
              metrics=['acc'])

# the data, split between train and test sets
train_dir = 'works/data/fruits-360/Training'
validation_dir = 'works/data/fruits-360/Test'
# rescaleで正規化
train_datagen = ImageDataGenerator(rescale=1./255)
validation_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
    train_dir,
    target_size=(img_rows, img_cols),
    batch_size=batch_size,
    class_mode='categorical'
)

validation_generator = validation_datagen.flow_from_directory(
    validation_dir,
    target_size=(img_rows, img_cols),
    batch_size=batch_size,
    class_mode='categorical'
)

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

train_step_size = train_generator.n // train_generator.batch_size
validation_step_size = validation_generator.n // validation_generator.batch_size

model.fit_generator(
      train_generator,
      steps_per_epoch=train_step_size,
      epochs=epochs,
      validation_data=validation_generator,
      validation_steps=validation_step_size,
      verbose=1,
      callbacks=[tensorboard_callback]
      )

model.save('fruit_1.h5')