- Hello TensorFlow
- TensorFlow C library
- TensorFlow Go bingding
Hello TensorFlow
人類喜歡將所有事物都納入鄙視鏈的范疇蔓纠,寵物當(dāng)然也不例外倦春。一般來(lái)說(shuō)泽疆,擁有一只純種寵物可以讓主人占據(jù)鄙視鏈的云端歼培,進(jìn)而鄙視那些混血或者流浪寵物捣染。甚至還發(fā)展出了專業(yè)的鑒定機(jī)構(gòu)诺舔,可以頒發(fā)《血統(tǒng)證明書》求泰。但是考究各類純種鑒定的常規(guī)方法:例如眼睛的大小芝加、顏色硅卢、鼻子的特點(diǎn)射窒、身軀長(zhǎng)度、尾巴特征将塑、毛發(fā)等脉顿,當(dāng)然也包括一些比較玄幻的特征:寵物家族的個(gè)性、氣質(zhì)等等点寥。拋開(kāi)“黑魔法”不在此討論之外艾疟,既然是基于生物外形特征鑒定,判斷是否純種的需求本質(zhì)上就是一個(gè)圖像識(shí)別服務(wù)敢辩。
Tensorflow is not a Machine Learning specific library, instead, is a general purpose computation library that represents computations with graphs.
TensorFlow 開(kāi)源軟件庫(kù)(Apache 2.0 許可證)蔽莱,最初由 Google Brain 團(tuán)隊(duì)開(kāi)發(fā)。TensorFlow 提供了一系列算法模型和編程接口戚长,讓我們可以快速構(gòu)建一個(gè)基于機(jī)器學(xué)習(xí)的智能服務(wù)盗冷。對(duì)于開(kāi)發(fā)者來(lái)說(shuō),目前有四種編程接口可供選擇:
- C++ source code: Tensorflow 核心基于 C++ 編寫同廉,支持從高到低各個(gè)層級(jí)的操作;
- Python bindings & Python library: 對(duì)標(biāo) C++ 實(shí)現(xiàn)仪糖,支持 Python 調(diào)用 C++ 函數(shù);
- Java bindings;
- Go binding;
下面是一個(gè)簡(jiǎn)單的實(shí)例:
[圖片上傳失敗...(image-8754c1-1518459129749)]
環(huán)境準(zhǔn)備
- 安裝 TensorFlow C library,包含一個(gè)頭文件 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 語(yǔ)言環(huán)境,參考:玩轉(zhuǎn)編程語(yǔ)言:Golang
安裝 Tensorflow Go binding library
go get github.com/tensorflow/tensorflow/tensorflow/go
go get github.com/tensorflow/tensorflow/tensorflow/go/op
- 下載模型(demo model),包含一個(gè)標(biāo)簽文件 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 模型實(shí)現(xiàn)圖像識(shí)別的主要流程如下:
- 圖像轉(zhuǎn)換 (Convert to tensor )
- 圖像標(biāo)準(zhǔn)化( 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
}
// ...
}
函數(shù) 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
}
函數(shù) maketransformimagegraph() 將圖形的像素值調(diào)整到 224x224迫肖,以符合模型輸入?yún)?shù)要求锅劝。
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 中運(yùn)算咒程。
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%"}]
}
通過(guò)上面的案例我們可以發(fā)現(xiàn)鸠天,這個(gè)服務(wù)目前可以對(duì)于黑天鵝圖像的推算概率值為 98.75%,非常準(zhǔn)確帐姻;但是對(duì)于另外兩張寵物狗的圖像稠集,最高的推算概率值也僅有 30% 左右,雖然也沒(méi)有被識(shí)別成貓咪或者狼饥瓷,但是和理想效果要求可用性還有一段距離(此處暫時(shí)忽略物種本身的復(fù)雜性)剥纷。主要是因?yàn)楝F(xiàn)在我們使用的還只是一個(gè)非常“原始”的模型呢铆,如果需要為小眾領(lǐng)域服務(wù)(寵物晦鞋,也可以是其它事物),需要通過(guò)訓(xùn)練(Training Models)增強(qiáng)優(yōu)化棺克,或者引入更豐富的標(biāo)簽悠垛,更合適的模型。當(dāng)然娜谊,訓(xùn)練過(guò)程中也會(huì)存在樣本質(zhì)量不佳的情況确买,錯(cuò)誤樣本和各種噪音也會(huì)影響準(zhǔn)確度。
擴(kuò)展閱讀
Getting Started with TensorFlow: A Machine Learning Tutorial
YoutubeIntroduction To TensorFlow
We Need to Go Deeper: A Practical Guide to Tensorflow and Inception
We know that label 866 (military uniform) should be the top label for the Admiral Hopper image.
擴(kuò)展閱讀:《The Machine Learning Master》
- Machine Learning(一):基于 TensorFlow 實(shí)現(xiàn)寵物血統(tǒng)智能識(shí)別
- Machine Learning(二):寵物智能識(shí)別之 Using OpenCV with Node.js
- Machine Learning:機(jī)器學(xué)習(xí)項(xiàng)目
- Machine Learning:機(jī)器學(xué)習(xí)算法
- Machine Learning:機(jī)器學(xué)習(xí)書單
- Machine Learning:人工智能媒體報(bào)道集
- Machine Learning:機(jī)器學(xué)習(xí)技術(shù)與知識(shí)產(chǎn)權(quán)法
- Machine Learning:經(jīng)濟(jì)學(xué)家談人工智能
- 數(shù)據(jù)可視化(三)基于 Graphviz 實(shí)現(xiàn)程序化繪圖