python宠物类的实现_Machine Learning(一):基于 TensorFlow 实现宠物血统智能识别

人类喜欢将所有事物都纳入鄙视链的范畴,宠物当然也不例外。一般来说,拥有一只纯种宠物可以让主人占据鄙视链的云端,进而鄙视那些混血或者流浪宠物。甚至还发展出了专业的鉴定机构,可以颁发《血统证明书》。但是考究各类纯种鉴定的常规方法:例如眼睛的大小、颜色、鼻子的特点、身躯长度、尾巴特征、毛发等,当然也包括一些比较玄幻的特征:宠物家族的个性、气质等等。抛开“黑魔法”不在此讨论之外,既然是基于生物外形特征鉴定,判断是否纯种的需求本质上就是一个图像识别服务。

Hello TensorFlow

Tensorflow is not a Machine Learning specific library, instead, is a general purpose computation library that represents computations with graphs.

TensorFlow 开源软件库(Apache 2.0 许可证),最初由 Google Brain 团队开发。TensorFlow 提供了一系列算法模型和编程接口,让我们可以快速构建一个基于机器学习的智能服务。对于开发者来说,目前有四种编程接口可供选择:

C++ source code: Tensorflow 核心基于 C++ 编写,支持从高到低各个层级的操作;

Python bindings & Python library: 对标 C++ 实现,支持 Python 调用 C++ 函数;

Java bindings;

Go binding;

下面是一个简单的实例:

环境准备

安装 TensorFlow C library,包含一个头文件 c_api.h 和 libtensorflow.so

wget https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-cpu-linux-x86_64-1.5.0.tar.gz

## options

TF_TYPE="cpu" # Change to "gpu" for GPU support

TF_VERSION='1.5.0'

curl -L \

"https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-${TF_TYPE}-$(go env GOOS)-x86_64-${TF_VERSION}.tar.gz" |

安装 Go 语言环境,参考:玩转编程语言:Golang

安装 Tensorflow Go binding library

go get github.com/tensorflow/tensorflow/tensorflow/go

go get github.com/tensorflow/tensorflow/tensorflow/go/op

下载模型(demo model),包含一个标签文件 label_strings.txt 和 graph.pb

mkdir model

wget https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip -O model/inception.zip

unzip model/inception.zip -d model

chmod -R 777 model

Tensorflow Model Function

//Loading TensorFlow model

func loadModel() error {

// Load inception model

model, err := ioutil.ReadFile("./model/tensorflow_inception_graph.pb")

if err != nil {

return err

}

graph = tf.NewGraph()

if err := graph.Import(model, ""); err != nil {

return err

}

// Load labels

labelsFile, err := os.Open("./model/imagenet_comp_graph_label_strings.txt")

if err != nil {

return err

}

defer labelsFile.Close()

scanner := bufio.NewScanner(labelsFile)

// Labels are separated by newlines

for scanner.Scan() {

labels = append(labels, scanner.Text())

}

if err := scanner.Err(); err != nil {

return err

}

return nil

}

Classifying Workflow

基于 Tensorflow 模型实现图像识别的主要流程如下:

图像转换 (Convert to tensor )

图像标准化( Normalize )

图像分类 ( Classifying )

func recognizeHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {

// Read image

imageFile, header, err := r.FormFile("image")

// Will contain filename and extension

imageName := strings.Split(header.Filename, ".")

if err != nil {

responseError(w, "Could not read image", http.StatusBadRequest)

return

}

defer imageFile.Close()

var imageBuffer bytes.Buffer

// Copy image data to a buffer

io.Copy(&imageBuffer, imageFile)

// ...

tensor, err := makeTensorFromImage(&imageBuffer, imageName[:1][0])

if err != nil {

responseError(w, "Invalid image", http.StatusBadRequest)

return

}

// ...

}

函数 makeTensorFromImage() which runs an image tensor through the normalization graph.

func makeTensorFromImage(imageBuffer *bytes.Buffer, imageFormat string) (*tf.Tensor, error) {

tensor, err := tf.NewTensor(imageBuffer.String())

if err != nil {

return nil, err

}

graph, input, output, err := makeTransformImageGraph(imageFormat)

if err != nil {

return nil, err

}

session, err := tf.NewSession(graph, nil)

if err != nil {

return nil, err

}

defer session.Close()

normalized, err := session.Run(

map[tf.Output]*tf.Tensor{input: tensor},

[]tf.Output{output},

nil)

if err != nil {

return nil, err

}

return normalized[0], nil

}

函数 maketransformimagegraph() 将图形的像素值调整到 224x224,以符合模型输入参数要求。

func makeTransformImageGraph(imageFormat string) (graph *tf.Graph, input, output tf.Output, err error) {

const (

H, W = 224, 224

Mean = float32(117)

Scale = float32(1)

)

s := op.NewScope()

input = op.Placeholder(s, tf.String)

// Decode PNG or JPEG

var decode tf.Output

if imageFormat == "png" {

decode = op.DecodePng(s, input, op.DecodePngChannels(3))

} else {

decode = op.DecodeJpeg(s, input, op.DecodeJpegChannels(3))

}

// Div and Sub perform (value-Mean)/Scale for each pixel

output = op.Div(s,

op.Sub(s,

// Resize to 224x224 with bilinear interpolation

op.ResizeBilinear(s,

// Create a batch containing a single image

op.ExpandDims(s,

// Use decoded pixel values

op.Cast(s, decode, tf.Float),

op.Const(s.SubScope("make_batch"), int32(0))),

op.Const(s.SubScope("size"), []int32{H, W})),

op.Const(s.SubScope("mean"), Mean)),

op.Const(s.SubScope("scale"), Scale))

graph, err = s.Finalize()

return graph, input, output, err

}

最后,将格式化的 image tensor 输入到 Inception model graph 中运算。

session, err := tf.NewSession(graph, nil)

if err != nil {

log.Fatal(err)

}

defer session.Close()

output, err := session.Run(

map[tf.Output]*tf.Tensor{

graph.Operation("input").Output(0): tensor,

},

[]tf.Output{

graph.Operation("output").Output(0),

},

nil)

if err != nil {

responseError(w, "Could not run inference", http.StatusInternalServerError)

return

}

Testing

func main() {

if err := loadModel(); err != nil {

log.Fatal(err)

return

}

r := httprouter.New()

r.POST("/recognize", recognizeHandler)

err := http.ListenAndServe(":8080", r)

if err != nil {

log.Println(err)

return

}

}

$ curl localhost:8080/recognize -F 'image=@../data/IMG_3560.png'

{

"filename":"IMG_3000.png",

"labels":[

{"label":"black swan","probability":0.98746836,"Percent":"98.75%"},

{"label":"oystercatcher","probability":0.0040768473,"Percent":"0.41%"},

{"label":"American coot","probability":0.002185003,"Percent":"0.22%"},

{"label":"black stork","probability":0.0011524856,"Percent":"0.12%"},

{"label":"redshank","probability":0.0010183558,"Percent":"0.10%"}]

}

通过上面的案例我们可以发现,这个服务目前可以对于黑天鹅图像的推算概率值为 98.75%,非常准确;但是对于另外两张宠物狗的图像,最高的推算概率值也仅有 30% 左右,虽然也没有被识别成猫咪或者狼,但是和理想效果要求可用性还有一段距离(此处暂时忽略物种本身的复杂性)。主要是因为现在我们使用的还只是一个非常“原始”的模型,如果需要为小众领域服务(宠物,也可以是其它事物),需要通过训练(Training Models)增强优化,或者引入更丰富的标签,更合适的模型。当然,训练过程中也会存在样本质量不佳的情况,错误样本和各种噪音也会影响准确度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值