2019/06/18


2016年、普段から現場でGoを使っている名立たるGoプログラマの皆さんと一緒に「みんなのGo言語」という書籍を執筆させて頂きました。

「みんなのGo言語」は他のリファレンス本とは異なり、Go言語の最新事情をお伝えする事に主眼を置いて書きました。

インストール方法や使い方、モダンなテストの書き方、ツールの使い方等も執筆時点での最新情報を書かせて頂きました。

これはとても意義がある事だった感じています。

しかしこれは逆に、時間が経つにつれ執筆した内容が次第に古くなってしまうというリスクを伴います。幾つかの内容は、3年経った現在に合わなくなっている物も出てきました。紹介したツールの中には開発が止まってしまっている物もあれば、執筆時点で制限事項と記したけれども現在では解消している物も出てきています。そればかりではなく新しく追加されたコマンドや機能、新しい制限事項もあります。特に Go Module の扱いは、今後Go言語を扱う開発者にとって知っておくべき最重要項目とも言えるでしょう。


今回、「みんなのGo言語」の改訂というチャンスを頂き、内容を再び更新させて頂く事になりました。古い情報をバッサリと書き直している章もあります。Go言語で開発をする上での最新のヒントも書かせて頂きました。特に今回、新しい章「第7章 データベースの扱い方」を執筆させて頂きました。データベースを使ったウェブアプリケーションの作り方を分かりやすく書かせて頂いたつもりです。

ぜひ新しくなった「みんなのGo言語」をお楽しみ下さい。

改訂2版 みんなのGo言語 改訂2版 みんなのGo言語
松木 雅幸, mattn, 藤原 俊一郎, 中島 大一, 上田 拓也, 牧 大輔, 鈴木 健太
技術評論社 単行本(ソフトカバー) / ¥2,398 (2019年08月01日)
 
発送可能時間:

Kindle 版はこちら

改訂2版 みんなのGo言語 改訂2版 みんなのGo言語
松木 雅幸, mattn, 藤原 俊一郎, 中島 大一, 上田 拓也, 牧 大輔, 鈴木 健太
技術評論社 Kindle版 / ¥2,350 (2019年08月01日)
 
発送可能時間:

Posted at by



2019/05/16


Go は最近のプログラミング言語にしては珍しくポインタを扱えるプログラミング言語。とはいってもC言語よりも簡単で、オブジェクトの初期化やメソッドの定義以外の場所ではおおよそポインタを使っている様には見えない。メソッドやフィールドへのアクセスも . で出来るし Duck Type によりインタフェースを満たしていれば実体であろうとポインタであろうとそれほど意識する必要はない。ところがこの便利さに乗っかってしまうと思わぬ所で足をすくわれてしまう。

package main

type foo struct {
    v int
}

func (f foo) add(v int) {
    f.v = v
}

func main() {
    var a foo

    a.add(3)

    println(a.v)
}

このコードは 0 が表示される。メソッドを呼び出す際にはレシーバのオブジェクトを得る必要があるが、foo は実体なのでコピーが生成される。例えばレシーバ f が引数であったと考えると理解しやすくなる。

package main

type foo struct {
    v int
}

func add(f foo, v int) {
    f.v += v
}

func main() {
    var a foo

    add(a, 3)

    println(a.v)
}

メソッドとレシーバの関係は、実は「単なる関数と第一引数」と考えると分かりやすい。特にC言語でオブジェクト指向をやる様な人達は訓練されているので、Go をやる上でもこの辺りの動作を意識せず扱えているのかもしれない。

実体のレシーバにメソッドを生やすメリットが無い訳ではない。例えばオブジェクトの値を明示的に変更させたくない場合がそれで、そういった設計にしたい場合は戻り値を使う。

package main

type foo struct {
    v int
}

func (f foo) add(v int) foo {
    f.v += v
    return f
}

func main() {
    var a foo

    a = a.add(3)

    println(a.v)
}

これとは別に、ポインタと実体をまぜて考えてしまうと失敗してしまう事もある。

この例のポイントは「for range の反復変数はループ毎に新しいコピーが作成されない」という事。つまり上書きになる。プログラマは一見このループが実行されると以下の様になると考えてしまう。

= append(b, c[0].f())
= append(b, c[1].f())

だが実際はこう。

var i a
= c[0]
= append(b, i.f())
= c[1]
= append(b, i.f())

The Go Playground

slice の b は一見、c の情報が詰め込まれている様に見えるが、実際は i の情報が詰め込まれている。なので2回目の i への代入時に「i が持っていたレシーバの情報 c[0]c[1] 上書きされてしてしまう事になり、結果 a, b ではなく b, b が表示される。Method values という仕組みは参考として見ておくと良い。i への代入時点でレシーバの情報が デリファレンス されコピーされた状態で代入されているのがポイント、f() の呼び出し時の話ではない。

package main

import (
    "fmt"
)

type a struct {
    N string
}

func (s *a) f() func() {
    return func() {
        fmt.Printf("%s\n", s.N)
    }
}

func main() {
    b := []func(){}
    c := []a{{"a"}, {"b"}}

    var i a

    i = c[0]
    b = append(b, i.f())

    b[0]()
    i = c[1]
    b[0]() // この時点で既に b になる
    b = append(b, i.f())
}

まとめ

混ぜるな危険

みんなのGo言語【現場で使える実践テクニック】 みんなのGo言語【現場で使える実践テクニック】
松木雅幸, mattn, 藤原俊一郎, 中島大一, 牧 大輔, 鈴木健太, 稲葉貴洋
技術評論社 大型本 / ¥112 (2016年09月09日)
 
発送可能時間:

Posted at by



2019/04/17


以前 TensorFlow Lite の Go バインディングを書いたのだけど

Big Sky :: TensorFlow Lite の Go binding を書いた。

Google launches TensorFlow Lite 1.0 for mobile and embedded devices | VentureBeat Google today intro...

https://mattn.kaoriya.net/software/lang/go/20190307190947.htm

これの mruby 版を作ってみました。

GitHub - mattn/mruby-tflite

model = TfLite :: Model .from_file " xor_model.tflite " interpreter = TfLite :: Interpreter . new (m...

https://github.com/mattn/mruby-tflite

TensorFlow Lite がライブラリ単体として配布されていないので、ビルドは少し難しいですが頑張って下さい。使い方は簡単です。以下 XOR (排他的論理和) なモデルの作り方と、そのモデルを使って推論する Ruby スクリプトを紹介します。keras で XOR... は説明が長くなるので省略します。知りたい方は調べて下さい。

import numpy as np 
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.optimizers import SGD

model = Sequential()
model.add(Dense(8, input_dim=2))
model.add(Activation('tanh'))
model.add(Dense(1))
model.add(Activation('sigmoid'))

sgd = SGD(lr=0.1)
model.compile(loss='binary_crossentropy', optimizer=sgd)
X = np.array([[0,0],[0,1],[1,0],[1,1]])
y = np.array([[0],[1],[1],[0]])
model.fit(X, y, verbose=True, batch_size=1, nb_epoch=1000)
model.save('xor_model.h5')

HDF5 なファイルを吐けば TFLiteConverter を使って TensorFlow Lite のモデルファイルが生成出来ます。

import tensorflow as tf
import tensorflow.contrib.lite as lite

converter = lite.TFLiteConverter.from_keras_model_file("xor_model.h5")
tflite_model = converter.convert()
open("xor_model.tflite""wb").write(tflite_model)

TensorFlow Lite の C API を wrap する形にしてあるので、API を知ってる人なら使いやすいと思います。以下は生成されたモデルファイルを使って XOR を推論するサンプルです。

model = TfLite::Model.from_file "xor_model.tflite"
interpreter = TfLite::Interpreter.new(model)
interpreter.allocate_tensors
input = interpreter.input_tensor(0)
output = interpreter.output_tensor(0)
[[0,0], [1,0], [0,1], [1,1]].each do |x|
  input.data = x
  interpreter.invoke
  puts "#{x[0]} ^ #{x[1]} = #{output.data[0].round}"
end

リポジトリには FizzBuzz を扱う例も置いてあるので Ruby で TensorFlow Lite やりたかった人(いるのか)には嬉しいかもしれません。ただ残念ながら現状 MRuby の gems には画像を描画できる物が無かったので顔認識の様な物を簡単に作る事が出来ませんでした。これは別途 gem が出来れば実現できるはずです。

ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装 ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装
斎藤 康毅
オライリージャパン 単行本(ソフトカバー) / ¥3,740 (2016年09月24日)
 
発送可能時間:

Posted at by