Machine Learning(一):基于 TensorFlow 實(shí)現(xiàn)寵物血統(tǒng)智能識(shí)別

  • 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 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
  }
}
識(shí)別案例:黑天鵝
$ 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%"}]
}
IMG_3560.png
IMG_3608.png

通過(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ò)展閱讀

We know that label 866 (military uniform) should be the top label for the Admiral Hopper image.

擴(kuò)展閱讀:《The Machine Learning Master》

image
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末纱皆,一起剝皮案震驚了整個(gè)濱河市湾趾,隨后出現(xiàn)的幾起案子芭商,更是在濱河造成了極大的恐慌,老刑警劉巖搀缠,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铛楣,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡艺普,警方通過(guò)查閱死者的電腦和手機(jī)簸州,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)衷敌,“玉大人勿侯,你說(shuō)我怎么就攤上這事〗陕蓿” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵祭埂,是天一觀的道長(zhǎng)面氓。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蛆橡,這世上最難降的妖魔是什么舌界? 我笑而不...
    開(kāi)封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮泰演,結(jié)果婚禮上呻拌,老公的妹妹穿的比我還像新娘。我一直安慰自己睦焕,他們只是感情好藐握,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著垃喊,像睡著了一般猾普。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上本谜,一...
    開(kāi)封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天初家,我揣著相機(jī)與錄音,去河邊找鬼乌助。 笑死溜在,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的他托。 我是一名探鬼主播掖肋,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼上祈!你這毒婦竟也來(lái)了培遵?” 一聲冷哼從身側(cè)響起浙芙,我...
    開(kāi)封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎籽腕,沒(méi)想到半個(gè)月后嗡呼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡皇耗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年南窗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片郎楼。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡万伤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呜袁,到底是詐尸還是另有隱情敌买,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布阶界,位于F島的核電站虹钮,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏膘融。R本人自食惡果不足惜芙粱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望氧映。 院中可真熱鬧春畔,春花似錦、人聲如沸岛都。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)疗绣。三九已至线召,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間多矮,已是汗流浹背缓淹。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留塔逃,地道東北人讯壶。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像湾盗,于是被迫代替她去往敵國(guó)和親伏蚊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容