2017年4月15日 星期六

Training A Simple Classifier - Algorithm

承續上一篇,Training A Simple Classifier,我們的問題是,想寫一支程式,該程式,經由透過指導員的訓練之後,可以學會區分Ladybird和Caterpillar這兩種生物。

我們把訓練電腦的次數限制為兩個,先是訓練Ladybird (3, 1),再來是訓練Caterpillar (1, 3)。當然,實際上,只訓練兩次是絕對不夠的,這裡只是為了說明方便而已。

訓練之前,程式隨機從原點畫出一條線叫Initial Line:
y = A * x
A = 0.25

進行第一次訓練:指導員告訴程式,位在(3, 1)的是Ladybird

程式判斷這Initial Line適不適合:
Actual Output = 0.25 * 3 = 0.75

0.75 表示Initial Line,在Ladybird的下面,不是我們要的線,要修正。

如何修正?

我們希望,線要在Ladybird的上面,而且一次不要修正太多。
我們決定:
Desired Target = 1.1
(在 y = 1 的上面)

目前的線是
y = (0.25) x

我們想調整它的斜率,使得
1.1 = (0.25 + △A) * 3

於是
△A = (1.1 / 3) - 0.25 = 0.1167

程序員,想把它寫程通用的公式 
△A = (Target / x) - A

在「Make Your Own Neural Network」這本書,公式是長這個樣子
△A = Error / x

其實是這麼來的
△A = (Target - A * x) / x = (Target - Output) / x = Error / x

這兩個公式的意思是一樣的。作為程序員的我,比較偏好前者。因為可以一目了然△A和A之間的關係。

於是調整後的A就是
A = 0.25 + 0.1167 = 0.3667

當然,我們寫把它寫成一行程式
A = A + △A

請注意,這是程式,不是數學式。若數學式這樣寫,可能會被數學家罵,請多包涵。另外,若變數名稱取△A,這對大部份程式語言而言,是有困難。我的習慣是,把它取名為DiffA。

至此,我們修正的線為:
Refined Line: y = (0.3667) x

接下來,進行第二次訓練:指導員告訴程式,位在(1, 3)的是Caterpillar
我們發現,Refined Line雖然在Caterpillar與Ladybird的中間,但離Caterpillar太遠,我們希望,它不要離Caterpillar太遠,但不要一次修正太多。

我們決定
Desired Target = 2.9 
(在y = 3的下面)

我們想調整線的斜率,使得:
2.9 = (0.3667 + △A) * 1

那就直接套用剛才寫那兩行程式吧!
△A = (Target / x) - A = (2.9 / 1) - 0.3667 = 2.5333
A = A + △A = 0.3667 + 2.5333 = 2.9

最後,修正的線為:
Final Refined Line: y = (2.9) x

我們把Initial Line、Refined Line、Final Refined Line的演化過程,表達為下圖:



Final Refined Line不是我們要的,因為離Caterpillar太近,而且離Ladybird太遠。我們期望的線應該要居中。是不是有Bug?

具我了解,大部份的程序員,不見得數學非常好,甚至不喜歡數學。其實,程序員遇到一些Bug,在解Bug的過程,所用到的思考方式,其實和數學家差不多,只是程序員沒有意識到這一點而已。我的意思是說,程式要寫的好,數學很重要。數學家,不見得想成為好的程序員。可是程序員,進級到某一階段,數學能力是必備的。

我的心路歷程是,非常喜歡寫程式,不排斥數學。但因為年輕的時候,時間都花在寫程式上,導致數學的底子不夠。後來,工作的關係,從參與Secure Flash與UEFI Secure Boot的開始,發現程式的核心部份和密碼學有關,而密碼學本質上就是一套數學。我才意識到,原來數學對程序員的修養,非常重要。彌補的方法就是,先把要用到的數學理論學好,而不用急者寫程式。如何做到?可以用程序員的思維來學習數學,我不敢說,這樣做最有效,但心理感覺比較踏實。

這種方法的好處就是,一旦了解之後,就不一定要花時間把程式寫出來,才為認自己懂了,因為程式已經Run在心裡面。同樣的學習方法,也可以從人工智慧的領域,去攻線性代數和微積分。當然,這個方法,謹適用在實作經驗很豐富的程式員身上。

這是題外話,該回歸正題了。如何解決直線太偏的Bug?程序員解這個問題?不外乎是改一改程式,看一看結果。若運氣好找到不錯的結果,再去找Root Cause,然後想辦法對自己的Solution自圓其說。若運氣不好,一直找不到,才去思考Root Cause。程序員通常都是這樣工作的。

下一篇,我會介紹如何用Learning Rate,來改善直線太偏的Bug。

沒有留言:

張貼留言