Translate

2017年6月19日月曜日

udemy のAI入門とTensorFlow入門を試してみた

AIブームというけれど、
それを使いこなすプログラマを育成する道具が
あまり揃っていない。

全員が全員、
TensorFlow のページをGoogle翻訳でゴリゴリ読むなんて
正直無理だ。

ド素人とまでは言わないが、
数年の経験をもつプログラマに使いこなしてもらわないと
とてもビジネスアプリケーション分野での発展は望めない。


..ということでいきついたのがudemy。

udemy は有料のeラーニングサービスで、
海外でも展開していてその日本版のサービスを試してみた。

日本版udemyはどうもあの Benesse が絡んでいるようなのだけど
..まあそのあたりのリスクはどうするかは始める人次第。

なぜ試してみたか..というのは、
AI、機械学習、ディープラーニングの良さげな研修が
あまりないこと。

幾つか存在するのだけど、
書籍も含め難易度が高い。
特に数式の出てこない本とかだと


私がパラ見した中では「はじめてのディープラーニング」という本くらい。
この本でも数式はどうしても出てくる。

個人的にはこの本はプロマネや営業..は辛いかもしれないけど技術系営業なら
できれば知っておいて欲しい単語がならんでいる。

なのでPMや技術系営業でAIと絡みそうない人は、
ちょっとづつ読みながら用語集を作っていくと
AI系のPMや営業業務にはついていける様になると思う。
#最後のCafeを使うセクションは飛ばしても良い

でも、これだと頭でっかちで、
どうしてプログラムを書かないで分類とか識別とかができるのか
というそもそもの本質的なところを埋めてくれないのだ。

それ用の本として



「ゼロから作るDeep Learning」というのがあるのだけど..
これが"ゼロから"とかいってるくせに
パーセプトロンとかXORとかNANDとか線形だ非線形だとか書いちゃって
「お前、教える気、ないやんけ!」
と思えるほど読む難易度が高い。


もっと3年目くらいのプログラマが手を使いながら
できればパーセプトロンとか線形とかの単語をそれほどつかわずに
おしえてくれそうな教材はないものか..

で、見つけたのがudemyの講座
「みんなのAI講座 ゼロからPythonで学ぶ人工知能と機械学習」
https://www.udemy.com/learning-ai/

だ。

で、実際にやってみた。

テキストの流れは、以下の通り。

・コースと人工知能の概要
・準備
 Python2.7と最新版PyCharmをインストールする。
 ここで手順に従わず、Anaconda最新版でPython2.7仮想環境を作るのが実は近道。
・Pyhtonの基礎
 この講座の中でもっともつまらないセクション。
 だけど、後でPythonコードを書くので、一応知っておかないと進められない。
 ここをクリアすればAIのはなしに入ることができる。
 既に知ってる人は2倍速で飛ばせばいい。
 他の言語を知っている人は、四則演算の演算器とクラス、関数の書き方、リスト[]/タプル()/ディクショナリ{}の違いと使い方のところだけしっかり学習すればOK
・必要な数学の学習
 次のセクションで使うシグモイド関数を勉強するセクション。
 matplotlibというライブラリを使ってグラフをpythonで図示させて、継続意識を絶やさない講師の努力が伺える。
・ニューラルネットワーク
 「ゼロから作るDeep Learning」の2章「パーセプトロン」をわかりやすく、かつ順番にコードを肉付けしながら学んでいくこの講座の中心。
 ニューロンクラスを完成させ、ニューラルネットワーククラスで複数連結させるところまで。
・機械学習
 前のセクションで作ったニューラルネットワーククラスのWとbをどうやって自動学習できるようにするかをおしえるセクション。ここも中心のひとつ。
 バックプロパゲーションで微分を傾きとして教えている。
・機械学習ライブラリの活用
 自分で実装しなくてもライブラリがあるのでそれを使えば簡単に実装できるよという、応用セクション。
 scikit-learnをインストールするが、WindowsOS上のPython2.7.x系に直にscipyをインストールするところは、皆結構引っかかるところなのだけど、そこが書かれていない。
 最新のAnacondaでcondaしてpython2.7仮想環境を作っていればもんだいなし。
 動かすのはサポートベクタマシンを使ったMNISTと株価分析。
・さらに学ぶために
 ここはGPUの話やディープラーニングの例としてCNNやDCGAN(贋作者つきCNN)のほんのさわりだけしょうかいしてまとめ
 TensorFlowも使おうとするが、AnacondaでないWindows利用者は確実にハマる。
 でも疎通用プログラムを動かすだけなので無視してOK
・ボーナスレクチャー
 講師主催の勉強会案内などの、塾帰り直前とかの案内的な話


Python知らなくても学習するところから始めるし、数学用語は知らなくても継続可能。
バックプロパゲーションで?となる人もいるだろうが、ニュートン法を計算機実習で学んだ人ならほぼスルー可能。
このあたりだけごまかせば、たぶん新入社員でもなんとかなるだろう。

この講座は、環境面の問題がクリアできれば初心者SEのAIへのエントリポイントに最適だ。
ただPMや営業が必要としているのは、"用語"集のインストールだが、この講座はそこは満たすことができない。先の「はじめてのディープラーニング」とかの本を読みつつExcelシート上に用語集を作っていくのが最短ルートだとおもう。



この講座の"次"候補として、


【4日で体験】 TensorFlow x Python 3 で学ぶディープラーニング入門
https://www.udemy.com/tensorflow/


を受けたが、前の講座を公立小学校としたら、これは中学2年か。
("中1"部分が抜けてる気がする)

TesnorFlowのチュートリアルの最初にあるMNISTを順番に解説するが、
その後はサンプルコードをGitから落として動かすだけなので、
知識としてはCNN(畳み込みとプーリング、全結合層で何やっているか)
にとどまる。

本音としては、
tf変数がなんであるのとか、
計算グラフは定義しただけでは動作せずsessionをrunしてうごかすとか
runするときのディクショナリのplaceholderでpython界とC++界を行き来しているとか
を説明する講座が欲しいところだ。

MNIST以外の2つのセクションはそれぞれサンプルコードの動かし方例だが
これを1本にして、自然言語系のチュートリアルをCNNのように
詳細解説してほしいなあ..

講師からのコメントによるとこれかららしいが、
1つのコース内でいれてくれるか
別コースになるか..
なんとなく別コースになりそうな気がする..

なんにせよこのコースは修正過渡期なので
この段階で評価することは難しい。

..というか、TensorFlow は私の学習時期が悪すぎた..
はじめた翌日にTesnroFlow1.2.0がリリースされたし..

バージョン自体がグラグラしている時期だからなあ..
Keras優先したにしても、tf.keras問題もあるし...


既に1.3.0の噂も聞いているので、TensorFlow系の教育はあまり手を出さないほうが実は件名だったりスルのだけど、組織や個人の事情でそうもいってられないひともいるだろうし..



p.s.
講座を完了すると、以下のような修了証が発行される。





まあ、これはどうでもいいですが..


2017年6月16日金曜日

TensorFlow1.2.0実行環境をnvidia-dockerで立ち上げるシェルスクリプトを書いてみる




とってもヘボいので、晒すのもどうかなと思うのですが、自分の忘備録として記事にしておこうかな..と、ふと。

環境はCentOS7、hara2devというdockerグループにも入っているユーザで以下の3つのスクリプトはホームの下にdockerというディレクトリを切ってその中に入っているてい。


/home/hara2dev/docker/env_tensorflow.sh

#!/bin/bash
############################################################
# filename: env_tensorflow.sh
#
# (C) hara^2 development, 2017 all rights reserved.
############################################################

## Jupyter notebook password

PASSWORD=harahara

## PORT

# Jyupiter port
JUP_PORT=8888
# TensorFlow Boad port
TFB_PORT=6006
# REST API port
REST_PORT=3000

## TensorFlow Version

TF_VER=1.2.0
#TF_VER=1.1.0
#TF_VER=1.0.1

## CPU / GPU

# CPU
#NODE=
#DOCKER=/usr/bin/docker

# GPU
NODE=-gpu
DOCKER=/usr/bin/nvidia-docker

## Python Version

# 2.x
#PY_VER=

#  3.x
PY_VER=-py3

## docker image

DOCKER_IMAGE=tensorflow/tensorflow

## docker tag

#DOCKER_TAG=latest
DOCKER_TAG=${TF_VER}${NODE}${PY_VER}

## pid file path

PID_DIR=/home/hara2dev/docker/pid
#PID_DIR=.
PID_FILE=${PID_DIR}/${DOCKER_TAG}.pid

## bin path
# ubuntu
CAT=/bin/cat
RM=/bin/rm
# cent
#CAT=/usr/bin/cat
#RM=/usr/bin/rm


/home/hara2dev/docker/start.sh

#!/bin/bash
############################################################
# filename: start.sh
#
# (C) hara^2 development, 2017 all rights reserved.
############################################################

## env script path
ENV_PATH=./env_tensorflow.sh

## operations
source ${ENV_PATH}

${DOCKER} run \
   --name "${DOCKER_TAG}" \
   --publish "${JUP_PORT}:8888" \
   --publish "${TFB_PORT}:6006" \
   --publish "${REST_PORT}:3000" \
   --volume /home/hara2dev/docker/work:/notebooks/work \
   --volume /home/hara2dev/docker/share:/notebooks/share \
   --env HTTP_PROXY="http://proxy.server:8080/" \
   --env HTTPS_PROXY="http://proxy.server:8080/" \
   --env NO_PROXY="localhost,127.0.0.1,*.hara2dev.local" \
   --env PASSWORD="${PASSWORD}" \
   --log-driver=syslog \
   --log-opt syslog-address=tcp://172.17.0.1:514 \
   --log-opt tag="${DOCKER_TAG}" \
   --detach \
   --cidfile ${PID_FILE} \
   ${DOCKER_IMAGE}:${DOCKER_TAG}


/home/hara2dev/docker/stop.sh

#!/bin/bash
############################################################
# filename: stop.sh
#
# (C) hara^2 development, 2017 all rights reserved.
############################################################

## env script path
ENV_PATH=./env_tensorflow.sh

## operations
source ${ENV_PATH}

PID=`${CAT} ${PID_FILE}`

${DOCKER} stop ${PID}
${DOCKER} rm ${PID}

${RM} -rf ${PID_FILE}




ログインして
cd dockerして
start.shで起動、
stop.shで停止、
docker ps で状態確認。

コンテナ停止、即コンテナイメージ削除してますが
shareとworkというディレクトリを共有させているので
ここにファイルを置けばなんとかなるとおもって..

TensorFlowのバージョンやGPU指定Pythonバージョン指定などを
変更する場合は、停止している状態で env_tensorflow.sh を修正する。

あと、rsyslogdも動いているていで。


172.17.0.1 はデフォルトルータの一つでホスト側IPを指しているんだけど、ここにIP書くわけに行かないので、代わりにこのIPを入れてます。

ホントは、docker-composeしたいんだけど、GPUイメージはnvidia-docker起動だから..

TensorFlow 1.2.0 の変更点を翻訳してみる

今朝、自分のTwitterのタイムラインで TensorFlow が 1.2.0 になったことを知った。


前日TensorFlowサイトではたしかに一番上には "API r1.1" だったのが、今みるとたしかに " AIP r1.2" になっている。

TensorFlow DevSummit2017 の動画で、怒涛の更新がかかることは知っていたが、つい昨日動いていたサンプルコードが今日動かない憂き目をここ数ヶ月何度味わったことか..


しょうがないので Release 1.2.0 のところだけ翻訳してみた。
いつもどおり参照するかたは at your own risk でお願いします。

-----

Release 1.2.0


主な機能と改善点


  • WindowsでのPython 3.6をサポートしました。
  • 時空間デコンボリューションのための tf.layers.conv3d_transpose レイヤが追加されました。
  • tf.Session.make_callable() を追加しました。これは、同様のステップを複数回実行するオーバーヘッドを削減します。
  • contrib ibverbs ベースの RDMA サポートが追加されました(Yahoo @junshi15 の黙認により)。
  • RNNCell オブジェクトは、 tf.layers.Layer のサブクラスになりました。 TensorFlow 1.1 リリースで説明されている厳密性はなくなりました。 RNNCell が初めて使用されたときに、そのスコープがキャッシュされます。将来の RNNCell の使用はすべて同じスコープの変数を再利用します。これは TensorFlow バージョン <= 1.0.1 の RNNCells の動作からの大きな変化です。 TensorFlow 1.1 には、古いコードが新しいセマンティクスで正しく機能することを確認するためのチェックがありました。このバージョンでは RNNCell の柔軟な使用が可能になりますが、 TensorFlow <= 1.0.1 のコードを使用すると微妙なエラーにつながる可能性があります。たとえば、 MultiRNNCell([lstm] * 5) と書くと、各層が同じパラメータを共有する5層 LSTM スタックが構築されます。独自のパラメータで5つのレイヤーを取得するには、 MultiRNNCell([LSTMCell(...) for _ in range(5)]) と記述します。全くわからない場合は、最初に TF 1.1 でコードをテストしてください。エラーが発生していないことを確認し、 TF 1.2 にアップグレードしてください。
  • TensorForest Estimator は、サーブ用の SavedModel エクスポートをサポートするようになりました。
  • クライアント提供の ClusterSpec をサポートし、それらをすべてのワーカーに伝播し、動的な TensorFlow クラスタの作成を可能にします。
  • TensorFlow C ライブラリが Windows 用に利用可能になりました。
  • TensorBoard の新しいオープンソース版をリリースしました。
  • SavedModelMetaGraph を調べて実行するための SavedModel CLI ツールの提供。
  • TensorFlow の Android リリースは、アプリケーションへの統合を容易にするため、 jcenter にプッシュされるようになりました。 詳細については、 https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/android/README.md をご覧ください。
  • RNNCells の変数名は、Keras レイヤーとの一貫性のために名前が変更されました。 具体的には、以前の変数名  "weights" と  "biases" がそれぞれ "kernel" と "bias" に変更されました。 このような RNN セルを含む古いチェックポイントに関する後方互換性が損なわれる可能性があります。この場合、ツール checkpoint_convert スクリプトを使用して古いチェックポイントの変数名を変換することができます。
  • 1.0 リリース以前の tf.nn 名前空間にあって、 tf.contrib.rnn に移動された多くの RNN 関数とクラスは、コア名前空間に戻されました。これには、 RNNCell 、 LSTMCell 、 GRUCell 、および他の多くのセルが含まれます。これらは現在 tf.nn.rnn_cell にあります(下位互換性のために tf.contrib.rnn のエイリアスが付いています)。元の tf.nn.rnn 関数は tf.nn.static_rnn になりました。双方向静的スタティック関数と状態保存静的関数も tf.nn 名前空間に戻ります。
  • 注目すべき例外は EmbeddingWrapper 、 InputProjectionWrapper 、 OutputProjectionWrapper です。これはゆっくりと tf.contrib.rnn の非推奨に移行します。これらは非効率的なラッパーで、 rnn の前処理または後処理として embedding_lookup または layers.dense を呼び出すことによって置き換えられることがよくあります。 RNN のデコードでは、この機能は tf.contrib.seq2seq の代替APIに置き換えられました。
  • インテルMKLインテグレーション( https://software.intel.com/en-us/articles/tensorflow-optimizations-on-modern-intel-architecture )。インテルは、数多くの最適化されたディープ・ラーニング・プリミティブを開発しました。行列の乗算とコンボリューションに加えて、これらのビルディング・ブロックには次のものがあります。直接バッチ・コンボリューションプール:最大、最小、平均正規化:LRN、多次元転置(変換)、分割、連結、合計、およびスケール。

廃止

  • TensorFlow 1.2 は、cuDNN 5.1 で構築する最後の機会になります。 TensorFlow 1.3 以降、cuDNN 6.0 を使用して、すべてのビルド済みバイナリをビルドしようとします。 私たちは、ソースコードを cuDNN 5.1 と互換性を保つように努めますが、最善の努力をします。

API の変更点

  • org.tensorflow.contrib.android.TensorFlowInferencefaceは可能な限り例外をスローし、メソッドシグネチャを単純化しました。


Contrib APIの変更

  • tf.contrib.util.create_exampleを追加しました。
  • tf.contrib.imageに双線形補間を追加しました。
  • カスタムのシードコントロールを使用してランダム操作にtf.contrib.statelessを追加します。
  • contrib/distributions/ に追加された MultivariateNormalFullCovariance
  • tensorflow/contrib/rnnは、Kerasレイヤーとの一貫性のためにRNNセル変数の名前を変更します。 具体的には、前の変数名「weights(重み)」と「biases(バイアス)」をそれぞれ「kernel(カーネル)」と「bias(バイアス)」に変更する。 このようなRNNセルを含む古いチェックポイントに関する後方互換性が損なわれる可能性があります。この場合、checkpoint_convertスクリプトを使用して古いチェックポイントの変数名を変換することができます。
  • TensorFlowのprimal(明示的)カーネルメソッドのためのOpsestimatorsを持つtf.contrib.kernel_methodsモジュールを追加しました。


バグ修正、その他の変更

  • Python では、 type 属性の Operation.get_attr は、 protobuf 列挙型ではなく、予想される get_attr ドキュメントに一致する Python DType バージョンの型を返します。
  • iOS ライブラリを構築する際に、 MIN_SDK のバージョンを 8.0 に変更しました。
  • LIBXSMM の統合を修正しました。
  • decode_jpeg/decode_png/ decode_gif がすべてのフォーマットを扱うようにするのは、ユーザーが画像を間違ったタイプとして解読しようとすることが多いからです。
  • 暗黙 broadcasting の低下を改善。
  • GCS/Bigquery クライアントの安定性を向上させます。
  • proto 依存関係を最小限に抑えるために、 OpKernelConstruction::op_def() を削除してください。
  • VectorLaplaceDiag ディストリビューションが追加されました。
  • Android のデモでは libtensorflow_demo.so を実行する必要はありません( libtensorflow_inference.so はまだ必要です)
  • categorical_column_with_vocabulary_file を追加しました。
  • Session::Run() 呼び出しでテンソルをバッチ/アンバッチするための ops を導入します。
  • tf.log_sigmoid(x) = tf.log(tf.sigmoid(x)) = -tf.nn.softplus(-x) を追加します。
  • フックリストを変更不能なタプルに変更しました。これで、関連する引数の任意の反復可能性が可能になりました。
  • TFDecorator を紹介します。
  • 音声機能の生成に Mfcc を追加しました。
  • 改善された DirectSession::Run() オーバーヘッドとエラーチェック。内部エラーを非同期的に発生させる代わりに、間違った型の値を入力すると INVALID_ARGUMENT エラーが同期的に発生するようになりました。間違った型のテンソルを与えるときの(未定義の)振る舞いに依存するコードを更新する必要があるかもしれません。
  • 還元されていない NONE を追加し、損失の MEAN オプションを減らしました。 他の縮小定数から "WEIGHTED_" 接頭辞を削除しました。
  • assertAllClose dicts を処理するようになりました。
  • HloInstructions 用の Gmock マッチャを追加しました。
  • 変数の復元時にエラーに var 名を追加します。
  • オーディオ機能生成用の AudioSpectrogram を追加しました。
  • 損失の削減 arg を追加しました。
  • tf.placeholder は、スカラー形状を表すことができ、部分的に知られています。
  • estimator_spec(mode) 引数を削除してください。
  • オーディオ機能生成用の AudioSpectrogram を追加しました。
  • TensorBoard は、40回以上実行されている場合、デフォルトですべての実行を無効にします。
  • 古いドキュメント生成コードを削除しました。
  • GCS ファイルシステムの統合で、ドメインバケット( gs://bucket.domain.com/path など )がサポートされるようになりました。
  • テキストを TensorBoard に出力するための tf.summary.text を追加します。
  • tfdbg のコマンドラインインターフェースの "run" コマンドは、ノード名、opタイプ、およびテンソルdtypeによるテンソルのフィルタリングをサポートするようになりました。
  • tf.string_to_numberint64 float64 の出力をサポートするようになりました。

 

貢献に対する謝辞


このリリースには、Googleの多くの人々の貢献が含まれていますのでここに感謝の意を表します:

4F2E4A2E, Aaron Schumacher, Abhi Agg, admcrae, Adriano Carmezim, Adrià Arrufat, agramesh1, Akimitsu Seo, Alan Mosca, Alex Egg, Alex Rothberg, Alexander Heinecke, Alexander Matyasko, Alexandr Baranezky, Alexandre Caulier, Ali Siddiqui, Anand Venkat, Andrew Hundt, Androbin, Anmol Sharma, Arie, Arno Leist, Arron Cao, AuréLien Geron, Bairen Yi, Beomsu Kim, Carl Thomé, cfperez, Changming Sun, Corey Wharton, critiqjo, Dalei Li, Daniel Rasmussen, Daniel Trebbien, DaríO Hereñú, David Eng, David Norman, David Y. Zhang, Davy Song, ddurham2, Deepak Subburam, Dmytro Kyrychuk, Dominic Rossi, Dominik SchlöSser, Dustin Tran, Eduardo Pinho, Egil Martinsson, Elliot Saba, Eric Bigelow, Erik Smistad, Evan Klitzke, Fabrizio Milo, Falcon Dai, Fei Gao, FloopCZ, Fung Lam, Gautam, GBLin5566, Greg Peatfield, Gu Wang, Guenther Schmuelling, Hans Pabst, Harun Gunaydin, Huaizheng, Ido Shamay, Ikaro Silva, Ilya Edrenkin, Immexxx, James Mishra, Jamie Cooke, Jay Young, Jayaram Bobba, Jianfei Wang, jinghua2, Joey Meyer, John Maidens, Jonghoon Jin, Julian Villella, Jun Kim, Jun Shi, Junwei Pan, jyegerlehner, Karan Desai, Karel Van De Plassche, Kb Sriram, KhabarlakKonstantin, Koan-Sin Tan, krivard, Kwotsin, Leandro Gracia Gil, Li Chen, Liangliang He, Louie Helm, lspvic, Luiz Henrique Soares, LáSzló Csomor, Mark Wong, Mathew Wicks, Matthew Rahtz, Maxwell Paul Brickner, Michael Hofmann, Miguel Flores Ruiz De Eguino, MikeTam1021, Mortada Mehyar, Mycosynth, Namnamseo, Nate Harada, Neven Miculinic, Nghia Tran, Nick Lyu, Niranjan Hasabnis, Nishidha, Oleksii Kuchaiev, Oyesh Mann Singh, Panmari, Patrick, Paul Van Eck, Piyush Chaudhary, Quim Llimona, Raingo, Richard Davies, Ruben Vereecken, Sahit Chintalapudi, Sam Abrahams, Santiago Castro, Scott Sievert, Sean O'Keefe, Sebastian Schlecht, Shane, Shubhankar Deshpande, Spencer Schaber, Sunyeop Lee, t13m, td2014, Thomas H. P. Andersen, Toby Petty, Umang Mehta, Vadim Markovtsev, Valentin Iovene, Vincent Zhao, Vit Stepanovs, Vivek Rane, Vu Pham, wannabesrevenge, weipingpku, wuhaixutab, wydwww, Xiang Gao, Xiaolin Lin, xiaoyaozhuzi, Yaroslav Bulatov, Yi Liu, Yoshihiro Sugi, Yuan (Terry) Tang, Yuming Wang, Yuxin Wu, Zader Zheng, Zhaojun Zhang, zhengjiajin, ZhipengShen, Ziming Dong, zjj2wry

私たちは、問題提起し、解決するのを助け、質問し、質問に答えたすべての人にも感謝しています。


--------
ここまで。

やはりというか、RNN系のサンプルはまた影響を受ける..というか戻すとかいうのは..正直「えっ」となってしまうよねえ..

このあたりのいじりが多いのは、テキスト操作系のディープラーニングをGoogleが頑張っていると読んで良いのだろうか..

1.2.0 で keras がとりこまれることは DevSummit の動画で知っていた。たしかあのときは tf.keras だったのだけど、 tf.contrib.keras ?まさかまた正式ライブラリとして tf.keras 昇格なんてないだろうな..


2017年6月12日月曜日

PROXY環境下でRedmine/Jenkins/RocketChatをdocker-composeで管理する

表題の環境を作ったので、ブログにも残しておきます。

docker/docker-composeが使用可能なアカウントが読み書きできる適当なディレクトリで、以下のような docker-compose.yml ファイルを作成します。

version: '2'

services:

  jenkins:
    image: jenkins:latest
    restart: unless-stopped
    volumes:
      - ./data/jenkins:/var/jenkins_home
    ports:
      - 3002:8080
      - 50000:50000
    environment:
      - TZ=Asia/Tokyo
      - HTTP_PROXY=http://your.proxy.server:8080
      - HTTPS_PROXY=http://your.proxy.server:8080

  redmine:
    image: redmine:latest
    restart: unless-stopped
    volumes:
      - ./data/redmine:/usr/src/redmine/files
    ports:
      - 3001:3000
    environment:
      - REDMINE_DB_MYSQL=mariadb
      - REDMINE_DB_PASSWORD=admin123
      - TZ=Asia/Tokyo
      - HTTP_PROXY=http://your.proxy.server:8080
      - HTTPS_PROXY=http://your.proxy.server:8080
    depends_on:
      - mariadb

  mariadb:
    image: mariadb:latest
    restart: unless-stopped
    volumes:
      - ./data/mariadb/conf:/etc/mysql/conf.d
      - ./data/mariadb/data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=admin123
      - MYSQL_DATABASE=redmine
      - TZ=Asia/Tokyo

  rocketchat:
    image: rocketchat/rocket.chat:latest
    restart: unless-stopped
    volumes:
      - ./data/rocketchat:/app/uploads
    ports:
      - 3000:3000
    environment:
      - PORT=3000
      - ROOT_URL=http://your.host.fqdn:3000
      - MONGO_URL=mongodb://mongo:27017/rocketchat
      - MONGO_OPLOG_URL=mongodb://mongo:27017/local
      - MAIL_URL=smtp://127.0.0.11
      - TZ=Asia/Tokyo
    depends_on:
      - mongo
    labels:
      - "traefik.backend=rocketchat"
      - "traefik.frontend.rule=Host: your.domain"

  mongo:
    image: mongo:3.2
    restart: unless-stopped
    volumes:
     - ./data/mongo/db:/data/db
     - ./data/mongo/dump:/dump
    command: mongod --smallfiles --oplogSize 128 --replSet rs0
    labels:
      - "traefik.enable=false"

  mongo-init-replica:
    image: mongo:3.2
    command: 'mongo mongo/rocketchat --eval "rs.initiate({ _id: ''rs0'', members: [ { _id: 0, host: ''localhost:27017'' } ]})"'
    depends_on:
      - mongo

ポートは3000~3002へ変更していますが、このあたりは各自で適当に振り替えてください。

RocketChatの http://your.host.fqdn:3000 はホスト側のFQDNに変更してください。
また your.proxy.server:8080 も環境に合わせて変更してください。

imageのタグ"latest"はそれぞれバージョンを指定してあげたほうが良いと思います。
なお Jenkins は自分でバージョンを上げる機能があるので、latestでも良いかもしれません(新バージョンが出てくるとトップにメッセージが出て、リンクを踏むと更新できるようになっている)。

起動するにはまず docker-compose.ymlが存在するディレクトリ上に data ディレクトリを作成します。
CentOSでSELINUX=enforcingしている場合は

chcon -Rt svirt_sandbox_file_t ./data

を実行しておいてください。
またfirewalldenableにしたまま運用する場合、firewall-cmdでポートを使えるように設定しておいてください。

firewall-cmd --zone=public --add-port=3000/tcp --permanent
firewall-cmd --zone=public --add-port=3001/tcp --permanent
firewall-cmd --zone=public --add-port=3002/tcp --permanent
firewall-cmd --reload



最初に起動する場合だけ

docker-compose up -d

でうごかします。 up は、イメージのダウンロードから起動までおこないます。
ただし Jenkins は、初回の起動時のみログ上に初回パスワードが表示されます。
なので

docker-compose logs jenkins

を実行してパスワードを確認してください。
最後のjenkins部分をdocker-compose.yml上のほかのコンテナ名(redmine, mariadb, rocketchat, mongo)にすることで、それぞれのログを参照できます。


コンテナの状態確認は

doker-compose ps

です。動作中かどうか確認できます。
mongo-init-replicaはレプリカなのでExitしているのが正常です。

全部一気に起動・停止させる場合は

docker-compose start
docker-compose stop

でおこないます。今回はrestart指定をunless-stoppedにしているので、上記のstopをかけずにOSのrebootを行うと、自動でコンテナも再起動します。


個別コンテナの起動・停止・再起動は、logs同様最後にdocker-compose.yml上のコンテナ名を最後に指定します。

docker-compose start redmine
docker-compose stop redmine
docker-compose restart redmine

redminedepend_onmariadbも指定しているのでstart時にmariadbが起動していなければ一緒に起動しますが、stop時はmariadbを落としません。

redmineのマイナーバージョンを3.3.1から3.3.2にしたい場合は、一旦redmineだけ停止し、docker-compose.ymlimageラストのタグを3.3.2に変えてから以下のコマンドを実行します。

docker-compose rm redmine
docker-compose up -d redmine

mariadb上のオブジェクト構成をマイナーバージョンで変えていなければ正常にバージョンアップが可能になります。

redmineのプラグインをインストールするためにログインしたい場合は、以下のコマンドで入ることができます。

docker-compose exec redmine /bin/bash

どうもredmine(、jenkins、rocketchatも,)コンテナはUbuntu/apt構成なのでaptしたり、curlしたりする場合は、それぞれのプロクシ設定を行う必要があります

Jenkins のプラグインは初期設定指示のプロクシ指定さえ正しく行えていれば、execする必要なく実行できます。


バックアップは、docker-compose.ymlの存在するディレクトリ上に backup をつくっておいて
以下のようなスクリプトをcrontabなどに仕込んでおけば1日分の復元は可能です。

#!/bin/sh
TAR=/usr/bin/tar
COMPOSE=/usr/local/bin/docker-compose
RSYNC=/usr/bin/rsync
# docker-compose.ymlのあるディレクトリフルパス
CONTAINERS_HOME=hogehoge
# rsync server config
RSYNC_SERVER=your.rsync.server
RSYNC_TARGET=your_rsync_server_target
#
# operations
#
cd ${HOGEHOGE}
${COMPOSE} stop
${TAR} cvfz ./backup/data.tar.gz ./data
${COMPOSE} start
#${RSYNC} -avz --delete ${CONTAINERS_HOME}/backup/ ${RDYNC_SERVER}:${RSYNC_TARGET}

上記スクリプトではrsyncで移動させていますが、別途rsyncサーバが必要なのでコメント化してあります。

当然、タグをlatestにしていて、復元時にメジャーバージョンアップされてしまうと戻せなくなったりするので注意してください。





おそらく、Redmine、Jenkins、rocketChatなどのアジャイル開発3種の神器はdocker-composeで上げ下げ・rysncでバックアップが正解なきがしています。

なので、PMOのおじさんたちはdocker/docker-composeはしっかり覚えて欲しいところですねえ..

2017年6月9日金曜日

Official なredmineイメージをdocker-composeしたらデフォルト設定ロード時にエラーになる


Docker HubにRedmineのofficialイメージがある。
これを使ってDocker CE(17.03)上でコンテナをあげようとしたのだけど、うまく行かなかった。


Official Repository redmine
https://hub.docker.com/_/redmine/

ここのREADME.md上にdocker-compose.yml

version: '2'

services:

  redmine:
    image: redmine
    ports:
      - 8080:3000
    environment:
      REDMINE_DB_MYSQL: db
      REDMINE_DB_PASSWORD: example
    depends_on:
      - db
    restart: always

  db:
    image: mariadb
    environment:
      MYSQL_ROOT_PASSWORD: example
      MYSQL_DATABASE: redmine
    restart: always

と書かれているので、既にjenkins(tomcat)で使ってる
8080のところを3000にして動かそうとしたら..

redmine コンテナがやたらRestartを繰り返すのだ。


で、docker-compose logs redmine したら
gem失敗していることに気づく。

どうも、proxyが引けないらしい..

ということでdocker-compose.yml上の environment: に
環境変数 HTTP_PROXY (と念のため HTTPS_PROXY)をセットした。

で、開こうとしたら..
http://redmine.. :3000/ から admin/admin でログインはできたのだけど、
管理画面の先頭に最初だけ出てくる日本語環境の「デフォルト設定のロード」ボタン
押すと

デフォルト設定がロードできませんでした: Mysql2::Error: Incorrect string value: '\xE7\xAE\xA1\xE7\x90\x86...'

なるメッセージが出てしまう..

これ..MySQL..じゃなく mariadb の文字コード設定の問題がでているらしい。

mariadbイメージ..official docker hubサイトを調べてみた。

Official Repository mariadb
https://hub.docker.com/_/mariadb/


残念ながら良さげな環境変数はなかった。
environmentを1行加えるだけという訳にはいかないらしい..

だが、ホスト側のcnfファイルを追加で読んでくれるconf.dexposeされているので
これを使った。

最終型のdocker-compose.ymlは大体以下のような感じ。

version: '2'

services:

  redmine:
    image: redmine:latest
    restart: unless-stopped
    volumes:
      - ./data/redmine:/usr/src/redmine/files
    ports:
      - 3001:3000
    environment:
      - REDMINE_DB_MYSQL=mariadb
      - REDMINE_DB_PASSWORD=example
      - HTTP_PROXY=http://your.proxy.server:8080
      - HTTPS_PROXY=http://your.proxy.server:8080
    depends_on:
      - mariadb

  mariadb:
    image: mariadb:latest
    restart: unless-stopped
    volumes:
      - ./data/mariadb/conf:/etc/mysql/conf.d
      - ./data/mariadb/data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=example
      - MYSQL_DATABASE=redmine

イメージのタグ、latest だと運用上マズイので、
本番ではキチンとバージョンを指定してやるようにしてください。

最初に docker-compose up する前に用意した
./data/mariadb/conf/server.cnf はホスト側のmariadbの本物(/etc/my.cnf.d/server.cnf)をつかったが、
たぶん

[mysqld]
character-set-server=utf8

だけでも大丈夫だとは思う。試してないけど...


運用上restartalwaysより最後のdocker-compose stopが効くコッチがよかろうということで
unless-stoppedに変更している。

あとバックアップをdocker-compose stopして ./data
まるっとコピーするので、exposeされたvolumeは全部使った。

SELINUX=enforcing のままredmineを導入する場合は
念のため chcon -Rt svirt_sandbox_file_t ./data しておいたほうがいいだろう。



にしても..

ひさしぶりにdocker-compose使ったが..
相当手が入っているなあ..

裏でネットワーク用コンテナ上がるようになっていて
bridgeだのhostだのnullだの選択できるようになってる..

docker-compose.ymlファイルごとにIPアドレスが172.17.0.2やら172.20.0.2やら
ちょっとづつ変わる。

コンテナ側のリゾルバはみな127.0.0.11をさしていて
どうもこれがホスト側のDNSリソルバ設定につながっているらしい..

なのでホスト側IPアドレスのエイリアスアドレスなのかと
内部からホスト側を呼ぶときにコレを使おうとしたら
うまく行かなかった...

ホスト側のFQDNをキチンとDNSで登録するかhostを使えということらしい..

裏技として..かならず作成されるデフォルトbridgeのゲートウェイIP
172.17.0.1 をホスト側のIPとしてつかうことはできる..けど美しくない!


ホストサーバをFreeIPAとかでたてていて
DESSEC設定変えたくないばっかりに
FreeIPAにはフォワーダ指定なしにして
ホスト側のリゾルバにフォワーダだけ登録して抜けていたが
このせいでホスト側のDNSサーバのforwarderをセットしなくちゃならない羽目にあった..


Dockerは、ますます重くなっていくのだろうか...

これじゃVMwareやVirtualBoxとかわらなくなってきちまうよ..


2017年4月26日水曜日

AIで長文の要約ができないか調べてみる


長文のテキストを短い文で要約するところをAIでできないか調べてみたら
以下の記事を見つけた。

Text summarization with TensorFlow
https://research.googleblog.com/2016/08/text-summarization-with-tensorflow.html

以下、翻訳した文章である。
いつもどおり参照する人は At your own riskでお願いします。

-------

TensorFlowを使ったテキスト要約


  • 2016年8月24日水曜日
  • 投稿者:Peter Liu、Xin Pan (ソフトウェアエンジニア、Google Brain Team)



毎日、人々はニュースストーリからソーシャルメディアポスト、検索結果まで、さまざまな情報源に依存しています。より長いテキストの正確な要約を自動的に提供できる機械学習モデルの開発は、大量の情報を圧縮形式で消化するのに役立ち、 "Google Brainチーム":https://research.google.com/teams/brain/ の長期目標となっています。

要約は、機械の興味深い読解力テストとしても役立ちます。 要約すると、機械学習モデルは、特に文書の長さが増すにつれて、文書を理解し、重要な情報、コンピュータにとって非常に挑戦的な課題を抽出することが可能です。

この研究を推進するため、 "TensorFlowモデルコード":https://github.com/tensorflow/models/tree/master/textsum をオープンソース化し、要約研究でよく使用されるデータセットである  "Annotated English Gigaword":https://catalog.ldc.upenn.edu/LDC2012T21 でニュース見出しを生成する作業を行っています。 また、ドキュメントのハイパーパラメータは、執筆時点で最も一般的に使用されている "メトリック":https://en.wikipedia.org/wiki/ROUGE_(metric) について、公開されている最先端のものよりも優れていると規定しています。 以下では、モデルによって生成されたサンプルも提供します。


抽象的および抽象的要約


抽出および抽象的な要約要約に対する1つのアプローチは、あるメトリック(例えば、逆文書頻度)によって興味深いとみなされる文書の部分を抽出し、それらを結合して要約を形成することです。このフレーバのアルゴリズムは、抽出集計と呼ばれます。

要約に対する1つのアプローチは、あるメトリック(例えば、逆文書頻度)によって興味深いとみなされる文書の部分を抽出し、それらを結合して要約を形成することです。 このフレーバのアルゴリズムは、抽出集計 (Extractive Summary) と呼ばれます。


原文:


Alice and Bob took the train to visit the zoo. They saw a baby giraffe, a lion, and a flock of colorful tropical birds.


アリスとボブは列車に乗って動物園を訪れました。彼らは、赤ん坊のキリン、ライオン、カラフルな熱帯鳥の群れを見ました。



抽出集計 (Extractive Summary) :


Alice and Bob visit the zoo. saw a flock of birds.


アリスとボブが動物園を訪問する。鳥の群れを見た。



上記では、元のテキストに 太字の単語 を抽出し、それらを連結して要約を作成しています。読んでわかるように、抽象的な制約により要約が不自然になったり、文法的に奇妙になることがあります。これとは別のアプローチは、人間がするようなシンプルに要約することであり、これは抽出制約を課さず、再評価を可能にすることです。これは抽象要約 (Abstractive Summary) と呼ばれます。


抽象要約 (Abstractive Summary) :


Alice and Bob visited the zoo and saw animals and birds.


アリスとボブは動物園を訪れ、動物や鳥を見た。



この例では、原文にはない単語を使用して、同様の量の単語でより多くの情報を保持しています。 良い抽象要約 (Abstractive Summary) が好まれるのは明らかですが、どのようにすればアルゴリズムにこれを始めるさせることができるのでしょうか?


TensorFlow モデルについて

短いテキストでは、 Smart-Reply for Inbox と同様の Sequence-to-Sequence 学習 と呼ばれる Deep Learning 技術を使用して、要約を学ぶことができます。特に、このようなモデルを訓練して、ニュース記事の見出しを作成することができます。この場合、モデルは記事テキストを読み取り、適切な見出しを書きだします。

モデルがどのような要約を生成するかを知るためには、以下のいくつかの例を見てください。最初の列はモデル入力であるニュース記事の最初の文を示し、2番目の列はモデルが書いた見出しを示しています。


入力:第1文モデルが書いた見出し
metro-goldwyn-mayer reported a third-quarter net loss of dlrs 16 million due mainly to the effect of accounting rules adopted this year (メトロ・ゴールドウィン・メイヤーは、主に今年採用された会計規則の影響により、第3四半期の純損失は1,600万ドル) mgm reports 16 million net loss on higher revenue (mgmはより高い収入で1600万の純損失を報告)
starting from july 1, the island province of hainan in southern china will implement strict market access control on all incoming livestock and animal products to prevent the possible spread of epidemic diseases (7月1日から、南中国の海南島は、流入する家畜や動物製品の厳しい市場アクセス管理を実施し、流行病の拡大を防ぎます) hainan to curb spread of diseases ( 海南は病気の広がりを抑制する)
australian wine exports hit a record 52.1 million liters worth 260 million dollars (143 million us) in september, the government statistics office reported on monday (オーストラリアのワイン輸出は9月に2億6100万ドル(1億4,300万米ドル)相当の5億2,100万リットルを記録した。政府統計局月曜日報告)australian wine exports hit record high in september (オーストラリアのワイン輸出は9月の最高記録をヒット)


研究の将来


我々は、ニュース見出しの性質上、記事の始めからちょうど少数の文章を読むことによって、モデルが良い見出しを生成できることを観察しました。この作業は概念実証のためのものですが、良い要約を作成するためには文書全体を読む必要があるため、より難しいデータセットを検討し始めました。これらのタスクでは、このモデルアーキテクチャによるゼロからのトレーニングは、我々が研究している他の技術と同様に機能しませんが、ベースラインとして機能します。 今回のリリースは、要約研究における他者のベースラインとしても役立つことを願っています。

------

ようは、

  • Googleでも長文の要約は初めているよ
  • やりかたには以下の2つがあるよ
  • 興味深いとみなされる文書の部分を抽出、結合する(Extractive Summary)
  • Sequence-to-Sequence ベース(Abstractive Summary)
  • 実際のアウトプットを載せたから確認してね※文章として後者のほうがまとも
  • ニュース見出しコーパスだとだいたい最初にサマリ書くから精度はあがっちゃうよね
  • 将来的にはほかの長文コーパスで全文を使ってより要約分らしい文章を抽出するモデルを検討するよ

ということらしい。

Google検索すると日本の方でいくつか
要約アルゴリズムだとかWebのフォームで実際に試せるサービスとか
提供しているところもあるけど、
アルゴリズム公開している情報 を読むと
いまのところ
この記事で言う
Extractive Summary
ばっかりのようだ。

バズワードで言えば
機械学習だけど、ディープラーニングではないアルゴリズム
たとえばTF-IDFベースだとかを併用したやつとか

まあでも、それで精度が出るのならそれでも良いのだけど...


ニュース記事だけで学習しちゃうと
機械学習で最初の方にばっかりattentionされたモデルになりかねないわけか..

このへんは TOEIC の Phase7 を人間がどう解いていたかを
モデル化しないといけないわけだけど..
とすると最初にニュースなのか広告なのか報告なのかメールなのか
種類分けをCNNなりRNNなりでやる必要があるだろうなあ..

でもなあそれだとせっかく Sequence-to-Sequence してるのに
なんとなくアレか..

しっかし、Googleはほんとに Sequence-to-Sequence 好きだねえ..

2017年4月11日火曜日

Dockerのバージョンが17.xになり、Ubuntu Serverへのインストールがまたちょこっと変わった



ひさしぶりにDockerサイトへ行ったら
Dockerのバージョンがかわっていた..

しかも昔Solarisとかがやったマイナーバージョンを
メジャーバージョンに繰り上げしやがった。

で、
今後は毎月リリースするらしい。
今は2017年3月だから17.3.xで
今月のDockercon2017あたりで17.4がでるらしい..

しかも有料版を docker-ee
無料版を docker-ce
としてaptリポジトリ管理されるらしい..


たしかにもうaptyumのパッケージ管理つかってやらないと
混乱してしまうよ..こっちも..

インストールは簡単になった、
Ubuntu Serverでsudoユーザでログインして、

# sudo apt-get -y install \
  apt-transport-https \
  ca-certificates \
  curl


proxy環境は vi .curlrc -x オプション使って

# sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
# sudo apt-get update
# sudo apt-get -y install docker-ce
# sudo systemctl enable docker

sudoなしでdocker操作したいなら、

# sudo usermod -aG docker $USER
してから再ログインする。


Proxy環境の場合は

# sudo mkdir -p /etc/systemd/system/docker.service.d
# sudo vi /etc/systemd/system/docker.service.d/http-proxy.conf


[Service]
Environment="HTTP_PROXY=http://proxy.example.com:80/" "HTTPS_PROXY=http://proxy.example.com:80/" "NO_PROXY=localhost,127.0.0.1,"

# sudo systemctl daemon-reload

でOK。



でも、中身はあんまかわってなさそう..


有料版は
ノード別月額料金で
$75(CEのCertified版?)、
$120(DCサポート-イメージセキュリティスキャン)、
$200(DCサポート、イメージセキュリティスキャン有り
というケレン味もきっちりはいってる。

セキュリティ恐怖症の企業を狙い撃ちだ...


あたらしく
Docker Store
https://store.docker.com/
なるマーケットプレイスが立ち上がっていて
MSのイメージなんかもふくめDocker Certifiedイメージが..

ひょっとしたらofficalイメージはStoreで有料になったりするかもね..
Linuxは別として..

2017年4月10日月曜日

Hubot Document: Patterns を翻訳して、チャットボットでありがちな実装を確認する

Hubot Document: Scripting
https://hubot.github.com/docs/scripting/
を読めばHubot上で動作するチャットボットの書き方がわかるとおもい
前回の記事で翻訳してみた。

が、よくあるパターンサンプル集もあるとうれしい..

ということで
Hubot Documentation: Patterns
https://hubot.github.com/docs/patterns/
も引き続き翻訳してみた。



参照する場合は at your own risk でお願いします。
----------

Hubot Documentation: Patterns




一般的な Hubot 活用シナリオを扱うためのパターンを共有します。

Hubot インスタンスのリネーム


Hubot の名前を変更すると、元の名前に反応しなくなります。 ユーザに新しい名前を慣れさせるために、古い名前への発言に非推奨通知を追加することを選択できます。 パターンロジックは次のとおりです;

  • 古い名前で始まるすべてのメッセージをlisten
  • ユーザにreplyして、新しい名前について知らせる

この設定はとても簡単です:

  1. Hubot インスタンスの scripts/ ディレクトリに rename-hubot.coffee という バンドルされたスクリプトを作成
  2. 必要に応じて変更された次のコードを追加:
# Description:
#   Tell people hubot's new name if they use the old one
#
# Commands:
#   None
#
module.exports = (robot) ->
  robot.hear /^hubot:? (.+)/i, (res) ->
    response = "Sorry, I'm a diva and only respond to #{robot.name}"
    response += " or #{robot.alias}" if robot.alias
    res.reply response
    return


上記のパターンでは、ニーズに合わせて hubot リスナと応答メッセージの両方を変更します。

また、リスナは Hubot アダプタが処理する前にチャットプログラムに入力されたものではなく、実際に聞こえるものに基づいている必要があることに注意することが重要です。 たとえば、"HipChat アダプタ" は @hubothubot: に変換してから Hubot に渡します。


非推奨リスナまたは改名されたリスナ


スクリプトを削除したり、スクリプトのコマンドを変更した際に、変更内容をユーザに知らせることができます。 1つの方法は、チャットでそれらを伝えること、またはもはや存在しないコマンドを使用することによって変更を検出させることです。 別の方法は、Hubot に動作しないコマンドを使用したときに知らせることです。

このパターンは、上記の Hubot インスタンスパターンの名前変更に似ています:

  • 古いコマンドと一致するすべてのメッセージをlisten
  • ユーザに reply して、そのユーザが非推奨になったことを知らせる

セットアップ方法はこちら:

  1. deprecations.coffee という Hubot インスタンスの scripts/ ディレクトリにバンドルされたスクリプトを作成します
  2. 古いコマンドリスナをコピして、そのファイルに追加します。たとえば、何らかの理由で help コマンドの名前を変更する場合は、次のようにします:
# Description:
#   Tell users when they have used commands that are deprecated or renamed
#
# Commands:
#   None
#
module.exports = (robot) ->
  robot.respond /help\s*(.*)?$/i, (res) ->
    res.reply "That means nothing to me anymore. Perhaps you meant `docs` instead?"
    return


Proxy経由による HTTPリスエストのフォワーディング


多くの企業環境では、インターネットおよび/または保護されたリソースにアクセスするためにWeb Proxy が必要です。 一回限りの制御の場合、 robot.http で使用する "Agent" を指定できます。 しかし、これでは、ロボットが Proxy を指すために使用するすべてのスクリプトを変更する必要があります。 代わりに、グローバルレベルでAgentを指定し、デフォルトですべてのHTTP要求にAgentを使用させることができます。

node.jsによるHTTP要求とHTTPS要求に対する処理方法のために、プロトコルごとに異なるAgentを指定する必要があります。 ScopedHTTPClient は自動的に、各要求に対して正しい ProxyAgent を選択します。

  1. ProxyAgent をインストールします npm install proxy-agent
    Hubotインスタンス上の scripts/ ディレクトリに proxy.coffee と呼ばれる バンドルスクリプト を作成します
  2. 必要に応じて変更された次のコードを追加します:
proxy = require 'proxy-agent'
module.exports = (robot) ->
  robot.globalHttpOptions.httpAgent  = proxy('http://my-proxy-server.internal', false)
  robot.globalHttpOptions.httpsAgent = proxy('http://my-proxy-server.internal', true)


メッセージの動的マッチング


状況によっては、異なるメッセージ(例えば、factoids、JIRAプロジェクトなど)を動的に一致させたい場合があります。 常に一致する広範な正規表現を定義するのではなく、特定の条件が満たされたときだけ Hubot に一致するように指示することができます。

シンプルなロボットでは、これはListenerコールバックに条件を入れることとあまり変わりませんが、ミドルウェアを扱うときに大きな違いがあります。基本モデルでは、汎用正規表現の一致ごとにミドルウェアが実行されます 。 動的整合モデルでは、動的条件が一致した場合にのみミドルウェアが実行されます。

例えば、factoids ルックアップコマンドは次のように再実装できます:
module.exports = (robot) ->
  # Dynamically populated list of factoids
  facts =
    fact1: 'stuff'
    fact2: 'other stuff'

  robot.listen(
    # Matcher
    (message) ->
      match = message.match(/^~(.*)$/)
      # Only match if there is a matching factoid
      if match and match[1] in facts
        match[1]
      else
        false
    # Callback
    (response) ->
      fact = response.match
      res.reply "#{fact} is #{facts[fact]}"
  )



コマンドへのアクセス制限


Hubot のすばらしい機能の1つは、単一のチャットメッセージを使用して本番環境に変更を加える能力です。 ただし、チャットサービスにアクセスできる人は誰もが、プロダクションの変更を引き起こすことはできません。

特定のニーズに応じてアクセスを制限するさまざまなパターンがあります:

  • アクセスの2つのバケット:フルリストとホワイトリスト/ブラックリストで制限付き
  • すべてのコマンド(ロールベースのアクセス制御)に対する特定のアクセスルール
  • 特定の部屋のブラックリスト/ホワイトリストのコマンド

単純なリスナごとのアクセス


一部の組織では、ほぼすべての従業員に同じレベルのアクセス権が与えられており、限られた少数のユーザ(たとえば、新規採用者、請負業者など)のみが制限されています。 このモデルでは、すべてのリスナのセットを分割して、「通常のコマンド」から「パワーコマンド」を分離します。

リスナを分離したら、ホワイトリスト/ブラックリストのユーザとリスナの間でいくつかのトレードオフの決定をする必要があります。

ホワイトリスト作成とブラックリスト登録の重要な決定要素は、各カテゴリのユーザ数、どちらのカテゴリの変更頻度、組織が受け入れるセキュリティリスクのレベルです。

  • ユーザをホワイトリストに登録すると(ユーザX、Y、Zはパワーコマンドにアクセスでき、他のすべてのユーザは通常のコマンドにのみアクセスできます)、より安全なアクセス方法です(新しいユーザはパワーコマンドにデフォルトでアクセスできません) 新しい各ユーザを「承認済み」リストに追加する必要があります)。
  • ユーザをブラックリストに登録すると(ブラックリストに追加されるまで、新しいユーザは電源コマンドにデフォルトでアクセスできます)、ユーザをブラックリストに登録する(すべてのユーザは電源コマンドにアクセスできますが、通常のコマンドにしかアクセスできないユーザX、Y、Zは除きます) ブラックリストが小規模/めったに更新されていない場合はメンテナンスオーバーヘッドが大幅に低くなります。

リスナを選択的に許可するかどうかを決定する重要な要因は、各カテゴリのリスナ数、内部スクリプトと外部スクリプトの比率、組織が受け入れるセキュリティリスクのレベルです。

  • すべてのリスナは通常のコマンドと見なされるリスナA、B、Cを除いてすべてのリスナを選択的に許可しますが、新しいリスナはデフォルトで制限されています (おバカな/遊びのためのリスナは明示的に「通常」の状態にダウングレードする必要があります)。
  • リスナを選択的に制限する(リスナA、B、Cはパワーコマンドですが、それ以外のコマンドはすべて通常のコマンドです)、セキュリティ保護されていない方法です(新しいリスナはデフォルトで通常のカテゴリに入れられます 。保守オーバヘッドは低くなります(アクセスポリシのすべての遊びのための/文化的なスクリプトを変更/列挙する必要はありません)。

追加の考慮事項として、ほとんどのスクリプトは現在リスナIDを持っていないので、リスナIDを追加するために使用する外部スクリプトをPR(またはfork)する必要があります。 実際の変更は簡単ですが、多くのメンテナと調整することは時間がかかることがあります。

可能な4つのモデルのうちどれを選択するかを決めたら、承認ミドルウェアに接続するための適切なユーザとリスナのリストを作成する必要があります。

例:選択的に制限されたパワーコマンドにアクセスできるユーザのホワイトリスト
POWER_COMMANDS = [
  'deploy.web' # String that matches the listener ID
]

POWER_USERS = [
  'jdoe' # String that matches the user ID set by the adapter
]

module.exports = (robot) ->
  robot.listenerMiddleware (context, next, done) ->
    if context.listener.options.id in POWER_COMMANDS
      if context.response.message.user.id in POWER_USERS
        # User is allowed access to this command
        next()
      else
        # Restricted command, but user isn't in whitelist
        context.response.reply "I'm sorry, @#{context.response.message.user.name}, but you don't have access to do that."
        done()
    else
      # This is not a restricted command; allow everyone
      next()

ミドルウェアは、特定のメッセージ( robot.hear /.+/ を含む) に一致するすべてのリスナに対して実行されるので、リスナを分類するときにそれらを含めるようにしてください。


リスナごとの特定のアクセスルール


大規模な組織では、通常、アクセスのバイナリ分類が不十分で、より複雑なアクセスルールが必要です。

アクセスポリシの例:

  • 各開発チームは、リリースをカットしてサービスを展開することができます
  • Operations グループは、すべてのサービスを展開するためのアクセス権を持っています(ただし、カットリリースではありません)
  • フロントデスクはリリースをカットしたり、サービスを展開することはできません

このような複雑なポリシは現在、コードで直接実装するのが最善ですが、アクセス管理のための一般化されたフレームワークを構築するための "継続的な作業" があります。


ルームごとの特定のアクセスルール


さまざまな目的を果たす多数のチャットルームを持つ組織では、同一の hubot インスタンスを使用できるようにすることがしばしばですが、各ルームで異なるコマンドセットを使用できます。

一般化されたブラックリストソリューションに関する作業が 進行中 です。 ホワイトリストのソリューションも同様のアプローチをとることができます。

以上
----------

想像していたのは、もっとアプリアプリしてるサンプルコードだったのだけど..

Proxy経由でのアクセス方法があったから、
まあ
よしとしようか..



udemy のAI入門とTensorFlow入門を試してみた

AIブームというけれど、 それを使いこなすプログラマを育成する道具が あまり揃っていない。 全員が全員、 TensorFlow のページをGoogle翻訳でゴリゴリ読むなんて 正直無理だ。 ド素人とまでは言わないが、 数年の経験をもつプログラマに使いこなしても...