この記事は高知工科大 Advent Calendar 2015の21日目の記事です.
大学生といえば機械学習が大好きですよね?
なので今日は機械学習についてゆるふわな感じで触っていきます.
先に言い訳しときますがプログラムを書き始めたのが21時過ぎなので学習データ用意出来てません.
- Python
- R言語
数値計算のライブラリが充実しているため結構機械学習に使われている印象があります.
実際ニューラルネット実装でググるとこんな感じで出てきます.
Python人気ですね.
しかし今回はPythonもR触る気無いのであしからず.
工学部の学生なら一度はGo言語触ったことがあると思います.
触ったこと無い人もいると思うので書いておくとGo言語はGoogleによって開発された言語です.
主な特徴として、軽量スレッディングのための機能、Pythonのような動的型付け言語のようなプログラミングの容易性、などがあります.
ちょっと前まではOS X, Linux, Windowsのみのサポートでしたが最近はAndroid, iOSもサポートしています.
- コンパイラ言語である
- 並列プログラミングが容易である
- Pythonに近い乗りでコーディングできる
- キャラクターが可愛い
今回何も無いところから機械学習を触っていくつもりは無いのでライブラリを使います.
go-neural
というライブラリを使っていきます.
go get -u github.com/NOX73/go-neural
でライブラリを取得します.
使い方は非常に簡単です.
公式のREADME.mdに書いてあるとおりに使えば基本的には動きます.
package main
import (
"fmt"
"github.com/NOX73/go-neural"
)
func main() {
n := neural.NewNetwork(9, []int{9, 9, 4})
n.RandomizeSynapses()
result := n.Calculate([]float64{0, 1, 0, 1, 1, 1, 0, 1, 0})
fmt.Println(result)
}
簡単ですね.
細かい使い方は実装を見ればわかると思うので割愛します.
Hello world
的なことをやっても面白く無いので画像処理をやってみましょう.
画像を読み込む処理を書いていきます.
func openFile(name string) (*os.File, error) {
return os.Open(name)
}
func getFormat(file *os.File) string {
bytes := make([]byte, 4)
n, _ := file.ReadAt(bytes, 0)
if n < 4 {
return ""
}
if bytes[0] == 0x89 && bytes[1] == 0x50 && bytes[2] == 0x4E && bytes[3] == 0x47 {
return "png"
}
if bytes[0] == 0xFF && bytes[1] == 0xD8 {
return "jpg"
}
if bytes[0] == 0x47 && bytes[1] == 0x49 && bytes[2] == 0x46 && bytes[3] == 0x38 {
return "gif"
}
if bytes[0] == 0x42 && bytes[1] == 0x4D {
return "bmp"
}
return ""
}
func readBMP(io *os.File) (image.Image, error) {
return bmp.Decode(io)
}
func readPNG(io *os.File) (image.Image, error) {
return png.Decode(io)
}
func readJpeg(io *os.File) (image.Image, error) {
return jpeg.Decode(io)
}
func readGIF(io *os.File) (image.Image, error) {
return gif.Decode(io)
}
func openFile(name string) (*os.File, error) {
return os.Open(name)
}
func decodeImage(name string) (image.Image, error) {
io, err := openFile(name)
if err != nil {
return nil, err
}
imageFormat := getFormat(io)
switch imageFormat {
case "bmp":
return readBMP(io)
case "jpg":
return readJpeg(io)
case "png":
return readPNG(io)
case "gif":
return readGIF(io)
default:
return nil, errors.New("can not read file.")
}
}
func isOutOfImage(x int, y int, img image.Image) bool {
rect := img.Bounds()
if x < 0 && y < 0 {
return true
} else if rect.Max.X <= x && rect.Max.Y <= y {
return true
}
return false
}
func getRGBA256(x int, y int, img image.Image) (uint8, uint8, uint8, uint8) {
r, g, b, a := img.At(x, y).RGBA()
return uint8(r), uint8(g), uint8(b), uint8(a)
}
func learnColor(cmp image.Image, org image.Image, networks []neural.Network) []neural.Network {
rect := org.Bounds()
bufR := make([]float64, 9)
bufG := make([]float64, 9)
bufB := make([]float64, 9)
for x := 0; x < rect.Max.X; x++ {
for y := 0; y < rect.Max.Y; y++ {
cnt := 0
for i := -1; i <= 1; i++ {
for j := -1; j <= 1; j++ {
if isOutOfImage(x+i, y+j, cmp) {
bufR[cnt] = 0
bufG[cnt] = 0
bufB[cnt] = 0
} else {
r, g, b, _ := getRGBA256(x+i, y+j, cmp)
bufR[cnt] = float64(r) / 100
bufG[cnt] = float64(g) / 100
bufB[cnt] = float64(b) / 100
}
cnt++
}
}
r, g, b, _ := getRGBA256(x, y, org)
learn.Learn(&networks[0], bufR, []float64{float64(r) / 100}, 0.01)
learn.Learn(&networks[1], bufG, []float64{float64(g) / 100}, 0.01)
learn.Learn(&networks[2], bufB, []float64{float64(b) / 100}, 0.01)
}
}
return networks
}
func filter(img image.Image, networks []neural.Network) image.Image {
rect := img.Bounds()
ret := image.NewRGBA(rect)
for x := 0; x < rect.Max.X; x++ {
for y := 0; y < rect.Max.Y; y++ {
bufR := make([]float64, 9)
bufG := make([]float64, 9)
bufB := make([]float64, 9)
cnt := 0
for i := -1; i <= 1; i++ {
for j := -1; j <= 1; j++ {
if isOutOfImage(x+i, y+j, img) {
bufR[cnt] = 0
bufG[cnt] = 0
bufB[cnt] = 0
} else {
r, g, b, _ := getRGBA256(x+i, y+j, img)
bufR[cnt] = float64(r) / 100
bufG[cnt] = float64(g) / 100
bufB[cnt] = float64(b) / 100
}
cnt++
}
}
r := networks[0].Calculate(bufR)
g := networks[0].Calculate(bufG)
b := networks[0].Calculate(bufB)
fmt.Println(r, g, b)
c := color.RGBA{R: uint8(r[0] * 100), G: uint8(g[0] * 100), B: uint8(b[0] * 100), A: 0xff}
ret.Set(x, y, c)
}
}
return ret
}
30分ぐらいで急いで書いたからバグあるかも
あと学習量たりなさすぎて微妙だが
とりあえず動かしてみた感じなんとなくそれっぽく動いてるんじゃないかと
とりあえずもう少し学習データ用意していろいろ試してみたい.