小松鼠嚇了一跳,有了魔法眼鏡後,這世界看起來完全不一樣了

2019年6月9日 星期日

找到你的熱情所在是個爛建議

因為都 2019 年了,還是很多人建議年輕人:「尋找自己的熱情」。這是一個爛建議。
簡單的說,熱情並不是用找到的,而是培養的。如果你還沒跟上,快一點,這個已經是一種很主流的建議了:
或者可以上網搜尋一下 Growth mindset vs Fixed mindset. 成長性思維與固定思維。雖然這個論點也有爭議,但目前還是一種可以接受的學說,有實驗證據。
接受成長型思維,不代表要否定人之與人之間的差異。人和人之間,絕對有天賦以及天性上的差異。但這個差異可能比你想像中的小。看看這個影片吧。
如果沒有手,都能彈鋼琴,那很多不會彈琴的人,問題很難歸因於天賦上的差異。多數人哀怨自己天賦不夠,有這麼大嗎?

當然,「尋找自己的熱情」,也可以解讀成內在探索上的意義。這點其實不算錯,不過要能真正找到自己真正的熱情,先決條件是要探索自我,搞清楚「我」到底是什麼。但真的要能了解真正的自己,差不多就能算是「明心見性」了。這個太難了。
而且,大多數需要「尋找自己熱情」這種建議的人,都會說類似「我不擅長記憶」、「我不喜歡算術」這類話。畢竟,如果他已經有喜歡的事物,也就不需要煩惱是否要「尋找自己的熱情」。大多數這樣的人,心態都在「這個也不是、那個也不是,我還在摸索還在找啊」這個情境下。
請注意,這些我喜歡什麼、我討厭什麼、我怎麼樣、我怎麼樣、我怎麼樣的的想法,都是「執著」。
抱持著執著之心,想要探索自我,明心見性,不是緣木求魚嗎?

我以前寫過「要當個興趣人」一文,有人會把我歸類為「跟隨熱情」一派。但那篇文章中,完全沒有說「要找到自己的興趣」,而是「要有對事物產生興趣的能力」:
就像一個電玩迷,通常不會只迷一個遊戲。一個電影迷也很少只看一部電影。一個「興趣迷」自然會不斷尋求新興趣。一直反覆看同一本小說的,也難稱為小說迷。
有多次這種「興趣」的經驗後,你甚至可以刻意誘導自己,讓自己對特定事物產生興趣。
 我有時也會跟學生說,既然你已經決定要念某一門課,即使再不喜歡,也要強顏歡笑,假裝自己很愛他。久而久之,就會假戲真做。
很多人可能沒有真的聽進去。還是抱持著「我不需要喜歡這門科目,靠努力和決心就能學會了」。
但是你的決心和努力夠嗎? 強顏歡笑,然後甚至假戲真做的人,才是真正有決心,有努力的人。真正有決心想學的人,為了學會,是連自我都可以捨棄的。拋棄掉那個「我覺得微積分很無聊」、「我不是理科人」的那個自我。真正努力的人,是想盡方法增加自己的極限。泯滅自我,讓自己愛上「微積分」,你才有辦法擠出更多能量來學習。不會每次學習,都要消耗不必要的恆毅力。
一般人常常會把「真正的努力」誤認為「天賦」,而把「讓自己很累」誤認為「努力」。

差不多就是這樣了。
對了,愛因斯坦從來沒有說過「假如你讓一條魚爬樹的話,牠會永遠相信自己是一個笨蛋。」那段話。
--


然後,問題才真正開始。有一個問題比較簡單,可以先回答。
「既然成長性思維,不需要跟隨熱情,而且熱情是可以培養的,那是不是可以任意逼小孩去念醫科?」
「先等你有能力可以對任何領域,都能自由自在產生熱情再說。」

2019年5月10日 星期五

未來的志向

分享給當老師的朋友或者好的大人。
常看到有人會問年輕人未來有什麼理想、想從事什麼職業,希望他們能立定志向和目標,更有動力。
但未來不是如此明確而自私的存在,是一團糾纏不清旋轉閃爍的亂流。
較好的方式是想像你希望的世界模樣(世界包含自己),然後讓未來的軌跡收縮到這個想像上。
自己的位置,會自然而然顯現在收斂的不動點上。
 

2018年7月27日 星期五

黃色小鴨除錯法及其他

StackExchange Rubber Duck Avatar April Fools 20
黃色小鴨除錯法是一個還算有名的概念,維基百科的介紹足夠清楚。
(Rubber Duck Debugging)是可在軟體工程中使用的一種偵錯代碼的方法。方法就是在程式的偵錯、除錯或測試過程中,操作人耐心地向小黃鴨解釋每一行程式的作用,以此來激發靈感與發現矛盾。 此概念是參照於一個故事。故事中程式大師隨身攜帶一隻小黃鴨,在偵錯代碼的時候會在桌上放上這隻小黃鴨,然後詳細地向鴨子解釋每行代碼。
乍看之下有點荒謬,但實際上類似的概念很實用也很常出現。 有一個腳踏車實驗,可能你也聽過,因為這本書「知識的假象:為什麼我們從未獨立思考?」的關係:
很多人都覺得他們了解腳踏車的原理,但是在一項知名的心理學研究中,自信滿滿的受試者有四○%無法正確畫出腳踏車的構造,有些人甚至會用鏈條把前後輪都連在一起,這樣的腳踏車要怎麼騎啊?
這種症狀可以被稱為是知識的幻覺。也不只是腳踏車,我們常常會高估自己對事物的了解程度。

但同一本書上也提到了,在實驗中,只要先請受試者解釋一下事物原理(沒有人批改),再請他評估自己理解的程度。則這種自我感覺良好的情形就會得到改善。 

不是所有人都有這種「知識幻覺」的症狀,很多人其實讀了那本書,可能會覺得莫名其妙。覺得「我本來就能正確評估我對抽水馬桶和汽車運行原理的了解程度啊」。的確很多人是這樣的,靠理解思考的人。但根據書上所說的,有更多人是另外一種,偏向靠感覺的人,所以會分不清「常見」和「理解」,兩種都能被稱為「熟悉」。 

這在某種程度上面解釋了黃色小鴨除錯法的原理,執行解釋這個動作,可以讓我們進入另外一種心理狀態。而這種狀態,能讓我們破除一些主觀的盲點。 

同樣的原理也會發生在閱讀自己的文章以及閱讀別人文章的差別。很多人閱讀自己寫的文章時,無法發現錯誤、錯字。所以會需要其他人幫忙校稿。因為對於自己的文章太過熟悉了。但是閱讀別人文章時,頭腦內部會有一個「讀懂」也就是解釋的步驟,所以是不同的心理狀態。 

更類似而常見的,是宗教上的禱告祈願告解。當你對著神像解釋著你的人生難題時,就是在執行黃色小鴨除錯法。 

從更大一點框架來看,這也可以看成是一種目的外部性的方式,將觀點轉移到小鴨、神明或不特定對象為理解主體,來述說整個故事。

舊文補發:「賈伯斯搶功 創意奇才很受傷」

賈伯斯搶功 創意奇才很受傷
今天在中國時報看了跨版大篇幅報導賈伯斯搶功 創意奇才很受傷,說到
艾夫對賈伯斯搶去太多功勞感到十分不爽,對賈伯斯「把我的創意講成是他的」十分受傷。當外界把賈伯斯形容為蘋果「創意之王」時,艾夫更會變得渾身是刺。
以及
「他常常會瀏覽一遍我的創意與設計,然後說,這個不太好,這個也普普;我比較喜歡那個,」艾夫說:「然後,過一陣子,我就會坐在觀眾席裡,看著他在講台上 口沫橫飛,彷彿一切都來自他的創意。我非常講究分辨自己的創意從何而來,我甚至有一本筆記本,裡面記滿了我的想法與點子。因此,當他把我的創意講成是他 的,我會覺得很不舒服。」

想像一下這種情形,在團體中聊天,偶然間你發現到了某個有趣的事,也許是諧音,也許是新奇的想法,所以你講了句幽默的話把這個想法點了出來。團體中有幾個人聽到了,也笑了,其中有一個人過了兩三秒之後,終於恍然大悟你的意思,似乎相當興奮,開始把你的想法複述了一遍,由於很興奮,所以聲音比較大,剛才沒聽到或者還沒注意聽你講話的人,也聽到了。而且似乎也因為興奮的緣故,所以在附和和複述你的想法時,有點太過細節了(比方把諧音或者笑點解釋出來),就你的品味來說,其實是有點太囉唆而且破壞趣味。但也許就在當時,也許之後,奇怪的是,團體中大部份人都認為那個人才是想到有趣點子的人,甚至可能連那個人都自己這麼認為的。

這也就是為什麼常常指導教授覺得關鍵 idea 都是自己告訴學生的,但是學生覺得教授只會出一張嘴。或者腦力激盪中,明明提出新點子的人是你,但大家卻覺得是別人的點子。或者艾夫和賈伯斯之間的情節也是如此。

原因在於彼此的認知基礎不同。你覺得你已經明白點出關鍵了,剩下的東西其實早就知道,沒什麼好解釋。但其他人也許不這麼覺得,那個搶功者花了兩三秒才明白你說什麼,表示那兩三秒鐘他思考了,他二次創造了你的點子。從他的角度來說,你只是個啟發或者現象,真正的發現者和創造者是他自己。你只是剛好講到那個諧音或者某個關鍵字,真正把東西聯想起來的是他。教授和研究生的例子就更典型了,因為研究生要花上更多時間來重新發現教授的想法(先不論教授嘴砲的情形)。

2017年1月1日 星期日

2017 is not just another prime number

Good bye year 2016. Hello year 2017.
We all know that 2017 is a prime number, but it is more than just another prime number.

  • 2017π (rounds to nearest integer) is a prime
  • 2017e (rounds to nearest integer ) is a prime.
  • The sum of all odd primes up to 2017 is a prime number, i.e. 3+5+7+11+...+2017 is a prime number. 
  • The sum of the cube of gap of primes up to 2017 is a prime number. That is (3-2)^3 + (5-3)^3 + (7-5)^3 + (11-7)^3 + ... + (2017-2011)^3 is a prime number.
  • The prime number before 2017 is 2017+(2-0-1-7), which makes it a sexy prime, and the prime after 2017 is 2017+(2+0+1+7). 2017 itself is of course equal to  2017+(2*0*1*7) 
  • Insert 7 into any two digits of 2017, it is still a prime number, i.e. 27017, 20717, 20177 are all primes. Plus, 20177 is also a prime number
  • Since all digits of 2017 is less than 8, it can be viewed as an octal. 2017 is still a prime number as an octal.
  • 2017 can be written as a sum of three cubes of primes, i,e,  p^3 +q^3 +r^3 for some primes p, q, r.
  • 2017 can be written as a sum of cubes of five distinct integers.
  • 2017 can be written as  x^2+y^2, x^2+2y^2, x^2+3y^2, x^2+4y^2 x^2+6y^2, x^2+7y^2, x^2+8y^2, x^2+9y^2 (for positive integers x, y)
  • 20170123456789 is also a prime
  • the 2017th prime number is 17539 and 201717539 is also a prime.
  • Let p=2017, then both (p+1)/2 and (p+2)/3 are prime numbers.
  • The first ten digits of the decimal expansion of the cubic root of 2017 contains all different digits 0~9. 2017 is the least integer has this property. 
  • 2017 = 2^11 - 11th prime 

You can check OEIS for more interesting facts for your favorite numbers :)

Update: a sagemath worksheet to verify these facts by William Stein

2016年8月17日 星期三

其實我們都是半桶水

像 pokemon go 這樣的社會級現象,往往有很多不同的面向。每個人真的都只是一知半解。
除了 pokemon 這個傳承外,還有很多。比方很多人可能也會因此開始認識 ingress 或其他 location based game.
gps 模擬、certificate pinning、VPN、MITM proxy 這些,也許很多人覺得稀鬆平常。但對很多人來說,可能是新大陸,正開始展開熱情研究。
可能也有人因為這個"不入流"的 AR 應用開始對 AR 產生興趣。
有人則好奇要怎麼樣的伺服器和架構才能處理這麼多玩家。
有人可能因為這個遊戲開始對「圓」產生的興趣(不是獵人那個,雖然有點像),因為要找出正確位置,開始研究圓心、割線、兩圓焦點、中垂線等等性質,開始對數學感興趣。
還有非常多的面向,多數我甚至根本列不出來。因為我只是一知半解。

當他們分享他們的心得,被一些更外行人的崇拜。也許很多真正的專家會覺得不爽、不屑。
level 30 的人看 level 1 的人崇拜 level 3 、level 5 的人,覺得不爽、不屑。
但多想一下,其實反而應該開心才對,因為這代表有更多外行人認同了你的價值觀、你的方向。即使他們目前還無法領略真正精妙之處,但至少方向是正確了。

本來,要開心欣慰,還是不爽不屑,是個人自由。
只是要改變大眾對次文化的害怕和誤解,是很困難的工作。光是站在那裡,沒有惡意,就很容易嚇跑人了(專家的溝通方式,通常外行人看來會太過尖銳、嚴厲)。
而且別忘了,我們剛開始時,也曾經被這種名不符實的稱讚激勵、推動過。像是因為在親友間的表演被大大的稱讚,或是從朋友、班上最強開始我們的旅程。

有一個說法是,如果有一件事,是所有成年人都該知道的事,那每一天都有 24 萬人第一次聽到。(https://xkcd.com/1053/)


一面踢初入門者、不屑人,一方面又抱怨大眾都不了解你,其實是有點自我矛盾。

其實換個角度,當作是回憶一下自己最初的感動也挺好的。
https://www.youtube.com/watch?v=oWCtSIqubUA

2016年1月26日 星期二

人類是如何被 AI 統治的

 在這篇 Apple co-founder on artificial intelligence: ‘The future is scary and very bad for people’ 後面的留言中, Woz 澄清: "And if AI gets smarter than humans, it would have much more intelligence than we do and figure out ways to make the world work, not fight."
這才是可怕的地方。
雖然像是 Stephen Hawking, Elon Musk, Bill Gates 等人都擔心人類被 AI 統治(如  Open letter on AI),但還是很多人覺得有點杞人憂天。

我猜多數人心中想像被 AI 統治的情景,大概會是魔鬼終結者、 駭客任務那樣。

其實 AI統治人類的未來,比較像 Psycho pass (表面上)或者關鍵報告那樣,至少剛開始會是這樣。而且時間上也至少五十年起跳,兩三個世紀這種數量級。
說起來也不是什麼壞事,而且基本上也無可避免,除非被更壞的未來取代。只不過情感上,還是希望看到人類能以現在的模樣發揮更多的潛力和可能性(也許還能給 AI 一些留下人類的理由)。
真的要說,這種未來正在實現。比方導航就是一個例子。也許你會說,這只是一個工具,像汽車、機車一樣,人類還是有主導權。但也真的有人導航導到水裡面的狀況發生。 差別在哪裡? 如果你對於導航的原理、特性夠了解,就比較能知道它什麼時候會出錯,為什麼會出錯,甚至能除錯,而不會盲目相信(或者說即使懷疑,也沒有別的辦法)。
所以延後 AI 統治人類時間的方式,就是跟他比賽,讓更多人更加了解它。

2015年12月14日 星期一

刺客聶隱娘觀後感


昨天看了聶隱娘,感覺有點後勁。
整部電影不斷在傳達孤獨、蒼涼這個感覺。剛看完其實覺得傳達的有點淺、有點不夠孤獨,但後來慢慢就不那麼確定了。可能也跟敘事有點複雜難解有關。
這這種感覺當然從對白中被很直接的敘述出來了,但我被電影的影像和聲音打中的,也就那一堆被人詬病的無聊鏡頭很乏味的聲音。
這種孤獨、蒼涼感,有點類似「前不見古人,後不見來者,念天地之悠悠,獨愴然而涕下」那種感覺,那種宇宙雖大、沒有同類的孤獨感。
事實上,電影中窈七也哭了,為了另外一個代表孤獨這個概念的娘娘而哭。這個哭不是單純因為孤獨寂寞而哭。而是一種同理心的哭法。因為窈七能同理娘娘的訣別與孤寂。但這還不到哭點。關鍵點是,窈七同理到,娘娘因為自身的孤獨,也能同理窈七的孤獨。
因為這種理解與被理解,能短暫的解放沒有同類的孤獨感。

 其實這類描寫沒有同類的孤獨感故事、電影很多。一堆中二救世主電影像是分歧者、飢餓遊戲這類莫名其妙的苦瓜臉主角,往往都是自認我很特別、你們沒有人了解我。
影集 Doctor who 三不五時也在玩這個把戲。
其實搜尋一下,the loneliest people are the kindest 的圖片,你就會了解有知道有多少這類的故事。而這句話也解釋了一部分聶隱娘的劇情與性格。
但聶隱娘有趣的是他幾乎單純用影像、聲音、動作、節奏這種方式來刻劃這種感覺。

要更進一步描述這部電影想傳達的孤寂感,我引用下面幾句話:

“You can have everything in the world and still be the loneliest man. And that is the most bitter type of loneliness.” ―Freddie Mercury

 “People think being alone makes you lonely, but I don't think that's true. Being surrounded by the wrong people is the loneliest thing in the world.”  ―Kim Culbertson


“Loneliness - If you find yourself struggling with loneliness, you're not alone. And yet you are alone. So very alone.”     ―Larry Kersten


但真正要能接收到,可能還是要直接去看電影。

2015年7月2日 星期四

心法: 解開封印

Ryo Chijiiwa
(CC-By)

這是我在教以及學上面,覺得能夠一以貫之的心法。那就是用解開封印的態度去面對學習的方法、目的或任何事,或者也可以叫做釋放、使自由。
比方說,與其說培養獨立思考的能力,不如說釋放獨立思考的能力。與其說培養自學的能力,不如說釋放自學的能力。畢竟,被培養出來的能力,是否真的能稱為獨立思考或者自學還有疑慮。
先看兩個故事:

剪斷翅膀的天鵝來源 以下引述並刪修)
 1968年,美國的一個媽媽發現他的三歲女兒居然認識了禮品盒上「OPEN」的第一個字母「O」,感到很吃驚。發現是幼稚園老師教的。這個媽媽一狀告上法庭,理由是幼稚園剝奪了女兒的想像力。因為她女兒在認識「O」之前可以把「O」說成太陽、蘋果、足球、鳥蛋之類的東西,然而在幼稚園教她認識「O」“之後,就失去了這種想像力。她要求幼稚園賠償精神傷殘費1000美元。
三個月後,幼稚園居然敗訴了。因為全部陪審員都被這位媽媽講的故事感動了:「我曾到東方某國旅行,在一家公園裏見到兩隻天鵝,一隻被剪去了左邊的翅膀,被放養在較大水塘裏;另一隻完好無損,被放養在較小的水塘裏。管理員說,這樣能防止它們逃跑。剪去左邊翅膀的天鵝無法保持平衡,所以無法飛;放在小水塘裏,因沒有足夠的滑翔路程,也只能待在水裏。當時我非常震驚和悲哀,今天這場官司,是因為幼稚園剪掉了小孩一隻想像的翅膀,過早地把她投進了那片只有26個字母的小水塘。一隻沒有翅膀的天鵝是永遠都飛不起來的。」

四分鐘魔咒來源 以下引述刪修)
  1945年,Gunder Andersson 創造了4分零1秒4跑完1英哩的紀錄。多數人認為,這超出了人的生理上限。有好幾年的時間,人們一直堅信,不可能在四分鐘的時間內跑完一英哩。慢慢就被大家公認、稱為「四分鐘障礙」。運動員們、甚至連生物學家也確定,這已經超過了人類身體和心理的生物極限。
這個障礙維持了九年。  1954年5月6日,英國醫學院學生羅傑班尼斯特率先以3分59秒4突破了這一障礙,新增了一個更強大的障礙。但事實上,他的記錄僅維持了 46天,之後四分鐘極限也一次又一次被打破。
現在,世界上能夠在四分鐘內跑完一英哩的運動員超過幾百名,他們中甚至還包括許多高中生。 
當羅傑班尼斯特成功突破「四分鐘障礙」後,其他運動員就看見了自己的可能性,他讓每個人都明白了,四分鐘內跑完一英哩是可能的。魔咒也就消失了。

封印以及解封
這兩個故事都說明了想像以及思考自由的重要性,兩個故事分別對應了封印以及解開封印這兩件事情。
我們所有的學習,其實都能視為一種解開封印、釋放、使自己自由過程。學習語言、文字是如此。與其將語言文字視為鍛鍊、訓練出來的能力,不如說,我們本來就有使用文字語言的潛能,教育及學習的過程,只是讓這項潛能發揮出來而已。而學習之後,可以使我們更自由,能接觸很多原本接觸不到的資訊,開放了一個新的世界中。反而原本不識字的情形,像是被鎖在一個小房間中一樣。
同樣的,程式語言、數學、運動、藝術、音樂的各項技能也是如此。 很多時候學到的東西是幫你清掉路障的。

教育的現況:加上封印
但有趣的事情來了,有時候,這種路障是無形的。比方你想探索一個新的世界,固然有一種路障是很直接的,把你的路擋住了。但相反的,如果出現成千上百個選項,你不知道從何選起,一樣不容易找到正確的路。這等於是一種無形的路障。
你要怎麼清掉這種無形的路障呢?最簡單的方法就是,就是把不能走的路,標上此路不通然後擋住。或者更輕鬆,直接標出可以走的路,其他的路全部當成不能走。
原本的目的是要釋放更開闊的世界,但實際上卻很容易退化成加上無數的封印。 兩者表面上的差異很微妙。
這就是第一個故事的點。關鍵就在於,學到 O 這個字母,到底是多了一種想像的可能,還是減少了無數的可能?

另外一個情形是,當你試著當一個解開封印者,解開了一些封印後,你很可能會被你放出來的東西嚇到,想用另外一個封印把他封回去。有點像是五行山腳下放出的孫悟空,馬上就加上頭箍一樣。
xkcd 241: Battle Room


其實這只是個心法,有點像是 "the enemy's gate is down"。比方,不是克服懶惰、戒除懶惰,而是從懶惰中釋放出來。打電玩是好還是壞?要看你是被電玩限制住了,還是電玩打開了你一個可能的世界? 是不是你除了電玩之外的路都被東西檔住了?
大概就是如此。

 --
附註:這兩個故事都有一些爭議,特別是第一個故事,很有可能是大量添油加醋甚至是偽造的故事。 而第二個故事大致上是事實,不過有一些歷史上的小爭議


2015年6月12日 星期五

弱者思維


今天看到這個臉書上看到關於  2013 年的這個事件(solidot) 的討論:
谋智中国开发的定制主页及快速拨号页扩展(xpi文件)被发现会 修改用户的快捷方式,如果中国用户在主页建立了京东商城(www.jd.com)的拨号快捷键,那么该快捷键会被定向到一个返利链接 (http://count.chanet.com.cn/click...www.jd.com”)。该扩展的中国开发者还非常幽默的在源代码里加了一 个注解——“do some evil here”。
在 news group 中,就有人質疑這件事情,然後得到的回答是說,中國很多廠商都做同樣的事情,不是我們的錯。別人都用賤招,你還在那裡乾淨的對決是沒用的。當你被擊倒淘汰時,什麼都別說了。
當然這有點斷章取義,不過這種想法很常見。所以我想討論的是這段文字討論的想法。

無獨有偶的,剛好也在臉書上看到有人提到魔術師抄襲的事情。當他勸他們不要抄襲的時候,得到的回應是:「剛開始總要抄襲啊,我又不像你,那麼厲害有創意。」

常常我們要別人思考理解,再來解數學題,而不要先看答案、背解答時,得到的回應也常常是:「一般人不像你們那麼聰明,你們不了解一般人只能靠背的來學數學。」

看出共同點了嗎? 就是滿滿的「沒辦法、沒辦法、沒辦法」,然後把原因歸咎到環境什麼的,不願意嘗試改變自己。

就是因為一直否認自己需要成長,所以才無法成長啊。

2015年5月13日 星期三

文化剝煮產業

遠看、近看各有不同的 Hybrid Image, 因為有 High pass, Low pass filter 以及高斯模糊化的概念,考慮拿來教學上當例子。 其實很早以前也弄過類似的東西" 遠看林志玲,近看像國父"。  也有人寫了 Python 的逐步解釋。 不過我用的是 GIMP。

2015年4月25日 星期六

Gigabyte 輕薄電競筆電 P34K V3 開箱



其實也不算開箱,因為已經開了一陣子了。 主要是想玩 CUDA(Theano, gpuarray, gputools) 但手邊沒有 nvidia 的顯卡,順便又能有台筆電玩 Unreal Engine 及 Kinect V2。
鎖定的機型是 GTX965m 以上的輕薄筆電。 輕薄的考量是因為攜帶方便,而且能在演講使用。鎖定新的 nvidia 9 系列是因為據說效能及省電能力都有進步(從資料上來說,965m以上的與 960m 以下的是不同等級)。
考慮的候選人有 Gigabyte P34K, P34W, P35W, P35X,  MSI GS60 系列, AORUS X3。
ASUS 的 UX501, GL501 也觀望中,不過因為是 GTX960m,所以捨棄。P35 系列重量約 2.2-2.3 公斤,雖然也不太重,但因為常常要攜帶,選擇了 2.0公斤以下的機種。

最後再考慮其實真正要做計算時,還是會用遠端的方式,所以選了使用新9系列入門級的 965m 的 P34K V3,耗電量可能比較低。
簡單列一下 P34K V3 的規格:
  • NVIDIA® GeForce® GTX 965M GDDR5 2GB
  • 8G DDR3L 1600  
  • 僅1.71-1.8Kg、20.9mm
  • 128GB mSATA SSD + 1TB HDD
  • Full HD廣視角液晶螢幕 
  • Intel® Core™ i7 4720HQ 
雖然硬碟只有 5400 rpm,記憶體只有 8G 感覺有點弱,但價格不到 45k, 送個背包和滑鼠。
自動光源調整背光鍵盤搭車時使用很實用。同時有 D-SUB 和 HDMI 接頭,到處演講報時比較方便。


實際拿到的第一感是有點重。但這大概是因為用習慣 MBA 11" (1.1Kg) 及 Sony VAIO DUO 13(1.33Kg),過一陣子之後就覺得還好。
實測重量 1818g

MBA 11" vs P34K

DUO 13 vs P34K
3台打開了比較
變壓器有點大,但不算太重。
實測變壓器重量 424g

和 Duo 13 及 MBA 11 變壓器比較
實際攜帶上,因為贈送的背包很輕,筆電連同變壓器背起來感覺不太到重量。加上都很薄,也不會顯得很笨重。

風扇有時沒什麼事也會吵,但 GPU 和 CPU 熱度都還好。電池電量用起來感覺也還好,但沒有完整實測。

拿到機器之後的第一件事是裝 Linux。把 Ubuntu 14.10 裝進 1TB 的硬碟沒有太大的困難。裝上 nvidia 346, Bumblebee, cuda 7 要多花一點力氣,不過也 OK。
實際上裝玩 Theano + OpenBLAS,跑 check_blas.py 來測, CPU 是 1.5-1.6 秒, GPU 則是 0.15-0.16 秒。  GPU 約等於 GTX770 在 CUDA 6.5 的成績。
另外一個可以拿來測試 CUDA 的是 Blender 的 BMW Benchmark 。在  blender 2.74 下, CPU  跑到 5 分 51 秒, GPU 在適當的切割下,可以跑到 2分 35 秒(win64/linux 下都差不多,linux 下最好可以到 2:30) 不曉得怎麼比,不過看到 GTX 980 有 1分 44 秒的紀錄。


Win8.1 64 bit, Blender 2.74
如果是舊版的 BMW 測試檔,則可以到 1分4秒。


總之, CUDA 的效能還算可以,只是僅限於 float32, float64 太弱。
至於遊戲方面,我沒有太常玩,所以手上積了一堆舊遊戲,只能拿舊遊戲來測,像是 Witcher 2, Alice Madness Return, Tomb Raider 都還算順。
另外也用Dolphin 跑了 Super Mario Galaxy 看看,D3D 也算順暢(60fps)。


Tomb raider 在 Full HD 的測試結果為

最高 Ultimate 1920x1080

很高 Ultra 1920x1080

高 High 1920x1080
 以最低、平均來說

  • High: 58.0/60.0
  • Ultra: 48.0/57.4
  • Ultimate: 29.1/38.5
既然提到 Kinect V2, Kinect V2 的測試也能維持穩定的 30 FPS



但是也有一些缺點

  • 螢幕蓋上時,風扇就會轉動(?)
  • Touch pad 有時會卡住一下,特別是在  BIOS 選硬碟開機啟動 Linux 時。
  • Linux 的 X 有時會卡住(我習慣用 Kubuntu)
這感覺是驅動硬體之間有點不穩的緣故。

有關安裝 Linux 及 Bumblebee 和 CUDA,那又是另外一個故事了,之後再來補充。



2015年3月12日 星期四

不要問國家能為你做什麼,要問你想拿國家來做什麼


常常有人會問,「某某東西」有什麼用。
其實這反應了兩件事情,一個是他可能不理解「某某東西」的用意或價值,另外外一個就是他可能缺乏利用這個「某某東西」的能力和想像力。這個不見得是人的錯,有時候「某某東西」真的就是無聊沒價值的東西,也有可能因為某些外在的因素,讓人無法或者不敢想像自己有利用「某某東西」的可能(比方說這個「某某東西」是國家的時候)。

但既然會問這句話,那這個「某某東西」有價值的可能性不低,因為如果你肯定「某某東西」完全沒價值的話,你根本不會問這個問題。 所以這通常比較像是一個心理框架的轉換,當你想問「某某東西」有什麼用的時候,對的問題應該是「某某東西」能怎麼用。

就像學到某個魔術技巧的時候,當你感受到這個技巧背後的巧思與神奇之後,你想的一定是要怎麼用這個技巧,如何用這個技巧來設計程序,而不是這個技巧有什麼用。 當然你更高階一點的話,你也不會執著於把技巧包裝成程序。你會把這個技巧的精神融入內化。當你想達成某個目標時,有需要時,自然會拿來使用。
剛在 Hacker News 上,看到一個人,在畢業多年,因為線上開放課程,再次接觸久違的線性代數時,留下這一段話:
As someone who hadn't studied it for 20 years, it was invaluable to revisit the subject as an adult with the ability to reflect "ah, I can use that for... " instead of "Ok but when am I ever going to use this"
其實就是這個精神。化被動為主動, 役物而不役於物。

2015年1月28日 星期三

馬力歐及樂高中正紀念堂的模型


 今天帶小孩及跟爸媽看樂高展及逛了一下新光三越 A8 五樓的玩具店,順手用 123D Catch 掃描了幾個 3D 模型,然後下載成 obj 檔,匯入 blender 修剪以及簡化,最後再用 blend4web 匯出成 .html 檔,過程相當無腦。掃描的結果如下。


2014年12月31日 星期三

別讓分數殺了你


先說個故事,關於一個充滿心機的老人的故事
有個老人愛清靜,可附近常有小孩玩,吵得要命。 於是他把小孩召集過來, 說:「我這很冷清,謝謝你們讓這更熱鬧」 說完分給每人三顆糖孩子們很開心,之後就天天來玩。幾天後,每人只給2顆,再後來給1顆,最後就不給了。於是,孩子們生氣了,說:「以後再也不來這給你熱鬧了」 
很多人詬病考試領導教學,也有不少建議要如何改善考試的方式。 其中很多意見都不錯,雖然實際執行還有很多技術細節及現實上的問題(勿忘建構式數學),但整體來說,我對於整體教育的改善是樂觀的。
不過,我想講一些更基本的東西。就像上面的故事一樣。
上面的故事還挺有趣的,只不過,事實比虛構的故事更加有趣。

70 年代的時候,心理學家 Lepper 和 Nisbett 就做過這樣的實驗。 他們在幼稚園(位於史丹佛大學的 Bing 托兒所)中找來一些本來就喜歡畫畫的四五歲小朋友,問他們願不願意畫一張畫給。接下來就是三組不同的地方了: 

  • 預期得獎組:事先告訴小朋友們,那個朋友帶了一些乖寶寶獎狀(上面有像下圖一樣,帶有權威認證的榮譽標誌),只要畫圖就能贏得獎狀。 
  • 無獎品組:事先只問小朋友是否願意幫忙。最後只是謝謝他,不會給獎狀。 
  • 意外得獎組:事先只問小朋友是否願意幫忙,但是畫完之後告訴他因為感謝他,所以給他乖寶寶獎狀。 
可能有人會擔心不同的問法會造成抽樣偏差, 不過其實大多數被問到的小朋友都答應了。
每個小孩有六分鐘的時間畫圖,詳細的研究方式可以參考下面列的原始論文。
結果呢?
兩星期之後,觀察這些小朋友自由時間從事的活動,發現無獎品組以及意外得獎組還是一樣喜歡畫圖,但預期得獎組畫圖的時間卻只剩一半了。




Undermining children's intrinsic interest with extrinsic reward: A test of the "overjustification" hypothesis.
Lepper, Mark R.; Greene, David; Nisbett, Richard E.
Journal of Personality and Social Psychology, Vol 28(1), Oct 1973, 129-137.  PDF

仔細想想,短短的六分鐘,就足以造成這麼大的差別。
你從小到大,有多少時間是處於類似的環境?
會講「要考試了,怎麼還不唸書」這種話嗎?

其實還有不少實驗( Daniel Pink 的 Drive 動機,單純的力量裡面列了不少),像知名的蠟燭實驗,不斷的印證了同樣的結果。不過對我來說,因為我還沒有真的仔細研究過這些論文,讓我相信這個結論的主因還是自身的經驗與觀察。

想一想,你有多少次在考前準備考試的經驗? 據說考試是用來測量學習成效用的,那為什麼要在考前額外做一些事情來影響測量結果? 如果能在幾天一週加強準備,就能準備好的東西,為什麼要花一個學期來學?

制度的存在,是為了解決 Scalability 的問題。 因為人(或者選項)太多,才需要評鑑來幫忙做。 制度可以改善,但再好的制度都無法完美,都是一種簡化的過程。最後一定會有比較,一定會有分數。
而且,一定會有漏洞。
一定有人會鑽漏洞。
而一但有人開始鑽漏洞,就便成了軍備競賽了。
你的評量標準是高度,就會有人揠苗助長。
考試領導教學是無法避免的。但可以某種程度改善。
讓鑽漏洞的難度變高,代價是 Scalability 就會下降,所以要投入更多資源。讓能鑽漏的人變少,所以要特別注意公平性的問題。
隨著老師、社會整體觀念、素質的改變、提昇,進而引導制度越來越合理(才不會重蹈建構式數學的覆轍)。

但有些問題是更本質性的,因為改革只能讓制度更合理、更合乎某種價值觀(不像現在的制度處處自我矛盾)。
有人的地方就有江湖。
個人能做的,就是意識到這件事情,不讓自己被殺掉。
也許這樣講稍微誇張一點。比較持平的講法是,不讓自己的內在動機被殺掉。
不過一個人的自我扣掉內在動機後,我很懷疑還剩下什麼。

 當然,老師們就處在一個更重要的位置了。

但問題是,如果你自己平常就被評鑑、金錢、榮譽、績效追著跑(或者追著他們跑),你要怎麼教學生用平常心來對待分數?

2014年12月19日 星期五

Leap motion 擴增實境


利用 OpenCV 校正攝影機以及 Leap Motion Sensor 的位置,再利用 Three.js 來達成擴增實境的效果。

這是試玩的結果(還是跟 IPython notebook 一起探索),所以並沒有以最佳效果為目標。實際上 leap motion sensor 可以放在比較好的位置。

稍早拿來和 google hangout api 配合的效果。

原理上不難,只是中間要解決一堆技術上的小麻煩。

2014年11月30日 星期日

用 Spynner 來抓 8Comic 的漫畫 (4): 多線程


平行化的好處

之前抓檔案的方式是,
  1. 用瀏覽器抓 .html,找到圖片 url。
  2. 下載圖片
  3. 換下一頁,跳到第一步。
但是網路可以同時開好幾個連線。所以我們要利用這點來加速。我們的策略是,
  1. 用瀏覽器抓 .html,找到圖片 url。
  2. 把圖片 url 丟進一個 Thread Pool 裡面(平行下載,但是不等待)。
  3. 換下一頁,跳到第一步。
當然也有其他的方式平行化,比方連抓 .html 的工作也一併丟入 Thread Pool。不過這樣代表要多開好幾個 browser,而且相對來說,抓網頁會比抓圖片快,所以我們選擇上面的方式。

import 將會用到的 module

因為使用 python 2.7, 我們利用 urllib2 來抓圖, ThreadPool 來 multi threading 平行處理。
In []:
import spynner
import os, sys
from PyQt4.QtWebKit import QWebSettings # 用來設定 QtWebKit
from PyQt4.QtNetwork import QNetworkAccessManager, QNetworkRequest # 控制 browser 的網路連線
from PyQt4.QtCore import QUrl # Qt 的 Url 類別

# 下面是新增的兩個 module
import urllib2
from multiprocessing.pool import ThreadPool

# 下面是 IPython 相關
from IPython.display import display, Image
from IPython.html.widgets import ImageWidget, IntProgressWidget

建立瀏覽器

這部份一樣
In []:
# 建立瀏覽器
browser = spynner.Browser(debug_level=spynner.ERROR, debug_stream=sys.stderr)

# 建立一個 webview
browser.create_webview()
settings = browser.webview.settings()
# settings.setAttribute(QWebSettings.AutoLoadImages, False)
settings.setAttribute(QWebSettings.JavaEnabled, False)        # 不需要  Java
settings.setAttribute(QWebSettings.DnsPrefetchEnabled, True)  # 試著節省 Dns 花的時間
settings.setAttribute(QWebSettings.PrivateBrowsingEnabled, True) # 不需要瀏覽紀錄或者 cookie

# 建立一個空的  url
BLANK_REQUEST = QNetworkRequest(QUrl())
# 建立一個空的圖片 url
DUMMY_IMG_REQUEST = QNetworkRequest(QUrl("data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="))

# 客製化的 NetworkAccessManager
class EightComicNetworkAccessManager(QNetworkAccessManager):
    # 只需要取代  createRequest 這個 method 即可 
    def createRequest(self, op, request, device=None):        
        url = str(request.url().toString()) # 參數很多,但只取 url 就夠用        
        if 'comic' not in url[:20]: 
            # 用很醜的方式來判斷非 8comic 網站的 url 
            # 用空的 url  取代原本的 url
            return QNetworkAccessManager.createRequest(self, self.GetOperation, BLANK_REQUEST)
        elif not url.endswith('js') and not url.endswith('css') and '.html' not in url:
            # 凡是  .js .css .html 之外的,都用空的圖片 url  取代原本的 url
            return QNetworkAccessManager.createRequest(self, self.GetOperation, DUMMY_IMG_REQUEST)
        else:
            # 傳回原本的 url
            return QNetworkAccessManager.createRequest(self, op, request, device)

# 設定  browser 的 NetworkAccessManager
browser.webpage.setNetworkAccessManager(EightComicNetworkAccessManager())

設定 Widget

增加一個 Progress Bar, 分別來顯示分析過的 .html 數字以及已經下載的圖片數
In []:
browser.show()
# 漫畫的網頁
base_url = 'http://new.comicvip.com/show/cool-5614.html?ch='

# 要下載第一本
book_no = 1

# 取得總頁數
browser.load(base_url+str(book_no))
total_pages = browser.runjs('ps').toInt()[0] 

# 建立 Image Widget 用來顯示圖片預覽
img = ImageWidget()
img.set_css("height", 300) # 讓圖片不要太大

# 顯示下載進度的 Progress bar
html_progress = IntProgressWidget(min=1, value=1, max=total_pages)
img_progress = IntProgressWidget(min=1, value=1, max=total_pages)

# 顯示 Widget
display(html_progress)
display(img_progress)
display(img)

利用 ThreadPool 來下載

另用 ThreadPool 來達成 multithreading (多線程) 即為容易,只要將想丟進 pool 的程式碼包進函數裡面即可。
In []:
# 建立一個下載目錄
dir_name = "download/{:02d}".format(book_no)
if not os.path.exists(dir_name):
            os.makedirs(dir_name) 
print "Download to {}/{}".format(os.getcwd(), dir_name)
sys.stdout.flush()

# 建立 ThreadPool, 5 條 thread
pool = ThreadPool(5)
        
# 開始下載
downloaded_images = 0
for page in range(1, total_pages+1):
    # 取得 image url
    browser.load("{}{}-{}".format(base_url, book_no, page))
    img_url = str(browser.runjs('document.getElementById("TheImg").getAttribute("src")').toString())

    # 將下載圖片的工作包成 save_img,推進 pool 裡
    def save_img(img_url, page):
        global downloaded_images
        fn = "{}/{:03d}.jpg".format(dir_name, page)
        data = urllib2.urlopen(img_url).read()
        with open(fn, "wb") as f:
            f.write(data)
        # 更新 widget 的狀態
        downloaded_images += 1
        img_progress.description = "img: %d/%d"%(downloaded_images, total_pages)
        img_progress.value = downloaded_images
        img.value = Image(filename=fn).data
    pool.apply_async(save_img, (img_url, page))
    
    # 更新 Widget 的狀態
    html_progress.description = "html: %d/%d"%(page, total_pages)
    html_progress.value = page

    # 等待所有任務結束
pool.close()
pool.join()
    

結果

到這裡,探索期正式結束,該有的技術已經完整。
有興趣的話,也可以實測比較一下有 multithreading 和沒有 multithreading 的差異。但這裡就發現我們需要封裝了,因為沒有封裝、整理好的關係,要測試兩種程式碼,必須要把程式碼寫兩遍,而無法共用相同的部份。
另外,程式碼裡面用到了 global 這個 keyword, 常常也代表我們需要封裝了。



用 Spynner 來抓 8Comic 的漫畫 (3): 節省頻寬


要解決的問題

  • 還是有文字廣告這樣不需要的流量來浪費頻寬和時間。
  • QtWebKit 的 QWebSettings.AutoLoadImages=false 有 bug,記憶體已用不還。

解法

如同這裡 http://stackoverflow.com/questions/21357157/is-there-any-solution-for-the-qtwebkit-memory-leak 以及相關的連結、討論,記憶體的 bug 目前找得到的解法就是定期砍掉 process 重新再開。
理論上,也可以深入 QtWebKit, 找到配置的記憶空間,然後手動釋放,順便將解法回給上游。這樣雖然是正解,但是與我們的主題無關。
既然無解,那要等 QtWebKit 修正 bug 之後再來抓? 太久。
定期砍 Process 重開? 可以,但太醜。
不用 QtWebKit, 改用其他套件來解? 可以,但其他套件可能有其他問題,人生不能一直逃避,會養成習慣的。
仔細思考,其實我們的目標是要讓 browser 不去抓不必要的網路資源,這個原則包含了圖片以及文字廣告,但不僅限於這兩個,還有像是 google 統計等等。
所以只要我們封鎖這些不必要的連線,看起來瀏覽器的圖片就不會被顯示了,不需要真的設定 QWebSettings.AutoLoadImages=false
比方可以設定 proxy,由 proxy 來控制網路資訊流。不過 QtWebKit 有幾個內建的功能,可以讓你控制網路的存取,比 proxy 更裡層一點。一個是 browser.webpage 的 acceptNavigationRequest, loadStarted, loadFinished. 這幾個搭配起來,你可以限制 browser 不抓取子 iframe。 但這個方法對我們來說,不夠用。我們想要控制更多,所以我們用另外一種方式,直接控制比較外層一點的 QNetworkAccessManager 。

一樣 import 所有我們將會用到的東西

In []:
import spynner
import os, sys
from PyQt4.QtWebKit import QWebSettings # 用來設定 QtWebKit
from PyQt4.QtNetwork import QNetworkAccessManager, QNetworkRequest # 控制 browser 的網路連線
from PyQt4.QtCore import QUrl # Qt 的 Url 類別

# 下面這行是 IPython 相關
from IPython.display import display, Image
from IPython.html.widgets import ImageWidget, IntProgressWidget

建立瀏覽器

In []:
# 建立瀏覽器
browser = spynner.Browser(debug_level=spynner.ERROR, debug_stream=sys.stderr)

# 建立一個 webview
# 我們不設定 AutoLoadImages=False, 但增加一些其他設定
# 這裡並不是重點,但適合我們的應用
browser.create_webview()
settings = browser.webview.settings()
# settings.setAttribute(QWebSettings.AutoLoadImages, False)
settings.setAttribute(QWebSettings.JavaEnabled, False)        # 不需要  Java
settings.setAttribute(QWebSettings.DnsPrefetchEnabled, True)  # 試著節省 Dns 花的時間
settings.setAttribute(QWebSettings.PrivateBrowsingEnabled, True) # 不需要瀏覽紀錄

建立一個 QNetworkAccessManager 子類別

當 browser.webpage 在要求網路資源前,會先詢問 QNetworkAccessManager 來確定要不要抓,或者怎麼來抓這個資源。 我們可以用 browser.webpage.setNetworkAccessManager 來指定自己客製過的 manager。
In []:
# 建立一個空的  url
BLANK_REQUEST = QNetworkRequest(QUrl())
# 建立一個空的圖片 url
DUMMY_IMG_REQUEST = QNetworkRequest(QUrl("data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="))

# 因為只需要用一次,可以取個又臭又長的名字
class EightComicNetworkAccessManager(QNetworkAccessManager):
    # 只需要取代  createRequest 這個 method 即可 
    def createRequest(self, op, request, device=None):        
        url = str(request.url().toString()) # 參數很多,但只取 url 就夠用        
        if 'comic' not in url[:20]: 
            # 用很醜的方式來判斷非 8comic 網站的 url 
            # 用空的 url  取代原本的 url
            return QNetworkAccessManager.createRequest(self, self.GetOperation, BLANK_REQUEST)
        elif not url.endswith('js') and not url.endswith('css') and '.html' not in url:
            # 凡是  .js .css .html 之外的,都用空的圖片 url  取代原本的 url
            return QNetworkAccessManager.createRequest(self, self.GetOperation, DUMMY_IMG_REQUEST)
        else:
            # 傳回原本的 url
            return QNetworkAccessManager.createRequest(self, op, request, device)

# 設定  browser 的 NetworkAccessManager
browser.webpage.setNetworkAccessManager(EightComicNetworkAccessManager())

後面的程式碼都一樣

In []:
# 漫畫的網頁
base_url = 'http://new.comicvip.com/show/cool-5614.html?ch='

# 顯示瀏覽器,確認 browser 內容乾淨清爽
browser.show()

# 要下載第一本
book_no = 1

# 取得總頁數
browser.load(base_url+str(book_no))
total_pages = browser.runjs('ps').toInt()[0] 

# 建立 Image Widget 用來顯示圖片預覽
img = ImageWidget()
img.set_css("height", 300) # 讓圖片不要太大

# 顯示下載進度的 Progress bar
progress = IntProgressWidget(min=1, value=1, max=total_pages)

# 顯示 Widget
display(progress)
display(img)

# 建立一個下載目錄
dir_name = "download/{:02d}".format(book_no)
if not os.path.exists(dir_name):
            os.makedirs(dir_name) 
print "Download to {}/{}".format(os.getcwd(), dir_name)
sys.stdout.flush()

# 開始下載
for page in range(1, total_pages+1):
    # 取得 image url
    browser.load("{}{}-{}".format(base_url, book_no, page))
    img_url = str(browser.runjs('document.getElementById("TheImg").getAttribute("src")').toString())
    # 下載圖片
    fn = "{}/{:03d}.jpg".format(dir_name, page)
    with open(fn, "wb") as f:
        browser.download(img_url, outfd=f)
    
    # 更新 Widget 的狀態
    progress.description = "%d/%d"%(page, total_pages)
    progress.value = page
    img.value = Image(filename=fn).data

結果

和第一篇的結果比較,
的確清爽很多,廣告和圖片都消失了。速度也快了很多。其實 .css 檔案也可以不用抓,不過因為有 cache 的緣故, .css 和 .js 本來都只會抓一次,所以影響有限。
因為這一部分的探索已經告一段落,所以現在是封裝的時候。不過因為之後我們要介紹兩種不同的封裝方式,所以在這之前,我們要再做一件事情,那就是更加節省一點。
看起來不是我們不是已經夠節儉了嗎?只抓有需要的東西,沒有多抓任何東西。 也許 .html 也可以不用抓?沒錯,也許可以直接反推出每一頁漫畫圖片的 url,但即使這個例子可以,但一般來說,伺服器端完全可以將必要的資訊放在 .html 裡面,讓你必須要抓 .html 才能獲得必要資訊。 這系列的目的是介紹一個簡單的萬用抓資料方式,所以做到這裡就可以了。
那還有什麼可以節省的? 頻寬就這樣了,但是時間還可以節省。 下一篇介紹簡單的 multithreading 抓圖。
In []: