顯示具有 工具收集 標籤的文章。 顯示所有文章
顯示具有 工具收集 標籤的文章。 顯示所有文章

2014年1月19日 星期日

[UI Automation] Sikuli 的入門使用

來源自 這裡 
Sikuli是什麼? 
用維基百科上的介紹來說,Sikuli 是一種可視化技術,它可以用來自動化的在一個圖形用戶界面(GUI)上進行操作和測試。而 Sikuli 腳本就是實現這一過程的一種腳本語言。它通過截圖來識別需要操作的圖形界面組件,再通 Jython 來完成操作動作從而實現自動化的操作(或者測試). 說得簡單一點,Sikuli 就是能通過截圖幫助我們自動操作電腦的一種便利的方式。如果想瞭解更多的Sikuli的意義,那就讀一讀 Sikuli 作者的 介紹 吧! 

那 Sikuli 是不是很難學呢?如果不追求精細的操控和精準的方式,那你只需要有一個操作電腦的心,再加上認識幾個英語單詞,就足夠了. 

先從安裝Sikuli開始吧: 
是不是要先檢查一下你的操作系統?不,當然不用,但是也有一樣需要確認,那就是你的電腦上是否安裝了Java呢?不知道如何檢測自己電腦上是否安裝了Java嗎?不要著急,只需要打開 Java官方的檢測網頁,然後根據頁面的指引就能得知自己是否安裝了Java,如果沒有,也將有相應的指引,幫助你安裝好Java. 

然後,得益於 Sikuli 作者的不懈努力,不論是什麼什麼操作系統,只要安裝有 Java,就可以容易的從官方網站上下載通用安裝包來完成安裝了

一點一點的學習Sikuli: 
1. 認識一下Sikuli的IDE 
要打開運行Sikuli的運行環境還有編輯環境,我們需要雙擊安裝完成後Sikuli文件夾裡名稱為“runIDE” (Integrated Development Environment) 的文件。打開之後,Sikuli 的 IDE大概就是這樣(下圖為windows中的式樣,Mac中同此差不多,只是圖標更為精緻): 
 

而我們需要關心的也只有三個地方:可以錄入文字的編輯區域,還有運行按鈕和截圖按鈕. 

2. 從點擊按鈕開始 
我們學習電腦的時候,最先學到的或許就是如何通過點擊按鈕來實現對應的功能了。而對於Sikuli而言,點擊操作同樣是重要的,畢竟GUI中按鈕是實現操作的重要組成. 在Sikuli裡,要實現這個操作也十分簡單,因為你只需要記住 “Click” 這個單詞。沒錯,就是英語的“點擊”一詞。它的代碼也極盡簡單: 
Click(…)

而上面這句代碼中的 “…” ,並不是什麼特別的語言,或者什麼複雜的代碼,而是代表了一個截圖。比如希望Sikuli點擊一下Mac OS左上角的蘋果標示,那麼,這樣的一句代碼就可以達到目的: 
Click()

簡單也很便利! 因為這就是 Sikuli 力求達到的一種直觀的自動化操作的方式了

其它的點擊方式也與此類似,比如右鍵點擊就是:`RightClick(…)`,而雙擊就是:`DoubleClick(…)`。 

3. 尋找按鈕或者圖案 
Sikuli 的本意就是讓某一個計算機程序代替人來做操作,而識別按鈕,或者某一個圖案,也就是一個很重要的部分了。雖然這一點的意義重大,但是,對於在Sikuli上的操作卻可以很容易的實現! 這時候,你只需要認識這樣的一個英文單詞——Find。沒錯,想要在屏幕上找到某一個按鈕或者圖案,只需要使用: 
Find(…)

就可以了。當然,這個函數括號裡的目標依然是某一個東西的截圖。我們可以寫這樣的一個簡單的小命令: 
x=find()
click(x)

那這個例子實現的又是怎樣的操作呢?這個命令其實還是等同於`Click()`,只是這個例子裡,我們關注的是 Sikuli 模仿人行為的過程。一個人來點擊某一個按鈕的過程是:找到按鈕,然後點擊。而通過“find-click”方式完成的 Sikuli 腳本也同樣實現的就是人的操作過程! 如果若們要一個一個找到所有相同的按鈕要怎麼辦?不用擔心,不用寫很多遍`find(…)`的,只需要使用: 
findAll(…)

就可以了。findAll()可以一次性把所有相同按鈕,或者圖案一次性都找到。這樣找到的按鈕就會形成一個集合,這個集合的形成應該很好理解,繼續就是要如何來逐一操作這個按鈕集合裡的按鈕呢?這就涉及到 Sikuli 的程序控制問題了。這也是,接下來要講到的內容. 

4. Sikuli 腳本的程序控制 
那什麼是程序控制呢?那也就是在涉及到重複做某一個操作,或者在判斷某一個條件之後再決定是否要進行某一個操作,以及類似的情況的時候,我們所談論的就是程序控制了. 在 Sikuli 裡面,這個表示條件運行某一個行為的語句就夠也和上面這個例子類似(`#`後是程序註釋內容): 
if … : … #do something

還有另一類程序控制的內容,那就是循環語句了。也就是,需要重複做某一個動作的程序語言命令。在一般的計算機語言裡,一般有兩種方式來完成這樣的重複。一個就是for循環語句,一個是while循環語句. 我們先來分別看看 for循環語句 和 while循環語句 在Sikuli裡的寫法吧: 
* for 循環語句: for i in set: … #do something 
* while 循環語句: while … #condition : … #do something 

從上面的這個結構中,我們很容易瞭解到這樣一件事情:for循環語句是先確定需要循環操作的某一個集合,然後再進行重複操作;而while循環語句則是先考慮某一個條件成立與否來,再決定是否結束重複的操作. 那麼,現在就可以解決上面那個點擊找到的所有相同按鈕的操作了,可以用這樣的代碼來實現: 
for x in findAll(): click(x)

為了做出對比,我們再來分別看一下while循環語句的例子吧. 我們可以舉這樣的一個例子:用Sikuli來實現一下,如果我的某一個 Skype 好友下線了,就提醒我的功能。首先,我們不能確定需要查看好友下沒下限需要多少次,或者是他會在線多久,所以也就不能確定重複次數的集合了,換句話說就是,這個問題,不能使用for循環語句來完成目標。而恰切,這個循環中有一個判斷的條件,也就是關注這個好友的在線狀態是結束於好友下線的瞬間,於是,我們就可以用 while循環語句 來解決這個問題了: 
while exists(): wait(5)
popup(u”vgod下線了”)

這個代碼中,除了while循環語句,還有三個新的功能函數,`exists(…)`函數表示判斷目標截圖是不是存在,放到我們的例子裡就是用來檢查好友 vgod 的skype圖標是否處於在線狀態; `wait(…)`函數表示等待,括號裡填上需要等待的秒數就好; 而最後的`popup(…)`函數就是用於彈出一個帶文字的提示框. 

5. 打開特定的程序 
在模仿我們操作行為上更進一步,就是:打開某個程序,然後在這個程序上進行操作。就比如打開Safari,然後進入Top Sites。對應打開程序這個操作的Sikuli函數依然十分貼近英文: 
App.open(…)

那麼,我們就可以這樣來完成這個例子: 
App.open(“Safari”)
click()

當然這是在Safari還沒打開的情況下,如果Safari打開了,但是,窗口被最小化了,我們又要如何操作呢?同樣簡單,使用 App.focus(…) 就可以了。只需要上面的例子裡的第一行修改成: 
App.focus()

類似的,關閉程序,就是:App.close(…),這個函數的使用方法也是類似的. 

6. 操作鍵盤 
直到上面,我們一直都在關注的都是鼠標操作,現在是我們需要開始關注一下鍵盤操作的時候了. 我們從一開始到現在,已經足夠多的了解到點擊鼠標在 Sikuli 裡是Click(…),而敲擊鍵盤在 Sikuli 裡其實也是差不多的,就是使用: 
type(…)

我們可以做這樣一個例子,就是在Spotlight中搜索一個單詞: 
click()
type(“Sikuli”)

對於普通的文字輸入,只需要把需要的文字用雙引號括起來在寫到 “type(…)” 的括號裡就可以了。如果是中文的話,就在雙引號前加上一個字母“u”: 
type(u”朱麗葉”)

那麼對於特殊字符又要如何處理呢?比如,Mac OS上的 CMD,又或者是 Windows 上的win鍵,這兩個極特殊的鍵,在 Sikuli 裡面都使用 KEY_META 來代表,使用的方法就是直接把它寫入括號內,如:type(KEY_META),注意喲,對於特殊按鍵是不用使用雙引號括起來的

對於 CTRL、ALT 之類的特殊鍵,也可以按照類似的模式使用,也就是“KEY_”加上對應的全大寫鍵名。不過,這個表示方法並不適用於全部特殊鍵。對於 “F1” 至 “F12” 和 “ESC” 鍵而言,需要使用 “Key.” 加上鍵名來表示. 當我們需要同時按下兩個按鍵來完成某一個操作的時候,又要如何在 Sikuli 裡實現呢?雖然還是使用 “type(…)”,但是也只是簡單的稍作增加,比如我們要使用快捷鍵刷新 Safar i的當前頁面. (更多說明可以參考 Key Constants
type(KEY_META,”R”)

7. 一個用於搶購的實例 
當我們已經明白並且記住了以上那些東西之後,就可以考慮做一些稍微複雜的事情了。選擇一個什麼樣子的實例比較有趣呢?我首先想到的,就是這類“手快有手慢沒”的網絡搶購的例子了! 

想想看吧,我們需要Sikuli不停的監視網頁,如果網頁不能實時自刷新、自更新,那麼,還要不斷刷新網頁,直到搶購的時機來到,當開始請購的時候,需要點擊搶購的按鈕,需要修改購買的數量,如果有需要還要填寫自己的地址和信用卡信息等等,一直到確認所有信息,並完成最後的訂單確認. 我們就以下面這個網頁的搶購為例吧! 
 

我們需要等到搶購的按鈕 "" 出現,為此我們假設網頁不能自更新,於是,在Mac OS裡面我們可以用這樣一段代碼實現: 
App.focus(“Safari”)
while not exists():
type(KEY_META,”R”)
click()

然後,在新的頁面上,修改需要搶購的個數(假設買三件),再確認購買進入訂單頁面。當然,也還是有可能需要我們滾動一下頁面來找到需要修改的位置。用 Sikuli 來實現的代碼也就是: 
while not exists():
  type(key.DOWN)
x=find().right().find()
for i in range(3):
  click(x)
click()

在這一段代碼中,兩個新的函數,一個是“right()”,這是用來表示搜索方向的函數;還有一個是“range(…)”,這是用來生成數列的函數,數列長度填入函數的括號內,這是一個 Python 裡的函數. 當我們進入訂單頁面之後,需要檢查是否已經填好地址,如果沒有填好地址,就把地址填上,再確認訂單,我們這次搶購就算完成了。相應的 Sikuli 代碼可以這樣寫出來: 
if exists():
  click()
  type(u”中國哏都”)
  click()
click()

現在,我們就可以把程序完整整理出來了,需要注意的是,Sikuli 在解讀代碼過程中使用的是Python/Jython的解讀模式,也是通過縮進來判斷那些程序是一起運行的。上面的程序中 while循環語句 等程序控制語句我都使用了這樣的方式來分行分別寫下運行條件和運行內容. 

8. 各種Sikuli的小提示 
1. 如果需要截圖的按鈕在比較深的菜單裡,那麼就需要手動啓動 Sikuli 的截圖快捷鍵。這個截圖快捷鍵是:Command+Shift+2 
2. 可以多是用幾個 “wait(…)” 函數來讓 Sikuli 暫停幾秒鐘,尤其是再打開網頁、刷新網頁的時候,因為未加載好的網頁可能讓識別出錯。 
3. Sikuli 自帶函數可操作的對象,大多數都可以使用截圖。雖然使用截圖會導致運行效率略有降低,但是使用截圖才是真正 Sikuli 的核心,所以不要為了速度本末倒置
4. 鼠標的拖拽操作對於 Sikuli 其實也是十分簡單的,只需要記住去使用 “dragDrop(…)” 函數就可以。 
5. Sikuli 是建立在截圖的基礎上的,也就導致,不同機器、不同分辨率、不同操作環境的電腦不能通用一個Sikuli腳本
6. if 條件運行語句的完整結構是: “if …: con1 else: con2”,含義就是如果滿足某一個條件,就運行 con1 的語句,否則,就運行 con2。 
7. 如果有時間,最好完整讀一讀 Sikuli 完整的函數介紹,因為我只是介紹了最為基本的內容,那不是 Sikuli 的全部! 

參考文獻:: 
Sikuli的發佈在2010年,到現在已經有三年的歷史了。但是 Sikuli 的發展並不快,其實它從一發佈就已經足夠完善了。有人說,Sikuli 很像按鍵精靈,嗯,確實是這樣,尤其是初學的時候。但是,當我們需要更複雜的操作的時候,當我們需要更為精緻的操作的時候,我們就會發現 Sikuli 的不同了. 
1. Sikuli (from Wikipedia) 
2. Sikuli Script 
3. Sikuli帶來的意義與無限潛力 
4. 會截圖就會自動化測試 
5. Sikuli常用函數與簡單事件操作. 
6. IDE (from Wikipedia) 
7. Sikuli——創新的圖形化編程技術 
8. Tutorials — Sikuli X 1.0 documentation 
9. Python (from Wikipedia) 
10. Jython入門教程

2013年5月23日 星期四

[ Tools ] CRF - Condition Random Field Toolkit in Java 使用入門


來源自 這裡
Preface:
因為我的專案有用到 CRF (Conditional random fields), 因此就去拜 Google 大神找找看有沒有好用的 Toolkit. 如果你是 C 的專家, 那你可以考慮 Wapiti , 或者是 CRF++. 這邊要介紹的是使用 Java 實作 CRF 的另一個選擇. 它是由 Prof. Sunita Sarawagi 開發並且可以在 這裡 得到更多該工具的使用說明與介紹.

有關 CRF 的介紹這邊我也不多說, 有興趣的就去看看 wiki, 而它一個很常見的運用便是在句子 POS (Part of speech) 的偵測: 當給你一連串的 word 的 sequence, 你能否根據 training 的 model 來預測每一個 word 的詞性 (名詞, 動詞 或是 形容詞 etc). 因此在使用這個工具時首先便需要知道如何將 sequence 的資料餵到工具裡, 並進行 training 然後 testing.

底下將一步步從 1) 資料的格式與餵入 2) Training 3) Testing 從新手的角度告訴你如何使用該工具.

Data Preparation and feeding:
因為我們輸入的資料需要是 sequence (序列) 的, 因此在該工具中提供了介面 DataSequence 讓我們來定義我們的資料格式並由它負責來解析輸入的資料. 這邊我們使用下面的訓練資料:
# R->Rail; S->Sun; C->Cloud
# 1->Play; 0->Stay Home;

R:0-S:1-S:1-S:0-C:0-R:0
S:0-R:0-R:0-S:1-S:0-C:0-C:0-C:1
C:0-C:1-C:0-S:0-S:1-C:1-R:0-R:0-S:1
R:0-S:1-S:0-C:1-C:0-R:0-R:0-R:1
R:1-C:0-C:0-S:1-S:0-S:0-C:1-R:0-C:0-R:0-R:0-C:1
R:0-R:0-C:0-S:1-S:0-S:0-S:1-C:0-C:0-C:1
S:1-R:0-R:0-S:1-S:0-C:0-R:0-R:0
R:0-R:0-R:0-C:1-S:0-C:1-S:1-C:0-C:0-R:0
C:0-S:1-S:0-S:0-C:1-R:0-R:0-R:0-C:1-S:1
R:0-R:0-C:0-S:1-S:0-S:0-S:1-C:0-C:0-C:1
S:0-S:1-C:0-C:0-R:0-R:0-C:0-C:1-C:0-S:1

每一行就是一個 sequence, 而 "S:0" 說明欲檢視的輸入資料為 "S" (Suny) 而對應該資料的 Label 為 "0" (Stay Home); 而每一個序列中的輸入資料都是以 "-" 當作分隔符. 而這邊我們建立類別DDataSequence 來實作介面 DataSequence 以讀入訓練或測試資料:
  1. package demo;  
  2.   
  3. import iitb.CRF.DataSequence;  
  4.   
  5. import java.util.ArrayList;  
  6. import java.util.List;  
  7.   
  8. public class DDataSequence implements DataSequence{  
  9.     private static final long serialVersionUID = 1L;  
  10.     public int                  miss = 0;  
  11.     private List         labelList; // List to keep label  
  12.     private List      tokenList; // List to keep token  
  13.   
  14.     public DDataSequence(){}  
  15.     public DDataSequence(String line){loadData(line);}  
  16.       
  17.     @Override  
  18.     public int length() {  
  19.         return labelList.size();  
  20.     }  
  21.   
  22.     @Override  
  23.     public void set_y(int idx, int value) {  
  24.         labelList.set(idx, value);        
  25.     }  
  26.   
  27.     @Override  
  28.     public Object x(int idx) {  
  29.         return tokenList.get(idx);  
  30.     }  
  31.   
  32.     @Override  
  33.     public int y(int idx) {  
  34.         return labelList.get(idx);  
  35.     }  
  36.   
  37.     public int size(){return length();}  
  38.       
  39.     /** 
  40.      * BD: We define how to load in data from file. 
  41.      * @param line: File path 
  42.      * @return 
  43.      */  
  44.     public boolean loadData(String line)  
  45.     {         
  46.         labelList = new ArrayList();  
  47.         tokenList = new ArrayList();  
  48.         String pairs[] = line.split("-");  
  49.         try  
  50.         {  
  51.             for(String pair:pairs)  
  52.             {  
  53.                 String ps[] = pair.split(":");  
  54.                 if(ps.length==2)  
  55.                 {  
  56.                     tokenList.add(ps[0]);  
  57.                     labelList.add(Integer.valueOf(ps[1]));  
  58.                 }  
  59.                 else {  
  60.                     tokenList.add(ps[0]);  
  61.                     labelList.add(-1);  
  62.                 }                 
  63.             }  
  64.         }  
  65.         catch(Exception e){e.printStackTrace(); return false;}  
  66.         return true;  
  67.     }  
  68. }  
接著多個 Sequence 可以包裝在介面 DataIter 裡面 (可以把一個 sequence 看做一個 training 或 testing 的 instance), 這邊我定義類別 DDataIter 來實作該介面:
  1. package demo;  
  2.   
  3. import java.util.List;  
  4. import iitb.CRF.DataIter;  
  5. import iitb.CRF.DataSequence;  
  6.   
  7. public class DDataIter implements DataIter{  
  8.     public List datas = null;  
  9.     public int pos = 0;  
  10.   
  11.     public DDataIter(List datas){this.datas = datas;}  
  12.       
  13.     @Override  
  14.     public boolean hasNext() {  
  15.         return pos < datas.size();  
  16.     }  
  17.   
  18.     @Override  
  19.     public DataSequence next() {  
  20.         return datas.get(pos++);  
  21.     }  
  22.   
  23.     @Override  
  24.     public void startScan() {  
  25.         pos = 0;          
  26.     }  
  27.   
  28.     public int size(){return datas.size();}  
  29. }  
到目前為止我們已經能讀入測試與訓練資料, 接著要處理的便是如何訓練與測試模型了

Handling Model:
同樣的資料, 你可能有多種模型, 但是模型的訓練與測試流程卻是一樣的, 因此下面我定義一個抽象類別 AbstModel 並使用它來實作我們要的模型:
  1. package demo.proto;  
  2.   
  3. import iitb.CRF.DataSequence;  
  4.   
  5. import java.io.BufferedReader;  
  6. import java.io.File;  
  7. import java.io.FileReader;  
  8. import java.util.HashMap;  
  9.   
  10. public abstract class AbstModel {  
  11.     public int          nlabels=5;  /*Number of label*/  
  12.       
  13.     /** 
  14.      * BD : Allocate default feature. 
  15.      */  
  16.     public abstract void allocFeat();  
  17.     /** 
  18.      * BD : Allocate feature as param 'feat' with weight as param 'wt'. 
  19.      * @param feat 
  20.      * @param wt 
  21.      */  
  22.     public abstract void allocFeat(IFeature feat, double wt);  
  23.     /** 
  24.      * BD : Save trained statistic data into file with path as param 'fn'. 
  25.      * @param fn 
  26.      * @throws Exception 
  27.      */  
  28.     public abstract void saveStatisticData(String fn) throws Exception;  
  29.     /** 
  30.      * BD : Load trained statistic data from binary file with path as param 'filename'. 
  31.      * @param filename 
  32.      * @throws Exception 
  33.      */  
  34.     public abstract void loadStatisticData(String filename) throws Exception;  
  35.     /** 
  36.      * BD : Predict label for input sequence as param 'seq'. 
  37.      * @param seq 
  38.      * @return 
  39.      */  
  40.     public abstract int[] predictSeq(DataSequence seq);  
  41.       
  42.     /** 
  43.      * BD : Predict label for input sequence as param 'seq'. 
  44.      * @param seq 
  45.      * @return 
  46.      */  
  47.     public abstract int[] predictSeq(DataSequence seq, PI pi);  
  48.       
  49.     /** 
  50.      * BD : Train the model. Before doing this, please call API parseRawdata(). 
  51.      * @throws Exception 
  52.      */  
  53.     public abstract void train() throws Exception;  
  54.     /** 
  55.      * BD : Load in the sequence data from file with path as param 'fn'. 
  56.      * @param fn 
  57.      */  
  58.     public abstract void parseRawdata(String fn);  
  59.       
  60.     /** 
  61.      * BD : Tagged file indicated by "testDataPath" and output to file indicated by "outputPath". 
  62.      * @param testDataPath 
  63.      * @param outputPath 
  64.      * @throws Exception 
  65.      */  
  66.     public abstract PI validate(String testDataPath, String outputPath) throws Exception;  
  67.       
  68.     /** 
  69.      * BD : Performance Index 
  70.      * @author John 
  71.      */  
  72.     public class PI /*Performance Index*/  
  73.     {  
  74.         public HashMap> missTagStat = new HashMap>();  
  75.         public int hit = 0;  
  76.         public int miss = 0;  
  77.         public int s_hit = 0;  
  78.         public int s_miss = 0;  
  79.         public int size(){return hit+miss;}  
  80.         public int ssize(){return s_hit+s_miss;}  
  81.         public void hit(){hit++;}  
  82.         public void shit(){s_hit++;}  
  83.         public void miss(){miss++;}  
  84.         public void smiss(){s_miss++;}  
  85.         public float hitRate() {return ((float)hit)/(hit+miss);}  
  86.         public float shitRate() {return ((float)s_hit)/(s_hit+s_miss);}  
  87.         public float missRate() {return 1-hitRate();}  
  88.         public float smissRate() {return 1-shitRate();}  
  89.         public void miss(int answer, int tagged){  
  90.             miss++;  
  91.             if(missTagStat.containsKey(answer)) {  
  92.                 HashMap mtagged = missTagStat.get(answer);  
  93.                 if(mtagged.containsKey(tagged)) mtagged.put(tagged, mtagged.get(tagged)+1);  
  94.                 else mtagged.put(tagged, 1);  
  95.                 missTagStat.put(answer, mtagged);  
  96.             }  
  97.             else  
  98.             {  
  99.                 HashMap mtagged = new HashMap();  
  100.                 mtagged.put(tagged, 1);  
  101.                 missTagStat.put(answer, mtagged);  
  102.             }  
  103.         }  
  104.     }         
  105. }  
而一個實作的範例類別 DModel 如下:
  1. package demo;  
  2.   
  3. import iitb.CRF.CRF;  
  4. import iitb.CRF.DataSequence;  
  5. import iitb.Model.FeatureGenImpl;  
  6. import iitb.Utils.Options;  
  7.   
  8. import java.io.BufferedReader;  
  9. import java.io.BufferedWriter;  
  10. import java.io.File;  
  11. import java.io.FileReader;  
  12. import java.io.FileWriter;  
  13. import java.util.HashMap;  
  14. import java.util.LinkedList;  
  15. import java.util.List;  
  16. import demo.proto.AbstModel;  
  17. import demo.proto.IFeature;  
  18. import flib.util.TimeStr;  
  19.   
  20. public class DModel extends AbstModel{  
  21.     String              modelGraphType = "naive";  // "semi-markov" or "naive"  
  22.     FeatureGenImpl      featureGen;  
  23.     CRF                 crfModel;     
  24.     Options             options;  
  25.     DDataIter               dataIter = null;  
  26.     public String       baseDir = "IRProj";  
  27.     public String       outDir = "Test";  
  28.   
  29.     public DModel(Options o){this.options = o;};  
  30.     public DModel()  
  31.     {  
  32.         this(new Options());  
  33.     }  
  34.       
  35.     public void  allocModel() throws Exception {  
  36.         featureGen = new FeatureGenImpl(modelGraphType, nlabels);  
  37.         crfModel=new CRF(featureGen.numStates(),featureGen,options);  
  38.     }  
  39.       
  40.     public void saveModel(String savePath) throws Exception  
  41.     {  
  42.         File bfdr = new File(savePath);  
  43.         if(!bfdr.exists()) bfdr.mkdirs();  
  44.         crfModel.write(new File(bfdr, "crf.txt").getAbsolutePath());  
  45.         featureGen.write(new File(bfdr, "features.txt").getAbsolutePath());  
  46.     }  
  47.       
  48.     public void loadModel(String path) throws Exception  
  49.     {  
  50.         allocModel();  
  51.         File bfdr = new File(path);         
  52.         crfModel.read(new File(bfdr, "crf.txt").getAbsolutePath());  
  53.         featureGen.read(new File(bfdr, "features.txt").getAbsolutePath());  
  54.     }  
  55.   
  56.     public void test(String testDataPath, String outputPath) throws Exception{        
  57.         doTest(testDataPath, outputPath);  
  58.     }  
  59.       
  60.     protected void outputTaggedData(BufferedWriter bw, DataSequence seq) throws Exception{  
  61.         if(seq.length()>0)  
  62.         {  
  63.             bw.append(String.format("%s:%d", seq.x(0), seq.y(0)));  
  64.             for(int i=1; i" %s:%d", seq.x(i), seq.y(i)));  
  65.             bw.append("\r\n");  
  66.         }  
  67.     }  
  68.       
  69.     public void doTest(String testDataPath, String outputPath) throws Exception  
  70.     {  
  71.         BufferedWriter bw = new BufferedWriter(new FileWriter(new File(outputPath)));  
  72.         parseTestData(testDataPath);  
  73.         DataSequence seq = null;  
  74.         int labels[] = null;  
  75.         while(dataIter.hasNext())  
  76.         {  
  77.             seq = dataIter.next();  
  78.             labels = predictSeq(seq);  
  79.             outputTaggedData(bw, seq);  
  80.         }  
  81.         bw.close();  
  82.     }  
  83.   
  84.       
  85.     public void parseTestData(String fn)  
  86.     {  
  87.         List trainReds = new LinkedList();  
  88.         try  
  89.         {  
  90.             File trainData = new File(fn);  
  91.             BufferedReader br = new BufferedReader(new FileReader(trainData));  
  92.             String line = null;  
  93.             DDataSequence seq = null;  
  94.             while((line=br.readLine())!=null)  
  95.             {  
  96.                 if(line.trim().isEmpty()||line.trim().startsWith("#")) continue;  
  97.                 System.out.printf("\t[Test] Read line=%s\n", line);               
  98.                 seq = new DDataSequence();                
  99.                 seq.loadData(line);  
  100.                 if(seq.length()>0) trainReds.add(seq);  
  101.             }  
  102.               
  103.             br.close();  
  104.             dataIter = new DDataIter(trainReds);  
  105.             System.out.printf("\t[Test] Total %d sequence data...\n", dataIter.size());  
  106.         }  
  107.         catch(Exception e)  
  108.         {  
  109.             e.printStackTrace();  
  110.         }  
  111.     }  
  112.   
  113.     @Override  
  114.     public void allocFeat() {  
  115.         // TODO Auto-generated method stub  
  116.           
  117.     }  
  118.   
  119.     @Override  
  120.     public void allocFeat(IFeature feat, double wt) {  
  121.         // TODO Auto-generated method stub  
  122.           
  123.     }  
  124.   
  125.     @Override  
  126.     public void saveStatisticData(String fn) throws Exception {  
  127.         // TODO Auto-generated method stub  
  128.           
  129.     }  
  130.   
  131.     @Override  
  132.     public void loadStatisticData(String filename) throws Exception {  
  133.         // TODO Auto-generated method stub  
  134.           
  135.     }  
  136.   
  137.     @Override  
  138.     public int[] predictSeq(DataSequence seq) {  
  139.         int labels[] = new int[seq.length()];  
  140.         crfModel.apply(seq);  
  141.         featureGen.mapStatesToLabels(seq);  
  142.         for(int i=0; i
  143.         return labels;  
  144.     }  
  145.       
  146.     @Override  
  147.     public int[] predictSeq(DataSequence seq, PI pi)  
  148.     {  
  149.         int labels[] = new int[seq.length()];  
  150.         for(int i=0; i
  151.         crfModel.apply(seq);  
  152.         featureGen.mapStatesToLabels(seq);  
  153.         for(int i=0; i
  154.         {  
  155.             if(labels[i] != seq.y(i))  
  156.             {  
  157.                 pi.miss(); labels[i] = seq.y(i);  
  158.                 if(i+1==seq.length()) pi.smiss();  
  159.             }  
  160.             else  
  161.             {  
  162.                 pi.hit();  
  163.                 if(i+1==seq.length()) pi.shit();  
  164.             }  
  165.         }  
  166.         return labels;  
  167.     }  
  168.   
  169.     @Override  
  170.     public void train() throws Exception {  
  171.         long st = System.currentTimeMillis();  
  172.         allocModel();  
  173.         featureGen.train(dataIter);  
  174.         double featureWts[] = crfModel.train(dataIter);  
  175.         System.out.printf("\t[Test] Training done...\n");          
  176.         System.out.printf("\t[Test] Total spending time : %s...\n", TimeStr.toStringFrom(st));  
  177.           
  178.     }  
  179.   
  180.     @Override  
  181.     public void parseRawdata(String fn) {  
  182.         parseTestData(fn);        
  183.     }  
  184.   
  185.     @Override  
  186.     public PI validate(String testDataPath, String outputPath) throws Exception {  
  187.         BufferedReader br = new BufferedReader(new FileReader(new File(testDataPath)));  
  188.         BufferedWriter bw = new BufferedWriter(new FileWriter(new File(outputPath)));  
  189.           
  190.         PI pi = new PI();  
  191.         String line = null;  
  192.         DDataSequence seq = null;  
  193.         int seqCnt = 0;  
  194.         while((line=br.readLine())!=null)  
  195.         {  
  196.             seq = new DDataSequence(line);  
  197.             if(seq.size()>0)  
  198.             {                 
  199.                 predictSeq(seq, pi);  
  200.                 outputTaggedData(bw, seq);  
  201.                 seqCnt++;  
  202.             }  
  203.         }  
  204.         bw.close();  
  205.         br.close();  
  206.         System.out.printf("\t[CRF-Mode] Total processing seq=%d...\n", seqCnt);  
  207.         return pi;  
  208.     }  
  209. }  
你可以使用屬性 modelGraphType = "naive" 來決定你要使用的模型. 更多支援的模型可以參考 這裡

Training process:
接著下面的範例代碼使用模型類別 DModel 來對輸入訓練資料 "data/wtraining_data.txt" 進行模型的訓練:
  1. String trainData = "data/wtraining_data.txt";         
  2. String outPath = "data/model";  
  3. /*Training model*/  
  4. DModel model = new DModel();  
  5. model.nlabels = 100;  
  6. model.parseTestData(trainData);  
  7. model.train();  
  8. model.saveModel(outPath);  
訓練完後會在 "data/model" 目錄下面產生檔案:
* features.txt : 訓練產生的 features.
* crf.txt : 對應 features 的 weighting.

Testing/Prediction Process:
當你使用上面的步驟產生模型的檔案後, 你便可以使用下面範例代碼載入模型檔案並對測試資料 "data/wtest_data.txt" 進行 Label 的預測並導出結果到 "data/wtag_data.txt":
- "data/wtest_data.txt"
R:0-R:0-C:0-S:1-S:0-C:1-R:0
S:1-C:1-C:0-R:0-R:0-R:0-C:1-C:0-S:1
C:1-C:0-C:0-R:0-S:1-S:1-R:0-C:0-C:1
C:1-R:0-R:0-C:0-R:0-S:1-S:0-C:1-R:0-R:0
S:0-S:1-C:1-C:0-R:0-R:1-R:0-R:0-S:1-C:1
S:1-C:1-C:0-R:0-C:0-S:1-S:0-R:0-R:0-C:1

  1. String testData= "data/wtest_data.txt";  
  2. String tagData = "data/wtag_data.txt";  
  3. String outPath = "data/model";  
  4. /*Training model*/  
  5. DModel model = new DModel();  
  6. model.nlabels = 100;  
  7.   
  8. model.loadModel(outPath);  
  9. PI pi = model.validate(testData, tagData);  
  10. System.out.printf("\t[Test] Hit rate=%.02f; Miss rate=%.02f\n", pi.hitRate(), pi.missRate());  
  11.   
  12. System.out.printf("\t[Info] Done!\n");  
輸出結果如下:
[CRF-Mode] Total processing seq=6...
[Test] Hit rate=0.71; Miss rate=0.29
[Info] Done!
This message was edited 18 times. Last update was at 24/05/2013 14:39:35

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...