ほろ酔い開発日誌

AI企業のエンジニアのブログです。機械学習、Web開発の技術的お話、ビジネスチックなお話、日常のお役立ち情報など雑多な内容でお送りします。

エンジニアの記事のアウトプット先はどこがいい?(Qiita/note/blog)

はじめに

普段から記事を書くことは多いのですが、アウトプット先を複数抱えており、投稿先を自分の中で整理したいと思いました。結論として少し冬眠していたこのblogをアクティブにしようとする宣言の意味も大きいのですが、それと同時にアウトプット先について考えたこともまとめておこうというのがこの記事の趣旨です。

エンジニアが記事を書くことについて

最近では、エンジニアは積極的にアウトプットしたほうがいいという論調の文章を見かける機会も増えたような気もしますし、Youtuberをはじめとしたインフルエンサーの波をエンジニアも受けたのか、文章としてのアウトプットにとどまらず、動画の配信やインフルエンサー化する方もいらっしゃいます。私自身、3、4年くらい各所で記事を公開していまして、QiitaのContributionも現段階で7000を超えています。それによって、恩恵を受けるところもあり、アウトプットをすることはよいという立場にいます。最近はnoteでも記事を書いてみて、思うところもあり、blogに戻ってきたというところです。

続きを読む

Rails5.0.0.1からRails5.1.5へのアップデート

はじめに

Railsのプロジェクトのアップデートをしたのでそのときのメモをしておきます。 利用しているGem等に大きくよると思いますが、アップデートの際の参考にはなるかもしれません。

環境: MacOS Sierra

Rubyのアップデート

Rubyのバージョンも2.4.1から2.5.0へバージョンアップしました。 rbenvを使っています。

続きを読む

GoodfellowさんのGANのオススメ論文10選まとめ (2018/02)

GANの作者のGoodfellowさんがおすすめの10論文を教えていたので、みてみます。

()内はGoodfellowさんのコメント。基本的には最新の論文をすすめるということでICLR2018のオーラル論文等最新のが多め。

1. Progressive GANs

[1710.10196] Progressive Growing of GANs for Improved Quality, Stability, and Variation

(probably the highest quality images so far)

ICLR2018のオーラルに採択された論文。 高解像度の画像の生成において、段々と出力画像のサイズを大きくしていく方法を使っている。1つのGeneratorの中でlayerを少しずつ追加して学習を重ねていく。

イントロ含めてGANの流れもすごく置いやすくて読み物としてもいいので、参考論文追うと良さそう。

なんか低解像度から高解像度みたいなことをするといい結果が得られるよっていうのが結構あったりとかするけど、それをlayerひとつひとつ追加して行うという方法でまあ確かにそこまでやれば精度上がりそうという印象は受けた。

2. Spectral normalization

Spectral Normalization for Generative Adversarial Networks | OpenReview

(got GANs working on lots of classes, which has been hard)

こちらもICLR2018のオーラル論文より。Lipschitzs制約を使ってGANの学習を安定化させる。GANの学習の安定は重要な点のひとつなので大事かと。個人的にはLipschizs制約まわりはちゃんと勉強しなきゃな、、と思う次第です。

参考

Spectral Normalization for Generative Adversarial Networks · Issue #388 · arXivTimes/arXivTimes · GitHub

続きを読む

Reactで 開発開始まで

以前、Reactの勉強のために以下のようなデモを作ったのですが、Reactのスタートをコピペベースで出来るようにメモしておきます。

github.com

ここではこちらを参考にセットアップしていきます。

qiita.com

npmの用意

適当なディレクトリを用意します(今回は stackyという名前にしました)。

$ mkdir stacky

念のため、npm をupdateして、initします。

$ npm update -g npm
$ npm init
(適当に答える、-yで初期設定をスキップ出来る)
$ ls
package.json

babel

babelのインストー

babel関連。babelはコンパイラ。ES6等のソースコードを一般的なブラウザに対応出来るようにES5にコンパイルする。

$ npm i -D babel-core babel-loader babel-preset-es2015 babel-preset-react

babelの設定

$ vi .babelrc

以下をコピペ。

require('babel-core/register');
module.exports = require('./development');

webpack

webpack。webappのビルドツール。Grunt とか Gulp とかが有名らしいが自分で定義していかないといけないのに対し、webpackは簡単な設定ファイルを書くだけで良いので楽。Browserifyという似たようなやつもいるらし。また、Grunt/Gulpと組み合わせることもあると。

参考:

qiita.com

webpack関連のインストー

$ npm i -D webpack webpack-dev-server html-webpack-plugin
$ vi webpack.config.js

webpackの設定

以下の設定を webpack.config.js にコピペ。

require('babel-core/register');
module.exports = require('./development');

development.jsをコピペ。

import path from 'path';
import HtmlWebpackPlugin from 'html-webpack-plugin';

const src  = path.resolve(__dirname, 'src');
const dist = path.resolve(__dirname, 'dist');

export default {
  entry: src + '/index.js',
  output: {
    path: dist,
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      }
    ]
  },
  resolve: {
    extensions: ['*', '.js']
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: src + '/index.html',
      filename: 'index.html'
    })
  ]
};

表示indexの用意

$ vi src/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>React Test</title>
  </head>
  <body>
    <div id="app" />
  </body>
</html>

Reactの用意

$ npm i -S react react-dom
$ vi src/index.js
import React, {Component} from 'react';
import {render} from 'react-dom';

class App extends Component {
  render () {
    return <p> Hello React!</p>;
  }
}

render(<App/>, document.getElementById('app'));

コンパイルと起動

$ ./node_modules/.bin/webpack
$ npm start

簡単なデモ

src/index.jsを以下のようにアップデート。

import React, {Component} from 'react';
import {render} from 'react-dom';

class Name extends Component {
  render () {
    const name = this.props.name;

    return <span>{ name }</span>
  }
}

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      name: ''
    }
  }

  render () {
    const name = this.state.name;

    return (
      <div>
        <h1>Hello, <Name name={ name } />.</h1>
        <input
          type='text'
          value={ name }
          onChange={ e => {
            this.setState({
              name: e.target.value
            })
          }}
        />
      </div>
    );
  }
}

render(<App/>, document.getElementById('app'));

Java 配列部分型 ( ArrayStoreException )

普段、Javaはあまり使わないほうですがJavaの型について学んだことがあったのでメモします。(触れるのはJavaですが、型の問題としては一般に関わる話です。)

BがAの部分型であるときにBの配列をAの配列の部分型にしてよいか

ということに関してです。

前提として、JavaはBがAを継承するとき、BがAの部分型といえます。 コードベースで説明します。

具体例

まず、Shape とそれを継承する Circle というclassを用意します。

public class Shape {
  public String name() { return "Shape"; }
}
public class Circle extends Shape {
  public String name() { return "Circle"; }
  public String check() { return "OK!"; }
}

このとき、 CircleShape を継承しており、 CircleShape の部分型となります。

部分型であるので以下のような代入が許容されます。

Shape s = new Circle();

Bの配列がAの配列の部分型であることを許容するとき、以下のような代入を許容するということです。

Shape[] arr_s = new Circle[1];

さて、以下のコードはその配列の部分型を許容したコードです。

public class CheckArray {

  public static void main(String[] args) {
    Shape shape = new Shape();
    Circle [] arr_circle = new Circle[1];
    Shape [] arr_shape = arr_circle;
    arr_shape[0] = shape;
    Circle circle = arr_circle[0];
    System.out.println(circle.check());
  }

}

このコードは問題が起きており、配列の部分型を許容したことで、最後の circleShapeのオブジェクトで、checkというメソッドがありません。

それにも関わらず、実際のコンパイル時にはエラーが起こりません。 代わりに実行時には ArrayStoreException というエラーが起こります。

本来であればコンパイル時でエラーを出したいところですが、Javaはこのミスに対処しておらず実行時にエラーを出すようにしたのだそうです。 ちなみに これに似たArrayList というやつはコンパイル時にちゃんとエラーを出してくれるようです。

まとめ

  • Javaコンパイル時に配列の部分型を許容してしまっているが本来はコンパイル時にエラーを出すべき。
  • Javaはその代わりに ArrayStoreException というエラーを実行時に出す。

悩ましくも面白い話だと思いました。

Google Formで回答を受けたらSlackに通知する (Google Apps Script)

やったこと

タイトル通り、Google Formで回答を受け付けたらそれをSlackに通知します。 大体の手順は以下のような感じ。

  1. Google FormでFormの用意。また、回答をSpreadSheetに出すようにしておく。
  2. Slackのincoming webhookの用意をする。
  3. Google Apps Scriptを書く。

これだけ。以下の記事を見つけたのでこの記事に沿ってやりました。基本はこれを見て下さい。スクリプトの箇所はちょっと変えたので記録しておきます。あとその他説明。

chezou.hatenablog.com

スクリプト説明

スクリプト

最初に最終型を出します。 url とかチャンネルは変えて下さい。

function sendToSlack(body, channel) {
  var url = "https://hooks.slack.com/services/hogehoge/pogepoge";
  var data = { "channel" : channel, "username" : "form-notification", "text" : body, "icon_emoji" : ":turtle:" };
  var payload = JSON.stringify(data);
  var options = {
    "method" : "POST",
    "contentType" : "application/json",
    "payload" : payload
  };
  var response = UrlFetchApp.fetch(url, options);
}

function test() {
  var body = "test message by notification bot\n";
  sendToSlack(body, "#notification");
}

function onFormSubmit(e){
  var name = e.namedValues["氏名"]
  var body = name + "さんからの回答";
  sendToSlack(body, "#notification");
}

説明

はじめ紹介した記事の e.response.getItemResponses() の箇所でなぜかエラーが出てしまいました。undefined 的なことを言われました。それでデバックすると e の中に response がいないんですよね。

Documentには response があるっぽいのですけど。。

Event Objects  |  Apps Script  |  Google Developers

よくわからないですけど e の中にいないものはしょうがないです。 e をデバックしたら中身に namedValues というのがいたのでこれを使いました。カラム名をキーにすると値がとれます。

実行エラー等は「表示」->「実行トランスクリプト」で見れました。 あとは Logger.log('test 内容'); とかを使って、「表示」->「ログ」でデバック出来ました。

ちなみに、最初に紹介した記事でやっていることは response オブジェクトを利用して値を取り出しているのですが、以下で説明がありました。

Class FormResponse  |  Apps Script  |  Google Developers

form全体のオブジェクトをループさせるのはいいのですが、1行に対応するオブジェクトをループさせるのはちょっと気持ちわるい感がありました。

ひとまず namedValues で短く書けるし結果オーライでした。

おわりに

他の記事もあたりましたが、 e.response.getItemResponses() のエラーの記事はちょくちょくありました。 namedValues で出来たという備忘録として残します。

Tensorflow run() vs eval() と InteractiveSession() vs Session()

はじめに

Tensorflowを使う際にコードによって若干の違いが見られたのでその点を理解しておきたいと思います。

  • run() と eval()
  • InteractiveSession() と Session()

この2点に違いについて説明します。

run() vs eval()

例えば、以下のような簡単なMLPの実装の一部を見て下さい。

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=t, logits=h_fc))
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(cost)
correct_prediction = tf.equal(tf.argmax(h_fc, 1), tf.argmax(t, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

sess = tf.InteractiveSession()
init = tf.global_variables_initializer()
sess.run(init)

n_epochs = 10
batch_size = 100
n_batches = train_X.shape[0] // batch_size
train_X, train_y = shuffle(train_X, train_y)

for epoch in range(n_epochs):
    for i in range(n_batches):
        start = i * batch_size
        end = start + batch_size
        train_step.run(feed_dict={x: train_X[start:end], t: train_y[start:end]})
    train_accuracy = accuracy.eval(feed_dict={x: valid_X, t: valid_y})
    print("EPOCH::%i, training_accuracy %g" % (epoch+1, train_accuracy))

print("test accuracy %g" % accuracy.eval(feed_dict={x: mnist.test.images, t: mnist.test.labels}))
sess.close()

上のコードの中で、例えば、

train_step.run(feed_dict={x: train_X[start:end], t: train_y[start:end]})

の部分では run が使われているのに

accuracy.eval(feed_dict={x: valid_X, t: valid_y})

の部分では eval が使われているじゃないですか。 evalrun って何が違うのでしょうか?

stackoverflow.com

上記のAnswerとして以下のようにあります。

op.run() is a shortcut for calling tf.get_default_session().run(op)
t.eval() is a shortcut for calling tf.get_default_session().run(t)

ここでいう tf.get_default_session().run()

sess = tf.Session()
sess.run()

の sess = tf.get_default_session と考えれば分かりやすいと思います。 じゃ、「結局どっちも同じじゃん」って感じですけど、run は Operation クラスで evalTensor クラスに属するのでオブジェクトに応じてメソッドを変える必要があるということです。これが結論です。

ここで、「あれれ、じゃあ sess.run ってどういうやつだっけ?」ともなっているかもしれません。次で説明します。

InteractiveSession() vs Session()

Session management  |  TensorFlow

InteractiveSession() がTensorflowの公式に載っていました。Session()に対してInteractiveSession() は何が違うのでしょうか?

A TensorFlow Session for use in interactive contexts, such as a shell.

The only difference with a regular Session is that an InteractiveSession installs itself as the default session on construction. The methods Tensor.eval() and Operation.run() will use that session to run ops.

This is convenient in interactive shells and IPython notebooks, as it avoids having to pass an explicit Session object to run ops.

つまり、 InteractiveSessonを使うとsess = Session() のようにして指定したsessを明示的に指定しなくてもよくなるよ、ということです。IPython notebookで使うときとかに便利だということですね。

Frequently Asked Questions  |  TensorFlow

以下は上記リンク先のコード例です。わざわざ sess.run() のような記述はいらなくなります。

sess = tf.InteractiveSession()
a = tf.constant(5.0)
b = tf.constant(6.0)
c = a * b
# We can just use 'c.eval()' without passing 'sess'
print(c.eval())
sess.close()

ちなみに with 公文を使えば、tf.Session() を使っても同様の記述が出来るようです。こちらも上記リンク先のコードです。

a = tf.constant(5.0)
b = tf.constant(6.0)
c = a * b
with tf.Session():
  # We can also use 'c.eval()' here.
  print(c.eval())

sess.run を使って書いてみます。

a = tf.constant(5.0)
b = tf.constant(6.0)
c = a * b
sess = tf.Session()
sess.run(c)
sess.close()

以上で違いが理解出来たのではないでしょうか?

おわりに

IPython notebookを使うときはInteractiveSession が便利のような気もしますが(ちょっと楽)、Sessionrun のメソッドで(eval とごちゃごちゃにならず)統一的に書けるので良いなと思ったりもしました。

RNNやWord2Vec関連のリンクの備忘録

RNN概要

LSTMについての説明が中心。 RNNのRがrecurrentの頭文字であることからも表されるように、RNNは同じネットワークを繰り返して前のネットワークで学習した結果の一部を後続のネットワークに渡すようなことをしています。それは前のネットワークの情報も現在のネットワークで使えるからいいよねって話なのですが、場合によっては直前の情報だけじゃなくて結構前のネットワークの情報も使いたいわけです。それをいい感じにやってくれるのがLSTMというわけです。以下の記事がこのあたりの説明をもっとちゃんと、詳しくしてくれてる記事です。 最近のアテンションというやつについても機会があればまとめたいところです。

Tensorflow tutorialにgreat articleとして紹介されてた記事。

Understanding LSTM Networks -- colah's blog

(日本語翻訳) qiita.com

かなり詳しくて分かりやすい qiita.com

Tensorflowのチュートリアル

Recurrent Neural Networks  |  TensorFlow

Sequence-to-Sequence Models  |  TensorFlow

Word2Vec

word2vecを使えば文章から単語のベクトル表現が出来て、単語の特徴が分かるよという認識です。 その中のアルゴリズムとしてcbowとskip-gramがあるよという感じです。 (word to vec ですもんね。文字をベクトルにってことですね)

word2vec、cbow、skip-gramが簡潔に説明されていてよい。 resola.ai

skip-gramについて詳しめに丁寧な説明。 qiita.com