漆黒な技術メモ

管理人が必要に応じて自分のメモを好き勝手に投下するたまり場的ブログ

【ちょっと技術的なことAdventCalender】Hack U(ハッカソンイベント)に参加してきました

この記事はちょっと技術的なことAdventCalenderの19日目です。
今日は日曜日に参加したHack U 2016 大阪会場 Student Hackathon - Yahoo! JAPANについてお話ししようと思います。 hacku.yahoo.co.jp

Hack Uとは

Hack U(ハック・ユー)は、限られた期間の中で、学生がプロダクトを自ら企画・開発・発表するイベントです。ものづくりの楽しさを体現できるよい機会となるよう、ヤフーの現役社員が学生のみなさんを全力でサポートいたします。

(公式サイトより)
まあすなわち、学生限定の相当大規模なハッカソンイベントと言ったところです。
今回のテーマは「自動○○」となっています。とはいうものの、何かプログラムを作ると大抵は何かを自動化しているので、結構何でもありの色彩が強い大会ではあります。
勿論優秀賞など、賞もありますが、残念ながら今回自分たちはじゅしょいうすることができませんでした。

自分たちの作ったもの

今回自分たちは、ネタに走りに行く気満々で「ブラックな人たちを助けよう」というお題目(当然このお題目の決め方もノリ)で、「残業防止座布団:‡漆黒からの解放‡」という作品をつくりました。
座布団の中に圧力センサ、加速度センサを埋め込み、長時間座っていることや貧乏ゆすりを検出して離席を促す作品です。 f:id:igbt3116redtrain:20161220052620j:plain この座布団の中にセンサとスピーカを仕込ませてあります。一見するとただの座布団(というかクッション)ですが
f:id:igbt3116redtrain:20161220052844j:plain 座面下にマイコン(mbed)、背もたれにバッテリーと通信モジュールを付加してあります(椅子は会場のモノです)
これらを利用して、

  • 離席を促すべき時に音楽を鳴らす機能
  • イライラ度可視化
  • 着席などのイベント発生に合わせたツイッターへの投稿機能
  • 可視化画面からの座布団の動作制御

を行っています。
f:id:igbt3116redtrain:20161220053343p:plain
この作品の主目的からは外れるためあまり注目はされませんでしたが、「webブラウザからの座布団動作」ができるようになっています。
自分はここに一番こだわりを持っていました。両方向のIoTを何とか形にしてみたかったからです。

利用した技術と自分の担当範囲

アーキテクチャ図にするとだいたいこんな感じです。 f:id:igbt3116redtrain:20161220055101p:plainバイス、マイコン、データベース、比較的新し目の通信規格&サーバ実行環境、可視化、他システムとの連携などIoTエコシステムと言われそうな部分を一通り実装しました。
(本当はAndroid連携をやりたかったのだけど実装に使える時間の確保ができませんでした…)
自分はデバイスを少しと、マイコンの通信部分、サーバサイド処理を担当しました。

次以降の記事の話

今回HackUの作品について書くのはここまでにしておいて、次回以降はこの実装で苦労した部分のことを自分のメモを兼ねて何回かに分け書いていきたいと思います。
またアドベントカレンダー期間が終わるころまでに今回のソースをgithub上に公開したいと思っています。
それでは!

【ちょっと技術的なことAdventCalender】改行区切りのログ出力をExcelとかで使えるようにCSVに変形するPythonスクリプト

この記事はちょっと技術的なことAdventCalenderの15日目です。
気づいたらもう折り返しを過ぎていますね…

プログラムを実行したときのログ出力

って、大体こんな感じで出力するようにプログラム組んでいる方が大半だと思います。

time : 10:00
power : on
value : 1

time : 10:10
power : off
value : 0

time : 10:20
power : on
value : 2

...

まあ実装上この形式で書くのが一番楽ですし、ログとして書く分には何も問題ないのですが… ある時、このログをExcelなどで集計しなくてはならない…!!なんてことになったら、この形式でやるのは超面倒ですね…

time,power,value
10:00,on,1
10:10,off,0
10:20,on,2

とかにできるのが一番理想です。
と、そんなことを実際にしなくてはならない場面に遭遇してしまったので、スクリプトを書きました

実際に作ったpythonスクリプト

引数でファイル名を指定します。空白行をCSVの行の分け目と認識するようにしています。
また、カラムはブロックごとに異なっても(途中から"Battery"カラムが増えたり、消えたり) 大丈夫なようになっています

#coding: utf-8
import sys

if len(sys.argv) < 2:
    print "usage filename"
    sys.exit(1)
filename = sys.argv[1]

f=open(filename)
lines=f.readlines()
valueText=""
columnTitles=[]
textBuf={}
for line in lines:
    if '\n' in line[0]:
        for col in columnTitles:
            if col in textBuf:
                valueText += textBuf[col]+","
            valueText+=","
        valueText += "\n"
        textBuf.clear()
    else:
        sptline=line.replace("\n","").split(":",1)
        if sptline[0] not in columnTitles:
            columnTitles.append(sptline[0])
        textBuf[sptline[0]] = sptline[1]

for col in columnTitles:
    print col+"," ,
print ""
print valueText ,

これを使って

$ python parser.py log.log > log.csv

とかやれば、変形できます。

実行結果

こんな感じです

$ cat status.log
time:2016/12/11 23:32:32
SSID:gp30
Mode:MultiShot
SubMode:TimeLapse
Recoding:True
Num. of taken:268
Num. of remaining:11794
SDcard:True
Battery:3

time:2016/12/11 23:40:25
SSID:gp29
Mode:MultiShot
SubMode:TimeLapse
Recoding:True
Recode:test
Num. of taken:278
Num. of remaining:11794
SDcard:True
Battery:3

$ python genlogparser.py status.log
time, SSID, Mode, SubMode, Recoding, Num. of taken, Num. of remaining, SDcard, Battery, Recode,
2016/12/11 23:32:32,gp30,MultiShot,TimeLapse,True,268,11794,True,3,
2016/12/11 23:40:25,gp29,MultiShot,TimeLapse,True,278,11794,True,3,test,

今日はここまで、それでは!!

【ちょっと技術的なことAdventCalender】自分がよく忘れがちなシェルスクリプトの文法&定型句まとめ

この記事はちょっと技術的なことAdventCalenderの13日目です。

このブログでもシェル関係のお話を取り上げることがそこそこ多いことからもわかるに、管理人はサーバ管理に研究にと、比較的多くの機械でシェルスクリプトを書いています。
が、シェルスクリプト歴は正直1年にも満たず、まだまだいろいろ覚えきれていないことが多い駆け出しシェルエンジニアです。
そこで今回は、「自分がよく使うにも関わらずよく忘れがちなシェルスクリプトの文法&定型句」をまとめてここに書いておきたいと思います。

現在時刻を任意のフォーマットで取得

どちらかというとdateコマンドの使い方ですね…

#!/bin/sh
echo `date '+%Y/%m/%d %H:%M:%S'` #2016/12/13 12:00:54

任意のコマンドの引数に変数を入れて実行、結果を変数へ

#!/bin/sh
var="value"
ret=`command ${var}

ファイルの絶対パスを分割し、ファイル名、ディレクトリ名、最下部のディレクトリ名だけ抽出する

fullPath="/home/user/document/file.txt"

fileName=`basename ${fullPath}` # => file.txt
dirName=`dirname ${fullPath}` # => /home/user/document
lastDirName=`${dirName%/*}` # ==> document

10回ループ

#!/bin/sh
for i in `seq 1 10`
do
    echo "$i times"
done

コマンドライン引数からファイル名を参照し、1行ずつ処理

#!/bin/sh
filename=$1
cat $filename | while read line
do
    ehco $line
done

今日はここまで

【ちょっと技術的なことAdventCalender】サーバのHDDをSSDに変えるのに苦労した話

この記事はちょっと技術的なことAdventCalenderの11日目です。

つい先日、研究室内のとあるサーバのHDDをSSDにして高速化しよう!というお話が上がり、サバ管を兼ねている自分が、その交換を行うことになりました。
研究室にはディスクの中身をハードウェア的にコピーするための機械があったので、適当にHDDとSSDをガチョンガチョン挿して動かせば終るだろうと思っていたのですが…大間違いでした。
ちなみに対象のサーバはRAIDが組んであるため、コピーするディスクは2枚になります。 そして購入の都合上、TrancendとSAMSUNGSSDを1枚ずつ購入したのですが、何故か同じ方法でできない…
ということで、自分の格闘記録を今後のために残しておきます。

共通

始めにGpartedをインストール

$ sudo apt-get install gparted

Trancend SSD

UbuntuSSDを接続し、Gpartedで1つパーティションを作成
File systemはcleardにする

その後、コピー用スタンドにHDDとSSDを接続し、コピーボタンを押す。

SAMSUNG SSD

UbuntuSSDとHDDを接続する。
SSDに何かパーティションができている場合は、Gpartedでパーティションを削除 その後、ddコマンドを用いて全てコピー

# /dev/sdbがコピー元、/dev/sdcがコピー先とする
$ sudo dd if=/dev/sdb of=/dev/sdc bs=512

進捗状況を見る場合、別のターミナルより以下を打ち込む

# nは進捗を表示する間隔(秒)
sudo watch -n 60 "pkill -USR1 dd"

ここまでこれば、SSDを接続し起動して、fdiscやcat /proc/mdstatなどでRAIDの状態を確認すれば完了です。
今日はここまで

【ちょっと技術的なことAdventCalender】ラズパイで接続先のwi-fiを切り替えるスクリプトを作った

この記事はちょっと技術的なことAdventCalenderの9日目です。
また多少遅刻してますがご愛嬌という事で

今日は、半年前ぐらいに研究で必要になったちょっとしたスクリプトをここに紹介しようと思います。
毎日テーマとなる題材がブレブレだけど、それがこのブログの趣旨なので…

他の方がそういうシチュエーションに遭遇するかわからないけど、自分が「接続するwi-fi親機を定期的に切り替える」という処理をラズパイに実装しなければならなかったので、
同じような人がいらっしゃれば手助けになれば、と思います。
結構突貫工事で作ったので、動作保証(特にラズパイ以外のLinux)はできないですが、参考程度にお使いください。

#/!bin/sh
#/!sbin/

ssid=$1
pass=$2

rm wpabuf.conf
for line in `wpa_passphrase ${ssid} ${pass}` 
do
    echo "$line" >> wpabuf.conf
done

sed -i -e "1i ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev" wpabuf.conf
sed -i -e "2i update_config=1" wpabuf.conf
sed -i -e "7i key_mgmt=WPA-PSK" wpabuf.conf
sed -i -e "8i proto=WPA2" wpabuf.conf
sed -i -e "9i pairwise=CCMP" wpabuf.conf
sed -i -e "10i group=CCMP" wpabuf.conf
sed -i -e "11i priority=2" wpabuf.conf

mv wpabuf.conf /etc/wpa_supplicant/wpa_supplicant.conf
/etc/init.d/networking reload
iwconfig wlan0

それでは

【ちょっと技術的なことAdventCalender】 Chainer Playgroundを少しだけ触ってみた

この記事はちょっと技術的なことAdventCalenderの7日目です。
7日目といいつつ書くのが遅くなってしまい日付を跨いじゃってますが、そこは大目に見てください…

さて、最近IT業界ではディープラーニングだのAIだの、機械学習系の話題がものすごく流行っていると思います。
筆者の所属する大学の研究室でも、機械学習を積極的にやっており、その分野で論文を書いている人もいます。(自分は機械学習とは異なる分野で研究しているのですが…)
で、そんな流行りものである機械学習ではそれを行うためのフレームワークなども出てきております。
そのような流れの中で、ひとつ気になるニュースがあったので今日はそれをピックアップしようと思います。
深層学習をウェブブラウザ上で学習できる「Chainer Playground」の無償公開について

そもそもChainerとは

先ほどお話しした、機械学習フレームワークの一つです。このフレームワークは日本の会社であるPreferred Networks(通称 PFN)が作成したフレームワークです。
Chainerの特徴はこんな感じらしいです。

In contrast, Chainer adopts a “Define-by-Run” scheme, i.e., the network is defined on-the-fly via the actual forward computation. More precisely, Chainer stores the history of computation instead of programming logic. This strategy enables to fully leverage the power of programming logic in Python. For example, Chainer does not need any magic to introduce conditionals and loops into the network definitions. The Define-by-Run scheme is the core concept of Chainer. We will show in this tutorial how to define networks dynamically.

http://docs.chainer.org/en/stable/tutorial/basic.htmlより引用

まあ英語で専門的なこと言われても何言っているかわかりませんね(読める人は読んでください)。
PFNの中の人のブログやSlideShareを見ると、要するにほかのフレームワークは"Define-and-Run"形式で、「ディープラーニングで使うネットワーク構造の構築」と「実際に構築した構造にデータを流して処理する」部分が別々の実装として書かなければならないのに対し、Chainerは"Define-by-Run"形式で構築と処理を一度に書けてしまうため、比較的簡単にニューラルネットワークの構造をかける点が特徴だそうです。(間違っていたらすいません)
ちなみに他に有名なライブラリとしてはGoogleのTensorFlowやカリフォルニア大学バークレー校の研究チームが開発したCaffeなどがあるようです。

Chainer Playgroundとは

Chainer Playgroundでは深層学習とChainerの基礎を実際のプログラミングを通しながら学べます。Chainer Playgroundを利用するにあたって必要なのはウェブブラウザのみで、PythonやChainerのインストールも必要ありません。ブラウザでChainer Playgroundに接続するだけですぐに学習を始められます。

深層学習をウェブブラウザ上で学習できる「Chainer Playground」の無償公開についてより引用

次は日本語でよかったです。まあ上に書いてある説明でだいたいは終わっていて、Chainerを使った機械学習の基礎をwebブラウザ上で簡単に学べるサイトになっています。Ubuntuを用意して環境構築してやっと…とかしいなくても機械学習を体感的に学ぶことができるみたいです。
ただしまだベータ版なので内容は完全版ではないみたいです。

少しだけ触ってみた

画面はこんな感じみたいです。 f:id:igbt3116redtrain:20161208030919p:plain
左側に説明、右側にエディタと実行結果が表示され、テキストを読みながら実行することができます。

早速管理人もやってみました。
最初は機械学習でいう「学習対象のモデル」とは何ぞやというところから入るわけですが…まあ数学チックな話がガンガン出てきます…結構本気で読む必要があり、理解するのにもなかなかの時間がかかります。そりゃあこんだけ難しいことをこなすデータサイエンティストは引く手あまたなわけだ…
ちなみに僕のような数学よくわかってない、プログラムガッツリやっていましたという人はおそらく「次元」って言葉で一気に混乱すると思います(実際しました)。100次元とかそういう字句がたくさん出てきますが、これは100次元「配列」のことではなく、100次元「ベクトル」のことですね。数学的なベクトルです。(x,y,z)みたいなアレです。そこを間違えるとコードを見ても???ってなるので気をつけてください。
そのあとは目的関数を定義して最適化することで、機械学習の基礎を学ぶみたいですが、この先は管理人も勉強中です…

機械学習にちょっと興味があるよって方、ぜひ試してみてはいかがでしょうか…!!

【ちょっと技術的なことAdventCalender】OpenCV3の環境構築について整理してみた

この記事はちょっと技術的なことAdventCalenderの5日目です

こんばんは。
しばらく書いてなかったのでAdventCalendarをきっかけに久々に更新を頑張ろうと思ってます。はい
でも一人で24日連続はさすがに無理なのでQiita側で記事を書いている友人と共同で頑張って埋めようと思ってます。
友人はあらゆる言語について少しずつ触っていくことをやるみたいです。僕は今まで書こうと思ったけどここに書いてなかったことをジャンル関係なしにブッ込もうと思います。
というわけで、ちょっと技術的なことAdventCalender見てやってください。

そんなこんなで今日の内容にいってみたいと思います。

OpenCVの環境構築で毎度死ぬ話

画像処理エンジンとしてこの上なく有名なOpenCVだが、新しいPCを買ったなどの理由で環境構築をしようとすると毎度躓く。
こいつめ…特にC++の場合はソースコンパイルして突っ込むしかないから本当に厄介だ。

そんなわけで、今回は自分へのメモを兼ねて(いつもそうなのだが)、OpenCV3の環境構築をおさらいしようと思う。
ちなみに今回の環境はUbuntu14.04 LTS (64bit)である。

環境構築 (Python編)

Pythonはフィーリングプログラミング言語と研究室内で勝手に呼んでいるだけあって、結構あらゆることが簡単にできるようになっている。
C++ではクソみたいに苦労したOpenCV3のインストールも、Pythonの仮想環境(Conda)上で動かせるようにするだけならだいぶ簡単だ。

anacondaのインストールと仮想環境のセットアップ

https://www.continuum.io/downloadsからanaconda本体をダウンロードしてくる。
ダウンロードが終わればシェルを実行して

# if you use python 3.5
bash Anaconda3-4.2.0-Linux-x86_64.sh 
# if you use python 2.7
bash Anaconda2-4.2.0-Linux-x86_64.sh

で完了だ。

続いて仮想環境を構築する。ENV_NAMEは仮想環境の名前だ

$ conda create -n ENV_NAME python=2.7 anaconda
# enter virtual environment
$ source activate ENV_NAME
$ python -m pip install --upgrade pip

OpenCVインストール

$ conda install -c anaconda numpy=1.11.1
$ conda install -c menpo opencv3=3.1.0

一瞬である。

構築の確認

import numpy as np
import cv2
cv2.__version__

これの結果が3.1.0と出てきたら成功だ。

環境構築 (C++編)

どちらかというと本番はこっち、C++Pythonほど便利な環境やツールが残念ながらそろっていない(まあかなり低レベルな言語だし)

鬼のインストールシェル

というわけで頑張ってwgetでソースを落としコンパイルするということになる。
インストール先ディレクトリは、標準の/usr/local/libである。

$ cd /usr/local/lib/
$ ls
$ mkdir opencv
$ cd opencv/
$ wget http://downloads.sourceforge.net/project/opencvlibrary/opencv-unix/3.1.0/opencv-3.1.0.zip
$ unzip opencv-3.1.0.zip
$ sudo apt-get update
$ sudo apt-get install build-essential libgtk2.0-dev libjpeg-dev libtiff4-dev libjasper-dev libopenexr-dev cmake python-dev python-numpy python-tk libtbb-dev libeigen3-dev yasm libfaac-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev libx264-dev libqt4-dev libqt4-opengl-dev sphinx-common texlive-latex-extra libv4l-dev libdc1394-22-dev libavcodec-dev libavformat-dev libswscale-dev default-jdk ant libvtk5-qt4-dev checkinstall
$ ls
$ cd opencv-3.1.0/
$ mkdir build
$ cd build/
$ #インストール先にディレクトリを変更する場合はCMAKE_INSTALL_PREFIXの値を変更する
$ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D BUILD_NEW_PYTHON_SUPPORT=ON -D WITH_V4L=ON -D WITH_FFMPEG=OFF -D WITH_CUDA=OFF -D BUILD_opencv_python2=ON 
$ #/usr/local下以外にインストールするときは以下のパスを通す
$ # PKG_CONFIG_PATH=$HOME/local/opencvlibrary/lib/pkgconfig:$PKG_CONFIG_PATH
$ # export PKG_CONFIG_PATH
$ # LD_LIBRARY_PATH=$HOME/local/opencvlibrary/lib:$LD_LIBRARY_PATH
$ # export LD_LIBRARY_PATH
$ #
$ ~/.profile
$ vi ~/.profile
$ #-jは並行オプションなので数字はコア数に合わせる
$ make -j4
$ sudo make install
$ source ~/.profile
$  sudo checkinstall
$ #ディレクトリは適宜変更する
$  sudo sh -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf'
$  sudo ldconfig
$  sudo cp 3rdparty/ippicv/unpack/ippicv_lnx/lib/intel64/libippicv.a /usr/local/lib
$  sudo cp ../3rdparty/ippicv/unpack/ippicv_lnx/lib/intel64/libippicv.a /usr/local/lib

見ただけで死にたくなるようなシェルの量である…こんなん覚えるのムリ…って感じである。
ちなみに、cmakeの部分で"WITH_CUDA=OFF"オプションを付けているが、これはCUDA側のバージョンが古いと(具体的な数字は失念してしまった…)CUDA側のバグでインストールできなくなってしまうので、CUDAを使う予定のない方は、なるべく切っておくことをお勧めする。使う方はCUDAを最新版にアップデートしてからインストールした方がよい。

構築確認

以下のソースをコンパイル、実行する

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>

using namespace cv;
using namespace std;

int main( int argc, char** argv )
{
  cout << "OpenCV version : " << CV_VERSION << endl;
  cout << "Major version : " << CV_MAJOR_VERSION << endl;
  cout << "Minor version : " << CV_MINOR_VERSION << endl;
  cout << "Subminor version : " << CV_SUBMINOR_VERSION << endl;
}
$  g++ -ggdb `pkg-config --cflags opencv` -o `basename testcv.cpp .cpp` testcv.cpp `pkg-config --libs opencv`
$ ./testcv

今日はこんなところでおしまい…!