RAG 小註解

Rag 聽起來就像一塊破布. 但是在 AI 領域還滿紅的! 不同於普通的破布, 這個 RAG 是 Retrieval Augmented Generation 的縮寫. 看 keyword 就知道包括檢索 – 增強 – 生成. 整個功能的目標還是做生成式 (generative) AI.

那麼和普通的 LLM 差在哪裡呢? 普通的 LLM 學習了大量的知識, 但是可能有些專業領域沒學到, 或是還可以加強, 這時候就會用 RAG.

首先我們要把這些 “新知" 進行編碼, 在自然語言處理當中會用到 Embedding 技術, 把普通的文字轉換成向量. 此處我們既然想依賴既有的 LLM model, 當然我們要把我們新知和 LLM 的習知, mapping 到同一個空間去! 此時就用到了增強 ( augmented ) 這部分.

Step 1: 找到 Embedding 模型

from sentence_transformers import SentenceTransformer
encoder = SentenceTransformer('一個 EMBEDDING 模型')

Step 2: 為新知建立向量空間

這裡有個熱身的步驟, 先在 memory 當中產生一個 instance.

from qdrant_client import QdrantClient, models
qdrant = QdrantClient(":memory:")

接下來就可以設定新知的參數, 主要是 size 和 distance.

qdrant.recreate_collection(
    collection_name="新知的名稱",
    vectors_config=models.VectorParams(
        size=encoder.get_sentence_embedding_dimension(),
        distance=models.Distance.COSINE
    )
)

Step 3: 把新知的內容搬到向量空間.

其中 data 當然就是由 index (idx) 和 doc 組成.

qdrant.upload_records(
    collection_name="新知的名稱",
    records=[
        models.Record(
            id=idx,
            vector=encoder.encode(doc["新知的內容"]).tolist(),
            payload=doc
        ) for idx, doc in enumerate(data)
    ]
)

Step 4: 以文字在向量空間檢索 (retrieval) 得分最高的新知.

answer = qdrant.search(
    collection_name="新知",
    query_vector=encoder.encode("針對新知的問題").tolist(),
    limit=1 # 想要前幾高分的回答, 例如 1,3,5 
)

for ans in answer:
    print(ans.payload, "score:", ans.score)

由於這個新知的 database 知道的東西比較偏門, 它怎麼跟大語言模型共用呢? 答案就是把上述 RAG 的結果當作 LLM 的提示, 這樣 LLM 就會去 RAG 的輸出找答案.

Step 5: RAG 跟 LLM 互助合作

底下是叫 Copilot 寫的範例. 示意 RAG 的結果被 LLAMA2 拿去參考. 實用性不高, 但畢竟整合起來了.

search_results = [ans.payload for ans in answer] # 上面的新知

# Import necessary libraries
import os
import pinecone
from langchain.llms import Replicate
from langchain.vectorstores import Pinecone
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.chains import ConversationalRetrievalChain

# Set your API keys
os.environ['REPLICATE_API_TOKEN'] = "YOUR_REPLICATE_API_KEY"
pinecone.init(api_key='YOUR_PINECONE_API_KEY', environment='YOUR_PINECONE_ENVIRONMENT')

# Initialize Llama-2 components
replicate = Replicate()
pinecone_store = Pinecone()
text_splitter = CharacterTextSplitter()
embeddings = HuggingFaceEmbeddings()
retrieval_chain = ConversationalRetrievalChain()

# Example query from the user
user_query = "What are the health benefits of red wine?"

# Retrieve relevant information from search_results (assuming it contains relevant data)
relevant_data = search_results  # Replace with actual relevant data

# Process the user query
query_vector = embeddings.encode(text_splitter.split(user_query))

# Retrieve relevant responses using the retrieval chain
retrieved_responses = retrieval_chain.retrieve(query_vector, pinecone_store)

# Generate an answer based on the retrieved responses
answer = replicate.generate_answer(user_query, retrieved_responses, relevant_data)

print(f"Chatbot's response: {answer}")

用這個方法, 就不需要重 train 大語言模型, 也不影響 LLM 原本的實力. 但看官一定可以發現, 同一個問題必須分別或是依序丟給 RAG 和 LLM, 此時 RAG 才能產出東西給 LLM 當小抄 (in-context prompting). 這就是它的缺點.

使用 Vector Store 並非唯一的方式, 想要學習 WIKI, database, …. 都是可行的. 只要能把它變成 prompt 就可以改善 LLM 資訊不夠新 (knowledge cut off) 的幻覺 (Hallucination) 問題.

Give Myself a Pat on the Back

以前連假的時候, 我都會趁機讀完一兩本書. 不過這次我用它來完成我網課的最後一哩路. 這是一個 Coursera 的 AI TensorFlow Developer 學程, 裡面包括 4 個子課程.

Introduction to TensorFlow for Artificial Intelligence, Machine Learning, and Deep Learning
Convolutional Neural Networks in TensorFlow

Natural Language Processing in TensorFlow

Sequences, Time Series and Prediction

這個課程大概需要兩個月, 本來我想我好歹也算有個一知半解吧! 打算在免費試用七天的時間就把課程走完, 不過它還是有點難度, 所以我破功了. 只好為它花了註冊費. 接著我以生日前通過為目標, 失敗! 改為 2024/3/31 前通過, 又失敗! 總算在清明連假最後一天通過最後一個 Lab 了! 花了快一個月之久.

model = tf.keras.models.Sequential([ 
    tf.keras.layers.Conv1D(64, input_shape = [64, 1], kernel_size = 3, padding = 'causal', activation = "relu"),
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32,return_sequences = True)),
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32)),
    tf.keras.layers.Dense(32, activation = "relu"),
    tf.keras.layers.Dense(16, activation = "relu"),
    tf.keras.layers.Dense(1),
    tf.keras.layers.Lambda(lambda x: x* 25)
]) 
model.compile(loss= tf.keras.losses.Huber(),
optimizer=tf.keras.optimizers.SGD(momentum = 0.9, learning_rate = 5e-4),
metrics=["mae"])

最後一堂課的結語是 give yourself a pat on the back. 所以我就拿它來當標題. 接下來找下一個可以學的東西.

生成式 AI 大材小用記

原本聽說三星的 S24 應該有很厲害的 AI, 結果玩了一天看不出任何不同的地方?? 假如我沒有買到假貨的話, 應該就是我不會用!!

上網找了一篇比較新的評測, 終於知道有哪些功能可以用了. 但所有特異功能幾乎都是預設關閉. 難怪我覺得跟掛掉的 S20 用起來幾乎沒差別.

在即時翻譯的部分, 要進到設定 –> 進階功能 –> 進階智慧工具, 然後把電話、三星鍵盤、翻譯助理一一打開. 翻譯還要下載語言包, 小包的越南文、泰文需要 300 MB 上下, 大包的中英日韓接近 450MB. 這些都要個別下載. 測試起來雖然有時會認錯, 不過我覺得還堪用, 這樣就不用買科大訊飛翻譯機了.

至於那個圈圖搜尋, 首先 APP 要相容. 初步試過 Chrome, Disney+ 不行, Netflix 可以操作但會隱藏掉 video, 只留 OSD. 而 Facebook 和 YouTube 可以. 另外, 不是想畫圈就畫圈, 我試了一下要先按 Android 底部的那個圓圈圈 home icon, 接下來才能圈或是框要搜尋的對象. 初步測試效果沒有很好. 不過以圖找圖大概就是那種程度.

在照片的部分, 生成式照片要先在照片編輯時, 選編輯 (一隻筆的 icon), 再按花花的藍底三星 icon, 才會進入生成功能頁面.

用手寫筆歪七扭八地把水管框住, 它就會自己貼到物件的輪廓上.

被框住的物件可以移動或是消除. 我選消除. 水管就拿掉了. 當然會有一點痕跡在. 被蓋掉的英文字也還拚不出來, 但以後進版應該有機會.

另外一個樣本是今年的尾牙, 當我們吃到甜湯的時候, 桌上已經一堆雜物了. 畢竟沒發垃圾桶, 座位又擠, 總不能塞到隔壁同仁那邊. 所以拍起來是這樣.

靠著 AI 生成技術, 衛生紙拿走了. 灑出來的湯汁也清掉了, 質感好了很多! 唉, 我真是讓它完全大材小用啊.

AI 學習小筆記

前陣子發現, 網路上不只是有很多學習資源, 而且好幾個單位都證書. 雖然這些證書把關通常很鬆散, 但是用來記錄自己學了什麼就很有幫助. 換個角度看, 畢竟我們不是被逼著上課, 已經知道的或重複的就可以跳過. 而不是像在學校裡, 不能因為聽懂就翹課或是不參加考試, 那就畢不了業了.

如果說 AI 有哪個東西要先學習, 我看起來還是 Python. 然後搭配自己的專業領域使用. 像是 audio, video, image, 或者是我以前用在 OCR. 新手可以學 Python 的地方超級多, 入門也非常簡單. 所以這應該是正確的第一步無誤. 再來介紹一下錯誤的第一步.

有些人, 像是我, 從小就對人腦很有興趣. 總是會想要用人腦的特性來做出更厲害的 AI. 比方說, 有一天我想到遺忘也是人的特性, 如果讓神經網路可以遺忘, 不就是一大突破了! 哇哈哈哈…不過我很快就發現 LSTM (Long Short-Term Memory) 已經有這招了! 我又想到, 意義相似的字應該用向量表示遠近比較好! 再一查, word embedding 已經有向量觀念….嗯, 我想得到人家也想得到.

我記錄 idea 的 Onenote 筆記

所以專家幾乎都不推薦用人腦去設計 NN. 頂多是在投影片裡, 從生醫角度切入, 使人覺得更高大上 (e.g. BERT 用上 DNA 雙螺旋來講解). 除非你就是要複製人腦, 不在乎它到底能不能實用 (make money)! 至於聽起來就沒有商機則是例外. 像是 hypothalamic-pituitary-adrenal axis [6] 和 AI 的關係就只限於  Adrenal Insufficiency (腎上腺機能不全), 表示未來讓 AI 談戀愛這個領域還有發展空間.

言歸正傳. 有了語言, 接下來要找環境. 以前我傻傻地自己開 Jupyter Notebook, 後來發現 Google Colabatory 就能直接用了. 除非需要很大的算力時, 才需要用到自己 PC 的顯卡. 若只是要練習 Python, 學 AI, 直接註冊一個免費的 Colab 帳號即可, 而且很多 Google 的網路資源都可以直接調用. 不用到處找. Colab 不開 GPU/TPU 時, 預設在 no power 等級. 設定裡面可以選柯基犬、貓咪、螃蟹模式, 我還以為有什麼差別, 原來是小動物跑來跑去~~

接下來, 我認為值得按讚是 CNN. 因為除了 CNN, 很多背景知識都跟我 30 年前學的差不多. (當然我那個時候講到 CNN, 一定是先想到 Concurrent 開頭的 CNN, 不是現在 Convolution 開頭的這個 CNN). 會強調 CNN, 主要是 CNN + DNN (deep learning) 把特徵值和絕對位置脫鉤了. 這個真的很厲害.

新 model 可以留給博士們研究, 要實做就需要學 framework. Google 主推的 tensorflow [3] 有許多教學網站. 除了 Youtube 上非常多老師在教. FreeCodeCamp [2] 也 “免費" 教很多技術, 他們在介紹 AI 相關技術時也會用到 tensorflow + Colab, 我覺得挺不錯. 其中, 講解的小哥可以快速講一些基本觀念. 當然他們沒辦法一行一行 trace code, 或是把細節講得很清楚. 講師帶我們瀏覽完大概, 細節就要自己花時間看, 最好是 Colab 開起來模擬一遍.

在 Youtube 也可以找到 FreeCodeCamp 小哥 Tim 的 7 小時學 tensorflow. 然而, 連復仇者終局之戰都沒演那麼久了, 誰能一口氣看得完這個? 所幸在 FreeCodeCamp 上, 這個影片會被分成大約每 15 分鐘一段的短片, 每個短片後面還有一個小測驗, 算是滿貼心的設計. 這樣就不需要太考驗耐心.

然而, FreeCodeCamp 不是 Google 這種大戶, 所以它需要大家自願 donate 才活得下去 (5 USD 起跳, 每個月捐 20 USD 可以讓其他人學習 1 千小時.). 畢竟 lib 或是 tool 會過時, 隔一陣子確實該更新或 debug. 像是 tensorflow 小哥影片中的 sklearn 已經可以改用新版的 scikit-learn, 或者講 DNN 的老哥在 7’51″ 這個地方線的顏色有些不對, 按圖 negative * negative 應該是 positive, 後續影片播到 10’10″ 左右這兩條線才更正為 positive. 總之, 他們值得贊助, 也需要贊助.

至於要學另一個主流 framework 是 Pytorch, 教學影片除了 Youtube, 就只找到 Microsoft [4]. Pytorch 當初是 Meta 推的, 不過 Meta 好像跟 Google, Microsoft (OpenAI) 的發展沒得比. 但是看在開源 llama2 的份上, 我對 Meta 感激不盡, 也原諒它一直偷聽我講話.

基於我們不會大改 model, 用 LoRA (Low-Rank Adaptation) [5] 可以小改. LoRA 訴求主要是在某幾層針對特定目標減少計算. 更小的修改是直接在既有模型後面再加一層 (或許幾層也是可以), 把原本的結果從新詮釋. FreeCodeCamp 的例子是從原本能分辨 10 種動物的模型, 改為只要能認貓或狗. 當然這沒省到計算量, 但是可以揀現成.

[REF]

  1. https://colab.research.google.com/
  2. https://www.freecodecamp.org/
  3. https://www.tensorflow.org/?hl=zh-tw
  4. https://learn.microsoft.com/zh-tw/shows/ai-show/pytorch-deep-dive
  5. https://d223302.github.io/AACL2022-Pretrain-Language-Model-Tutorial/lecture_material/AACL_2022_tutorial_PLMs.pdf
  6. https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3181830/

少即是多, 我是說 Mesh

原本家裡裝 100mb 的 VDSL 網路, 用起來也還算順手. 家中一度有網路死角的問題, 也都用 mesh 路由器搞定了. 不過中華電信一直來推銷光纖到府, 我同意安裝之後, 裝的人說他沒辦法拉到 4 樓, 把我勸退. 隔了幾年, 我自己也考慮升級了, 又是同一位師傅被派來安裝. 這次他戳了半天電話管線, 說連 1 樓也裝不了.

雖然我不記得他, 但是他依稀記得已經來過一次, 那應該就沒錯了. 在同一個地方跌倒兩次, 師傅也受不了. 沉默了一陣子厚, 他決定破釜沉舟, 用電話線拉光纖穿牆. 就這樣從傍晚弄到天黑, 我老婆拿手機當手電筒幫他在社區路邊照明, 我在房裡聽電話施力, 或拉或送或停, 這樣搞了半天才算打通到一樓.

終於升級 400mb 了! 不過中華電信送的那支全屋通, 幾乎沒辦法傳到 4F~~ 所以我只好把原本的 mesh 路由器搬出來. 第一版網路布局用 4 支 TP-Link deco M5, 我自己在 4F 沒甚麼訊號, 女兒也抱怨網路比以前差! 這下就有點糗了, 花了更多錢結果大家網路都變慢. 雖然一樓訊號變超好, 但沒有人表示感謝! 每當大家回房間訊號都變差, 導致民怨四起!!

我想說那個 mesh 已經停產了, 不如多買幾隻新的來彌補死角. 所以買了 3 隻新的 TP-Link deco X20, 這是第二個版本. 豬 (殊 O) 不知, 死角可能少了, 但是網路不但沒有改善, 路由器常常由綠燈轉成紅燈. 這個 7 路由器版本相當失敗! 因為我 4F 房間的網路太差了, 我試著用電力線橋接器從 1 樓直接拉到 4 樓, 結果如預期中沒訊號~~~

看到路由器經常是紅燈, 我以為它壞了. 於是再買 3 隻 X20 (這玩意兒一次就要買好幾隻), 淘汰掉一隻舊的, 家裡變成有 9 隻 mesh – 這是第三版. 已經裝到幾乎沒地方可以放了. 那訊號有變好嗎? 並沒有. 反而是網路常常重啟, 自動找路徑. 有時候路由器自己找的路徑和我想得一樣, 但有時卻是悲劇的星狀 – 所有路由器連回接 modem 的那隻, 或者明顯地把我的房間連到更長的路徑去~~~網速只剩下 1~3 Mbps 了.

有時候, 我們不是不夠, 而是太多. 不是搞不定, 而是偏離了正確的道路. 週六逛完商場, 難得走了一萬多步後領悟到這點, 回到家我就把網路改裝回最初的樣子. 光纖 modem 放一樓, 用老舊的 1800 Mbps 電力線橋接器連到二樓. 以此為起點, 只留 5 顆 AX1800 (mbps) 的 mesh, 其實 4 顆應該也可以, 懶得拆了. 用簡單的接法, 就把 4 樓的網速提升到 85 Mbps 以上. 下面是還沒調校完的第五版數據, 隨便都大勝以前水準. 現在我的備用路由器都足夠換一輪了, QQ!

結論: Mesh 很好用, 但路由器不要裝太多. WIFI 6 從 1 樓傳到 4 樓基本上做不到, 傳兩層樓差不多是極限 (下行 2.45 Mbps, 上行 8.34 Mbps). Mesh 搭配電力線橋接器是跨樓層布局的好選擇.

[2023/12/13 後記]

TP-link X20 舊版 (v1.0.7) 沒有指定訊號來的功能, 但 FW 升級到 v1.1.14 之後就可以自己安排哪個路由連哪個. 我發現自己排的還是比自動選得好, 速度還可以再提升一點.