機械学習の勉強を真面目に始めましたわ[part1]

機械学習の勉強を真面目にはじめました!

今回しっかりと基礎から見直そうと思い、入門書を精読することにしました。 具体的には上記の本を精読し、しっかりとゼロから作っていこうかと。 なんとなく難しかったところとかを適当にまとめたり、シンプルに要約したりしてる(つもり)です。とりあえず長くなりそうだったので、畳み込みニューラルネットワークの手前まで!機械学習の基本事項までですかね?

ニューラルネットワークの構成要素

入力ネットワークの構造

入力層、隠れ層、出力層に分けられる。 入力層は例えば、28x28の画像であれば、28x28=784の入力。 隠れ層は何層重ねてもよく、さらにどれだけ縮小しても拡大しても良い。 出力層はクラス分類問題であれば、クラスの数となる。 行列計算と非常に相性が良い構造である。

活性化関数

これらを回帰問題か分類問題かなどに応じて使い分ける。 主に、重みを付与しながらの層から層への情報伝播の後、 各層で行われる処理はこのような関数による変換。

バッチ処理

一回に入力する量を増やす処理。 画像であれば、何枚もの画像を別次元に格納する。 この処理により高速化の恩恵が得られる。

データの学習に関する主な手法

損失関数

損失関数とは機械学習における目標値である。 損失関数から出力される値を最小化することを目標に機械は学習を行う。 主に用いられる関数として下記のものがあげられる。

勾配法

極小値にハマり学習の進まないプラトーという状況に陥ることに注意。
毎回の学習の更新量を定めるパラメタを 学習率 と呼ぶ。 学習率は人間があらかじめ設定する必要があるため ハイパーパラメタ と呼ばれる。

ここまでのまとめ

まとめてみると学習の流れは

  1. ミニバッチ
  2. 勾配の算出
  3. パラメタの更新

これらを繰り返すことになる。この流れを確率的勾配降下法と呼ぶ。 また、ミニパッチ一回分の繰り返しを 1epoch と呼ぶ

テクニック的なものも多分に含む様々な手法

過学習

学習に用いたデータセットに特化した学習を行ってしまい汎化能力が失われた状態。 この状態を避けるために学習データとテストデータを分け、 定期的にテストデータの認識精度も測ることで、 両方の認識精度が向上していることを確認する必要がある。

誤差逆伝播(backpropagation)

微分値によってパラメタを進める方向、量を決めるが、 微分は一般的に重たい計算のため、高速化するために誤差逆伝播法を用いる。 これは各計算を分解、独立化し、chain ruleによって、 独立した計算それぞれに対する微分を考えていくことで、 行列計算として微分計算を行えると言う利点がある。
隠れ層での行列の形状を変化させる計算をAffineレイヤと呼び、 Affineレイヤを含む、上記の活性化関数それぞれに対し、 独立して計算済みのレイヤを実装していくことで、 部品を組み立てるようにニューラルネットワークを実装することができ、 かつ高速に微分計算を行うことができる。

勾配確認

実装の難しい誤差逆伝播法のバリデーションのため、 実装の簡単な数値微分の結果と比較すること。

最適化手法

パラメタの更新のことを最適化と呼ぶ。

上記の4つをこの書籍では取り上げていた。

SGD

最もシンプルな手法。 勾配に学習率をかけたものを次のパラメタ更新に用いる。 欠点として、最小値までの傾斜が等方的でない場合、 ジグザグな動きをすることとなり、学習スピードが遅くなる。

Momentum

前回の学習スピードを保持することで、 同じ方向に進むときは加速度的に進み、 ジグザグな動きをするときはSGDと比べて減速するようにした。

AdaGrad

学習率を定数ではなく変数にする。 過去全ての更新量を記憶し、そのぶん学習率を小さくしていく。 欠点として、学習に長時間かかった場合、学習率が0に近づき、 学習が進まなくなることが挙げられるが、それを改善したRMSProp と言う手法も存在する。

Adam

直感的にはMomentumとAdaGradを組み合わせたようなものらしい

重みの初期値

1を標準偏差としたガウス分布

0と1にアクティベーション(各レイヤの出力)が固まることから 勾配消失が起きているとわかる。

0.001を標準偏差としたガウス分布

0.5付近に固まるため、勾配消失は怒っていないが、 その代わり表現力が小さくなっている。 ある値にアクティベーションが集まると、 単一のレイヤで全てのレイヤを表現できてしまうと言う問題や、 学習が効率よくいかない問題が挙げられる。

Xavierの初期値

前層のノードの数に準じて初期値を小さくする手法。 活性化関数が線形関数(線形関数に近似される関数)の際に用いられる。

Heの初期値

Xavierに2倍の広がりをもたせたもの。 非線形関数に用いられる。

Batch Normalization

データを綺麗な分布にならす手法。 Affineレイヤと活性化関数レイヤの間に Batch Normalizationレイヤを入れて使用する。

  • 学習スピードの増加
  • 初期値に対する依存度の減少
  • 過学習の抑制

などの効果がある。

正則化

過学習を抑制するための手法

Weight decay(荷重減衰)

損失関数に重みに準じた量を加算することで、 大きな重みを持つことにペナルティを課す。

Dropout

確率で、ノードを消去することで何かうまいこと過学習が抑制されるらしい。

昔のgitがやばいらしかったからupdateしたわ

Gitの脆弱性 ( CVE-2017-1000117 )対策 | 東京エンジニア

gitがやばいらしい

どうやら昔のgitに脆弱性が見つかったらしい。さすがに脆いギットとか怖すぎて使ってられないからupdateすることにした。

homebrewでgit

デフォルトのgitを使っていたが、updateしたり管理したりするのにhomebrewのgitを使った方が楽らしいから再インストールすることにした。

$ brew install git

これでいけるのかと思いきや、どうやらhomebrewの方のgitにpathが通っていないっぽい。ということで.zshrcを開いて毎度のごとくpathを通す

export PATH="/usr/local/bin:$PATH"

これで確認したら

$ git --version
git version 2.14.1

オッケーっぽい! 脆弱性についてはあんまり調べてないけどとりあえずこれでオッケなのかな?笑

atom最高なんだけど日本語入力できない話するわ

atomは最高

went-went-takkun135.hatenablog.com

この記事で、atomに乗り換えたことをお伝えしたと思いますが、どんどんぞっこんになっています。この時から割とatom扱えるようになり、

  • TeX環境
  • Markdown環境
  • Jupyter環境
  • PDF参考書を片側に表示した勉強環境

等々の環境を整備いたしました!UIもめっちゃ綺麗だし、ほんとatom最高ですわ!!デメリットとしてはやっぱりshell環境とのコネクトが少し悪くなったことでしょうかね。

今回の記事について

上記のように非常に楽しくatom生活を送らせていただいてるというか、非常に楽しくなるようにちゃんと整備したというかで、これらについての記事も書きたいのですが、とりあえず困ってることを書きたいです

なんか日本語入力おかしくなったくない??

というのが今回の記事内容です。
日本語入力してもカーソル移動しないんですよね。なんか少し前にもバグったことあるっぽくてその時はatomのアップデートで解消されたみたいだったので、今回もアップデート待ちなのでしょうか。

現環境

Mac OSX 10.12.6 atom 1.19.0

解決した人いたら教えてください

調べても明らかな対処法が見えないので、とりあえず待っています。TeX書くときとか、Markdown書くときとか絶望的なので早く治ってくれないかなーと。

書いた直後の追記(8/16)

書いた直後にお祈りしながらアップデート確認したらニューバージョンリリースされてて、アップデートしたら無事日本語入力元どおりになりました!よかったよかった。。

TensorFlow Object Detection API をしこたま教育してやるわ[TFRecord編]

TensorFlow Object Detection

went-went-takkun135.hatenablog.com

この記事の続きです。 独自のデータセットで学習を行いたいから, このモデルに学習させる方法を調べてこいとのことだったので,

github.com

上記のチュートリアルを変形しながら進めていきたいと思います。

Data setの用意

まずはデータセットを用意しなければ始まりません。 チュートリアルの通りデータをダウンロードしてもいいのですが, めちゃくちゃ時間がかかるのが難点です。 自分で用意してもいいんですが, 形式がわからないと思うので下記においておきます。 チュートリアルでダウンロード予定だったannotationsの中にあるxmlのファイルです。

<annotation>
  <folder>dataset</folder>
  <filename>shiba_inu_11.jpg</filename>
  <source>
    <annotation>OXIIIT</annotation>
  </source>
  <size>
    <width>500</width>
    <height>334</height>
    <depth>3</depth>
  </size>
  <object>
    <name>dog</name>
    <pose>Frontal</pose>
    <truncated>0</truncated>
    <occluded>0</occluded>
    <bndbox>
      <xmin>140</xmin>
      <ymin>1</ymin>
      <xmax>384</xmax>
      <ymax>235</ymax>
    </bndbox>
  </object>
</annotation>

これがshiba_inu_11.jpgの画像ファイルに1対1対応するxmlファイルになります。

  • 画像ファイルをimages/
  • xmlファイルをannotations/
  • 二つのディレクトリをdataset/

に入れておくといいと思います。 そのほかにもペットのannotationsをダウンロードしてくれば色々入ってくるんですが, とりあえずこの形式に沿っていくつかデータあれば大丈夫だと思います。 要はPythonのlxmlライブラリでこれらの値をdictionaryとして格納して, それをTFRecordとして取り出すのが今回の流れです。

create_pet_tf_record.pyの変更

置換などはvimのコマンドで書いていこうかと思います(すでにAtomに乗り換え済み)

対象変更

とりあえず,今回はpetじゃなくて人間を検出したかったため,

:%s/pet/person/gc

しました。とりあえず。笑

画像形式変更

次に,今回のデータセットで用いる画像形式がjpgではなくpngであったため

:%s/jpg/png/gc
:%s/JPEG/PNG/gc

しました。TensorFlowではjpgかpngが使えるらしいですね。

不要なデータ部分を消去

筆者の用意したデータセットには

  • difficult
  • pose
  • truncated

の3項目が入っていなかったため,既存のコードではエラーを吐かれました。そのため,該当箇所をコメントアウトする必要がありました。(データセットにそれらの情報を加えるのもありだと思いますが,めんどいとも思います)

line 109~145

for obj in data['object']:
    difficult = bool(int(obj['difficult']))
  if ignore_difficult_instances and difficult:
    continue

  difficult_obj.append(int(difficult))

  xmin.append(float(obj['bndbox']['xmin']) / width)
  ymin.append(float(obj['bndbox']['ymin']) / height)
  xmax.append(float(obj['bndbox']['xmax']) / width)
  ymax.append(float(obj['bndbox']['ymax']) / height)
  class_name = get_class_name_from_filename(data['filename'])
  classes_text.append(class_name.encode('utf8'))
  classes.append(label_map_dict[class_name])
  truncated.append(int(obj['truncated']))
  poses.append(obj['pose'].encode('utf8'))

example = tf.train.Example(features=tf.train.Features(feature={
    'image/height': dataset_util.int64_feature(height),
    'image/width': dataset_util.int64_feature(width),
    'image/filename': dataset_util.bytes_feature(
        data['filename'].encode('utf8')),
    'image/source_id': dataset_util.bytes_feature(
        data['filename'].encode('utf8')),
    'image/key/sha256': dataset_util.bytes_feature(key.encode('utf8')),
    'image/encoded': dataset_util.bytes_feature(encoded_jpg),
    'image/format': dataset_util.bytes_feature('jpeg'.encode('utf8')),
    'image/object/bbox/xmin': dataset_util.float_list_feature(xmin),
    'image/object/bbox/xmax': dataset_util.float_list_feature(xmax),
    'image/object/bbox/ymin': dataset_util.float_list_feature(ymin),
    'image/object/bbox/ymax': dataset_util.float_list_feature(ymax),
    'image/object/class/text': dataset_util.bytes_list_feature(classes_text),
    'image/object/class/label': dataset_util.int64_list_feature(classes),
    'image/object/difficult': dataset_util.int64_list_feature(difficult_obj),
    'image/object/truncated': dataset_util.int64_list_feature(truncated),
    'image/object/view': dataset_util.bytes_list_feature(poses),
}))

これを↓に変更

for obj in data['object']:
  # difficult = bool(int(obj['difficult']))
  # if ignore_difficult_instances and difficult:
  #   continue

  # difficult_obj.append(int(difficult))

  xmin.append(float(obj['bndbox']['xmin']) / width)
  ymin.append(float(obj['bndbox']['ymin']) / height)
  xmax.append(float(obj['bndbox']['xmax']) / width)
  ymax.append(float(obj['bndbox']['ymax']) / height)
  class_name = get_class_name_from_filename(data['filename'])
  classes_text.append(class_name.encode('utf8'))
  classes.append(label_map_dict[class_name])
  # truncated.append(int(obj['truncated']))
  # poses.append(obj['pose'].encode('utf8'))

example = tf.train.Example(features=tf.train.Features(feature={
    'image/height': dataset_util.int64_feature(height),
    'image/width': dataset_util.int64_feature(width),
    'image/filename': dataset_util.bytes_feature(
        data['filename'].encode('utf8')),
    'image/source_id': dataset_util.bytes_feature(
        data['filename'].encode('utf8')),
    'image/key/sha256': dataset_util.bytes_feature(key.encode('utf8')),
    'image/encoded': dataset_util.bytes_feature(encoded_png),
    'image/format': dataset_util.bytes_feature('png'.encode('utf8')),
    'image/object/bbox/xmin': dataset_util.float_list_feature(xmin),
    'image/object/bbox/xmax': dataset_util.float_list_feature(xmax),
    'image/object/bbox/ymin': dataset_util.float_list_feature(ymin),
    'image/object/bbox/ymax': dataset_util.float_list_feature(ymax),
    'image/object/class/text': dataset_util.bytes_list_feature(classes_text),
    'image/object/class/label': dataset_util.int64_list_feature(classes),
  #   'image/object/difficult': dataset_util.int64_list_feature(difficult_obj),
  #   'image/object/truncated': dataset_util.int64_list_feature(truncated),
  #   'image/object/view': dataset_util.bytes_list_feature(poses),

データセットへのpath指定を細々と変更

xmlまでのpath
path = os.path.join(annotations_dir, 'xmls', example + '.xml')

上記の'xmls',が邪魔ですので消去です。 petのデータセットではannotationsの下にxmlsというディレクトリがあって, その中にxmlファイルが入っているらしいですね。

各データへのpath

line 191~192

examples_path = os.path.join(annotations_dir, 'trainval.txt')
examples_list = dataset_util.read_examples_list(examples_path)

ここを↓に変更

xml_list = os.listdir(annotations_dir)
examples_list = []
for xml_name in xml_list:
  temp_splited_name = xml_name.split(".")
  examples_list.append(temp_splited_name[0])

また,各データの名前を入れたテキストファイルも用意していなかったので, Pythonに頑張ってもらいました。

実行

多分上記の変更でTFRecord作れるようになっていると思います! 今,このTFRecord使って学習させようと奮闘中なのですが, なーんか時間かかりすぎてて絶対間違ってるなーって状態です笑

次回,奮闘の末に勝利を納めて入れば学習のセットアップまで書きます!

「俺,Vimmerになる!」って言ってから4ヶ月でatomに乗り換えた話するわ

言い訳を聞いてください

まずは前回記事をみていただきたいのですが,

went-went-takkun135.hatenablog.com

そう,私,この度,Mac買い換えました!!!
最高ですね。もう。前のPCはMacBook Pro 2012-midモデルだったわけですが,皆さんご存知ですか,私の元カノはまだHDDだったのですよ。物理的にも動作的にも重たかった元サヤと比べ今のこの快適さはもう。。ね!!

それと乗り換えになんの関係があるのかと,疑問に思う方がいるかもしれませんので,箇条書きにしてみました。

  • 2012モデルでは重すぎて使えなかったatomが快適に使える
  • ディスプレイがretinaになった途端,vimのUIがなんとなく残念に感じる
  • atomをベターVimとして使えるプラグインがある!

kesin.hatenablog.com

qiita.com

ということで,主な理由は,atomってなんかいかしてへん??でした。

インストー

公式から大昔にダウンロードしてきました。 ボタンを4,5回押したらインストールは終わった気がします。

パッケージインストー

以下のパッケージをとりあえず入れました。

apm list --installed --bare

Hydrogen@1.19.0
ariake-dark-syntax@0.1.3
atom-beautify@0.30.4
atom-clock@0.1.13
atom-html-preview@0.1.22
atom-monokai@0.10.9
atom-runner@2.7.1
autoclose-html@0.23.0
autocomplete-js-import@1.4.0
autocomplete-paths@1.0.5
autocomplete-plus@2.35.7
autocomplete-python@1.9.1
busy@0.7.0
busy-signal@1.4.3
clip-history@0.4.0
compare-files@0.8.1
emmet@2.4.3
ex-mode@0.15.0
file-icons@2.1.9
git-history@3.3.0
git-log@0.4.1
git-plus@7.9.3
highlight-selected@0.13.1
intentions@1.1.2
javascript-snippets@1.2.1
jquery-snippets@11.0.0
kite@0.30.1
linter@2.2.0
linter-flake8@2.2.1
linter-js-standard@3.9.1
linter-jscs@4.1.2
linter-ui-default@1.6.3
markdown-preview-plus@2.4.10
markdown-scroll-sync@2.1.2
minimap@4.29.2
minimap-bookmarks@0.4.2
minimap-cursorline@0.2.0
minimap-find-and-replace@4.5.2
minimap-git-diff@4.3.1
minimap-highlight-selected@4.6.1
pretty-json@1.6.4
project-manager@3.3.5
regex-railroad-diagram@0.19.3
show-ideographic-space@1.0.2
sort-lines@0.14.0
split-diff@1.4.3
vim-mode-plus@0.95.0
vim-mode-plus-ex-mode@0.9.1

とりあえず入れたまではいいのですが,linterとかいうのめっちゃ便利なものの,既存のファイルに対してめっちゃ怒って来てうざかったので消しました。今度ちゃんと勉強してから導入しようかと思います。(褒められて伸びるタイプなんで)

入れておけばいいかなと思ったのは,autocomplete系ですね。なんか自動補完って便利だなと思いました。笑

あとはminimap系ですね。なんかかっこよくていいなと思いました。笑

入れておく系と入れてから使う系があると思うんですけど,とりあえず shift + cmd + p でコマンドパレット出してプラグイン名を叩けば起動できて,さらにショートカットのチートシートにもなっているので,当分コマンドパレットと濃密なおつきあいをすることになりそうです。

Macの移行作業

起動してから黒い画面を開かずに行ったこと

起動してから黒い画面を開いて行ったこと

homebrew

homebrewのインストー

homebrewの公式サイトにあるコードをコピペ

formulaのインストー

  • zshとtmux関係のインストー

    $ brew install zsh zsh-autosuggestions zsh-completions zsh-syntax-highlighting colordiff reattach-to-user-namespace tmux

  • vimのインストー

    $ brew install vim

  • PythonとNode.js

    $ brew install pyenv $ brew install pyenv-virtualenv $ brew install nodebrew

  • ここでdotfilesをcloneすると良さそう

  • 残りの細々したもの
    • heroku
    • awscli

dotfiles

$ cd ~
$ git clone https://github.com/dondakeshimo/dotfiles.git
$ cd ~/dotfiles
$ ./symlink.sh
$ cd ~
$ mkdir .vimbackup

zsh

qiita.com

oh-my-zshはもう古いらしいから新しいものを検討しなければならないかも

tmux

バージョンが変わってたから,.tmux.confの中身を一部分書き直し

qiita.com

vim

NeoBundleのインストー

$ mkdir -p ~/.vim/bundle
$ git clone git://github.com/Shougo/neobundle.vim ~/.vim/bundle/neobundle.vim
$ vim
$ :NeoBundleInstall

git

初期設定

$ git config --global user.name "俺の名前"
$ git config --global user.email 俺のメアド@example.com

ssl発行

qiita.com

Python

$ pyenv install 3.5.3
$ pyenv install anaconda3-4.1.1

後は,tensorflow使ってるディレクトリまで行って,

$ pip install -r requirements.txt

opencv

$ conda install -c https://conda.anaconda.org/menpo opencv3 

それぞれ仮想環境をpyenv-virtualenvで作成

Node.js

$ mkdir -p ~/.nodebrew/src
$ nodebrew install-binary stable
$ nodebrew use stable

$ npm install -g grunt
$ npm install -g bower
$ npm install -g yo

それぞれのディレクトリで

$ npm install

データ移行について

写真とiTunesと漫画

容量でかいやつは昔のMacから外付けHDDに全部ぶち込んどいた

その他持ってきたいもの

そんなになかったけど,基本的にAir dropで持ってきた。まじで早くて引く。

TensorFlow Object Detection API をしこたま教育してやるわ[GCP編]

概要

went-went-takkun135.hatenablog.com

上記の記事の続きです!
TensorFlowの物体検出ライブラリを使う環境構築は終わったと思って、しばらくいろんな画像見せて遊んでました。たまに突っ込みどころ満載の判断してくるcocoちゃんも可愛いんですけど、やっぱり自分色に染めた学習済みモデルが欲しいなと思ってしまいました。少し調べたら、今の環境じゃ足りずにまだなにやら環境構築せなあかんとのこと。罠やな。ということで、環境構築しながら書いてる忘備録です。

Google Cloud Platform

最初にGCP(Google Cloud Platform)のプロジェクトを作れと言われます。初心者プログラマなので当然GCPのアカウントなんぞ持っておりません。ということで登録から

GCPのアカウント登録

book.mynavi.jp

この記事で丁寧に解説してあったので詳しいやり方は割愛します。Google Playでクレジットカード登録してたらめっちゃ楽に作れてしまった。

GCP SDKのインストー

今回初めてSDKがなんの略か調べました。その名も
Software Development Kit
なるほどでしたね。さて、インストールですが、下記ページの対話型でやりたいと思います。なぜなら、一番簡単そうだから!macならざっくり言うと、

Installing Cloud SDK  |  Cloud SDK Documentation  |  Google Cloud Platform

  • コードをダウンロードして手動でインストー
    • 自分の好きなバージョンを選べる
  • shell上で対話型インストー
    • 自分の好きなバージョンは選べない

の2パターンだと思います。

curl https://sdk.cloud.google.com | bash (or zsh)

ってシェル上で打ち込めばインストールがスタートします。そのまま全部yを押しました。
なんかかっこいいインストール画面が全て終わってしまうと、次はシェルを再起動しましょう。

exec -l $SHELL

最後に

gcloud init

ってコマンドを打つと、

  1. 自分のGoogle アカウントの選択
  2. 自分のプロジェクトの選択(数字押せばおっけー)

    [1] (既存のプロジェクト名)
    [2] new project

  3. Google compute engineを利用するか(Y/n) 当然Y

  4. コンピュータの選択→asia-northeast1にした(確か東京)

で初期設定完了です!!

GCPAPIを有効化

https://console.cloud.google.com/flows/enableapi?apiid=ml.googleapis.com,compute_component&_ga=1.73374291.1570145678.1496689256

ここでちょいちょいっと指示に従えば有効化できます!

Google Cloud Storage (GCS) bucket の作成

https://cloud.google.com/storage/docs/creating-buckets

今度はこのサイトの指示に従ってbucketを作成しましょう。割と適当に名前とかつけました。

これにてGCP周りの環境構築は完了です!次はデータセット取ってきて何やらかんやら!