pretty code

2023年6月17日 星期六

人終究還是會確診一次吧?

新冠疫情爆發後,不知不覺已經三年半了,一直以為自己應該是不會確診了?沒想到前幾天終究還是逃不開確診的命運, 趁著今天狀況勉強還行,記錄一下確診的狀態,也給未來的我老婆參考XD

直到現在還是想不通怎樣中的?回家後仍然保持消毒習慣的我,一天會用 2 個口罩,一個星期會用酒精消毒車子內裝一次,偶爾走在路上沒戴口罩以及離開辦公室座位為了洗臉沒帶口罩外,剩下有可能中的地方就是餐廳內用了,但我一向都是找人少的地方吃,即使貴一點也沒關係(這時不得不抱怨一下,不論男女,總是有人喜歡吃飯時一直講話,這種人偏偏又喜歡講話講得很大聲影響別人,每次,遇到這種客人就是覺得內心很幹)。總之,這三年除了禁內用時期外,我幾乎都還是正常內用居多,偏偏卻在這個時候確診,真是不可思議?

以下是到目前為止的狀況,記錄一下。

星期三下午時突然覺得莫名的累,喉嚨也突然覺得痛,就像是之前連續視訊上課一天半後的講話喉嚨痛,晚上快篩正常,但身體開始輕微發燒,約莫是 37.1 度左右。半夜因為身體燙都沒睡好,故隔天很早起來就決定請假一天。

星期四雖然請假在家,但發燒依舊,最高有到 37.8 度,好一點是 37.3 度,但似乎上上下下不定?因為發燒昏昏沉沉了一天,全身肌肉有點小酸痛。晚上八點多左右快篩陽性確診,但覺得好像還行,決定隔天看狀況決定是否要請假。半夜依舊身體發燙睡不好,再加上戴口罩不太好睡,半夜兩點起來就沒睡了,一直到早上五點多決定請假後又回去睡到八點多起床。

星期五一樣請假在家,今天似乎肌肉不再酸痛,但下午開始出現比較頻繁咳嗽狀況,另外,左膝蓋後方,左後臂外側,左後耳及左腦勺,開始出現不定期神經抽痛狀況,就好像之前帶狀皰疹的症狀?這次晚上比較好睡,但半夜也是醒來好幾次,半夜忘記哪一次醒來開始出現吞口水喉嚨就會痛的狀況。

星期六早上因為車子要保養不得不出門,只好全程戴口罩開車,順便去看皮膚科讓醫生確認,避免皰疹又發作了!今天咳嗽似乎變比較嚴重開始有痰,但在外面卻只有偶爾咳個兩三次,真佩服自己的忍耐力。另外,體溫似乎已經回到正常,只有一次量是 37 度。好像從快晚上開始,身體會莫名的發寒,尤其是下半身,本來是以為吹冷氣的緣故,後來才確定是身體自己在發寒。半夜也是睡到兩三點就睡不好,一直到早上又回龍睡了一下。

星期日早上又測了一下快篩一樣還是陽性,中午硬開車出去買午餐吃,下午下半身發冷的情況依舊,疑似皰疹神經痛的現象也是沒有舒緩,晚上睡覺最慘,一分鐘咳一次,不知道過了多久才睡著。

星期一早上上班前快篩依舊陽性,繼續請假一天休息。

2023年6月2日 星期五

Python 優化小經驗

這幾天看數學看到有點煩,剛好之前有寫一個函數實作 warpPerspective 的功能,只是一個很簡單的做插值計算並將數值填回去 numpy array 的程式,Python 居然要花到好幾秒鐘,為了轉換一下心情,底下是我有嘗試過的一些優化技巧,做個記錄先,有些我也不知如何解釋?

01. 陣列運算一次做比在 two for loop 中做還快。

比如說將一張圖像的齊次座標乘上 Homography matrix,將 3 x (width x height) 的座標先填上 ndarray,之後在一起乘 H matrix,並除以第 3 個分量,比在 loop 中每個 pixel 單獨計算還來得快。

這個好理解,numpy 底層應該有對 matrix 運算優化,可能是 multiprocess 之類的,故有吃到 numpy 的 buffer 靈氣。

02. image[h, w, :] = xx1 * yy1[h, w, :] + xx2 * yy2[h, w, :] + xx3 * yy3[h, w, :] + xx4 * yy4[h, w, :] 優化。

上句右邊計算結果也是一個 ndarray,將上句拆成 3 句可以優化。

image[h, w, 0] = xx1 * yy1[h, w, 0] + ...
image[h, w, 1] = xx1 * yy1[h, w, 1] + ...
image[h, w, 2] = xx1 * yy1[h, w, 2] + ...

這個也好理解,可能是少掉中間那個臨時變數的消耗?

03. 使用 cProfile 做 profile 追蹤,看是否能看出端倪?

---------
command line

py -m cProfile -o xxx.prof xxxx.py
py -m cProfile -s tottime xxx.py

---------
In xxx.py

import cProfile, pstats, io
from pstats import SortKey

pr = cProfile.Profile()
pr.enable()

warpPerspective(img, M, (maxWidth, maxHeight))

pr.disable()
s = io.StringIO()
sortby = 'tottime'
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats(20)
print(s.getvalue())
---------

cProfile 可以在程式碼中直接呼叫相關 class 也可以在 command line 中觸發,如果在 command line 觸發時有儲存檔案 xxx.prof,可以用 SnakeViz 這個第三方模組開啟並作分析,SnakeViz 會另外開啟一個 browser window 方便看 call stack,會比原來的 cProfile 結果好看。

---------
pip install snakeviz
snakeviz xxx.prof
---------

但因為我已經知道是那個函數花時間而我的函數又都是計算賦值的工作(純 Python code,沒有呼叫 other functions),故這個工具幫助不大。

04. 改用 multiprocess 並配合 SharedMemory 分享 read data 和 write data。

share read data 沒有什麼問題,但 share write data 一直沒成功,後來才知道要如何寫,如果照文件說的應該同時讀寫是沒問題的?至少我在 Process 和 Thread 中都沒有使用 lock 來保護 share write data。

---------
This style of shared memory permits distinct processes to potentially read and write to a common (or shared) region of volatile memory.
---------

分享 write data 的用法,重點是在 main process 中複製建立的 blank_ 而不是建立 Process 前將 blank 指給 blank_(在個別的 Process 中寫到的還是 blank_ 而不會是 blank)。

---------
blank = np.ones((max_h, max_w, 3), np.uint8)

share_blank = shared_memory.SharedMemory(name='share_blank', create=True, size=blank.nbytes)
blank_ = np.ndarray((max_h, max_w, 3), dtype=np.uint8, buffer=share_blank.buf)

p_count = 1
p = Process(target=warpPerspective_task, args=(p_count, i, H_Inv, img.shape[1], img.shape[0], max_w, max_h))
p.start()
p.join()

blank = blank_.copy()

p.close()
p.unlink()
---------

另外,我電腦有 4 核心,開 4 個 process 分區塊寫 blank_ 對加速並沒有幫助,跟沒有開 Process 時運行時間差不了太多?

05. 將 01 步驟中的大 matrix 計算,配合 4 個 process,各個 process 在 task 中各自計算自己那部份的 matrix。

看起來跟 04 步驟很像,但這樣卻可以再省個 300 ~ 400 毫秒?

06. 如果在迴圈中有存取 class variable,用一個 local variable 來接它,可以減少執行時間。


總之,在不懂 Python 底層的情況下,我目前也只能先試到這樣﹍