部落格

  • Python 大量修改陣列賦值 – 陣列索引賦值法

    在 Python 裡面用索引取陣列裡面的值,通常我們會這麼寫:

    var = tensor[index]

    進階一點,如果你今天得到的索引值是一張陣列,而且你需要得到一張陣列的返回值呢?
    在 C 語言裡面,比較直覺的方法可能是 For loop,
    但是我們都用到 Python 了,該用高級一點的方法了!

    以下介紹 Python (list, numpy 適用)中 PyTorch 的 tensor 陣列索引賦值法:

    data = np.random.randint(0,1023, size=(32, 32))
    data = torch.from_numpy(data)
    index = np.argmin(data, axis=1)
    data = data.contiguous().view(-1)
    base = np.arange(0,32)*32
    index = index + base
    output = data[index]
    上面程式碼等效:

    output = np.min(data, axis=1)

    這樣你會問我:哇!Ben 為什麼一行能解決的問題,你要這麼費工?

    傻傻的,
    今天是因為有 np.min() 可以用,如果你今天要取得的並不是這麼簡單的統計值呢?
    這種賦值法的價值在於核心演算法複雜時,
    還能提供高效率的計算複雜度。
    讓我們來看一個比較實際的例子,
    當你今天是一個通訊所的學生,老師要你量化 16-QAM 的訊號:

    B, C, H  = 32000, 3, 16
    Q = 16
    data = np.random.randint(0,1023, size=(B, C, H))
    data = torch.from_numpy(data)
    data = data.contiguous().view(-1)
    
    ###################   Kernel    #########################
    q_list = torch.unsqueeze(torch.arange(1,Q+1)*64, dim=0)
    data = torch.unsqueeze(data, dim=1).repeat(1, Q)
    q_matrix = q_list.repeat(int(list(data.size())[0]), 1)
    index = np.argmin((data - q_matrix)**2, axis=1)
    feature = q_list[0, index]
    #########################################################
    

    上述核心來自於我先前提到的 KNN 算法

    既然都算出來了,讓我們來比較與 double for loop 賦值 的速度:

    f1s = time.time()
    feature = q_list[0, index]
    f1e = time.time()
    print("non-loop processing time: " + "%.3f" %(f1e-f1s))
    
    feature2 = torch.ones(int(list(data.size())[0]))
    f2s = time.time()
    k=0
    for i in index:
        for j in torch.arange(0,len(q_list[0]+1)):
            if j == i:
                feature2[k] = q_list[0][int(j)]
                k=k+1
                break
    f2e = time.time()
    print("for-loop processing time: " + "%.3f" %(f2e-f2s))
    
    feature = feature.type(torch.FloatTensor)
    print("feature = feature2? : " + str(torch.equal(feature, feature2)))
    
    差了六十萬倍呢!
    結論:當數據足夠大時,陣列索引賦值法會與迴圈賦值法速度差距會越來越明顯。


    如果對於文章內容有疑問的,歡迎聯絡我: wuyiulin@gmail.com


  • 一行就寫完 For 迴圈 – Python 列表推導式

     

    近期因為要趕畢業,

    大量參考前人大佬的 CODE,出現一堆列表推導式,

    加上 co-worker 學弟有資策會背景,對接的時候他也寫列表推導式,

    所以要學怎麼寫列表推導式,並留個紀錄。

     先來看一個簡單的例子:

    [expr0 for i in iterable if expr1]

    這種列表推導式等效於:

    for i in iterable:
        if (expr1):
            expr0
    超棒
    想要進階拓展 N 層迴圈?
    [expr0 for i in iterable for j in iterable if expr1]

    沒問題,這種表達式等效於:

    for i in iterable:
        for j in iterable:
            if (expr1):
                expr0 

    N 層迴圈也沒問題!
    準備好面對真正的難題了嗎?
    query, key, value = [l(x).view(nbatches, -1, self.h, self.d_k).transpose(1, 2).contiguous() 
    for l, x in zip(self.linears, (query, key, value))]

    哇靠這在寫三小?

    先讓我們簡化一下程式碼:
    把:

    l(x).view(nbatches, -1, self.h, self.d_k).transpose(1, 2).contiguous()

    改成:

    l(x)

    既然 self.linears 是某種包好的函式,替換成:

    fs(x)
    所以程式被我們簡化成:
    query, key, value = [l(x) for l, x in zip(fs, (query, key, value))]
    讓資料從列表推導式跑過一次:
    def f(x):
        a = x[0]*x[0]
        b = x[1]*x[1]
        c = x[2]*x[2]
        return [a, b, c]

    query = [1, 1, 1]
    key   = [2, 2, 2]
    value = [3, 3, 3]
    fs    = [f, f, f]

    print("n")
    print("Origin data:n")
    [ print(i) for i in (query, key, value) ]
    print("n")

    query, key, value = [l(x) for l, x in zip(fs, (query, key, value))]


    print("Processed data:n")
    [ print(i) for i in (query, key, value) ]
    print("n")
    結果會等於:
    Origin data:
    
    [1, 1, 1]
    [2, 2, 2]
    [3, 3, 3]
    
    
    Processed data:
    
    [1, 1, 1]
    [4, 4, 4]
    [9, 9, 9]
    唯一要注意 zip() 的關係,所以要造 fs。

    好棒,現在你也看得懂機器學習大佬的列表推導式了!

  • Cross Entropy 與 Binary Cross Entropy 之選擇。

     


    To be, or not to be, that is the question.

    BY William Shakespeare

    選擇 CE 或是 BCE,這是一個問題。

    要解答這個問題,我們要從兩個層面探討:

    1. 前置 Activation funtion 選擇(Softmax, Sigmoid)
    2. 下游任務的目標


    前置 Activation funtion 選擇:


    Softmax 與 Sigmoid 都是把數值壓縮到 [0, 1] 區間的函數,
    差別在於 Softmax 會考慮整體數值向量做處理。
    舉例來說:
    如果給定向量 S = [1, 2, 3]:
    Softmax(S) = [0.09003057 0.24472847 0.66524096]
    Sigmoid(S) = [0.73105858 0.88079708 0.95257413]
    Softmax 輸出的總和會是 1,會有抑制相對小數值的作用;
    Sigmoid 則會把每個輸出入都視為獨立去做壓縮。
    下游任務的目標:

    目前是還沒看到拿 CE 或 BCE 做分類以外的任務,
    所以這邊只探討三種分類情境。

    • 單標籤二分類
    • 單標籤多分類
    • 多標籤多分類

    先解釋一下標籤跟分類的意思,
    這邊標籤指的是 Loss function  input 進去的那張 Ground True,
    單標籤 = 對於每個樣本來說只有一個屬性(或類別)標成對的(1),其他都是 0 。

    分類的意思是依據任務需求分成幾類,
    不一定一個標籤對一個類別。


    舉例來說,如果有一則新聞標題是:

    “職棒啦啦隊性愛影片外流”
    假設有棒球、啦啦隊、性愛的標籤,
    那要歸類到棒球、啦啦隊、性愛,還是八卦?
    這就是一個多標籤多分類的問題。
    單標籤二分類:


    CE + Softmax 可以做, BCE + Sigmoid 也可以做。

    有一派說法是 BCE 要用一個節點
    (意指只提供一個類的正確率,第二類正確率則用 1 – 該類正確率去算。),
    否則用兩個節點的話,因為有可能你模型訓練出來會給出 [1, 1]。
    (模型認為這個樣本兩個類型都符合,直接做成多標籤任務。)
    但是根據我拿 BCE 做單標籤多分類的結論,
    應該不會出現這種現象。
    單標籤多分類:

    CE + Softmax 可以做, BCE + Sigmoid 也可以做。
    接續上面一個節點的問題,我認為就算給出 [1, 1] 的 logit 預測結果,
    訓練後也會乘上 Ground True 壓抑掉,反而因為有提供預測錯誤標籤的梯度收斂會更快。
    提供 CE 與 BCE 公式參考:
    多標籤多分類:


    CE + Softmax 完全不能做,因為 Softmax 會把最大機率以外的其他機率壓抑掉。
    那就用 CE + Sigmoid 不就好了(天真),
    不能這樣做的原因是 CE 只會照正確的標籤分類給梯度,
    多標籤裡面會難以收斂。
    所以這邊通常拿 BCE + Sigmoid 來做。
    結論:

    腦袋當機不知道要放什麼 Loss function 的時候拿 BCE 先試試看就對了,
    反正這顆很泛用。
    單標籤多分類任務只關心一個標籤,其他分類梯度不管的,再拿 CE + Softmax 減少計算量。
    以上。

  • Focal Loss – 基於 cross entropy 的分類 Loss function 改進

     

    假設各位都知道並了解  Cross Entropy 是什麼的前提下,

    這篇文章主要提到 Focal Loss ,一種基於  Cross Entropy 的改進方法。


    Cross Entropy 的簡介


    主要改進兩個方向:


    1. Data imbalanced
    2. Difficulty sample in weight ( Focal Loss )

    首先我們先來比較 Cross Entropy 與 Focal Loss 的 function:

    CE vs FL


    如上圖所見, 
    Alpha 負責解決 Data imbalancedGamma 負責解決 Difficulty sample 的問題。
    • Alpha
    講解 Alpha 之前,先讓我們了解什麼是 Data imbalanced
    Data imbalanced 就是關於你的資料集,如果每個類別的樣本分布不均,
    這樣模型就容易被樣本多的類別所決定。
    模型被牽著鼻子走 -> 樣本少的類型容易分不好 -> 分類精準度就會遇到瓶頸。
    像是 Modelnet40 就有這種問題。

    所以 Alpha 是一個 Vector ,把 Alpha 乘回原本該進去 CE 的分佈機率表,
    便可以用來來平衡樣本少與樣本多的類別。
    (個人是使用 總樣本數 / 該類別樣本數,作為該類別的 Alpha t 值)


    (但是如果你在一些優秀的公家機構,
        他們會花整整兩個月找工讀生,並用人工增加樣本少的樣本數,
        以達到 Data balanced這種工人智慧實在是讓我嘆為觀止。
        所以說數學很重要對吧?
         PS. 我絕對沒有說花試所會這麼做。)




    • Gamma


    Gamma 就比較難解釋了,
    首先假設分類網路分對且高信心(i.e. 好分類樣本)的情況下
      ( assume y = 1 , p = 0.8 , gamma = 1):


    原始的 CE 給出的 Loss 會是: -log(p) ~ 0.096
    改進後的 FL 給出的 Loss 會是: (-1) * (1-p)^gamma * log(p) ~ 0.019


    而在分類網路分對且低信心度(i.e. 難分類樣本)的情況下
      ( assume y = 1 , p = 0.2 , gamma = 1 )
    原始的 CE 給出的 Loss 會是: -log(p) ~ 0.698
    改進後的 FL 給出的 Loss 會是: (-1) * (1-p)^gamma * log(p) ~ 0.559

    在高信心度分類正確情況下,FL 的 Loss 會更低,
    在低信心度分類正確情況下,FL 的 Loss 會更低,
    這代表 FL 比 CE 更好對嗎?

    如果妳到目前為止覺得我說的超對!
    身高又超過 160、長髮過肩,麻煩聯絡我: wuyiulin@gmail.com

    無論在哪個城市,我總是知道哪間牛排館最好吃。
    只差一位無條件支持我的另一半!



    分類網路分錯且低信心度(i.e. 難分類樣本)的情況下
      ( assume y = 1 , p = 0.2 , gamma = 1 )
    原始的 CE 給出的 Loss 會是: -log(p) ~ 0.698
    改進後的 FL 給出的 Loss 會是: (-1) * (1-p)^gamma * log(p) ~ 0.559

    哇靠,怎麼 FL 給出的 Loss 比較低?
    難分類的就算了,如果好分類的分錯怎麼辦?
    分類網路分錯且高信心度(i.e. 好分類樣本)的情況下
      ( assume y = 1 , p = 0.8 , gamma = 1 )
    原始的 CE 給出的 Loss 會是: -log(p) ~ 0.096
    改進後的 FL 給出的 Loss 會是: (-1) * (1-p)^gamma * log(p) ~ 0.019

    將近四倍的 Loss 值,超級優秀。


    原論文中 gamma 值是 Hyperparameter
    參照下所畫的曲線。 



    結論:

    個人覺得 FL 的 Gamma 部分比較適合在精確度已經 push 到很極端的模型。
    但是 Alpha vector 看起來倒是通用沒問題。


    如果本篇數學部分推導有任何錯誤,
    歡迎聯絡:wuyiulin@gmail.com




    References







  • [論文筆記] 三維點雲的 Transformer 方法 Spatial Transformer for 3D Point Clouds

     

    前幾天 meeting 被老師單獨叫過去說:

    "黑武士,你知道你這學期要畢業對吧?"


    於是乎,為了早點把論文生出來(#)最近看了比較多論文,

    其中一個很感興趣的是 3D Spatial Transformer  方法。

    這個方法有部分 depened on 2D Spatial Transformer ,

    至於 2D Spatial Transformer,李弘毅大師講得很清楚,

    我就不多贅述了。

    李弘毅老師 – Spatial Transformer Layer

    借用一下 2D Spatial Transformer 的架構圖:

    Spatial Transformer 架構圖

    原本 2D Spatial Transformer 的 Localisation Net 等於 Affine ,

    但是因為 3D 嘛,多了一個維度,而且抓特徵的方法不同,就用需要新增兩個方法處理。

    首先我們要知道三維任務裡面,我們是拿什麼樣的資料來做處理?

    這篇文章以 DGCNN 為主幹,DGCNN 抓特徵的方法就是先假設一張圖有 N 個點。

    N 個點裡面,每個點都去做 KNN,假設 K值設為 20,

    最後我們就是拿 N*20 個最近鄰居點的三維座標當作特徵,進入網路處理。

    KNN 示意圖

    知道了要處理的資料長什麼樣子,那就分別來看看 3D Spatial Transformer 的三種方法。

    • Affine & Projective Transformations

    這兩個合在一起講,因為相當於 2D Spatial Transformer 的 Affine 功能,

    包含 旋轉、縮放、位移,其中 Projective Transformations 是專門處理位移問題。


    讓 R 矩陣 代表 Affine , T 矩陣 代表 Projective ,

    這兩個矩陣合起來就會變成 M 矩陣,能夠一次處理旋轉、縮放、位移


    M矩陣一次處理 旋轉、縮放、位移。

    • Projective Transformations


    講到這裡一定又很多人會問了,問我怎麼知道每次投影都會把位移量投回來?

    論文明明寫共扼到高次方維度,所以怎樣怎樣才會一樣。

    黑武士你又在搞,到底在說什麼?

    很簡單,四維的世界人類無法想像,那就用三維投二維來舉例:

    假設在三維空間中恆有一 av 向量,

    我們希望這組猴死囝仔 av 向量在 xy 平面上恆有一點 xy 座標代表,

    這樣我們就知道不管這條 av 向量怎麼跑,我們都有方法辨別。

    (口裡面一個子 = ㄐㄧㄢˇ,不用謝了。)

    這還只是一條向量,如果很多個向量平行,是不是就能在 xy 平面上投出一個圖案?

    再加上我們前面有辦法處理 3D 圖片 的旋轉,

    是不是一定程度上能在三維空間得到旋轉與平移的容許值?

    讓機器更好辨別哪些 3D 圖片 是一樣的?

    • Deformable Transformations

    這邊論文講了一堆說什麼最重要的、可以改變 3D 圖片外觀的,

    簡單來說只做了兩件事情:

    1. 融合前後層特徵(第一層為原始三維座標)。
    2. 把融合後的特徵做成 C向量 往下傳播。

    原文寫得不是很好,
    前面黑色C代表上一層傳遞來的向量,後面紅色C代表往下傳的向量,
    兩者是不同內容,避免混淆我就用顏色區分。


    以上就是我對於 Spatial Transformer for 3D Point Clouds  的論文理解,

    如果大家有不同理解,歡迎底下留言讓我知道。

  • OpenCV AI Kit 1 (OAK-1)從零開始的傻瓜式教學

     

    起因是因為主管塞了兩盒工程機包裝的東西給我,

    叫我趕快做點東西出來。

    :大勾請問這兩盒是什麼?

    "窩也不是很清楚,應該是攝影機吧?"

    "上禮拜才送來的,就交給你好好幹了!(瞇眼。"

    回到座位拆開包裝,奇妙的字眼映入眼簾 – OAK-1?橡樹一號?

    乖乖隆叮咚?

    我的業務範圍上從先進飛彈制導,下至林業技術輔導了嗎?

    看來下一任臺灣隊長就是我了對吧?

    現在應該抓緊時間去曬太陽之類的?

    Anyway 這的確是攝影機,不是什麼先進的橡樹、農業技術輔導。

    OAK-1 的全名是 OpneCV AI Kit

    會出現這東西,我猜是 OpenCV 覺得大家用的環境太混帳了,

    導致沒辦法發揮我們程式的實力,所以自己跳出來賣攝影機的概念。

    (我看過學弟拿沒 GPU 的文書機配 WEBCAM 在那邊掃口罩偵測,FPS 著實感人。)

    做影像辨識是這個樣子:

    影像辨識是需要算的,就算你模型都訓練好,

    還是要有一個地方可以判斷(計算),像是我學弟那個例子就是把影像丟回電腦用 CPU 算,

    結果就是出來的影像 FPS 感人。

    這麼感人的 FPS 肯定是不行的,畢竟未來要用在載具上,

    任務時間來到毫秒級,FPS 必須提高,下游任務的準確度才會提高。

    (才不會上演街頭人肉保齡球。)

    但是 OpenCV 左想右想,總不可能在每臺載具上面塞一張很貴的 GPU 對吧?

    為了教育我們這些只用 CPU 算的弱智兒童(X)

    為了讓貪財產業鏈侵入學生生活(O)

    (OpenCV 後面是 Intel,Intel 最近重新出了自己的 GPU 你知道的。)

    就出了 OAK 系列,裡面幫你塞了一張 VPU。

    VPU 是一種介於 CPU 與 GPU 中的東西,

    可以想像成沒那麼強的 GPU ,但是可以負責簡單的判斷。

    總之有這張 VPU 塞進去以後捏,好處有兩個:

    1.後端(伺服器端)可以不用塞 GPU,這種 Camera 又比 GPU 便宜很多,省錢!

    2.判斷直接在 Camera 直接做完,理論上比較省傳輸的 latency。

    好,前面廢話那麼多,來裝環境。

    首先這篇環境是 for Windows 10 ,因為我在公司被分配到 Windows 10 的機子,

    順便做個紀錄,聽起來以後要交報告的,多塞點廢話(X)。

    首先用管理員權限打開你的 Windows Shell (藍底白字的那個)

    Windows Shell

    Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
    

    如果你沒有喜歡的編輯器 加上 還沒有安裝 Python 

    就下這行,幫你裝 PyCharm + Python-least:

    choco install cmake git python pycharm-community -y
    

    然後你可能會發現阿幹怎麼 GIT 裝失敗?

    下這行:

    winget install --id Git.Git -e --source winget

    然後就裝起來了,一整個正確!

    去載這包:

    https://github.com/luxonis/depthai-python

    啟動 example/Yolo/tiny_yolo.py

    偵測結果

    好欸!

    你也可以說自己會偵測物件了(ㄍ。

    之後應該會做其他東西吧?(望天。

    Ref. 

    官網教學:https://docs.luxonis.com/projects/api/en/latest/install/#installation

    輔助影片教學:https://www.youtube.com/watch?v=ekopKJfcWiE&ab_channel=BrandonGilles

  • [論文筆記]POINTVIEW-GCN SOTA of ModelNet40 導讀

     

    沒錯又是我,實驗是越來越好了。

    總之學弟講了一個 ModelNet40 有人 Classfication 的 Overall ACC 做到 95%,

    所以大頭很開心地要我去 Survey 一下前幾名的方法來做。

    目前第一名的方法就是這款 POINTVIEW-GCN,拿多視角的方法來分類。

    主架構有兩個亮點:

    1. NonLocal, Local 的 Skip connection:

    簡單來說就是每層神經網路分成兩路輸出, Local 會直接進 Skip connection 後 Concat 到最後一層;

    NonLacl 放進下一層繼續轉。

    2. Selective View-Sampling(SVS):

    從多視圖裡面找最好的那張,再傳下去。

    個人認為是簡單的資料增強。

    這個架構是怎麼更新參數呢?

    首先我們知道這個架構有四個視圖(G),每個的後綴是 j 。

    先來看 Local Conv 的部分,

    在每個視圖裡面的特徵為:

    L為 ReLU 函數。

    A是與鄰居關係的矩陣(抓特徵的意思,視為 KNN 結果。)

    右側的Fj 應該是誤植,應該是表上一層 F(j-1) 的意思。

    W,alpha 是訓練來的權重參數、矩陣。

     完成 Local Conv 的 Fj 會送進 Skip connection 到最後一層。

    有 Local 當然有 NonLocal 啊!

    那 NonLocal 是 Non 在哪裡?

    NonLocal Conv 其實就是多了一個更新比較遠節點的部分,

    (因為 Local Conv 做了一次 KNN,

     而 NonLocal Conv 的 input 是 Local Conv 的 output,

     這兩個的 Conv 其實有前後的關係。)

    論文裡面利用 message 函數 來做這件事情。

    j 是 G視圖 的層級,i,p 是 node 的編號(F有 N 個 node,i & p 屬於 N。)

    這樣應該比較好理解。

    最後那個 R(.) A.K.A 相關函數,我一直看不太懂,

    總之在程式碼裡面是長這樣的,首先 input 是一顆尺寸 (X,Y,Z) 的 Feature:

    R(.)

    有行 參數 20 的,是用 repeat 做出來的。

    所以我們用 R(.)得到 message 函數 的結果 = Feature M。

    最後利用 M 來更新參數:

    實際上就是 concat 起來。 

    經過 R(.)還有 C(.),據論文所說是要更新參數啦,

    寫得有模有樣,但是很懷疑單純 concat 起來是要更新什麼參數?

    或許進到下一層 Conv 可以利用這些資訊?

    加上這篇只有給出 Overall 的 數據(做最好的那次數據,不是平均。),

    這邊我打個大大的問號。

    以上,大概是這篇的簡介。

    我對於這篇貢獻的理解是讓最後的 Feature 保留粗的特徵(因為只抓附近鄰居+少層 Conv),

    越後面的 G 視圖 特徵越抓越遠、越細。

    與我手上這篇 DGCNN 的做法最大的區別應該是少了每層 KNN + 多視圖的 SVS。

    Skip connection it’s worked for me.

    附上論文連結:https://ieeexplore.ieee.org/document/9506426

    與 GIthub Repo:https://github.com/SMohammadi89/PointView-GCN

    以上

  • TelegramBot :花十分鐘開發聊天機器人,多執行十小時的程式!(Python)

     

    身為一個工科的研究生,你是否也有以下的困擾:

    "總是搶不到實驗室機器"、"擔心這個禮拜的實驗做得不夠多"、"睡前忘記收數據,導致下的實驗比別人少?"

    沒問題,你遇到的情況我通通都有遇過!

    筆者本人是心血來潮就會從臺中出發去花東吃早餐的放浪少年(#。

    但是週六日還要下實驗,那該怎麼辦?

    近期又要面臨暑期工作壓力,實驗進度更是要顧,

    所以產出了這篇文章。

    這篇文章能幫助你什麼?

    在 Python 程式跑完的時候,發 Telegram 訊息通知你。

    OK,讓我們開始吧。

    首先先安裝一下本文所使用的套件:

    pip3 install telegram
    pip3 install python-telegram-bot

    移到你目前想提醒 Python 程式的目錄底下

    cd ~/your_Python_program

     

    建立 Telegram 機器人的主程式(或是從這裡下載我寫好的)

    touch TelegramBot.py

    寫檔,接著複製貼上就可以了。

    vim TelegramBot.py
    import os
    import sys
    import re
    import configparser
    import telegram.ext
    import requests
    import time
    
    
    import logging
    
    from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
    
    # Enable logging
    logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                        level=logging.INFO)
    
    logger = logging.getLogger(__name__)
    # Initial bot by Telegram access token
    
    config = configparser.ConfigParser()
    config.read('config.ini')
    
    
    def start(update, context):
        """Send a message when the command /start is issued."""
        update.message.reply_text('Hi!')
    
    def echo(update, context):
        """Echo the user message."""
        update.message.reply_text(update.message.text)
    
    def help(update, context):
        """Send a message when the command /help is issued."""
        update.message.reply_text('Help!')
    
    def getUID(update, context):
        update.message.reply_text(update['message']['chat']['id'])
        print(update['message']['chat']['id'])
    
    def Alert():
        TOKEN = config.get('Bot','ACCESS_TOKEN')
        UID = config.get('Bot','UID')
        updater = Updater(token=TOKEN, use_context=True)
        dp = updater.dispatcher
        text ='實驗跑完啦!快上來收數據!'
        dp.bot.send_message(chat_id=UID, text=text) # 發送訊息
    
    
    def error(update, context):
        """Log Errors caused by Updates."""
        logger.warning('Update "%s" caused error "%s"', update, context.error)
    
    def main():
        
        TOKEN = config.get('Bot','ACCESS_TOKEN')
        UID = config.get('Bot','UID')
        updater = Updater(token=TOKEN, use_context=True)
        dp = updater.dispatcher
        dp.add_handler(CommandHandler("start", start))
        dp.add_handler(CommandHandler("help", help))
        dp.add_handler(CommandHandler("Alert", Alert))
        dp.add_handler(CommandHandler("getUID", getUID))
        dp.add_handler(MessageHandler(Filters.text, echo))
        updater.start_polling()
        updater.idle()
    
    if __name__ == '__main__':
        main()
    
    (然後向 BotFather 申請自己的機器人並拿到 Token,這部分可以看別的大大寫的這篇。)
    在同目錄底下建立 config.ini

    touch config.ini
    寫 config.ini
    vim config.ini

    把 your_token 換成你剛剛拿到的 TOKEN,
    UID 待會再教你拿:

    [Bot]
    ACCESS_TOKEN = your_token
    UID = your_uid

     

    填完之後,好沒問題來!
    我們來拿 UID!
    把這支程式跑起來:

    python TelegramBot
    如果一切沒問題,你的終端機會顯示:
    apscheduler.scheduler – INFO – Scheduler started
    再開 Telegram 到你與這隻機器人的對話框,輸入:

    /getUID

    這樣在 Telegram 對話框 及 終端機應該都會把你的 UID 噴出來,

    把 UID 回填到 config.ini 裡面去。
    然後把這支程式關掉(Ctrl-C)
    在你想監聽的 Python 程式最上面加入:

    from TelegramBot import Alert
    程式執行完處加入:

    Alert()
    把機器人跑起來,把你想監聽的程式也跑起來。
    當程式執行完時便會出現:

    已解決!

  • 費波納契數列的最佳計算複雜度 O(logn) 實現及推導(fibonacci sequence in cpp)

    因為最近在解 Leetcode 的 91. Decode Ways


    要用到 Fibonacci sequence 來解,就我所知上次解 70Climbing Stairs 的時候,
    用 recursive 求解 Fibonacci sequence 的時候會 TLE。
    (所以我就偷懶跑去用 Python3 解大數)


    這次再遇到應該是要進步了xDDD


    正文開始:

    Fibonacci sequence 會長這個樣子:



    根據基本定義,第 N 個 Fibonacci value 等於前兩個 Fibonacci value 相加,
    我們便可以得到公式:



    得到公式以後把它擴展成 轉移矩陣 M 的形式,
    因為我們把前兩項當作初始值,所以 轉移矩陣 M 的指數會減二:



    所以我們現在只要計算 M 的 (n-2) 次方就能得到第 N 個 Fibonacci value。
    (左上角的 M00 會等於 第N個 Fibonacci value

    此時的計算複雜度為:O(n)

    以第 45 個 value 值來比較,此方法已經比遞迴快很多了xD




    但是我還要教你一個威力加強版外掛:平方求冪
    (左岸又稱快速冪 or double-and-add


    我們在這裡要用平方求冪去優化轉移矩陣 M。


    平方求冪的想法是把任何高階指數都化為與指數二有關的指數和,
    屁話一堆直接看數學比較快:


    如果你說 n 是 odd 怎麼辦?
    啊不簡單?直接減一再乘回去R~:




    這樣的好處是能大大的減少計算量,數學意義上來說是二分搜尋法,
    以找 n = 16 舉例,

    沒有平方求冪的版本會很老實地計算十五次乘法,
    而有平方求冪外掛的版本會跳著算:



    像是圖中有幾個節點,就計算幾次,
    每次都是跟自己相乘,所以實際上只要算黃色螢光筆那條路徑,
    不必考慮其他條黑色路徑。

    由此可以 16 = 2^4,所以有 4 個節點,只需計算 4次。
    此時又可推導出 計算複雜度為:O(logn)
    (log 以 2 為底。)


    用 C++ 實現的程式碼我放在這裡


    有興趣的可以直接拿來用,不用再造車輪了xD

    感謝各位

  • [論文筆記] Point2SpatialCapsule 看完這篇就入門 CapsuleNet!

     

    最近要提升手上模型分類的準確度,

    所以在讀各種各樣的論文(#

    這篇主要發想來自 Geoffrey E. Hinton 大師覺得 BP 根本太荒謬了,

    人腦不會有 BP 這種架構,他想把神經網路更優化、更趨近於人腦所做的 Capsule 計畫。

    (避免誤會,這篇是左岸同胞的延伸論文,並不是 Geoffrey E. Hinton 大師手筆。

    CapsuleNet 架構最主要想解決的問題是:

    1.傳統 CNN 需要大量資料學習

    2.提升 Permutation invariance

    (廢話xD 一堆論文都在做這東西)

    這篇論文與 CapsuleNet 架構最大的不同就是:

    把空間特徵塞進去膠囊裡面

    簡單用一張圖解釋:

    人腦辨識左邊是R的過程是把圖型旋轉過來,但是 CNN 是需要看過很多不同狀態的R。

    像是轉了30度、60度、90度 的 R 都拿下去訓練,最後把這些結果分給 R 這個 Label,

    CNN 才知道:噢?這個是R?

    大師覺得要解決這種問題,就要從圖型的內部結構下手。

    像是人臉的眼睛會在鼻子的上面、鼻子在嘴巴的上面、嘴巴會在下巴的上面。

    只要獲得這一連串的內部對應關係,神經網路就不用每個角度再造一次車輪。

    這篇怎麼做的?



    Geometric Feature Aggregation

    Multi-Scale Local Feature Extraction

    首先用 GMM (Gaussian Mixture Model – Free Mind) + MSG (Multi-Scale Grouping)

    抓相鄰點特徵。

    作者說因為計算量會比較小所以用 GMM 而不是 K-Means。

    這點我認為是完全唬爛,

    GMM的計算量、變數量都比 K-Means 要來得大。


    經過 MSG抓特徵的影響

    經過 MSG 抓特徵後會有特徵太相似的困擾,

    設想一個狀況,上圖是 MSG 抓兩層特徵 ( K=2 )  的狀況下的圖示。

    外面那圈重疊的面積比裡面那圈大很多,對吧?

    面積在這裡可以換成機率,所以對於相鄰點來說:

    外面那圈的大尺度抓到的特徵有很大的機率會很像。

    Multi-Scale Shuffling

    洗牌!(T代表抓取的尺度,C代表通道維度)

    所以我們做一個洗牌的動作(文字癌),把大小尺度的特徵混在一起增強特徵。

    Spatial Relationship Aggregation

    Rearrange and Squashing

    其中 C(qk) 代表 xyz 軸輸入、 C(yk) 代表 MLP 過後的 高維度特徵。
    C(Sk) 僅代表 C(qk) 與 C(yk)  concat 起來,也是本篇最大的改進
    ui是 C(Sk) 經過全連接層做出來的東西,論文用 256個 輸出的全連接層做。
    物理意義上ui代表每個不同的特徵(顏色、深度、方向…等)。
    以下詳細解說膠囊如何運作:

    我們要知道 CapsuleNet 架構裡面,
    每個特徵點被觸發的方式是由底層的膠囊一層一層傳播上去。

    至於為什麼膠囊架構會長成這樣,這篇講得很好,我就不多贅述了。
    fixation point 的部分
    首先從第 i 層抓一個膠囊啟動,輸出向量為 Ui。
    這個 Ui 會乘上權重矩陣 變成預測的 hat Uij,
    hat Uij 的物理意義是估計 Uj 這顆膠囊的輸出向量來說 Ui 輸出向量的比重。

    然後乘上耦合函數 Cij 後用 squashing函數 做真實輸出 -> 這顆膠囊的真實輸出 Vj
    乘上耦合函數 Cij 的物理意義是當 Ui 這顆膠囊對於 Uj 貢獻巨大時,
    Cij 會趨近於一(或等於一),Uj 的參數會全部灌給 Uj 去做輸出。
    很巧妙的一個設計。

    CapsuleNet 系列都有一個 squashing 函式,
    這邊給出的解釋是 Geoffrey E. Hinton 大師 希望膠囊的長度(本篇膠囊=ui)能夠代表機率,
    長度越長的膠囊長度越要趨近於一、長度越短的膠囊長度要趨近於零。

    所以這個函數會把每個向量(膠囊)長度正規化,
    圖形會長這樣:

    X軸代表原向量長度、Y軸代表經過函數轉換後乘上的乘積。


    這邊的長度要用 Two-norm 帶入,否則會證不出來。

    然後特別要注意的一點是這裡的 squashing 只會在 Vj 做一次,
    第一行 squashing 的函式與 第三行的 Ui 沒有半點毛線關係。
    這篇看很久都看不透,一部分是因為數學符號混用,
    強烈建議這篇方程式要跟原版論文對照著看。
    (嚴重懷疑變數會長這麼醜,是為了規避論文重疊性比對。)

    後面的 bij 就是迭代真實輸出與估計去更新 Cij 而已。