いっきのblog

技術とか色々

TensorFlow2.0とTensorFlowHubを使ってみる

TensorFlow2.0betaが出てたので、試してみる。

TensorFlowとは?

TensorFlow(テンソルフロー)とは、Googleが開発しているOSS機械学習のライブラリ。Googleはもちろんアルファ碁で有名になったDeepMindでも使われている。
対応言語は、Python, C, C++, Java, Goなどがある。
今回は使わないが、Mobileにも入れることができたりする。

TensorFlow - Wikipedia

また、Tensor(テンソル)については、以下の記事が参考になった。

mathcommunication.hatenablog.com

とはいっても難しくてあまり理解できなかったので、以下の記事がFlow(フロー)部分も含めて、ざっくりの理解ができた。

www.codexa.net

ようは、テンソルとは多次元配列のこといっているとの理解で一旦とどめて置く。

TensorFlow1.0と2.0の違い

以下の記事がいいまとめすぎて、理解しやすかった。

qiita.com

PyTrouchをだいぶ意識したバージョンアップみたい

TensorFlow2.0のインストール方法

pip install tensorflow==2.0.0-beta0

さっそくエラー

ERROR: Cannot uninstall 'wrapt'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall

wrapt周りが怪しいので、uninstallすると無事インストールできた。

pip install -U --ignore-installed wrapt enum34 simplejson netaddr

ニューラルネットワークチュートリアル

以下の記事を行なった。エラーなしで動くので、ここでは特に何もしない。

www.tensorflow.org

ただ、とりあえず具動かせるが、理解が足りてない部分を以下を参考とした。

www.sbbit.jp

ついでに、CNNも

lp-tech.net

softmax

qiita.com

TensorFlowHubのインストール

公式のチュートリアルを参考に動かしてみる

www.tensorflow.org

!pip install "tensorflow_hub==0.4.0"
!pip install "tf-nightly"

つづいて、

import tensorflow as tf
import tensorflow_hub as hub

tf.enable_eager_execution()

module_url = "https://tfhub.dev/google/tf2-preview/nnlm-en-dim128/1"
embed = hub.KerasLayer(module_url)
embeddings = embed(["A long sentence.", "single-word",
                    "http://example.com"])
print(embeddings.shape)  #(3,128)

ここでエラー

AttributeError: module 'tensorflow' has no attribute 'enable_eager_execution'

TF2.0だとeager-modeがデフォルトtrueなので、コメントアウト

www.tensorflow.org

// tf.enable_eager_execution()

1.x => 2.x のマイグレーション

エラーの一つを紹介すると

AttributeError: module 'tensorflow' has no attribute 'logging'

TF2系なのでloggingがないっぽいので、
tf.logging => tf.compat.v1.loggingに変更で動く
tf.gfile => tf.io.gfileなど

www.tensorflow.org

基本はcompat.v1つければよさそう

終わりに

ざっくりと駆け足でTensorFlow2.xを使って見た。
2系らしい動きはまだできてないので、次は深掘りする。

GoでAtCoder(競技プログラミング)やってみる

最近Goを勉強して行く上で、アルゴリズムの勉強も同時にしながらできないかなーと思い、競技プログラミングというアルゴリズムのコンテストはどっちも満たせると信じ、始めて見た。

今回はAtCoderと言われる、日本製のコンテストサイトでやってみる。
以下の方が代表で、元々世界のプログラミングコンテストのランカーだったのか、すごい。
twitter.com

とりあえず読んでみるべき記事

どう進めたらいいのかはもうここで完結しそうなくらいよかった。 qiita.com

登録したら上記の問題をコンテスト形式で用意してくれるのでそれをやったほうがいい。

atcoder.jp

Goで書いてみる

https://github.com/kzkohashi/at_coder_practice

全然まだまだ途中だけど、自分なりの答えはgithubにあげている。
groutineとか使えば早くなるんだろうな。今はこなすことに集中。

テクニックみたいなやり方をまとめてくれていてすごく助かっている記事。
qiita.com

まだ爆速をもとめられていないが、参考になりそうな記事。@hama_duさんや。

qiita.com

感想

少ししかまだ始められてないが、すごく良さそうな印象だった。
採用とか社内のエンジニアのレベルアップに良いな〜とも思うので、継続してやっていこ。

GoroutineとChannelについて学ぶ

前回Goのインタフェースについて書いた。

kzkohashi.hatenablog.com (アイキャッチが更新されてない・・)

今回はGoの真髄とも言える、ゴルーチンとチャネルによる並行処理(Concurrent)について学んでいく。

並行(Concurrent)処理と並列(Parallel)処理

間違えやすいのだが、並行処理は並列処理と概念的に異なる。

こちらの記事がわかりやすかったので、引用させていただく。

Concurrent(並行)は「複数の動作が、論理的に、順不同もしくは同時に起こりうる」こと Parallel(並列)は、「複数の動作が、物理的に、同時に起こること」
引用: freak-da.hatenablog.com

並行は1人の人が複数の仕事をし、並列は複数の人が複数の仕事をしている状態だ。
とはいっても、並行処理は擬似並列ともいえるので、日本語的には「並列処理」を使っても問題ないと思う。

この辺りも面白かった。

興味がある人は以下を読むと良さそう。
自分は近々届くので、また別途まとめたい。

www.oreilly.co.jp

Goroutineで並行処理を行う。

Goroutineの実装は簡単で、関数の前にgoをつけるだけだ。
これだけで並行処理がとりあえずは実装できる。

func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}


func main() {
    go say("world")
    say("hello")
}

引用: https://go-tour-jp.appspot.com/concurrency/1

並行処理のプログラミングをする際は、mainでの処理とは別に処理が走ってしまうので、Channelをうまく使って制御したり、Sleepで待つという方法もある。
Sleepは処理が終わる終わらないに限らず、その時間しかまたないのでよくない。

Channelを使う

A Tour Goをやってもあまり理解しなかったが、以下の記事がよかったのでこちらを見た方がいい。
channelは値をやり取りをするためのキューみたいなもんだ。しかも、goroutine(スレッド)間で値の受け渡しを安全にできるので、とても簡単に扱える。

qiita.com

func main() {
  // 容量2のchannel型で作成
  c := make(chan string, 2)
 // データを入れる
  c <- "hello"
  // データを入れる
  c <- "hello2"
  // c <- "hello3" 容量2のため3個目をいれたらエラー
  // 最初に入れたデータをchannelから取り出す
  fmt.Println(<-c)
  fmt.Println(<-c)
  // fmt.Println(<-c) 3つ目はない

  c = make(chan string, 1)
  c <- "world"
  fmt.Println(<-c)
}

Exercise: Web Crawler を解く

A Tour Goの最後に、goroutineの問題があったので解いて見た。
go-tour-jp.appspot.com

package main

import (
    "fmt"
)

type Fetcher interface {
    // Fetch returns the body of URL and
    // a slice of URLs found on that page.
    Fetch(url string, resultUrl ResultUrl) (body string, urls []string, err error)
}

type ResultUrl struct {
    v   map[string]int
}

// Value returns the current value of the counter for the given key.
func checkUrl(c *ResultUrl, key string) bool {
    return c.v[key] == 1
}


// Crawl uses fetcher to recursively crawl
// pages starting with url, to a maximum of depth.
func Crawl(url string, depth int, fetcher Fetcher, c ResultUrl, quit chan bool) {
    // TODO: Fetch URLs in parallel.
    // TODO: Don't fetch the same URL twice.
    // This implementation doesn't do either:
    if depth <= 0 {
        quit <- true
        return
    }

    if checkUrl(&c, url) {
        quit <- true
        return
    }

    body, urls, err := fetcher.Fetch(url, c)
    if err != nil {
        fmt.Println(err)
        quit <- true
        return
    }
    fmt.Printf("found: %s %q\n", url, body)

    quit2 := make(chan bool)
    for _, u := range urls {
        go Crawl(u, depth-1, fetcher, c, quit2)
        <-quit2
    }

    quit <- true
    return
}

func main() {
    c := ResultUrl{v: make(map[string]int)}
    quit := make(chan bool)
    go Crawl("https://golang.org/", 4, fetcher, c, quit)
    <-quit
}

// fakeFetcher is Fetcher that returns canned results.
type fakeFetcher map[string]*fakeResult

type fakeResult struct {
    body string
    urls []string
}

func (f fakeFetcher) Fetch(url string, c ResultUrl) (string, []string, error) {
    c.v[url] = 1

    if res, ok := f[url]; ok {
        return res.body, res.urls, nil
    }
    return "", nil, fmt.Errorf("not found: %s", url)
}

// fetcher is a populated fakeFetcher.
var fetcher = fakeFetcher{
    "https://golang.org/": &fakeResult{
        "The Go Programming Language",
        []string{
            "https://golang.org/pkg/",
            "https://golang.org/cmd/",
        },
    },
    "https://golang.org/pkg/": &fakeResult{
        "Packages",
        []string{
            "https://golang.org/",
            "https://golang.org/cmd/",
            "https://golang.org/pkg/fmt/",
            "https://golang.org/pkg/os/",
        },
    },
    "https://golang.org/pkg/fmt/": &fakeResult{
        "Package fmt",
        []string{
            "https://golang.org/",
            "https://golang.org/pkg/",
        },
    },
    "https://golang.org/pkg/os/": &fakeResult{
        "Package os",
        []string{
            "https://golang.org/",
            "https://golang.org/pkg/",
        },
    },
}

すでにクロールしたURLを判定する処理に、sync.Mutexを最初入れてたが、入れなくてもできたのでちょっと怪しい。
キモとしては、channel型のquitに値を入れ、<-quitgoroutineの処理を待つことができる。

終わりに

Goの勉強を駆け足でやってみた。
最初は意味がわからなかったが、毎日少しずつ見ていくと慣れていくもんだな。
次からはGoAPIサーバー作ることをしようかな。

Goのインタフェースについて学ぶ

以前初めてGoに触った感想をまとめたが、インタフェースについては書いてなかったのでまとめる。 kzkohashi.hatenablog.com

インタフェースの定義

A Tour of Goの内容をベースに話していく。
go-tour-jp.appspot.com

インターフェースの定義は以下のように、type xxx interfaceで作成し、その中に実装するメソッドを定義する。
ここでは、AbserインターフェースにAbs関数を定義している。

type Abser interface {
    Abs() float64
}

ややこしいんだけど、interface{}型とは全く違う概念みたいなので、注意しとく。
interface{}型はintboolなど全ての値を取りうる型とのこと。

var a interface{}
a = 1 // int
a = 1.0 // float
a = "あ" // string

こちらが参考になった。ただ、ゆるく使うにしてもどう使うんだろう。
初心者に送りたいinterfaceの使い方[Golang] – Since I want to start “blog” that looks like men do, I do start. – Medium

インタフェースの実装

次にインタフェースを実装する。
float型のMyFloatを定義し、先ほどインターフェスで定義したAbsメソッドを実装する。

type MyFloat float64

func (f MyFloat) Abs() float64 {
    if f < 0 {
        return float64(-f)
    }
    return float64(f)
}

ちゃんと理解していなかったんだが、typeは構造体で使うというより、指定した型を別名でつけれるようものとのこと。
上記のMyFloatリテラルfloatの別名として、新しい型として定義されたものだ。
言われてみると当たり前な気はするけど、忘れないようにと。以下の記事がとても参考になった。

qiita.com

また、以下のようにstructにもAbsメソッドを実装している。

type Vertex struct {
    X, Y float64
}

func (v *Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

準備は整ったので、実際に使用してみる。
すこし変更させてもらって、実装したどちらのメソッドも実行している。

func main() {
    var a,b Abser
    f := MyFloat(-math.Sqrt2)
    v := Vertex{3, 4}

    a = f  // a MyFloat implements Abser
        // a = &v
    b = &v // a *Vertex implements Abser

    fmt.Println(a.Abs())
    fmt.Println(b.Abs())
}

終わりに

勉強っぽい感じの作りなんで、実際のインタフェースの使い所など学んで行きたい。
以下の記事ではGoでのインタフェースを書く注意点が書いてあるので参考になった。

qiita.com

次はGoルーチンとチャネルを書こうかな。

LaravelerがGoを初めてさわって見る

ここ最近LaravelPythonしか書いてないので、技術のアップデートをしよう思ったのがきっかけ。
なぜGoなのかと言われると、以下の理由で決めて見た。

  • Laravel(PHP)が動的型付け言語なので、静的型付け言語を学び直したい
  • 流行っている風のものをやりたいため(流行る理由があると思うので)
  • Laravel(PHP)Webサービス用、Pythonは分析用、Goはちょっとしたツール用という立ち位置にしやすいので、継続しやすいと思っているため
  • 毎日お世話になっているpecoみたいなのを作って見たい

学び方の順序などは、こちらの記事を参考にさせてもらった。 qiita.com

Goの背景や網羅的な使い方などを学ぶ

こちらの記事が全体感を掴むにはちょうどいいと思う。 gihyo.jp

細かいところや、理解が深まらない箇所が必ずでてくるのでその場合はこちらから細かいやり方を学ぶ。 go-tour-jp.appspot.com

大体の理解なら技評の記事 <-> A Tour Goを行き来すればできるけど、部分的にググったりして学んでいく。

忘れている箇所やつまった点をまとめる。

静的型付けと動的型付けの違い

Wikipediaがわかりやすい。 動的型付け - Wikipedia

とても極端に分かれているが、PHP8ではJITコンパイラの採用が可決されたみたいで、IDEとの組み合わせで静的型付けみたいなこともできるんじゃないかなと考えてる。
この記事が面白い。どっちもいいとこ取りはし始めてる。

jp.quora.com

関数とメソッドの違い

自分の頭の中で関数 = メソッドと勝手に認識してるせいで、途中こいつらは何を言っているんだ・・と思ってしまった。
関数

func sum(i, j int) int {
    return i + j
}

func main() {
    fmt.Println(sum(1,2)) // 3
}

関数の方はPHPとほぼ同じなのでわかりやすい。
メソッドの方は構造体(ここだとData)と言われる入れ物に、sumという振る舞いが追加されてるかのように扱える。
GoにはClassがないため、ここらへんで色々工夫するのかな。

type Data struct {
    i int
    j int
}

func (d *Data) sum() int {
    return d.i + d.j
}

func main() {
    data := Data {1, 2}
    fmt.Println(data.sum()) // 3
}

エラー処理

Goでは、errorインターフェースがあって、それを使ってエラーを通知するが、それとは別に例外処理が存在する。
どこまで深く勉強したいところだけど、以下の方の記事がすごく腑に落ちそう。

blog.amedama.jp

終わりに

インターフェースや、醍醐味の一つである並列処理などを書きたかったが、久々のブログで体力がないので次回。

Laravel ShiftでLaravelを簡単アップグレード!

Laravel #2 Advent Calendar 2018の11日目です!
今回は、Laravelのアップデートのやり方について書きたいと思います。

バージョンをあげる時の課題

僕らのチームは元々Laravelのバージョンを5.5を使っていて、そろそろあげたいよねって話をしてました。
ただ、「調査や変更による工数がかかる」という(多分心理的な)課題があり、そんな時にメンバーの一人が「Laravel Shift」使えば楽そうですよという話から今回に至りました。

Laravel Shiftとは

簡単にいうと、課金すればLaravelのアップグレードを自動でやってくれるというものです。

laravelshift.com

なかなか便利そうな感じが漂ってますが、いっきにバージョンアップすることはできないので一つずつバージョンをあげていきます。
今回は5.5から5.7にあげたいので、5.5から5.6($9)、5.6から5.7(7$)の計16$でバージョンアップをしたいと思います。

f:id:kzkohashi:20181210202747p:plain

5.5から5.6へのアップグレード

アップグレードは簡単で、GitHubと連携し、クレジットカードを入力すれば始まります。

f:id:kzkohashi:20181210203204p:plain

数分待つと、指定したブランチへプルリクが自動で作られます。
(自分が英語で話した気分になるので、すごくできた気分になれます)

f:id:kzkohashi:20181210203417p:plain

主なプルリクの内容は以下です。

  • PSR-2によるコードスタイルの変更のコミット(準拠してなかったのでいい機会なので変更)
  • アップグレードに伴う各種ファイルの修正コミット
  • 自動で直せない部分を、コメントで教えてくれる

自動で直せない部分もあるのかよっと思うかもしれませんが、コメントで教えてくれるのでそれの通り直すだけなので楽チンです。
修正後は、「ユニットテスト」と「E2Eテスト」をしてバグがないことを確認したらマージします。

5.6から5.7へのアップグレード

こちらも同じように行います。

f:id:kzkohashi:20181210204250p:plain

ユニットテストだと全てのテストを網羅できてないので、E2Eテストはかなり念入りに行い、無事マージ/リリースを行います。

アップグレードによるバグ

大きいバグは1ヶ月たった今もまだありません。
ただ、5.7にあるbootstrap/cacheservices.phppackages.phpのオーナー権限がおかしい問題のせいでデプロイのたびにすごく困ってます・・。
修正済みなので、composer updateすればもう大丈夫です。

github.com

と、おもったら今度はTestResponseJSON周りがおかしくてテストがこける。。。 マージはされたので早くreleaseしてほしいと願っております(12/11現在)

github.com

終わりに

最後はあまり関係ないバグの話になってしまいましたが、かかった工数は全部合わせても数時間です。 たった16$でエンジニアの工数をあまり使わずでき、新規開発にすぐ取り組めて、ビジネスサイドにもほぼ迷惑かからない最高のツールでした。ありがとうございます。

Genderize.ioを使って性別判定してみる

以前、顔写真を使って性別判定についての検証をした。
顔写真による性別判定はそこそこ判定が高くすごく満足しているのだが、顔がない場合の判定はどうすればいいんだろうと思い、ちょい調べてみた。

kzkohashi.hatenablog.com

名前による判定

Genderize.ioと呼ばれる、名前による男女の判定はすでに存在していた。
自分たちでもできそうな気もしなくもないけど。。。とりあえず使ってみる。

https://store.genderize.io/

デモでapiが使えるため、実際に自分の名前出たていてみると

curl https://api.genderize.io/?name=kazuki
{"name":"kazuki","gender":"male","probability":1,"count":16}

jsonでデータがかえってくるため、各項目の意味を調べると以下になる。

name: 入力した名前
gender: 性別
probability: 確からしさ(精度)
count: ヒットしたデータ数

公式には、probabilitycountを使って自分たちで閾値みたいなのを決めてねと書いてある。
今回だとprobability1なのでほぼあってそうに見えるけど、countが少ないため少し怪しいのかなーと思う。kazukiでも女性の名前はいるので、日本語は少し弱いのかな?という印象を受ける。

終わりに

いくつか名前の検証をした感じだと良さそう。本番である程度試したらまた検証記事書こうと思う。