Caffe Windows系列(4): 中文識別初探(續(xù))

0. 預備

上一篇文章中霜威,我們測試了100個中文字符使用Lenet5模型的正確率,其正確率達到了100%册烈。(不達到100%就有問題了戈泼,我的訓練集和測試集是極其近似的,僅僅是為了自己練手赏僧,而并未達到實際用途大猛。) 接下來要做的事情是,用C++ API讀取一個圖像淀零,并對其進行識別挽绩。在《Caffe Windows系列(2): 使用C++ API進行分類》一文中,談到了如果要能夠進行識別驾中,需要準備五個文件唉堪。

  1. deploy.prototxt:這個文件目前還沒有模聋。
  2. network.caffemodel:這個文件已經(jīng)有了,即lenet_iter_10000.caffemodel唠亚。
  3. mean.binaryproto:這個文件還沒有链方。
  4. labels.txt:這個文件就是一個分類文件。
  5. img.jpg:要測試的圖像

我的labels.txt文件類似于如下的列表

丁
萬
嚴
于
任
何
余
侯
傅
馮
劉
盧
史
葉
向
呂
吳

...
馬
高
魏
黃
黎
龍
龔

1. deploy.prototxt

在mnist的例子中灶搜,lenet.prototxt就相當于deploy.txt祟蚀。它與真正用于訓練的lenet_train_test.prototxt有一些差別,但好在差別也不大占调。

  • 差別1:輸入層暂题。lenet_train_test.prototxt的輸入是lmdb文件。而deploy.txt中是沒有使用lmdb文件的究珊。因此薪者,lenet.prototxt將輸入層簡化為:
layer {
  name: "data"
  type: "Input"
  top: "data"
  input_param { shape: { dim: 64 dim: 1 dim: 28 dim: 28 } }
}

不過我認為,使用中剿涮,shape的第一個dim應當寫為1才對言津。因為64是batch_size。而我們測試的時候取试,是一個一個測試的悬槽,因此,可以設(shè)置為1瞬浓。

  • 差別2:作為TEST階段的accuracy層可以不再需要了初婆。
  • 差別3:loss層變?yōu)閜rob層。因為不需要進行損失函數(shù)的計算了猿棉。
    loss層:
layer {
  name: "loss"
  type: "SoftmaxWithLoss"
  bottom: "ip2"
  bottom: "label"
  top: "loss"
}

prob層:

layer {
  name: "prob"
  type: "Softmax"
  bottom: "ip2"
  top: "prob"
}

依樣畫葫蘆磅叛,我們就可以寫出自己的deploy.prototxt文件來。

name: "LeNet"
layer {
  name: "data"
  type: "Input"
  top: "data"
  input_param { shape: { dim: 1 dim: 1 dim: 40 dim: 40 } }
}
layer {
  name: "conv1"
  type: "Convolution"
  bottom: "data"
  top: "conv1"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  convolution_param {
    num_output: 20
    kernel_size: 5
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "pool1"
  type: "Pooling"
  bottom: "conv1"
  top: "pool1"
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layer {
  name: "conv2"
  type: "Convolution"
  bottom: "pool1"
  top: "conv2"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  convolution_param {
    num_output: 50
    kernel_size: 5
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "pool2"
  type: "Pooling"
  bottom: "conv2"
  top: "pool2"
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layer {
  name: "ip1"
  type: "InnerProduct"
  bottom: "pool2"
  top: "ip1"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 1000
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "relu1"
  type: "ReLU"
  bottom: "ip1"
  top: "ip1"
}
layer {
  name: "ip2"
  type: "InnerProduct"
  bottom: "ip1"
  top: "ip2"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 100
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "prob"
  type: "Softmax"
  bottom: "ip2"
  top: "prob"
}

2. 繞開均值文件

由于Lenet-5的訓練并未使用到均值文件萨赁,因此弊琴,可以生成一個全零的均值文件來代替。如果使用python接口杖爽,生成全零的均值文件比較方便敲董,網(wǎng)上有很多文章。但如果使用C++接口慰安,它使用的均值文件是binaryproto后綴的腋寨,不是直接可視化的那種,因此泻帮,生成全零的均值文件并不是那么容易的事精置。相比之下,可能在cpp_classification代碼的基礎(chǔ)上進行修改锣杂,從而繞過這個均值文件會更容易一些脂倦。

之前對于mean_file的處理番宁,主要是SetMean這個函數(shù):

/* Load the mean file in binaryproto format. */
void Classifier::SetMean(const string& mean_file) {
  BlobProto blob_proto;
  ReadProtoFromBinaryFileOrDie(mean_file.c_str(), &blob_proto);
 
  /* Convert from BlobProto to Blob<float> */
  Blob<float> mean_blob;
  mean_blob.FromProto(blob_proto);
  CHECK_EQ(mean_blob.channels(), num_channels_)
    << "Number of channels of mean file doesn't match input layer.";
 
  /* The format of the mean file is planar 32-bit float BGR or grayscale. */
  std::vector<cv::Mat> channels;
  float* data = mean_blob.mutable_cpu_data();
  for (int i = 0; i < num_channels_; ++i) {
    /* Extract an individual channel. */
    cv::Mat channel(mean_blob.height(), mean_blob.width(), CV_32FC1, data);
    channels.push_back(channel);
    data += mean_blob.height() * mean_blob.width();
  }
 
  /* Merge the separate channels into a single image. */
  cv::Mat mean;
  cv::merge(channels, mean);
 
  /* Compute the global mean pixel value and create a mean image
   * filled with this value. */
  cv::Scalar channel_mean = cv::mean(mean);
  mean_ = cv::Mat(input_geometry_, mean.type(), channel_mean);
}

現(xiàn)在,我將SetMean函數(shù)改為:

void Classifier::SetMean(const string& mean_file) {
    mean_ = cv::Mat::zeros(input_geometry_, CV_32F);
}

這樣的話赖阻,不管輸入的mean_file是啥蝶押,我都會讓mean_成為一個全零矩陣。

3. 正式測試

將examples\classification設(shè)為啟動項火欧,配置調(diào)試參數(shù):

配置調(diào)試參數(shù)

命令參數(shù)為:

deploy.prototxt lenet_iter_10000.caffemodel mean.binaryproto labels.txt test.bmp

test.bmp為:

測試圖像

運行后的結(jié)果為:

---------- Prediction for test.bmp ----------
1.0000 - "潘"
0.0000 - "萬"
0.0000 - "于"
0.0000 - "任"
0.0000 - "丁"

也就是說棋电,這個圖,100%像“潘”字苇侵,而0%像后面的“萬”赶盔、“于”、“任”榆浓、“丁”于未。這個結(jié)果是一個非常不錯的鼓勵。有理由相信陡鹃,CNN完全可以勝任印刷體漢字的識別烘浦。接下來,我會去嘗試身份證信息的識別~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末萍鲸,一起剝皮案震驚了整個濱河市闷叉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脊阴,老刑警劉巖握侧,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嘿期,居然都是意外死亡藕咏,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門秽五,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人饥悴,你說我怎么就攤上這事坦喘。” “怎么了西设?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵瓣铣,是天一觀的道長。 經(jīng)常有香客問我贷揽,道長棠笑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任禽绪,我火速辦了婚禮蓖救,結(jié)果婚禮上洪规,老公的妹妹穿的比我還像新娘。我一直安慰自己循捺,他們只是感情好斩例,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著从橘,像睡著了一般念赶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上恰力,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天叉谜,我揣著相機與錄音,去河邊找鬼踩萎。 笑死停局,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的驻民。 我是一名探鬼主播翻具,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼回还!你這毒婦竟也來了裆泳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤柠硕,失蹤者是張志新(化名)和其女友劉穎工禾,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝗柔,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡闻葵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了癣丧。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片槽畔。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖胁编,靈堂內(nèi)的尸體忽然破棺而出厢钧,到底是詐尸還是另有隱情,我是刑警寧澤嬉橙,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布早直,位于F島的核電站,受9級特大地震影響市框,放射性物質(zhì)發(fā)生泄漏霞扬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望喻圃。 院中可真熱鬧萤彩,春花似錦、人聲如沸级及。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饮焦。三九已至怕吴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間县踢,已是汗流浹背转绷。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留硼啤,地道東北人议经。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像谴返,于是被迫代替她去往敵國和親煞肾。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

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