pretty code

2020年2月27日 星期四

淺綠色背景 on Windows 10

以前 XP, Win7 時代,都習慣把預設軟體背景透過顯示設定設成淺綠色,長期看下來眼睛比較舒服。

Windows 10 已經沒有這個選項,不過可以透過 regedit,調整下面值並重新登入即可。

[HKEY_CURRENT_USER\Control Panel\Colors]
"Window"="199 237 204"

Office, Notepad 看起來都有生效。

IBM SK8835 Keyboard on Windows 10

1. Install "tpusbkybdwtrackpoint_110.exe".
2. Reboot.
3. Unzip "sk88xx_ultranav_drivers.zip".
4. Run "ultranav_drivers\Drivers\vista\x64\TOUCHPAD\WinWDF\x64\setup.exe".

After reboot system, you will find the IBM mouse settings tab in original mouse dialog.

在 windows 下 ssh 遇到 diffie-hellman-group1-sha1 問題

1. Add C:\Users\XXX\.ssh\config file.
2. Add "KexAlgorithms +diffie-hellman-group1-sha1" in config file.

2020年2月24日 星期一

mooInk Pro 13.3 預購

此活動只到 3/2 為止,目前已達成 70% 的目標,記得上星期五(2/20)看還只有 50 幾,我原本猜測是無法順利集資,現在似乎多了變數,我也很好奇最後結果為何?

坦白說,即使是很支持讀墨的我,我也沒有考慮過 13.3 吋,不是說這個產品不好,但我還是覺得可以把 mooInk Pro 10 做得更好才對。

在不考慮 mooInk Pro 10 是否有更新的情況下,mooInk Pro 13.3 至少要滿足下面幾個條件之一我才會考慮購買:

1. 內建 A2 模式並且支援 javascript 的瀏覽器 - 我還是需要一個可以瀏覽網頁的電子書閱讀器,護眼無價。

2. 開放自行安裝 App - 這個不難,加個 adb daemon 即可,使用者風險自負,如果操作不當需自費修復我也覺得沒差。

3. 內建 Kindle App - 喜歡讀墨的人,大部份的人一定早已用過其他的電子書閱讀器,最多人用的應該還是 Kindle,應該也有人跟我一樣在 Kindle 買了不少書,如果可以內建 Kindle App,那我一堆原文技術書籍就不需要轉檔了。

以上選項目前看來最難的是 1,2 跟 3 都是動動指頭的事,當然 3 還有授權等問題。無奈電子書閱讀器真的是小眾市場,想要 mooInk 硬體的也是小眾裡的小眾,故公司高層考量的點也非外人可以得知。

與其出 13.3 吋,倒不如出電子紙手機,但我覺得這個想法更是遙遙無期吧!

2020/02/28 更新
恭喜讀墨,今天早上順利達成 1000 台集資目標。

2020/03/03 更新
最後達成率 128%,坐等 7 月大家開箱文。

2020年2月21日 星期五

Build a TensorFlow pip package from source on Windows

一直以來都有這樣的感覺,想要編譯任何大專案,最好還是乖乖在 Linux,否則即使該專案有提供在 Windows 編譯的方法,根據我的經驗都沒有那麼順風順水。

底下是我在 Windows 7 成功編譯的方法以及遇到坑的處理方式,記錄一下避免忘記。

官方指南
https://www.tensorflow.org/install/source_windows

TensorFlow:r1.15 (CPU-Only)

Install Python 以及相關 modules
這部份直接照官方網站即可。

Install Bazel
這個要配合 TensorFlow 的版本,我是下載 0.26.1,並放在 C:\Windows\System32 下。

Install MSYS2
這部份直接照官方網站即可。

Install VS2017
安裝完需要更新到最新,即執行 cl 時版本要為 19.16,也就是 "_MSC_VER" 這個值要是 1916

開啟 cmd prompt
適用於 VS 2017 的 x64 Native Tools 命令提示字元。

設定環境變數
set BAZEL_VC=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC
set Path=C:\msys64\usr\bin;%Path%

切換工作目錄
切到 TenosorFlow code root。

開始編譯
bazel --connect_timeout_secs=120 build --config=opt //tensorflow/tools/pip_package:build_pip_package --test_timeout=120 --http_timeout_scaling=3.0

編譯過程中遇到的問題
1. 一開始沒多久就遇到網路問題,即使如上面放寬相關 timeout 也沒用,後來靈機一動判斷是公司網路問題,改用自己的網路即可。

2. "_MSC_VER" 版本太舊,這個問題花了我 2 天才搞定,底下是個人猜測,原來是我的 VS2017 環境一直有更新,故我的 "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC" 裡面會有各種不同的版本,而 bazel 在一開始會去此路徑下找到第一個擁有相關 bin 檔的路徑,並將其寫到 "C:\Users\XXX\_bazel_XXX\mfg32ytw\external\local_config_cc\cc_toolchain_config.bzl" 等相關檔案的區塊,例如 cpp_link_nodeps_dynamic_library_action 此區塊,故即使你開的 cmd prompt 是對的,但此處的 cl 版本如果是在錯的資料夾, "_MSC_VER" 這個變數便會是錯的。

解決方式也很簡單,去控制台針對 VS2017 做修改,把較舊版本的 tool 移除,印象中我原本有多達 6 ~ 7 個之多,後來就只剩 "14.16.27023" 這個資料夾,而這個就是 1916 的版本。

其實我也有安裝 VS2019 Build Tools,但一樣會有 "_MSC_VER" 版本太舊的問題,但因為我那時還不知道問題在哪,故並未更新 VS2019 到新版本。

在我解決了上面 2 個問題後,我就順利的編譯出 "bazel-bin\tensorflow\tools\pip_package\build_pip_package" 這個執行檔,而我們需要它來產生 pip 的安裝檔,這部份就參考官網即可。

一些小秘訣
1. bazel 可以使用 --jobs=2 --local_cpu_resources=2 參數去限制 CPU 資源,一開始沒限制每個 Core 都跑到 100%,此時電腦做什麼事都很慢。
2. 成功編譯過一次後,如果都沒改檔案並用上上面的參數,再檢查一次大概要花 3 分鐘多。
3. 檢查需不要需要重新編譯的程式應該是用 java 寫的。
4. C:\Users\XXX\_bazel_XXX\mfg32ytw 裡面會有編譯過程的 log 及 java 的 log。

VS2019相關(未嘗試,僅猜測)
1. 如果是安裝 VS2019 Build Tools,VC 路徑是在 "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC"。
2. 相對 VS2017,VS2019  多個版本是在 "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC",用一樣的方式留下最新的即可。

Print integer string in the macro of GCC

前一篇文章提到的例子是 for VC。

既然平常都是用 GCC,還是查一下 GCC 要怎麼做。

底下是來自 stackoverflow rob05c 的解答。

#define STRINGIFY(s) XSTRINGIFY(s)
#define XSTRINGIFY(s) #s

#define XDEFINE __GNUC__
#define YDEFINE __GNUC_MINOR__
#define ZDEFINE __GNUC_PATCHLEVEL__

#pragma message "GCC = " STRINGIFY(XDEFINE)"."STRINGIFY(YDEFINE)"."STRINGIFY(ZDEFINE)
輸出結果

test.c:12:9: note: #pragma message: GCC = 4.9.2
 #pragma message "GCC = " STRINGIFY(XDEFINE)"."STRINGIFY(YDEFINE)"."STRINGIFY(ZDEFINE)

後記

這兩篇指的都是在編譯時期,需要做一些前置檢查,如果不符合某些條件,就停止編譯。如果是在執行時期就不需要那麼麻煩了。

2020年2月20日 星期四

Print integer string in the macro of VC

有些軟體編譯時在標頭檔會檢查 Compiler 版本,以 VC 來說,版本號是定義在 "_MSC_VER"。

今天為了檢查 TensorFlow build error 的問題,需要知道編譯時期在錯誤的 include file 中,這個 "_MSC_VER" 的值為何?

查了一下,可以用底下的方式搞定。

#pragma message("_MSC_VER is " _CRT_STRINGIZE(_MSC_VER))

另外,在 llvm\include\llvm\Support\Compiler.h 裡,有列出一些 VC 版本對應參考。

/// * 1910: VS2017, version 15.1 & 15.2
/// * 1911: VS2017, version 15.3 & 15.4
/// * 1912: VS2017, version 15.5
/// * 1913: VS2017, version 15.6
/// * 1914: VS2017, version 15.7
/// * 1915: VS2017, version 15.8
/// * 1916: VS2017, version 15.9
/// * 1920: VS2019, version 16.0
/// * 1921: VS2019, version 16.1

2020年2月19日 星期三

The migration of tensorflow/contrib/lite path

最近一直在看相關的文章,很多文章在提到 lite 時,路徑都是指向 tensorflow/contrib/lite,但實際上已經沒有這個路徑,好奇查了一下,原來是在 2018/10/31 時,TensorFlow 將 tensorflow/contrib/lite 改成 tensorflow/lite。

故文章看到有 contrib 這層的都是舊資料,自行修正即可。

2020年2月17日 星期一

Run MLPerf-inference Mobilenet on Windows.

My Environment

Windows 7 x64
Python 3.6.8 x64

Install python modules

1. pip install TensorFlow==2.0.0
2. pip install wheel
3. pip install Cython
4. pip install onnx
5. pip install git+https://github.com/philferriere/cocoapi.git#subdirectory=PythonAPI(This is pycocotools module that someone built).

Install Load_Gen

1. cd mlperf\loadgen
2. set CFLAGS=-std=c++14
3. python setup.py develop
4. cd mlperf\v0.5\classification_and_detection
5. python setup.py develop

Prepare Dataset

Because the link of imagenet is gone, you must search by Google.

Prepare Model

https://zenodo.org/record/2269307/files/mobilenet_v1_1.0_224.tgz

Run Mobilenet-tflite

1. cd mlperf\v0.5\classification_and_detection
2. modify python\main.py, add profile below.
"mobilenet-tflite": {
    "inputs": "input:0",
    "outputs": "MobilenetV1/Predictions/Reshape_1:0",
    "dataset": "imagenet_mobilenet",
    "backend": "tflite",
    "model-name": "mobilenet",
},
3. py python\main.py --backend=tflite --cache=1 --config=..\mlperf.conf --dataset-path=D:\MLPerf-Win\Dataset\dataset-imagenet-ilsvrc2012-val --max-batchsize=1 --model=D:\MLPerf-Win\Model\mobilenet_v1_1.0_224.tflite --model-name=mobilenet --profile=mobilenet-tflite --scenario=SingleStream --threads=2 --output=D:\MLPerf-Win\Result\tflite-mobilenet-singlestream

2020年2月13日 星期四

python venv

理論上使用 python 應該要用虛擬環境會比較保險,不過一直都懶得記指令,最近因為要同時使用不同版本 python,記錄一下避免忘記。

OS:Ubuntu 18.04

安裝環境
1. sudo apt-get install python3.7
2. sudo apt-get install python3-venv
3. sudo apt-get install python3.7-venv

建立虛擬環境
1. python3.7 -m venv XXX (XXX 是你要的環境 folder,python 版本是 3.7)
2. python3 -m venv XXX (XXX 是你要的環境 folder,python 版本是 3.6,18.04 預設)
3. source XXX/bin/activate

安裝 module
1. pip install YYY

執行 python
python ZZZ.py

離開虛擬環境
deactivate

venv 缺點
venv 的 python 會依賴主環境,但目前對我來說已經夠用,如果要安裝各種版本 python,較好的選擇可能是 conda。

2020年2月7日 星期五

使用 GDB 跑 MLPerf-inference

我們家的硬體跑 MLPerf 都會 Segmentation Fault,不知為何也沒有 core dump 檔案。

想了一下,乾脆使用 GDB 來跑,看能不能看出什麼端倪?

步驟如下:
1. GDB python。
2. run xxx.py,如果有 argv 參數就接在後面即可。

嗯,沒有 source code  我也是看不出所以然,不過至少知道死在那個函數!

TensorFlow 和 numpy 相容性問題

跑較高版本 TensorFlow 時,都會出現下列訊息:

FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy

Google 了一下,是因為 numpy 版本太新,只要安裝 numpy 1.16 版本即可。

2020年2月6日 星期四

口罩地圖上線試用

今天是口罩實名制上線的第一天,趁著坐公車時,觀察沿路藥局的排隊狀況並比對系統回報結果。

第一家是位於新店捷運站的某藥局,系統 8:50 分更新後,成人口罩剩 198 片,原本以為以後可以趁上班時間買,等公車經過門口才發現,門口有一看板提醒下午 2:00 開始發放。

之後陸續經過幾家,也沒看到排隊人潮,唯當時不方便拿手機出來,故未知系統顯示狀況。

等到公車上人少一點後拿出手機,第二家是位於新店中正路中正國宅附近的某藥局,門口約有 12 ~ 16 人的排隊人潮,系統顯示成人口罩剩 148 片。

再來因為趕著上班,就沒再繼續觀察。

就我的感覺實名制是個不錯的措施,避免有人重覆排隊,也可以減輕超商店員的負擔。

雖然以目前產量來說還是會有人買不到,不過希望政府不要為了討好大眾,而壓縮了第一線醫護等人員的配給,畢竟防役這場大戰還是得靠他們才能有效防範。

我到現在也還買不到半片口罩,還好有半年前剩下的幾十片應應景,等到真的彈盡援絕,就開車上下班吧。

2020/02/06 更新

晚上走路回家好實測各藥局機制,雖然某些藥局還有數量,但實際走訪發現都是分兩段式發放,第一階段要先領號碼牌,第二階段才過卡,故導致系統無法反映真實狀況,另外少部份藥局數量超過 200 個,明顯系統有問題。

2020/02/07 更新

今天較早出門,觀察昨天發現排隊人潮的藥局在 8:48 分更新資料後,成人口罩數量就只剩 2 片,可能跟它 8:30 開門有關,繼續觀察中。

2020/02/07 下午更新

同一家藥局下午看又變 198 片,我猜早上看到的 2 是昨天未賣完的,資料庫不知為何沒歸零或是今天的 200 片在早上 8:48 未加入到資料庫?我猜沒賣完的應該是可以隔天繼續賣?(也許跟系統上線時間有關?還是不要太苛責開發人員,我覺得問題還是出在號碼牌機制,不過藥師也是很辛苦,兩難?)

2020/02/13 更新

實名制上線第二個禮拜,還是覺得實名制是個不錯的措施,確保不會有人重覆領取,雖然苦了上班族就是,我到現在也還沒買到,都是用最近買到的一般口罩坐公車,反正防禦力加 1 也比沒有好,哈。

沒辦法,開車還是太傷本了,多花的幾千塊我可以買好多書來看。

2020年2月1日 星期六

Parse pure text from EPUB.

最近測試時,常常需要盯著螢幕,否則會錯失一些資訊。這時電腦就不能做其他的事,不過一直盯著 console 也很無聊,也不方便看其他技術文件。

乾脆來寫個小程式,把小說 EPUB 裡面的純文字取出來,就能開一個最小視窗放在 console 旁邊,也不會影響測試。

一開始只想簡單用 C 語言來處理就好,不過 EPUB 都是 UTF8 編碼,故不適合用 C 來處理。

本想趁這個機會熟悉一下 python,但還是不想花太多時間在這上面,畢竟我只是拿來打發測試時的無聊時間,重點還是我的測試結果。

想了一下,還是用 node.js 好了,畢竟現在專案後端都是用它,雖然我跟它也不是很熟XD

花了不到半個小時,寫出類似 C 寫法的程式,用起來還算滿意。

只是從來沒有好好使用正規工具,都是把 HTML 硬當字串解析,感覺人家都上太空了,我還在學走路?

大概找了一下,決定使用 parse5 這個模組,反正重點還是測試,不要浪費太多時間。

底下是測試程式及時間,測試檔案為 10,303 bytes :

parse5                             - 解析 HTML Tree 及走訪 Tree 要 29 毫秒,單純走訪只要 11 毫秒。
Regex + string function - 無法分離 Regex 時間,全部要 14 毫秒。

Parse5 Example

const fs = require('fs');
const process = require('process');
const parse5 = require('parse5');

let s = '';

function parseTree(root) {
    if (Array.isArray(root.childNodes)) {
        for (let i = 0; i < root.childNodes.length; i++) {
            parseTree(root.childNodes[i]);
        }
    } 

    if (root.tagName == 'p') {
        console.log(s);
        s = '';
    } else if (root.value) {
        s += root.value;
    }
}

const content = fs.readFileSync('p-06.xhtml', {encoding: 'utf8'});

let t1 = new Date();

const document = parse5.parse(content);

let t2 = new Date();

parseTree(document);

let t3 = new Date();

console.log('\nUsed ms :', t3 - t1, t3 - t2);


Regex Example

const fs = require('fs');
const process = require('process');

function arrangeStr(str) {
    let newStr = '';
    let begin;
    let end;

    while (true) {
        begin = str.indexOf('<');
        if (begin != -1) {
            newStr += str.substring(0, begin);
            end = str.indexOf('>', begin);
            str = str.substring(end+1);  
        } else {
            newStr += str;
            break;
        }
    }
    return newStr;
}

const content = fs.readFileSync('p-06.xhtml', {encoding: 'utf8'});

let t1 = new Date();

let regex = />(.+)</g;

let info;
while ((info = regex.exec(content)) != null) {
    for (let i = 1; i < info.length; i++) {
        console.log(arrangeStr(info[1]));
    }
    console.log('');
}

console.log('\nUsed ms :', new Date() - t1);