Go 语言——Tensorflow

介绍

之前的博客中,翻译过 Go 语言可以通过 Tensorflow 的 go 客户端进行操作,但是其中有两个问题很容易在编码时遇到下面的问题。

  1. Scope:每次调用定义操作的函数时,Go API 并不会自动生成新的节点名称。会出现
panic: failed to add operation "Placeholder": Duplicate node name in graph: 'Placeholder'
  1. Typing system: REGISTER_OP 宏对 MatMul 定义接口的操作描述中,提到 T 支持的类型有 {half, float, double, int32, complex64, complex128},Go 绑定版 tf 有自己的一套类型,基本与 Go 本身的类型 1:1 相映射,如果错误使用类型则出会错,例如使用 int64,则会出现
panic: failed to add operation "MatMul": Value for attr 'T' of int64 is not in the list of allowed values: bfloat16, half, float, double, int32, complex64, complex128;

第三方包

为了避免出现上述问题,在这里可以引入第三方包 galeone/tfgo。 GitHub 地址为:
https://github.com/galeone/tfgo

主要解决问题:

  1. 作用域(Scope):每个新节点都有一个新的惟一名称;
  2. 类型系统(Typing system):属性将自动转换为受支持的类型,而不是在运行时抛出错误。

Tensorflow 的 Go 绑定的核心数据结构是 op.Scope 结构。包 galeone/tfgo 允许创建新的 *op。解决了上面提到的作用域(Scope)问题。

既然我们定义了一个图,让我们从它的根开始(空图),代码示例:

root := tg.NewRoot()

现在可以将节点放入这个图中并将它们连接起来。假设要为一个列向量乘以一个矩阵,然后向结果中添加另一个列向量。

测试代码如下:

package main

import (
	"fmt"
	tg "galeone/tfgo"
	tf "github.com/tensorflow/tensorflow/tensorflow/go"
)

func main() {
	root := tg.NewRoot()

	A := tg.NewTensor(root, tg.Const(root,[2][2]int32{{1, 2}, {-1, -2}}))
	x := tg.NewTensor(root, tg.Const(root,[2][1]int32{{0}, {100}}))
	// 矩阵 A * x
	Y := A.MatMul(x.Output)
	//  结果输出
	results := tg.Exec(root, []tf.Output{Y.Output},  nil, &tf.SessionOptions{})

	fmt.Println("Y: ", results[0].Value())
}

输出结果:

Y:  [[200] [-200]]

下面是官方完整的源代码:

package main

import (
        "fmt"
        tg "github.com/galeone/tfgo"
        tf "github.com/tensorflow/tensorflow/tensorflow/go"
)

func main() {
        root := tg.NewRoot()
        A := tg.NewTensor(root, tg.Const(root, [2][2]int32{{1, 2}, {-1, -2}}))
        x := tg.NewTensor(root, tg.Const(root, [2][1]int64{{10}, {100}}))
        b := tg.NewTensor(root, tg.Const(root, [2][1]int32{{-10}, {10}}))
        Y := A.MatMul(x.Output).Add(b.Output)
        // Please note that Y is just a pointer to A!

        // If we want to create a different node in the graph, we have to clone Y
        // or equivalently A
        Z := A.Clone()
        results := tg.Exec(root, []tf.Output{Y.Output, Z.Output}, nil, &tf.SessionOptions{})
        fmt.Println("Y: ", results[0].Value(), "Z: ", results[1].Value())
        fmt.Println("Y == A", Y == A) // ==> true
        fmt.Println("Z == A", Z == A) // ==> false
}

结果如下:

Y:  [[200] [-200]] Z:  [[200] [-200]]
Y == A true
Z == A false

利用数据流图实现计算机视觉
Tensorflow 中有很多对图像执行操作的方法。tfgo 提供了图像包,允许使用 Go 绑定以一种优雅的方式执行计算机视觉任务。

例如,可以读取图像,计算其沿水平和垂直方向的方向导数,计算梯度并保存它。

下面的代码就是这样做的,显示了使用相关性和卷积操作得到的不同结果。

package main

import (
        tg "github.com/galeone/tfgo"
        "github.com/galeone/tfgo/image"
        "github.com/galeone/tfgo/image/filter"
        "github.com/galeone/tfgo/image/padding"
        tf "github.com/tensorflow/tensorflow/tensorflow/go"
        "os"
)

func main() {
        root := tg.NewRoot()
        grayImg := image.Read(root, "../image/1.png", 1)
        grayImg = grayImg.Scale(0, 255)

        // Edge detection using sobel filter: convolution
        Gx := grayImg.Clone().Convolve(filter.SobelX(root), image.Stride{X: 1, Y: 1}, padding.SAME)
        Gy := grayImg.Clone().Convolve(filter.SobelY(root), image.Stride{X: 1, Y: 1}, padding.SAME)
        convoluteEdges := image.NewImage(root.SubScope("edge"), Gx.Square().Add(Gy.Square().Value()).Sqrt().Value()).EncodeJPEG()

        Gx = grayImg.Clone().Correlate(filter.SobelX(root), image.Stride{X: 1, Y: 1}, padding.SAME)
        Gy = grayImg.Clone().Correlate(filter.SobelY(root), image.Stride{X: 1, Y: 1}, padding.SAME)
        correlateEdges := image.NewImage(root.SubScope("edge"), Gx.Square().Add(Gy.Square().Value()).Sqrt().Value()).EncodeJPEG()

        results := tg.Exec(root, []tf.Output{convoluteEdges, correlateEdges}, nil, &tf.SessionOptions{})

        file, _ := os.Create("convolved.png")
        file.WriteString(results[0].Value().(string))
        file.Close()

        file, _ = os.Create("correlated.png")
        file.WriteString(results[1].Value().(string))
        file.Close()
}

用 Python 训练,用 Go 服务

只要深入研究下面的示例,就可以理解如何使用 tfgo 为经过训练的模型提供服务。

首先使用 Python 进行训练:

import sys
import tensorflow as tf
from dytb.inputs.predefined.MNIST import MNIST
from dytb.models.predefined.LeNetDropout import LeNetDropout
from dytb.train import train

def main():
    """main executes the operations described in the module docstring"""
    lenet = LeNetDropout()
    mnist = MNIST()

    info = train(
        model=lenet,
        dataset=mnist,
        hyperparameters={"epochs": 2},)

    checkpoint_path = info["paths"]["best"]

    with tf.Session() as sess:
        # Define a new model, import the weights from best model trained
        # Change the input structure to use a placeholder
        images = tf.placeholder(tf.float32, shape=(None, 28, 28, 1), name="input_")
        # define in the default graph the model that uses placeholder as input
        _ = lenet.get(images, mnist.num_classes)

        # The best checkpoint path contains just one checkpoint, thus the last is the best
        saver = tf.train.Saver()
        saver.restore(sess, tf.train.latest_checkpoint(checkpoint_path))

        # Create a builder to export the model
        builder = tf.saved_model.builder.SavedModelBuilder("export")
        # Tag the model in order to be capable of restoring it specifying the tag set
        # clear_device=True in order to export a device agnostic graph.
        builder.add_meta_graph_and_variables(sess, ["tag"], clear_devices=True)
        builder.save()

    return 0


if __name__ == '__main__':
    sys.exit(main())

使用 Go 进行服务,代码如下:

package main

import (
        "fmt"
        tg "github.com/galeone/tfgo"
        tf "github.com/tensorflow/tensorflow/tensorflow/go"
)

func main() {
        model := tg.LoadModel("test_models/export", []string{"tag"}, nil)

        fakeInput, _ := tf.NewTensor([1][28][28][1]float32{})
        results := model.Exec([]tf.Output{
                model.Op("LeNetDropout/softmax_linear/Identity", 0),
        }, map[tf.Output]*tf.Tensor{
                model.Op("input_", 0): fakeInput,
        })

        predictions := results[0].Value().([][]float32)
        fmt.Println(predictions)
}

之所以会这样,是因为用图来表示计算,并且用这种方式描述计算是很有挑战性的。

此外,tfgo 支持 GPU 计算,并允许编写并行代码,而且无需担心执行设备问题。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值