高維世界與一維價值

我前幾天去德國萊比錫參加了ISC學生集羣大賽。這個比賽的內容是在限定功率(3000W)的條件下,優化集羣的計算性能。每個隊伍的集羣分別由贊助商提供,清華大學隊是浪潮公司贊助的。由於硬件實在沒法和別的學校比,我們只好從軟件上來優化,比賽的程序包括了LINPACKHPCCHPCGQuantum ESPRESSOGadget。最終清華隊獲得了全球第三名,也算是盡力了——畢竟我們的集羣連GPU都沒,而許多隊伍配置極盡奢華,像愛丁堡大學連液冷系統都上了。

世界上「最快」的超級計算機

在ISC會議期間,我們得知了中國的「天河2號」以LINPACK峯值54902.4 TFlop/S的速度保持了超級計算機TOP500榜首,全球媒體爭相報道。但是在各個媒體的報道中,我們看到的是「天河2號」成爲「全球最快的超級計算機」,如Forbes的報道,而紛紛忽略了一個重要細節,即TOP500是以LINPACK的速度來排名的。LINPACK基準測試求解的問題是一個稠密的線性方程組,它完全是計算密集型的應用,其內存訪問、並行通信、磁盤讀寫都不成爲瓶頸。因此有人批評LINPACK提供的數值是「基本上無法到達的,卻有一小撮程序員在無聊地優化它的代碼,爲了使得他們的機器獲得更好的數值」。實際上衡量一個計算機性能的好壞,僅僅通過浮點計算密集型的應用來估計絕對是以偏概全,真實的系統性能還取決於整數計算性能、內存訪問性能、網絡通信性能和磁盤讀寫性能等等各個方面。哪怕是僅僅在科學計算領域,許多應用也不僅僅是在求解稠密線性方程組。許多時候可以認爲LINPACK數值完全不具備參考意義,因爲大多數科學計算應用的性能瓶頸根本不在這上面。

作爲「國家安全戰略投資」的天河2號,想必許多時候在求解的問題是破解密碼。然而一個可怕的事實是,大量密碼學算法,包括散列、非對稱加密(如MD5、RSA),都只進行整數計算,完全沒有任何浮點計算操作。如此看來,追求高LINPACK數值來提高密碼破解的性能,差不多是緣木求魚。

高維世界的序關係

說到CPU的性能,幾年前,大家在裝電腦的時候選購CPU只看主頻,頻率越高越好。於是英特爾爲了迎合市場,推出了奔騰四3.0GHz甚至3.6GHz主頻的CPU。後來進入多核時代,大家就看核心數,雙核的肯定比單核的好,四核的肯定比雙核的好。殊不知CPU的性能好壞有太多的參數,盲目追求高的主頻或者核心的數量沒有意義。不單單是CPU,想想看大家買數碼相機看什麼呢?許多人第一反應當然是像素啊。買單反鏡頭?光圈大小!買汽車?排量!買房?面積!

事實上這個道理淺顯易懂,但人們卻對它無能爲力。作爲沒有相關知識的普通消費者,面對這個世界紛繁複雜的參數真的是無能爲力,於是只好選擇一個「公認」的參數作爲基準了。

這一切的根源在於,向量和向量是無法比較大小的,只有標量纔能比較。向量只能通過一些函數變換到標量纔能比較,如模長,或者在某個空間上的投影。世界上的任何一件東西都可以用一個高維向量來表示,但爲了獲得序關係,我們通常只能把它映射到一個一維空間。在這個過程中,大量的信息都丟失了。對於同一組向量使用不同的函數,獲得序關係可以是完全不一樣的。

這是一個淺顯易懂的道理,而人們卻無能爲力。因爲人們天生傾向於用一個一維的數值來比較一切同類的事物(甚至不同類的事物),但事物天生是高維的。

價值觀是一個從高維空間到一維空間的映射

人們經常談論價值觀,譬如價值觀不同的人不要在一起,現代社會通過價值觀把人分爲不同的羣體。價值觀實際上是一個從高維空間到一維空間的映射,也就是一個高維向量的函數。人們面對紛繁複雜的事物,一個與生俱來的衝動就是對它進行評價,然後與其他事物相互比較。在這個過程中,不同價值觀的人使用了不同的函數,因此得出的結果是大相徑庭的。

商品的價格與價值

作爲一個通用的價值衡量工具,商品的價格成爲一個被廣泛使用的尺度。價格短期看來反應的是供求的關係,但本質上反映了一個長期的、多人的價值。用數學的語言方式表示,價格是一個高維的泛函(Functional),其中每一維的變量都是一個個體的價值觀函數,或者用以下代碼(OCaml)表示:

(* 價值觀是一個從任意向量到整數的函數 *)
type value = (anything -> int)

(* 價格是一個從多個價值觀函數到一個價值觀函數的函數(泛函) *)
val price : (values_of_all : value list) -> value

(* 一個簡單實現:價格即爲所有人價值觀的平均值 *)
let price values_of_all =
  fun thing ->
    let sum = List.fold_left (
      fun sum value_function -> sum + (value_function thing)
    ) 0 values_of_all in
    let number_of_people = (List.length values_of_all) in
    sum / number_of_people

換人話說,價格反映了全體生產者和消費者的價值觀,儘管可能各不相同,但卻用一個工具把它們統一了起來,變成了一個單一的可以衡量不同事物的價值的函數。對於一個個體來說,商品的價格可能偏離個人對商品的價值衡量,因此會有感覺便宜或者感覺貴。根據個人是否有錢,個人對價值的衡量也會不同,個人資產可以作爲價值觀函數的一個其他參數。

用價格衡量價值的方法看似簡單粗暴,有諸多弊端,卻也有着其他方法無可比擬的優點。其最大的優點就是簡單性,因爲人類對複雜事物的理解力實在有限。這也是爲什麼計劃經濟無法執行的一個原因,因爲沒有一個把萬物映射到一維的函數,或者這個函數取樣過於有限,只能反應少數統治者的意願。

價值多元化

一元價值儘管有着便於比較排序的優點,但卻會導致優化目標的單一化。譬如超級計算機只優化LINPACK或其他某個性能,學生爲了應付高考成爲做題機器,全社會「向錢看」道德淪喪等等。儘管着本身沒有什麼問題,卻會讓導致潛在的評估偏差風險。對此,價值多元化的主張被提了出來。價值多元化是把一維的價值標量變爲多維向量,也可以理解爲是多個價值函數的組合。價值多元化以後,價值本身重新變得不可比較,只能按照維度比較(或者價值向量的函數)。

在我看來,價值多元化沒有解決太多的問題,反而喪失了序關係,事實上是一種掩耳盜鈴的方法。價值多元化就等於沒有價值,只是把一個高維向量映射到了另一個向量,不僅丟失了信息,還無法比較。價值多元化可以當作進一步價值比較的「中間結果」,方便進一步計算而已,最終還是要歸結於一維。用金錢衡量一切的一元價值儘管不能解決許多問題,卻是人類目前能想到並實踐的最有效的方法。但願會有更好的方式被發明出來。

誰說中國醫療差——談醫療制度

昨天晚上由於喫飯過快,咀嚼用力過猛,一不小心咬到了舌頭,頓時鮮血淋漓,差點噴涌而出。我立刻去買了點冷飲冰激凌,企圖冷敷止血。一開始效果不錯,但是過了一會,流血又開始了,而且越來越多,血流不止。沒過多久感覺嚥了一肚子血。想去去醫院看看,但看看錶十點了,怕是學校醫院急診看不了,還是第二天早上去吧。又過了一會,感覺嗓子嚥血過多,有點不舒服了。對着鏡子看了看舌頭,那流血的速度把我嚇了一跳,每秒可能有將近0.2毫升。掐指一算,一個小時就是720毫升,睡一覺就好幾升了。這一想不得了,腿都軟了,於是立即前去醫院。

果然校醫院急診看不了,讓我去魏公村附近的北京大學口腔醫院。我打車到了口腔醫院,走進急診室,這時已經是深夜一點了。我花了5塊錢掛了個號,排隊等了一會就進去了。年輕漂亮的女醫生問我怎麼了,我把我的病情說了一下,醫生讓我躺下,問我平時有沒有什麼病症。我想了想,說「我應該有低血糖吧」,醫生笑了笑,就讓我張開嘴開始處理傷口。醫生看到我傷口的位置實在奇怪,竟然是在舌頭中間,還是豎着的。只是因爲咬到了一個小血管,纔這樣血流不止。處理的時候醫生一直問我疼不疼,雖然之前有點疼,但不知怎麼在醫生處理的時候竟然不疼了,可能是因爲女醫生年輕漂亮吧。沒過一會,傷口就處理好了,等了半個小時都沒有再出血。

繳費的時候讓我挺吃驚的,費用一共8.2元,我的第一反應就是好便宜啊。雖然作爲學生這個醫療費用是可以報銷的,但這便宜得讓我都懶得去報銷了(不過作爲一個理性人我還是要去報銷的,勿以利小而不爲嘛)。交完費以後醫生還告誡我注意事項,不要喫熱的東西云云,那服務態度令我簡直感激涕零。

對比一下美國歐洲的醫療機構,遇到這種小病要麼去公立醫院排隊到死,要麼去私立的口腔診所,同時做好心理準備收到鉅額賬單,而且半夜去人家還未必理你。只有天朝帝都纔有這種物美價廉,24小時隨到隨看的醫療服務。

我爲什麼能享受這一切

儘管這次醫療體驗很愉快,但是我還是清醒的認識到,天下沒有免費的午餐。中國這種優質廉價的醫療服務,其代價是對公立醫院尤其是醫生利益的壓榨。這樣的醫療服務並不是哪裏都有的,而是集中在北京、上海等少數幾個大城市,因此遭到全國人民的覬覦。君不見北京各大醫院門口二十四小時都擠滿了來自全國各地求醫問診的人,他們爲什麼來北京?因爲只有北京纔有這樣優質的醫療服務啊。

但是公共資源總是有限的,再多的醫療資源也會被無窮無盡的病人佔滿。針對這種僧多粥少的情況如何解決,無非排隊、抽籤和市場。排隊是最常見的方式,大多數公立醫院,以及春運火車票都採用了排隊這種「公平」的方式。抽籤也不少見,譬如北京車牌照搖號、優質中小學入學抽籤,這種方式也是看似公平的。市場的方式就是競價拍賣,這種方式用得也挺多的,只是離一般人比較遠,譬如政府賣地,價高者得,也算是公平吧(不考慮貪污腐敗的問題)。這三種方式很難「誰更公平」之說,只有「對誰更加有利」之說。排隊顯然是對窮人有利的,因爲富人的時間成本較高。拍賣則是反過來,對富人有利。而抽籤,則對所有人都一樣,所以有人認爲抽籤是最公平的。譬如古希臘雅典的民主制度,發展到後來爲了追求絕對的公平就採用了抽籤。

但是市場是無孔不入的,排隊和抽籤的方式都可以被市場轉嫁,譬如僱人排隊、僱人抽籤,或者有人主動倒賣排到或抽到的資源。就像美國南北戰爭時期的兵役制度,雖然是強制隨機抽籤徵兵,但是如果被招募者可以找到一個人代替,就可以免除兵役讓別人代替,這使得富人大多都選擇了僱傭兵代替自身。對於醫院來說,經常見到黃牛倒賣掛號,幾十塊錢的專家號掛號費能被炒到幾千塊很常見。先不說這種倒買倒賣是否符合道義,這種行爲至少解決了一個問題,那就是優質資源的真實價值。如果沒有黃牛倒買倒賣,我們很難知道這樣一個專家號到底值多少錢,這就是二級市場的意義所在。

相信沒有人會覺得五塊錢的掛號費貴,也正因爲如此,醫院和醫生的利益被剝奪了。醫療服務本身是一種專業的服務,無論從其市場需求還是道德需求,專業的醫生(道義上)應得應有的經濟回報和社會尊重。但由於國家控制的醫療費用價格,醫院幾乎不能從上面賺到可以維持運營的資金,只能依靠其他手段,也就是我們經常說的「以藥養醫」。至於公立醫院的國家補貼,我不知其具體數字,但估計很難維持醫院運營。因此醫院和醫生就成了替罪羊,彷彿醫生拿回扣成了「看病貴」的罪魁禍首,殊不知醫療服務本身昂貴的成本。

由於我的病實在不大,而且醫生沒有存心從我身上拿回扣,所以沒用到什麼昂貴的藥。畢竟在當今緊張的醫患關係下,醫生想拿回扣還是要三思的。我之所以能夠享受到這樣的服務,完全是建立在醫院和醫生的利益被犧牲的基礎上的。因此我在看完病以後,忍不住對醫生說了好幾句「謝謝」。

醫療成本昂貴的罪魁禍首——准入制度

醫療成本分爲醫療服務的成本和醫藥的成本,這兩部分貴的原因是不同的。在中國,前者被人爲壓低,使得醫院不得不使用後者補貼前者。而在歐美國家,尤其是美國,爲什麼醫療貴得嚇人呢?我認爲,其根源在於嚴苛的行醫准入制度。如果你看過電影「北京遇上西雅圖」,可能會注意到一個細節,劇情最後Frank經過多年努力終於考取了美國醫生執照,從此步入高收入階層。然而Frank本身就是北京阜外醫院行醫多年的醫生啊!這個細節反映了在美國當醫生有多難,而這個難完全是人爲造成的。

美國醫師執照由各個州的醫學委員會頒發,考試者必須通過「美國執業醫師執照考試(United States Medical Licensing Examination, USMLE)」等各種考覈。一般在一個醫生開始行醫之前,需要學習十餘年,並且通過實習。由於苛刻的准入制度,美國醫療市場上醫生的數量被嚴格限制,造成了一種人爲的供不應求,醫生的收入自然水漲船高。

美國既然也有醫療費貴的問題,爲什麼還要維持這個制度呢?原因很簡單,是爲了「公衆安全」。不合格的醫生給你看病,你會放心嗎?這個理由看似說得通,卻只是一面之辭。這樣嚴苛的准入制度是保證了醫生的質量,但犧牲的是廣大患者和還沒有獲得執照的醫生的利益。並不是每個人都需要非常高的醫療標準的,有的人需要的僅僅是水平一般,但是廉價的醫療服務。然而醫生爲了維持自己的高收入和社會地位,利用各種政治勢力遊說權力機構,通過綁架公衆利益的方法保證了自身利益。

中國過去有赤腳醫生,在鄉間提供廉價的醫療服務。香港九龍寨城在被拆之前,由於香港政府對其沒有管轄權,也成了無牌牙醫及中醫診所的集中地(港英政府不承認中醫有行醫資格)。其中的診所雖然良莠不齊,但是解決了相當一部分窮人的看病問題。而現在,香港窮人只能去公立醫院排隊,小病可能一排就是半年。

類似的由於准入制度造成的價格昂貴的例子還有倫敦和紐約出租車的價格。在倫敦,出租車司機的准入門檻出奇得高,所有出租車司機的申請者要花三到四年學習The Knowledge(光這名字聽起來就很厲害),其中知識不僅要求司機牢記25000個城市街道和30到50個郊縣街道,還要對倫敦的歷史、文化、景點熟記在心。因此能通過考試的人非常少,倫敦出租車司機自然也成了「高收入職業」。對於消費者來說,結果就是倫敦出租車價格非常昂貴,我曾經一次從希思羅機場到倫敦市區打車花了105英鎊,還不含小費。而紐約的准入制度體現在出租車牌照上,2013年,紐約出租車牌照拍賣出了130萬美元的天價。事實上在過去並不是這樣,以前紐約共有30000餘量出租車(人口卻遠少於今天),但是後來紐約市長簽署了《哈斯法案》,使得出租車數量下降到了16900輛,到現在紐約830萬人口僅有13336個出租車,相比之下北京人口比紐約多一倍,但有69000多輛出租車。因爲這種懸殊的數量差別,紐約的出租車價格非常貴(同時也有勞動力市場的原因,按下不表),但也正因爲如此,纔給了像Uber這樣的公司獲利的空間。

相比醫療服務價格,醫藥價格無論在美國還是中國都很貴,這是什麼原因呢?直接原因是醫藥的研發成本很高(儘管邊際生產費用很低),一種新藥的研發成本高達數億到數十億美元和十幾年時間。但背後原因是FDA苛刻的醫藥上市管制制度,造成了藥品研發成本劇增。爲什麼會這樣呢?原因是FDA要求上市的藥品符合一系列的標準,並且需要做完整的臨牀實驗,這給醫藥研發企業帶來了巨大的經濟開支和時間開支,使得企業不得不把鉅額支出轉嫁到消費者頭上。雖然說FDA目的是爲了公衆安全(又是公衆安全……),但這不知道阻礙了多少新藥的開發,使得更多原本可以得救的人悲慘地死去。至於中國,中國實際上很少有自行研發的藥物,大部分是進口的專利,所以美國醫藥研發貴,也會造成中國藥品貴。同時中國也效仿美國,制定了越來越嚴格的藥品GMP認證。現在FDA的觸角已經伸向了醫療手機應用,甚至造成硅谷相關的創業企業生存困難,阻礙了醫療技術的進步。

理想的醫療制度

談一下我認爲的理想的醫療制度。我認爲理想的醫療制度應該是完全市場化的,所有的醫生准入制度、藥品審覈制度都應該取消強制性。但並不是完全拋棄,還是可以保留作爲參考。任何人只要有意願,都可以行醫,患者可以自行選擇是否信任。如果醫生願意考取執照,可以增加患者的信任度,相當於一個專業證書而已(假證屬於欺詐,是另一個問題)。同時辦法醫生執照的機構應該破除壟斷,任何機構都可以頒發證書,其含金量由其考取難度、頒發數量決定,類似於金融界或IT界的各種證書。就像金融界從業者不是有CFA證書纔能買賣證券,IT界從業者不是有MCSA證書纔能編程,至於公司是否僱傭你,證書只是一個參考,其他經歷經驗也是重要的一部分。

同理FDA對藥品的准入制度也應該廢除,轉而由第三方的藥品評級機構(公共的或私人的)來對藥品進行評價,類似證券評價機構。注意這並不能解決賄賂等非正常方式造成的欺詐問題,但有FDA同樣不能解決,如何解決是另一個問題了。

在這樣理想的情況下,公立醫院存在的必要性就不大了,因爲市場可以提供各個層次的醫療服務,窮人選擇廉價的,富人選擇優質的,如同其他任何商品或服務。我認爲沒有任何需求是「剛性」的,非要政府介入不可,包括醫療、住房、教育,都可以由市場有效調節(在取消行政干預的前提下)。

有人認爲完全有市場提供醫療服務是有悖於倫理的,一個例子就是患了重病的窮人,他負擔不起昂貴的醫療費用,難道就應該死去嗎?這的確是一個很有爭議的問題。其實我認爲涉及到人的「生存權」的問題不止醫療一個,還包括溫飽、自然災害。關於溫飽,即使是發達國家也是在最近一百年內纔逐漸消滅的,不是任何平等主義政治運動的原因,而是生產力的大幅提高,導致糧食、紡織品價格變得非常便宜,纔讓每個人負擔得起溫飽。即使有人還是負擔不起,通過政府補助的方法,讓一個人喫飽也花不了太多錢。而醫療目前還是一種非常稀缺的資源,無論如何分配總是無法滿足每一個人的,而且面對很多疾病即使你再有錢也無能爲力。這完全是受限於人類醫療技術的,沒有任何辦法可以完美解決。政府誇下海口負責每一個人的醫療的行爲是極端不負責任的,因爲根本就是「何不食肉糜」。所以終極解決方案還是提高醫療技術,而不是任何政治運動。在這種前提下,爲了保證醫學研究的發展,其資金是必不可少的,因此資源優化配置的方式就是市場的分配方式,這樣纔能讓資本有效流入醫療領域,刺激其發展。

最後解釋一下標題,中國醫療制度的確有很多問題,但是美國也有不少問題,相比之下中國的醫療制度對患者不算差,犧牲的是醫生的利益(患者利益間接受損,造成雙輸局面)。而美國則是犧牲患者利益,養肥了醫生。

icc的過程間優化和性能分析引導優化

icc(Intel C++ Compiler)是一個非常厲害的編譯器,對優化計算密集型的程序遠超其他任何編譯器,如gcc、llvm、Visual C++。

icc提供了過程間優化(Interprocedural Optimization)技術,可以幫助編譯器在不同的目標文件之間進行全局優化。傳統的編譯器的編譯過程是編譯每個源文件到獨立的目標文件,然後再通過鏈接器將目標文件鏈接成可執行文件。傳統的編譯器的編譯優化主要集中在每個源文件內部,鏈接過程比較簡單,因此每個文件都是獨立的,而icc提供的過程間優化打破了這一限制。

過程間優化可以對整個程序進行全局優化,而不是僅僅在單個文件、單個函數或者單個代碼塊內部優化。過程間優化可以減少過程之間重複計算、內存的低效訪問以及簡化迭代過程,通常會採用內聯函數的方式。過程間優化還可以重排代碼的順序以優化內存的分配方式和局部性。

通過指定編譯參數-ipo,icc可以開啓過程間優化,icc將在編譯時生成特殊格式的目標文件(中間語言),並在鏈接時進行進一步的編譯和過程間優化,如圖所示:

使用icc啓動過程間優化的方式是在編譯參數中加上-ipo參數,還要設置環境變量AR=xiar,使用Intel的版本代替默認的ar

性能分析引導優化(Profile Guided Optimization)通過分析程序運行時的實際行爲,將結果反饋給編譯器,使得編譯器可以重新安排代碼以減少指令緩存問題和分支預測誤判,從而獲得性能的提升。性能分析引導優化通過實際執行代碼統計出運行頻率最高的部分,編譯器通過這些信息可以更加針對地優化代碼。性能分析引導優化分爲三個階段:

  1. 第一步是生成分析程序。在這個階段,編譯器創建一個有采樣注入的可執行程序。在icc中使用的編譯指令是-prog-gen,以及-prof-dir=[dir]
  2. 第二步是運行第一步生成的被注入採樣分析的程序,每次運行這個程序,都會生成-prof-dir指定的目錄下生成一個動態信息文件(dynamic information file),將會被最終編譯時使用。
  3. 第三步是最終編譯的步驟。第二次編譯的時候,動態信息文件會合併成一個彙總文件。通過彙總文件,編譯器會嘗試將最常使用的執行路徑優化。

過程間優化和性能分析引導優化可能會相互影響,性能分析引導優化通常會幫助編譯器生成內聯函數,這會幫助過程間優化的效率。性能分析引導優化對分支預測效率的提升最有效果,許多分支執行的可能性無法在編譯時判斷,而通過性能分析引導優化,編譯器可以針對經常執行的分支(熱代碼)和不經常執行的分支(冷代碼)生成高效的彙編代碼。

使用性能分析引導優化的方法如下:

  • 第一階段:編譯參數中加上:-prof-gen=srcpos -prof-dir=/tmp/profdata。其中-prof-dir是存儲性能分析文件的目錄。
  • 第二階段:運行編譯好的程序,然後運行profmerge -prof_dir /tmp/profdata生成彙總文件。
  • 第三階段:重新編譯程序,使用參數:-prof-use=nomerge -prof-func-groups -prof-dir=/tmp/profdata

這樣最終生成的代碼就是經過性能分析優化過後的了。

以上方法在icc 14.0.2上試驗通過。

參考