LoginSignup
6
1

More than 3 years have passed since last update.

gonumでopenblasを使うメモ

Last updated at Posted at 2019-07-26

goやdepは適当に入れておくとする

blas

macの場合は以下。OpenBLAS以外でも、MKL、Atlasでも良さそう。試してはいない。

brew install openblas

これで、/usr/local/opt/openblas/以下にヘッダとライブラリが入る

ビルドするとき

gonumの取得は普通にdep ensureとかすれば良い。depなどを使わない場合は、gonumを入れた上で、ドキュメントの通り、gonum/netlibパッケージをCGO_LDFLAGを指定してgo installする。

CGO_LDFLAGS="-L/usr/local/opt/openblas/lib -lopenblas" go install gonum.org/v1/netlib/blas/netlib
CGO_LDFLAGS="-L/usr/local/opt/openblas/lib -lopenblas" go install gonum.org/v1/netlib/lapack/netlib

gonumの行列・ベクトル計算をOpenBLASを利用するようにする場合は、以下のような設定が必要

import(
    "gonum.org/v1/gonum/blas/blas64"
    "gonum.org/v1/netlib/blas/netlib"
)

func init(){
    blas64.Use(netlib.Implementation{})
}

ここではinitに書いているが、プログラムの初期化時に一度呼び出されるように書いておけばどこでも良さそう。

go installした場合はいらないと思うが、depに入れた場合は、go buildgo testをする場合にはCGO_LDFLAGSにblasのパスを指定して実行しなければリンクエラーになる。direnvなどに書いておこう。

適当なベンチマークコード

10万*100の行列と100次元のベクトルの行列ベクトル積をスッと計算してみる。基本行列を作るほうが重いので、initでfillしている。

package main

import (
    "math/rand"
    "testing"

    "gonum.org/v1/gonum/blas/blas64"
    "gonum.org/v1/gonum/mat"
    "gonum.org/v1/netlib/blas/netlib"
)

var (
    m *mat.Dense
    v *mat.VecDense
)

func init() {
    blas64.Use(netlib.Implementation{})
    m = makeRandMat(100000, 100)
    v = makeRandVec(100)
}

func makeRandMat(row, col int) *mat.Dense {
    data := make([]float64, row*col)
    for i := range data {
        data[i] = rand.NormFloat64()
    }
    return mat.NewDense(row, col, data)
}

func makeRandVec(num int) *mat.VecDense {
    data := make([]float64, num)
    for i := range data {
        data[i] = rand.NormFloat64()
    }
    return mat.NewVecDense(num, data)
}

func BenchmarkMatVecDot(b *testing.B) {
    res := mat.NewVecDense(100000, nil)
    for i := 0; i < b.N; i++ {
        res.MulVec(m, v)
    }

}

blas64.Use(netlib.Implementation{}) をコメントアウトした場合としなかった場合でだいたい50%弱高速化している。まぁbrewで適当に入れたOpenBLASとの比較ならこんなものな気はする。というかgonumのデフォルトgo実装もそれなりに早いのね。

MacBook Pro (13-inch, 2017, Four Thunderbolt 3 Ports)
プロセッサ: 3.5GHz Intel Corei7
blas64.Use(netlib.Implementation{})あるとき
goos: darwin
goarch: amd64
pkg: hoge
BenchmarkMatVecDot-4         300       4018419 ns/op
PASS
blas64.Use(netlib.Implementation{})ないとき
goos: darwin
goarch: amd64
pkg: hoge
BenchmarkMatVecDot-4         200       7239200 ns/op
PASS

alpineで使う

Dockerfileはこんな感じ

FROM golang:1.12.9-alpine3.10 as builder
ENV CGO_ENABLED=0
ENV GOOS=linux
ENV GOARCH=amd64
RUN apk add --no-cache ca-certificates git build-base openblas-dev
WORKDIR /go/src/{PACKAGE_PATH}
ENV GO111MODULE=on
ENV CGO_ENABLED=1
ENV CGO_LDFLAGS="-L/usr/lib -lopenblas"
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
RUN mkdir -p bin
RUN go build -o bin/{EXECUTABLE} ./{PATH_TO_COMMAND}/main.go

# runtime image
FROM alpine
RUN apk add --no-cache ca-certificates openblas
WORKDIR /var/app
COPY --from=builder /go/src/{PACKAGE_PATH}/bin/{EXECUTABLE} /var/app/{EXECUTABLE}
ENTRYPOINT ["./{EXECUTABLE}"]
6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1