Tensorflow gtx 1060 installation

前言

上個禮拜電腦在開機時又開始產生了異常狀況,算一算大概壽命快要到達盡頭了。於是心一狠準備花大錢來組台新的來使用,目標是可以讓 tensorflow 跑 GPU 的版本。原訂目標是直上 gtx 1080 ,後來和朋友討論之後是不需要太衝動買這張,但是又要有一定的效能和記憶體容量,考量了一下價錢,最後選擇了 msi gtx 1060 版本。因此目前新的這一台系統環境如下:

System Info

環境準備

安裝 nvidia driver

這邊我是參考別人的作法,從 “Graphics Drivers Team” team 找 driver 下載,若是直接從 nvidia 官網下載 driver 步驟會比較麻煩,看 github 上的討論也有不少問題。

1
2
3
4
5
sudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt-get update
sudo apt-get install nvidia-367
sudo apt-get install mesa-common-dev
sudo apt-get install freeglut3-dev

裝好後,重開機將 driver load 進來。

安裝 dependencies 套件

1
sudo apt-get install libglu1-mesa libxi-dev libxmu-dev libglu1-mesa-dev

安裝 gcc & g++ 4.8

在裝 CUDA 之前,需要先將 gcc & g++ 準備好,由於 ubuntu 預設是使用 4.5 ,因此需要裝額外的版本。

1
2
3
4
5
6
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install gcc-4.8
sudo apt-get install g++-4.8
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 50
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50

10/11 更新

Ubuntu 16.04 使用的 gcc 版本已經非常的新 (Gcc version 5.4),會造成 #error -- unsupported GNU version! gcc versions later than 5.3 are not supported! 訊息出現,需要去修改 /usr/local/cuda/include/host_config.h

1
2
3
4
5
#if __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ > 3)
//#error -- unsupported GNU version! gcc versions later than 5.3 are not supported!
#endif /* __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ > 1) */

安裝 CUDA Toolkit 8.0

CUDA Toolkit 8.0 裡選擇適合的版本。

CUDA Toolkit 8.0

接下來執行:

1
sudo bash cuda_8.0.27_linux.run

安裝過程中第一步會詢問是否要安裝 nvidia driver ,這裡就填 n ,避免先前安裝的 driver 被蓋過。

安裝完之後,設定環境變數到 .bashrc 裡:

1
2
export PATH=/usr/local/cuda-8.0/bin${PATH:+:${PATH}}
export LD_LIBRARY_PATH=/usr/local/cuda-8.0/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}

現在就可以下指令來觀察是否有正確安裝好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ nvidia-smi
Sun Aug 21 22:54:45 2016
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 367.35 Driver Version: 367.35 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce GTX 106... Off | 0000:01:00.0 On | N/A |
| 0% 54C P0 30W / 200W | 310MiB / 6069MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 3359 G /usr/lib/xorg/Xorg 172MiB |
| 0 4089 G cinnamon 104MiB |
| 0 4380 G /usr/lib/firefox/firefox 1MiB |
| 0 4523 G ...s-passed-by-fd --v8-snapshot-passed-by-fd 31MiB |
+-----------------------------------------------------------------------------+

安裝 cuDNN 5.0

cuDNN Download 從此處選擇 Download cuDNN v5 (May 27, 2016), for CUDA 8.0 RC

解壓縮後放到指定的位置。

1
2
3
4
5
tar -zxvf cudnn-8.0-linux-x64-v5.0-ga.tgz
sudo cp cuda/include/cudnn.h /usr/local/cuda/include/
sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64/
sudo chmod a+r /usr/local/cuda/include/cudnn.h
sudo chmod a+r /usr/local/cuda/lib64/libcudnn*

安裝 Tensorflow with GPU

這邊要使用最新版本的原始碼。目前 release 的 r0.10 RC0 有 bug 還沒有修好。

下載原始碼

1
git clone https://github.com/tensorflow/tensorflow.git

安裝 dependencies

1
2
3
4
sudo apt-get install openjdk-8-jdk openjdk-8-jdk-headless openjdk-8-jre
sudo apt-get install python-numpy swig python-dev python-wheel
sudo apt-get install python-setuptools python-pip
sudo apt-get install zlib1g-dev

安裝 Bazel

Bazel 是 google 在推的 build 工具,適用於大型專案裡有不同語言和套件整合的需求上。

1
2
wget https://github.com/bazelbuild/bazel/releases/download/0.3.1/bazel-0.3.1-installer-linux-x86_64.sh
bash bazel-0.3.1-installer-linux-x86_64.sh

設定 Tensorflow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ ./configure
Please specify the location of python. [Default is /usr/bin/python]:
Do you wish to build TensorFlow with Google Cloud Platform support? [y/N] N
No Google Cloud Platform support will be enabled for TensorFlow
Do you wish to build TensorFlow with GPU support? [y/N] y
GPU support will be enabled for TensorFlow
Please specify which gcc nvcc should use as the host compiler. [Default is /usr/bin/gcc]:
Please specify the Cuda SDK version you want to use, e.g. 7.0. [Leave empty to use system default]:
Please specify the location where CUDA toolkit is installed. Refer to README.md for more details. [Default is /usr/local/cuda]:
Please specify the cuDNN version you want to use. [Leave empty to use system default]:
Please specify the location where cuDNN library is installed. Refer to README.md for more details. [Default is /usr/local/cuda]:
Please specify a list of comma-separated Cuda compute capabilities you want to build with.
You can find the compute capability of your device at: https://developer.nvidia.com/cuda-gpus.
Please note that each additional compute capability significantly increases your build time and binary size.
Setting up Cuda include
Setting up Cuda lib
Setting up Cuda bin
Setting up Cuda nvvm
Setting up CUPTI include
Setting up CUPTI lib64
Configuration finished

基本上設定要啟用 GPU ,剩下的版本環境使用預設值就好。

修改 Tensorflow

在設定完之後,接下來是測試是否可以編譯成功。在這邊編譯時會出現 ERROR: … undeclared inclusion(s) in rule … ,這邊翻到 issue 3760 裡有人提到需要修改 Tensorflow 的設定。

1
vim tensorflow/third_party/gpus/crosstool/CROSSTOOL

在 65 行那邊加入這一行 cxx_builtin_include_directory: “/usr/local/cuda-8.0/include” ,測試加了之後就可以編譯成功。

Build Tensorflow with GPU

這裡之後就沒遇到什麼問題, 跟著官網安裝指令走就好。

1
2
3
4
5
6
7
8
$ bazel build -c opt --config=cuda //tensorflow/cc:tutorials_example_trainer
$ bazel-bin/tensorflow/cc/tutorials_example_trainer --use_gpu
# Lots of output. This tutorial iteratively calculates the major eigenvalue of
# a 2x2 matrix, on GPU. The last few lines look like this.
000009/000005 lambda = 2.000000 x = [0.894427 -0.447214] y = [1.788854 -0.894427]
000006/000001 lambda = 2.000000 x = [0.894427 -0.447214] y = [1.788854 -0.894427]
000009/000009 lambda = 2.000000 x = [0.894427 -0.447214] y = [1.788854 -0.894427]

Create pip package

1
2
3
4
5
6
$ bazel build -c opt --config=cuda //tensorflow/tools/pip_package:build_pip_package
$ bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
# The name of the .whl file will depend on your platform.
$ sudo pip install /tmp/tensorflow_pkg/tensorflow-0.10.0rc0-py2-none-any.whl

結論

到此就大功告成,開始享受 GPU 加速之後的威力,以及…更多的 GPU 問題。

References

8/13 痞客邦克漏字比賽心得

昨天就是痞客幫克漏字比賽的日子,一大早7點爬起來梳洗一下就出發到現場。然而到達目的地華山文創園區時要找會場在哪時迷路了一下,在裡面繞一繞找不太到會場在哪裡。

進到會場後,痞客邦工作人員帶我到比賽時使用的桌子,組員其他三位都已經到達現場在為今天比賽做準備。由於我們很早就開始討論今天的比賽要怎麼做,所以到了當天只差投影片還沒有開始製作,剩下其實沒多少事。於是我就用當天得時間去詢問 AWS 無法使用 GPU instance 的問題,現場也有 AWS support 人員和工程師在場,過不了多久就順利開起來,原來是 GPU instance 預設限制使用量是0,需要去申請才可以使用。

既然能開啟有 GPU 的環境,那當然就是要嘗試一下利用 GPU 的計算能力來看看我們使用的 RNN 模型有沒有計算比較快。這次比賽時我們就決定好全力嘗試使用 RNN/LSTM 模型,不過過程中沒那麼順利,直到比賽前幾天才弄出了一個可以跑的模型出來。實際開始訓練已經是比賽前一天,而且訓練速度真的是慢的超乎想像,借了一台性能不錯的 server 來跑還是需要好幾個星期才能訓練完畢。不得已,我們只能先拿訓練一部份的結果來先測試看看能不能在比賽時使用。結果是在算預測值時也是需要花上不少時間,無法在比賽時拿出來用。因此在正式比賽時就不是使用 RNN ,而是使用另一組員先建好的 Word2vec 模型。

即使如此,有了 GPU 環境可以使用,不嘗試看看也說不過去。於是整個上午的時間,我都在弄 AWS 環境。嘗試把 tensorflow build 出使用 CUDA 的版本,過程中看似一切都很順利,最後要使用時卻會出現找不到 GPU device 的問題。鑑於時間的關係,就不去找尋找原因,而是改去找別人弄好的還境。這邊還好泡在 tensorflow community 時有看到相關的訊息,因此順利地找到可以使用的環境。

有了神兵利器,該是屠殺獵物的時刻。立即將我們使用的模型拿下去跑。然後…然後它就死了。GPU 的記憶體稱不過大量的文字向量表,真是沒用過不曉得記憶體使用的問題會這麼大。後來嘗試把訓練資料不斷縮小,縮小到剩 20mb 左右才跑得起來。不過即使是這樣的資料量,用 GPU 訓練起來還是需要一兩個小時。所以到此 RNN 就從比賽中出局啦。

剩下的時間就幫忙製作投影片,看一下其他組的成果。其中有一組資料科科家的成果非常驚人,在整場比賽裡丟出來的測試樣本都可以 100% 答對。我們的模型在測試過程中大概排第4名。

到了比賽時間,開始了第一輪淘汰賽。這時戲劇性的結果出現了,資料科科家在第一輪比賽時程式出了問題,沒有回答,結果就被刷掉了。每個參賽成員、主辦單位都大吃了一驚。頓時比賽變成了人人都有機會,一下子氣氛開始緊張起來。第一輪三次淘汰賽下,我們組別幸運地擠進前三名,準確度排第二。

第二輪比賽是採搶答方式,第一個回答正確才得分,累積10分為優勝者。這一輪比賽更刺激,因為大家的回答速度都很快,幾乎時間都只差一咪咪。不過我們沒有針對回答速度特別去調整,因此幾乎搶不到第一名回答,於是比賽過程不久就開始落後,成績都還掛0。當好不容易因前面組的失誤,才讓我們拿下一分時,全場都還鼓掌了起來,內心真的是頗感動的。後來劣勢一直都在,不過有幾次前面2組都答錯,只有我們答對,成了在比賽中的驕傲。

最後成績是我們排名第3名,雖然無法獲得更佳的名次有點可惜,不過已經超乎我們的預期。真是感謝組員的參與和付出。

附上報告組員的帥照。
Present

比賽時各組的投影片:
2016 PIXNET HACKATHON DEMO

7/29 痞客邦克漏字比賽紀錄

最近這陣子都熱心在學習 Deep learning 的東西,動機來自於和同事組隊參加 2016 PIXNET HACKATHON Cloze Contest。這個比賽會給出一句話,裡面會挖一個洞,並給出 4 個選項來選出符合這個洞的答案,也可以說是傳統的選擇題考試。對從小到大都是考試機器的我們來說是最常見不過的問題,因此都練出的一身本領來回答。但是對於機器來說,要選出正確答案還真不是件簡單的事,更可說是巨大的挑戰。

因此為了可以讓機器有辦法回答,需要有一些技巧來使用。以下紀錄目前我和同事做到的進度。正式比賽是在8/13 日,離比賽還有兩星期。

爬取文章

在這個比賽裡,訓練資料集放出來是在 7/01 時,而我們準備的時間從 6 月初就開始,因此在沒有資料的情況下,我們就決定要開發爬網程式將痞客邦的文章抓取下來。這部分使用 Scrapy 來幫助我們開發爬網程式。

目前做到的成果為針對每天有被痞客邦視為熱門的文章抓取下來,並且順便將這些文章的作者曾經寫過的文章也一併抓取。跑一次爬網程式需要花費半天的時間,目前累積了將近 2G 的資料。不過現在的機制只是堪用,要做進一步改善還有很大的空間,只是考慮到接下來還有更困難的問題要解決,因此先開發到這邊。

斷詞斷句

將文章抓取下來後,接下來使用 Jieba 來幫助我們做斷詞。這裏就直接使用現成的工具,因此不是太困難的工作。當然使用過程中會看到很多奇奇怪怪的字詞出現,這就需要人工介入將一些字詞濾掉。

Word2vec

將上面斷出來的字詞整理出一個字詞庫出來,接下來要做的動作是把字詞變成向量。根據 Word2vec 演算法,字詞轉成向量後會有一些有趣的相關性,像是 國王 - 男人 + 女人 = 皇后。因此要完成這次的競賽,其實用 Word2vec 就可以做到不錯的成果,把選項的向量拿去和題目比對相似度,把最高相似度的選項當作正確答案,就會是一個不錯的解題模型。目前有組員利用這個方法做到 6 成正確率。

RNN/LSTM

這部分就是真正的挑戰啦,對於我這個初學者而言,要跟很多不熟悉的演算法和公式搏鬥。而且要處理部落格文章並拿去訓練也很不容易。基本上要面對龐大的字詞庫,動輒幾十萬的字詞,要算出每個字的機率出來,光想就覺得困難重重。目前這塊還在努力中,希望可以真的玩出一個模型出來。

感想

在這個比賽裡,由於接觸到的東西很多且都頗有挑戰性,所以做起來其實滿快樂的。學到很多東西,感覺很過癮。在目前工作上覺得進展有點停滯的時刻,弄這些東西真的有如及時雨一般滋潤我的內心,邊做邊感到持續有在進步中。希望到時能做出不錯的結果出來!

Data at rest encryption

目前一般的 data at rest encryption 有三種方式,分別為:

  1. Encrypted drives

    獨立於作業系統之外,由硬體提供加密的功能。避免硬體遺失時資料被輕易拿出,缺點是無法避免系統運行時被惡意使用者或惡意程序拿取資料。

  2. Full disk encryption

    在這種模式下不需要硬體支援,可針對 disk 或 volume 整個加密。實作方式各家 filesystem 都有不同,所以也有不同的限制,像是有的可以對 /root 資料夾加密,有的不行。缺點和 Encrypted drives 一樣無法避免 disk 或 volume 運行起來時被惡意使用者或惡意程序拿取資料。

  3. Filesystem encryption

    又稱為 file/folder encryption 。此種方式可以讓使用者分別對某個檔案或資料夾加密,加密時也可選擇不同的 key ,因此優點就是可以避免上面兩種方式的缺點,讓惡意使用者或程序難以解讀內容。缺點是針對密碼控管需要注意,特別是加密很多東西時。

    其實我初看到 Filesystem encryption 名詞時還以為是對整個 filesystem 加密,不過後來查 wiki 看到別稱才明白是指什麼。

參考資料

Disk encryption

Filesystem-level encryption

使用 Openssl 建立憑證

最近工作上需要建立程式之間的 TLS 連線,而 TLS 之間的連線步驟需要驗證憑證 (Certificate) ,讓之間的加密連線可以成立。不過由於處於測試階段,需要自己產生憑證出來。因此學習使用 Openssl 來產生憑證,也藉此讓自已對 TLS 連線和憑證機制有更清楚的了解。

TLS 介紹

傳輸層安全協議(Transport Layer Security,縮寫:TLS),前身為安全通訊協定(Secure Sockets Layer,縮寫:SSL),由網景公司 (Netscape) 開發出來用在 http 協定上,後來由 IETF 將 SSL 進行標準化,就是後來的 TLS 。

TLS 在建立連線時,會經過以下的步驟:

  1. client 送出 ClientHello 訊息給 server ,裡面包含可支援的 TLS protocol,一個由 client 端隨機產生的數字(隨機數字只用在此次連線期間,避免被封包重播攻擊),以及支援的加密和壓縮演算法。
  2. server 回應 ServerHello 訊息,提供要使用的 TLS protocol ,一個由 server 端隨機產生的數字,以及要使用的加密和壓縮演算法。
  3. server 根據上面選擇的 TLS protocol 和加密及壓縮演算法,提供憑證給 client
  4. client 驗證 server 提供的憑證,將憑證內的 public key 取出
  5. 利用 server 提供的 public key ,將 client 的憑證,沒有憑證則隨機產生的 public key ,加密送回。
  6. 雙方使用交換出來的資訊,產生一組通訊用的加解密方式,有對稱式或非對稱式,取決於採用哪種演算法。
  7. 連線建立。

使用 Openssl 產生憑證

以下描述使用 openssl 來產生可供 TLS 連線所需的憑證,主要參考 OpenSSL Certificate Authority 這個網站的步驟來一步一步執行,根據自己的需求修改設定。

建立 root 憑證

一般公開網路上憑證不會是自己產生的,因為網路傳輸過程中不能確保會不會被偽造或修改。因此為了有可靠的信任機制,於是就有了憑證機構 (Certificate Authority, CA) ,由憑證機構產生憑證。最上層憑證機構通常由被信任的第三方公正機關來擔任,然後對個人或公司團體產生憑證簽章,如此才能確保憑證可以不被修改。

以瀏覽器為例,存有一串信任的憑證機構,藉由檢視連線網站的憑證是否由這些憑證機構產生,來判別網站可否受信任,不信任情況下就會出現不安全連線的提示。

而對公司企業內的私人網路來說, 不需要透過第三方憑證機構,因此會由自己產生 root 憑證,往下建立一連串的認證階層。也因此 root 憑證必須保護好,放置在與網路隔絕的環境並只有特定人士可以存取。一般網路上的認證機構的 root 憑證會互相簽章,表示彼此信任,而自己產生的 root 憑證因沒有其他機關互相簽章,因此會是自我簽章的憑證。

步驟:

  1. 產生 root key。

    1
    2
    3
    4
    mkdir /root/ca
    cd /root/ca
    openssl genrsa -aes256 -out private/ca.key.pem 4096
    chmod 400 private/ca.key.pem
  2. 參照 config 產生 openssl.cnf

  3. 產生自我簽章的 root 憑證。

    1
    2
    3
    4
    5
    6
    openssl req -config openssl.cnf \
    -key private/ca.key.pem \
    -new -x509 -days 7300 -sha256 -extensions v3_ca \
    -subj "/C=TW/ST=Taipei/O=RAIX/OU=RAIX.IO/CN=raix.io.rootca/emailAddress=raix@mail.com" \
    -out certs/ca.cert.pem
    chmod 444 certs/ca.cert.pem

    root 憑證過期日期建議設定長一點,因為是最重要的環節,不太適合頻繁的過期造成整串憑證失效。

    另外因為是產生自我簽章的憑證,和接下來產生 intermediate 或 client/server 的 Certificate signing request (CSR) 指令多了 -x509 參數。

  4. 驗證 root 憑證

    1
    openssl x509 -noout -text -in certs/ca.cert.pem

建立 intermediate 憑證

intermediate 憑證介於 root 和 client server 之間,可避免 root 憑證直接被使用,也可用來分群組,區分可使用的範圍。

步驟

  1. 設置相關資料夾和資訊

    1
    2
    3
    4
    5
    6
    7
    mkdir /root/ca/intermediate
    cd /root/ca/intermediate
    mkdir certs crl csr newcerts private
    chmod 744 private
    touch index.txt
    echo 1000 > serial
    echo 1000 > crlnumber
  2. 產生 intermediate key

    1
    2
    3
    openssl genrsa -aes256 \
    -out private/intermediate.key.pem 4096
    chmod 400 private/intermediate.key.pem
  3. 修改 openssl.cnf 產生 openssl-im.cnf

    1
    2
    3
    4
    5
    6
    [ CA_default ]
    dir = /root/ca/intermediate
    private_key = $dir/private/intermediate.key.pem
    certificate = $dir/certs/intermediate.cert.pem
    crl = $dir/crl/intermediate.crl.pem
    policy = policy_loose
  4. 產生 intermediate CSR

    1
    2
    3
    4
    openssl req -config openssl-im.cnf -new -sha256 \
    -subj "/C=TW/ST=Taipei/O=RAIX/OU=RAIX.IO/CN=raix.io.imca/emailAddress=raix@mail.com"\
    -key private/intermediate.key.pem \
    -out csr/intermediate.csr.pem

    Certificate signing request (CSR) 裡紀錄個人或組織的資訊,並且提供給憑證機構簽章。

  5. 對 intermediate CSR 簽上 root 憑證,產生 intermediate 憑證

    1
    2
    3
    4
    5
    openssl ca -config /root/ca/openssl.cnf -extensions v3_intermediate_ca \
    -days 3650 -notext -md sha256 \
    -in csr/intermediate.csr.pem \
    -out certs/intermediate.cert.pem
    chmod 444 certs/intermediate.cert.pem
  6. 驗證 intermediate 憑證

    1
    2
    3
    4
    openssl x509 -noout -text \
    -in intermediate/certs/intermediate.cert.pem
    openssl verify -CAfile certs/ca.cert.pem \
    intermediate/certs/intermediate.cert.pem
  7. 產生憑證鍊 (certificate chain)

    1
    2
    3
    cat intermediate/certs/intermediate.cert.pem \
    certs/ca.cert.pem > intermediate/certs/ca-chain.cert.pem
    chmod 444 intermediate/certs/ca-chain.cert.pem

    當應用程式要驗證 intermediate 憑證時,也需要同時驗證 root 憑證,因此需要產生憑證鍊來完成一整串驗證。

建立 client/server 憑證

最後就是對要使用的 client/server 產生憑證,讓彼此之間 TLS 連線可以成立,確保處於安全的連線下。

步驟

  1. 產生 client/server key

    1
    2
    3
    cd /root/ca/intermediate/
    openssl genrsa -out private/client.raix.io.key.pem 2048
    chmod 444 private/client.raix.io.key.pem
  2. 產生 client/server CSR

    1
    2
    3
    4
    openssl req -config openssl-im.cnf \
    -key intermediate/private/client.raix.io.key.pem \
    -subj "/C=TW/ST=Taipei/O=RAIX/OU=RAIX.IO/CN=client.raix.io/emailAddress=raix@mail.com" \
    -new -sha256 -out client.raix.io.csr.pem
  3. 產生 client/server 憑證

    1
    2
    3
    4
    5
    openssl ca -config openssl-im.cnf \
    -extensions server_cert -days 375 -notext -md sha256 \
    -in intermediate/csr/client.raix.io.csr.pem \
    -out intermediate/certs/client.raix.io.cert.pem
    chmod 444 certs/client.raix.io.cert.pem
  4. 驗證憑證

    1
    2
    3
    4
    openssl x509 -noout -text \
    -in certs/client.raix.io.cert.pem
    openssl verify -CAfile intermediate/certs/ca-chain.cert.pem \
    certs/client.raix.io.cert.pem

參考資料

Wiki: Transport Layer Security

Wiki: Certificate authority

Wiki: Certificate signing request

OpenSSL Certificate Authority

Python - @property

今天在 trace 一個 python 專案時,看到類似 getter/setter 函式,不過實際使用時卻不像其他語言的 getter/setter 用法。於是就去 google 一下,找到 @property 的用法。

原來,在 python class 中,因為沒有 private 變數,全部都是 public ,任何人都可以存取,頂多只有透過命名風格在變數前加 ‘_‘ 或 ‘__‘ ,讓別人了解這個變數是給內部使用,不建議直接呼叫。也因此 getter/setter 的設計模式在 python 較沒意義,取而代之的是使用 @property 裝飾器(decorator)來達到類似的效果。

範例 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/python
class Example(object):
_text = 'This is an origin string'
@property
def text(self):
return self._text
@text.setter
def text(self, string):
if isinstance(string, str):
self._text = string
else:
raise TypeError('%s url must be str, got %s:' % (type(self).__name__,
type(url).__name__))
if __name__ == '__main__':
ex = Example()
string = 'This is a test'
print 'Get Example.text: %s' % (ex.text)
print 'Set Example.text: %s' % (string)
ex.text = string
print 'Get Example.text: %s' % (ex.text)

執行結果

1
2
3
4
$ ./decorator_property.py
Get Example.text: This is an origin string
Set Example.text: This is a test
Get Example.text: This is a test

不過在 trace 的 python 專案中,用的是另一種方法。

範例 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/python
class Example(object):
_text = 'This is an origin string'
def _get_text(self):
return self._text
def _set_text(self, string):
if isinstance(string, str):
self._text = string
else:
raise TypeError('%s url must be str, got %s:' % (type(self).__name__,
type(url).__name__))
text = property(_get_text, _set_text)
if __name__ == '__main__':
ex = Example()
string = 'This is a test'
print 'Get Example.text: %s' % (ex.text)
print 'Set Example.text: %s' % (string)
ex.text = string
print 'Get Example.text: %s' % (ex.text)

執行結果

1
2
3
4
$ ./decorator_property_2.py
Get Example.text: This is an origin string
Set Example.text: This is a test
Get Example.text: This is a test

可以看到兩種寫法都可以達到相同的效果,而且用 type(ex.text) 看型態都是 <type 'str'>

至於哪種寫法比較好?就本人覺得,比較偏好範例 2 ,畢竟可以對應到其他語言的寫法,相較之下可讀性較高。

References

  1. 使用@property
  2. Python @property versus getters and setters

5/31 日記

今天終於將 blog 上面的圖換掉,換成東方project中的三位魔女,左至右分別為魔理沙,帕秋莉和愛莉絲,Pixiv ID:51596801

在一開始隨便將圖放上,效果其實是非常差的。因為上面呈現的範圍只有一小區塊,而且預設是置中呈現,會對原圖人物的頭部部份給切掉,而且色彩偏向明亮,對文字會干擾模糊。因此就要根據這張圖來調整網頁呈現。

在準備開始調整時,其實我內心一點頭緒也沒有,對前端網頁呈現一丁點也不懂,這時候就只能先把 firefox 的網頁開發者工具開啟,觀察頁面元素,找出上頭呈現範圍所對應的 html 元素。如下圖:
Inspector

然後看到右邊分隔頁的 rule ,看起來是 css 設定,於是去找其他網頁來比對設定。接著就是開始 google 大法,找這些關鍵字要怎麼設定,再利用 firefox 提供的開發工具可以隨手改動數據,立刻顯出效果。經過幾番嘗試後,開始知道要怎麼調整了,後面就開始邊調邊想像我想要做成的畫面。結果就做出感覺還不錯的成果,這也歸功於於設計者先天設計良好,隨便調都好看。

到這邊為止算是稍微撇到前端千變萬化的一小小部份,不過能改變別人寫好的程式,內心會開始沾沾自喜起來。接下來想要在右邊欄位放上個人簡介,將會是另一番工程要奮鬥。

Hexo 安裝和佈署到 Github

Octopress 剛架設好後立刻使用 markdown 寫了一篇文章,滿心期待看到轉出來的成果,結果就是一連串格式不合無法轉出的錯誤發生。我現在使用的編輯是 Atom ,預覽呈現出來的排版都很美好,然而一旦要被 Octopress 轉出時,就會出現問題。無奈之下開始上 Github 查詢 issues ,這才發現 Octopress 目前開發進度有點處於停滯的情況,所以乾脆開始尋找另一套解決方案。就是本篇的 Hexo

將為數不多的文章改用 Hexo 產生後,呈現上果然有比較好些。雖然還需要經過一些微調,但對於純粹使用上來說,是已經足以。以下紀錄我的安裝過程。

安裝

參照 官網的文件 上提供了詳細的步驟,而且動作也比起 Octopress 來說簡單。基本需求只有:

  • Node.js
  • Git

Git 不用說,對程式開發者而言都是必裝的套件。而 Node.js 在目前使用的 Ubuntu 16.04 環境上沒有安裝,因此直覺得下 apt-get install nodejs 安裝。豈知之後要安裝 Hexo 就開始遇到麻煩。最後是照著官網建議的安裝 Node.js 方式才成功安裝。因此這邊就不誤人子弟,直接使用官網的方式安裝吧。

安裝 Node.js

我這邊使用 wget 方式:

1
$ wget -qO- https://raw.github.com/creationix/nvm/master/install.sh | sh

安裝完成後要重開終端機。接著在下:

1
$ nvm install 4

以上指令查一下是安裝版號 4.x ,裝好之號看 Node.js 版號是 v4.4.4 。

安裝 Hexo

安裝 Hexo 指令只須一行。

1
$ npm install -g hexo-cli

之後就可以開始使用囉。

建立

建立網站範本

Hexo 是透過指令來產生網站的範本,相比 Octopress 是先去 git clone 自己的 repo 下來做修改,簡潔不少。使用以下指令來建立範本:

1
2
3
$ hexo init <folder>
$ cd <folder>
$ npm install

建完之後會看到設定的資料夾下多了一些目錄和檔案。其中 _config.yml 是用來設定 Hexo 的配置,其他的目錄和檔案就請參考官網說明。

建立新文章

透過 Hexo 提供的指令一樣可以方便的建立出新文章樣本出來。

1
$ hexo new [layout] <title>

其中 [layout] 提供了三種布局。

佈局 路徑
post source/_posts/
page source/
draft source/_drafts/

post 是一般要建立新文章使用的指令。

page 可以在網站中產生新的頁面出來,存放其他種類文章。像是拿來開一個頁面做 “About” 介紹。

draft 可以用來當作草稿使用,佈署的時候會忽略這裡面的內容。需要另外下指令 hexo publish 來發表。此外預覽時可以加參數來呈現。

佈署

產生網頁

內容準備完成後,接下來就下指令來產生網頁。

1
$ hexo generate

以上指令會依據使用者提供的內容和設定,產生想要的網站內容。

佈署到 Github 上

在佈署之前,需要先在 _config.yml 裡設定要採取 git 模式佈署。設定如下:

1
2
3
4
5
deploy:
type: git
repo: <repository url>
branch: [branch]
message: [message]

repo 欄位上就填寫 Github repo 的 url 。

另外還須額外安裝 hexo-deployer-git

1
$ npm install hexo-deployer-git --save

接下來就可以透過 Hexo 一行指令完成佈署囉。

1
$ hexo deploy

另外如果想再產生網頁時同時佈署上去, Hexo 也有提供指令參數使用,不過我想還是先預覽看過再佈署上去比較明智。

1
2
$ hexo generate --deploy
$ hexo deploy --generate

完成

至此,我的網站就更新完成啦。真的和 Octopress 比起簡單快速不少。

不過 Octopress 的管理模式還是值得學習一下, Hexo 預設只會把產生的網站 commit 到指定的 branch 上,但是本身的內容並沒有提供方式來做版本控制。而這部份 Octopress 就會切出 master 和 source 兩個 branch 出來, master 用來放置管理網站內容,而 source 用來對自身做版本管理。接下來目標是參照這種模式把

Octopress 安裝和佈署到 Github

時常在逛網路 blog 時可以看到有不少人架設在自己的 Github 上,查了一下才了解 Github 有提供 Github Pages 的功能,可以讓使用者免費架設自己的網站。不過當然有一些限制,如下:

  1. 只能使用靜態網頁,無法透過 ajax 方式來交換前後端資料,動態生成出網頁。
  2. 每個月有 100 GB 和 100,000 requests 限制。
  3. Source repositories 有 1 GB 限制。
  4. 連線只能透過 http ,因此不適合傳送敏感資料。

然而以上限制對一般使用者來說,並不太會碰到。因此可以好好放心的架設自己的 blog 在 Github 上面,接著再透過 git 強大的版本控制功能,對文章內容可以好好保存修改紀錄。

在 Github 官網上官方推薦使用 Jekyll ,Github Pages 也是透過 Jekyll 做出。不過在架設的教學文章上,還是 Octopress 居多數,因此採用 Octopress 作為我的 blog 基礎。至於其中差異,我就沒有打算深入比較。

安裝

在我常用的機器上,有灌 Ubuntu 16.04 的一般桌機和 Mac 筆電,安裝時參考Octopress 官網文件提供的安裝方式。在安裝在 ubuntu 環境上時有遇上一些問題,而在 mac 上安裝就很順利 。因此對 Ubuntu 上提供詳細的安裝步驟。

Ubuntu 16.04 環境

  1. 安裝 git。

    1
    sudo apt-get install -y git
  2. 安裝 ruby 和 rbenv。

    1
    sudo apt-get install -y ruby2.3 ruby2.3-dev rbenv
  3. 下載 Octopress。

    1
    2
    git clone git://github.com/imathis/octopress.git octopress
    cd octopress
  4. 安裝 dependencies,這邊需要額外安裝 nodejs ,不然在bundle install時會出現錯誤。

    1
    2
    3
    4
    sudo apt-get install -y nodejs
    gem install bundler
    rbenv rehash # If you use rbenv, rehash to be able to run the bundle command
    bundle install
  5. 安裝 Octopress 預設的 theme。

    1
    rake install

至此 Octopress 就算安裝完成,接下來就開始來設定 blog 吧。

設定

將 Octopress 設定架設到 Github 上。

  1. 建立以自己為域名(Ex. your_username.github.io)的 Github repository。

  2. Octopress 設定 Github repository,輸入自己的 repository (Ex. git@github.com:your_username/your_username.github.io.git)。

    1
    rake setup_github_pages
  3. 產生樣板網頁,在這步驟中rake generate會根據設定產生樣板網頁出來,而rake deploy會將網頁佈署到 Github 上。完成之後就可以開啟自己的 Blog 出來看囉。

    1
    2
    rake generate
    rake deploy
  4. 到這步就可以開始變更 blog 設定,新增文章,並將修改 commit。

    1
    2
    3
    git add .
    git commit -m 'your message'
    git push origin source

Octopress 除了提供架設在 Github 上以外,還有提供架設在 heroku 和透過 rsync 的方式,有需求的人就請操考官方文章操作吧。

產生 About

想要在 blog 上有一個分頁是 “About” 來介紹嗎?以下兩個步驟可以輕鬆產生。

  1. 產生 about 頁面

    1
    rake new_page["about"]

    這步驟會產生新的檔案在 source/about/index.markdown ,接下來就編輯這份文件來寫內容。

  2. 加入上方分頁連結。

    編輯source/_includes/custom/navigation.html,加入第4行的內容。

    1
    2
    3
    4
    5
    <ul class="main-navigation">
    <li><a href="{{ root_url }}/">Blog</a></li>
    <li><a href="{{ root_url }}/blog/archives">Archives</a></li>
    <li><a href="{{ root_url }}/about">About</a></li>
    </ul>

    以上就可產生 About 頁面囉。

產生新文章並發表

產生新文章

使用 Octopress 提供的指令來生出範本。

1
rake new_post["title"]

新的範本會產生在source/_posts/下,開啟就可以開始透過 markdown 語法編輯文章內容。

發表

編輯完成後別急著使用 deploy 指令開始發表,Octopress 有提供預覽的功能,透過以下指令來預覽。

1
2
rake generate
rake preview

接著使用瀏覽器開起localhost:4000,就能搶先看文章呈現的樣貌。

確認都沒有問題後,就能 deploy 出去啦。

1
rake deploy

上傳完之後要記得還需要 commit 將紀錄保存下來呦。