[線上課程筆記]DeepLearningAI - Advanced Retrieval for AI with Chroma

image-20240108172844892

課程簡介

Deep Learning AI 新的課程,如何優化 IR/RAG on Chroma 。 講師是 Chroma co-founder 有以下三個技術:

  • Query Expansion: 透過相關概念來擴展查詢。
  • Cross-encoder reranking: 透過不同檢索編碼來排序查詢結果。
  • Training and utilizing Embedding Adapters: 透過加入 adapter 來優化檢索結果。

課程資訊: https://learn.deeplearning.ai/advanced-retrieval-for-ai/

RAG Pitfall

經常查詢 RAG 結果回來會是不相關的,怎麼看出來? 透過一個 umap 套件

import umap
import numpy as np
from tqdm import tqdm

embeddings = chroma_collection.get(include=['embeddings'])['embeddings']
umap_transform = umap.UMAP(random_state=0, transform_seed=0).fit(embeddings)


# 畫點出來
import matplotlib.pyplot as plt

plt.figure()
plt.scatter(projected_dataset_embeddings[:, 0], projected_dataset_embeddings[:, 1], s=10)
plt.gca().set_aspect('equal', 'datalim')
plt.title('Projected Embeddings')
plt.axis('off')

比較相近的問題(單一問題,比較容易)

image-20240108175808801

這樣看起來查詢的資訊跟我們問得蠻相近的,紅色是回答的。綠色是前面幾個相關的。

如果問句有兩個以上,或是問句本身就不太相關。

image-20240108180009118

這樣就會出現差相當多的結果,造成查詢的資料相關度過少。出來的結果當然也就很差。

解決方式就要靠接下來的三個方法。

Query Expansion

image-20240108194721737

透過延伸的假設答案,加上原來的問題。一起下去詢問:

def augment_query_generated(query, model="gpt-3.5-turbo"):
    messages = [
        {
            "role": "system",
            "content": "You are a helpful expert financial research assistant. Provide an example answer to the given question, that might be found in a document like an annual report. "
        },
        {"role": "user", "content": query}
    ] 

    response = openai_client.chat.completions.create(
        model=model,
        messages=messages,
    )
    content = response.choices[0].message.content
    return content

e.g.

  • Q: Was there significant turnover in the executive team?
  • 先用這個 Q 直接問 OpenAI 得到可能的解答 hypothetical_answer,但是因為沒有查詢特有 RAG 資料可能不會正確。
  • 透過 f"{original_query} {hypothetical_answer}" 結合再一起,再來透過 VectorDB 來尋找答案。
original_query = "Was there significant turnover in the executive team?"
hypothetical_answer = augment_query_generated(original_query)

joint_query = f"{original_query} {hypothetical_answer}"
print(word_wrap(joint_query))

Cross-encoder reranking

image-20240108173134289

透過不同問句,取得相似問句。透過該捷達來評分。這邊的作法如下:

  • 原本問句 original_query ,得到數個 generated_queries:
  • 然後把原本問句跟其他問句下去找數組的解答。
  • 將每一組解答,透過 scores = cross_encoder.predict(pairs) 評分來打分數。
  • 挑選出比較高分的幾個項目再來去 RAG
original_query = "What were the most important factors that contributed to increases in revenue?"
generated_queries = [
    "What were the major drivers of revenue growth?",
    "Were there any new product launches that contributed to the increase in revenue?",
    "Did any changes in pricing or promotions impact the revenue growth?",
    "What were the key market trends that facilitated the increase in revenue?",
    "Did any acquisitions or partnerships contribute to the revenue growth?"
]

queries = [original_query] + generated_queries

results = chroma_collection.query(query_texts=queries, n_results=10, include=['documents', 'embeddings'])
retrieved_documents = results['documents']

# Deduplicate the retrieved documents
unique_documents = set()
for documents in retrieved_documents:
    for document in documents:
        unique_documents.add(document)

unique_documents = list(unique_documents)

pairs = []
for doc in unique_documents:
    pairs.append([original_query, doc])
    
    
print("Scores:")
for score in scores:
    print(score)

Training and utilizing Embedding Adapters

image-20240108195535753

# 產生相關問句
def generate_queries(model="gpt-3.5-turbo"):
    messages = [
        {
            "role": "system",
            "content": "You are a helpful expert financial research assistant. You help users analyze financial statements to better understand companies. "
            "Suggest 10 to 15 short questions that are important to ask when analyzing an annual report. "
            "Do not output any compound questions (questions with multiple sentences or conjunctions)."
            "Output each question on a separate line divided by a newline."
        },
    ]

    response = openai_client.chat.completions.create(
        model=model,
        messages=messages,
    )
    content = response.choices[0].message.content
    content = content.split("\n")
    return content

產生相關答案

generated_queries = generate_queries()
for query in generated_queries:
    print(query)

透過 10 ~ 15 個問題,產生衍生的答案。約有 150 個。 這個就變成是新的資料集。(RAG)

透過新的相似度比較方式 (mse_loss):

def mse_loss(query_embedding, document_embedding, adaptor_matrix, label):
    return torch.nn.MSELoss()(model(query_embedding, document_embedding, adaptor_matrix), label)

透過這個方式,再來找出最好的解答。

image-20240108202350286

這張圖可以看出 adapted query 結果不容易產生不相關的答案。這邊也有建議,如果可以拿到使用者的資料來作為 adapted 問句,可能可以讓答案變得更好。

衍生思考:

  • 發現結果過於不相關的時候。
  • 透過多問幾題,然後找出相關答案。
  • 變成新的資料集,作為查詢。就可以優化整個 RAG 的資料集,進而得到更好的解答。

課程總結:

  • 先解釋 RAG 經常會遇到的陷阱。過於分散的問句,造成相似的解答不相關,回覆就會無法準確。
  • Expanding Query: 請 OpenAI 幫你多問幾題,然後把問題跟答案都放進去詢問。
  • Cross Re-Rank: 算是上面的進化版,透過產生問句的答案。透過一個評分機制。找到比較好的答案再下去 RAG 。
  • Embedding Adapter: 產生更多問句,透過問句產生的解答。當作是新的 dataset ,並且下來 RAG 。

更多參考:

[Golang][LINE Bot SDK] 如何更新 Golang LINE Bot SDK v8 OpenAPI(Swagger)

image-20240105183407936

前情提要:

2023 年 LINE Bot SDK 積極推動 OpenAPI (a.k.a. swagger) 的標準介面。透過與 OpenAPI 的整合, LINE Bot SDK 有了許多好處(文章後半段補充)。本篇文章將稍微解釋一下,OpenAPI 導入後的優點,並且帶著大家一起來將有使用 LINE Bot Go SDK v7 版本的升級到 v8 的版本。

本次的程式碼,會用前幾篇文章提到的: https://github.com/kkdai/linebot-gemini-pro 作為範例。

支援 OpenAPI 的好處

LINE Bot Go SDK 近期也在 2023/11 月也將版號更新到了 v8,並且正式支援 OpenAPI。 那麼簡單的來說,一個 SDK 套件支援 OpenAPI 有哪些好處呢?

1. 標準化的 API 設計

  • 許多 API 呼叫的方式,變得更加的直觀。也比較容易了解。後面也會稍微提到。

2. 程式碼自動生成

image-20240105200853423

  • 以往要開發新的 API Entry 的時候,都要透過發送 issue -> 發送 PR -> 審核 -> 發布後才能發送到開發者手中。
  • 但是導入後, LINE Bot SDK 使用的方式,是透過 Github Action 來自動去將最新的 LINE OPENAPI Repo抓下來後,根據新的變動產生相關的對應程式碼。 (參考上圖)(參考 Code Generator 產生的commit)

更多好處:

  • 自動化文件生成:有許多相關文件可以幫忙自動化產生 OpenAPI 的文件。

  • 客戶端與服務端驗證:透過 OpenAPI 的導入可以達成自動化測試與 Consumer-Driven Contract 的驗證。
  • API 生態系統工具的整合等等

開始 Migrate LINE Bot Go SDK from v7 to v8

先修改套件版本 v7 -> v8

先加入以下三個套件,接下來會解釋一下:

	"github.com/line/line-bot-sdk-go/v8/linebot"
	"github.com/line/line-bot-sdk-go/v8/linebot/messaging_api"
	"github.com/line/line-bot-sdk-go/v8/linebot/webhook"
  • linebot: 主要處理 v7 相關的內容,儘量不要使用。會逐步 deprecated 。
  • messaging_api : 發送訊息用。
  • webhook: 接受訊息與處理相關 event 用的。

接下來將慢慢整合,並且開始說明相關套件使用到的部分。

開始整合,並且說明相關變動之處:

“github.com/line/line-bot-sdk-go/v8/linebot/webhook”

  • 負責接受 Webhook 相關資料,裡面包括兩大系列:
  • MessageEvent 要處理相關訊息 Webhook 包括:
    • TextMessageContent: 文字訊息。
    • StickerMessageContent: 貼圖訊息 ..
    • ImageMessageContent: 圖片訊息,由使用者上傳的相片或是圖片訊息。
  • 其他相關 Event 處理,包括:
    • FollowEvent: 有新的好友。
    • PostbackEvent: 這個比較常用,就是透過 postback 將使用者選擇作為輸入。
    • BeaconEvent: 可以透過這個訊息來接受來自有登記過的 Beacon HWID 的訊息。
  • Webhook 處理方式也有點不同,細節稍微寫一下:
// 需要透過不同 Channel Secret 才能 Parse request 。
cb, err := webhook.ParseRequest(os.Getenv("ChannelSecret"), r)
	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	// 這邊比較類似以前方式,透過 callback 的 event 來 switch 個別 event type 。
	for _, event := range cb.Events {
		log.Printf("Got event %v", event)
		switch e := event.(type) {
		case webhook.MessageEvent:
			switch message := e.Message.(type) {
			// Handle only on text message
			case webhook.TextMessageContent:
			.......
  • 關於 UserId 與 RoomId 的取得方式:

    • 以前都是透過 source.RoomID 來取得,但是現在透過另外一種方式來處理。但是得要有特殊處理:
    if source.RoomID != "" //不是群組,可能是 1 on 1
    	....
    
    • 現在則是透過不同的方式,要透過 webhook.Source.(type) 來處理:
    // 取得用戶 ID ,個人覺得更加容易了解。
    var uID string
    switch source := e.Source.(type) {
    case webhook.UserSource:
      uID = source.UserId
    case webhook.GroupSource:
      uID = source.UserId
    case webhook.RoomSource:
      uID = source.UserId
    }
    

“github.com/line/line-bot-sdk-go/v8/linebot/messaging_api”

  • 這個是負責發送相關訊息或是 Event 給使用者的。也就是要發送任何訊息都要透過過這個套件。 這個套件將資料格式有切開來了:

    • messaging_api.MessagingApiAPI: 負責處理小量訊息,包括 text message, sticker message … 等等。
    • messaging_api.MessagingApiBlobAPI: Blob 負責處理比較大量的資料,比如說你需要抓取使用這上傳的圖片。
    • 這兩個都需要分開初始化,參考以下:
    	if err != nil {
    		log.Fatal(err)
    	}
      
    	blob, err = messaging_api.NewMessagingApiBlobAPI(channelToken)
    	if err != nil {
    		log.Fatal(err)
    	}
      
    
    • 如果要回覆一個訊息,變得更加容易了解:
    // v7: 需要先初始化之後,還要透過 Do() 才會執行
      
    if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(outStickerResult)).Do(); err != nil {
    	log.Print(err)
    }
      
    // v8: 可以直接呼叫
    if _, err := bot.ReplyMessage(
    		&messaging_api.ReplyMessageRequest{
    			ReplyToken: replyToken,
    			Messages: []messaging_api.MessageInterface{
    				&messaging_api.TextMessage{
    					Text: text,
    				},
    			},
    		},
    	); err != nil {
    		return err
    	}
    

總結:

Golang LINE Bot SDK 套件這一次除了升級到 OpenAPI 的版本之外,也對於許多呼叫方式與變數處理方式做了一個通盤的整理。在處理許多訊息上,變得更加直覺與異動。雖然要變動可能會比較多,並且還有一些 API 持續搬遷之中。 不過由於套件也還保持著 v7 的相關套件可以繼續使用 legacy API ,所以歡迎大家可以儘快開始整合到 v8 的版本。 這樣一來可以看到許多更新的 API 在第一時間就會釋放出來。

參考資料:

[Cloud Platform] 身為 AI (LLM) Engineer 關於雲平台的挑選 Heroku v.s. Render

image-20240104115649015

前情提要:

有在持續關注我的部落格的朋友,都知道我喜歡透過 Heroku 來快速部署我自己的雲服務 (或是 LINE Bot)。 當初 Heroku 就打著好上手,並且有免費方案的流程來讓許多開發者都有使用到。但是在 2022 十一月之後,就開始收費的 Heroku 也開啟許多人跑走的路途。這邊可以查看以下相關資料:

由於我手上的 Hobby Project 大概有 50~80 個,所以也就選擇先留在 Heroku 看看? (要搬移真的太累) 每個月五美金的費用,也算是中規中矩,畢竟也是某些程度吃到飽(1000 dyno hours) ,也足夠我用。

但是又聽到朋友們的提醒與鞭策,於是來認真看一下跟測試結果。

tl;dr 先講結論

  • Heroku ($5) 雖然沒有免費,但是共用的 Eco Dyno 其實後夠力。 Render ($7) 每一個要單獨收,有點貴。
  • 我會開始放一些到 Render $0 的方案,原因後提。
  • 兩個都部署跟發布,但是我還是會留在 Heroku ($5) (因為它是共用 1000 hours)

價位比較 (based: 2024/01/02)

Render 的價格跟性能: (free/Starter)

根據 Render vs Heroku by Render 有一些比較表:

image-20240104095253552

認真看了一下 Render 的費用

image-20240104095320382

  • 看起來 Free-tier 就有 512MB RAM,很不錯(但是要注意 CPU 0.15)
  • 但是要注意 Free Bandwidth 是 100GB ,這個感覺會踩到。

image-20240104095420088

  • 更別說有免費 90 天的 PostgresSQL 資料庫

image-20240104095506022

  • Redis 有 25MB 也夠用,但是會砍掉。

Heroku 的費用與效能部分

  • 沒有 Free-tier
  • 最低收費 Eco $5

根據 Heroku Dyno Types:

image-20240104095813909

  • 效能其實不比 $7 差太多(當然遠遠多於 Render Free-Tier)

image-20240104095917259

快速測試結果

拿了專案 https://github.com/kkdai/linebot-gemini-prohttps://github.com/kkdai/linebot-gemini-pro 來測試,發現:

  • 回覆速度上 Heroku ($5) 跟 Render ($0) 不會差太多。 (Golang App)
  • 但是上傳照片後,要處理 Render ($0) 就會炸掉。 由於記憶體兩者都是 512MB ,考量可能問題出在 CPU 上面。

交叉測試:

加上我另外一個小專案: https://github.com/kkdai/pdf_online_editor?tab=readme-ov-file

img

測試結果 Render ($0) 一樣會炸掉。

測試檔案 44.8MB PDF

Heroku ($5)

image-20240104121612188

Render ($0)

等太久失敗….

image-20240104121857862

付費後的測試 (\(\))

image-20240104122958983

  • 一樣沒反應……. (!!!)
  • 好吧! 悲劇了~~~ 做 RAG 的時候,需要大量的 CPU 這件事情。 Render ($7) 也不能滿足我的需求。

Render 是每一個專案收費, Heroku 是共用 1000 hours

  • 開了兩個專案,每個預計 $7 。總共預期被收 $12 。這就有點讓我吃驚。

image-20240104123423199image-20240104123424548

結論

雖然 Heroku ($5) 比起 Render ($7) 還要便宜,但是考量以下的部分,可能會開始同步開啟:

  • Render 有免費方案,更適合作為活動推廣之用。
  • Render ($7) 有 DB 可以使用,但是 Heroku ($5) 的資料庫要額外付錢。
  • Render ($7) 提供的管理頁面跟相關功能比較多。

但是… 因為 Heroku($5)(CPU) »» Render ($7) ,加上 Render ($7) 是每個專案都要收費。如果開的一多,可能會完全吃不消。

可能要多多考慮…

請推薦給我好用的雲服務

如果有其他好推薦的,請各位留言給我。我的需求如下:

  • 由於 Hobby Project 眾多 (30 ~ 50) 希望可以共用費用。 (e.g. 1000 hours 共用)
  • 希望有收費上限,不要不小心爆表。
  • CPU 希望可以高一點,畢竟 RAG 跟 LLM 需要 CPU 跟 RAM 都不少。

參考資料:

[Golang][Gemini Pro] 使用 Chat Session 與 LINEBot 快速整合出有記憶的 LINE Bot

image-20240103174806953

前提

前幾篇的文章 [Golang] 透過 Google Gemini Pro 來打造一個基本功能 LLM LINE Bot 曾經提過,如何整合基本的 Gemini Pro Chat 與 Gemini Pro Vision 兩個模型的使用。 本次將快速提一下,打造一個具有記憶體的 LINE Bot 該如何做。

相關開源程式碼:

https://github.com/kkdai/linebot-gemini-pro

系列文章:

  1. 使用 Golang 透過 Google Gemini Pro 來打造一個具有LLM 功能 LINE Bot (一): Chat Completion and Image Vision
  2. 使用 Golang 透過 Google Gemini Pro 來打造一個具有LLM 功能 LINE Bot (二): 使用 Chat Session 與 LINEBot 快速整合出有記憶的 LINE Bot(本篇)
  3. 使用 Golang 透過 Google Gemini Pro 來打造一個具有LLM 功能 LINE Bot (三): 使用 Gemini-Pro-Vision 來打造名片管理的聊天機器人

什麼叫做有記憶的聊天機器人

原本在 OpenAI Completion API 是採取一問一答的方式,也就是你問一次,他回答。 下一次詢問的時候,就會完全的忘記。這邊提供網頁上的說明程式碼:

from openai import OpenAI
client = OpenAI()

response = client.completions.create(
  model="gpt-3.5-turbo-instruct",
  prompt="Write a tagline for an ice cream shop."
)

在之前,如果需要有記憶的功能,就需要把之前的問與答都附在問句的前面。到了之後, OpenAI 推出了 ChatCompletion 的功能,相關的程式碼如下:

from openai import OpenAI
client = OpenAI()

response = client.chat.completions.create(
  model="gpt-3.5-turbo",
  messages=[
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Who won the world series in 2020?"},
    {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
    {"role": "user", "content": "Where was it played?"}
  ]
)

這時候,要加入相關的對話就需要更加的精確。但是出來的結果也就會更棒。

Gemini-Pro 套件提供的 ChatSession

大家可以參考一下這篇文章 Google GenerativeAI ChatSession Python Client 裡面提供了 ChatSession 讓大家可以直接開啟一個聊天的 Session 。進而會自動把所有訊息都放入 History (也就是放入聊天記錄中)。

# Python ChatSession demo code
>>> model = genai.GenerativeModel(model="gemini-pro")
>>> chat = model.start_chat()
>>> response = chat.send_message("Hello")
>>> print(response.text)
>>> response = chat.send_message(...)

其實 Golang 也有 (refer code) (GoDoc ChatSession Example)

ctx := context.Background()
	client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("API_KEY")))
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()
	model := client.GenerativeModel("gemini-pro")
	cs := model.StartChat()

  // ... send() inline func ...
  
	res := send("Can you name some brands of air fryer?")
	printResponse(res)
	iter := cs.SendMessageStream(ctx, genai.Text("Which one of those do you recommend?"))
	for {
		res, err := iter.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		printResponse(res)
	}

	for i, c := range cs.History {
		log.Printf("    %d: %+v", i, c)
	}
	res = send("Why do you like the Philips?")
	if err != nil {
		log.Fatal(err)
	}

這邊可以看到:

  • 透過 cs := model.StartChat() 建立一個新的 Chat Session 。
  • 接下來將你的問題 (prompt) 透過 send()傳送,並且取得回覆 res
  • 這兩個資料都會自動儲存在 cs.History 裏面。

結合 Gemini-Pro 的 Chat Session 與 LINE Bot

看完了套件內提供的 Chat Session 之後,要如何跟 LINE Bot SDK 來做結合呢?

以 LINE Bot SDK Go v7 來舉例

因為 v8 有使用到 Open API (a.k.a. swagger) 的架構,整個方式不太一樣。之後會透過新的文章來說明。這裡透過大家比較熟悉的 v7 來舉例:

			case *linebot.TextMessage:
				req := message.Text
				// 檢查是否已經有這個用戶的 ChatSession or req == "reset"
				cs, ok := userSessions[event.Source.UserID]
				if !ok {
					// 如果沒有,則創建一個新的 ChatSession
					cs = startNewChatSession()
					userSessions[event.Source.UserID] = cs
				}
				if req == "reset" {
					// 如果需要重置記憶,創建一個新的 ChatSession
					cs = startNewChatSession()
					userSessions[event.Source.UserID] = cs
					if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage("很高興初次見到你,請問有什麼想了解的嗎?")).Do(); err != nil {
						log.Print(err)
					}
					continue
				}
  • 首先建立一個 map 存放資料為 map[user_Id]-> ChatSession
  • 如果在 key map 沒有找到,就建立一個新的。 startNewChatSession()
  • 詳細內容如下,裡面重點是透過 model 來啟動一個聊天 model.StartChat()
// startNewChatSession	: Start a new chat session
func startNewChatSession() *genai.ChatSession {
	ctx := context.Background()
	client, err := genai.NewClient(ctx, option.WithAPIKey(geminiKey))
	if err != nil {
		log.Fatal(err)
	}
	model := client.GenerativeModel("gemini-pro")
	value := float32(ChatTemperture)
	model.Temperature = &value
	cs := model.StartChat()
	return cs
}
  • 當然,如果覺得 token 可能爆掉。可以透過 reset指令來重新建立一個。

那真正聊天跟回覆要如何處理呢?

				// 使用這個 ChatSession 來處理訊息 & Reply with Gemini result
				res := send(cs, req)
				ret := printResponse(res)
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(ret)).Do(); err != nil {
					log.Print(err)
				}

其實就是透過 res := send(cs, req) 來將你的詢問的內容,發送給 Gemini Pro 並且接收相關回覆 res

只要這樣,不需要一步步將文字貼在 Chat context 之後。就可以達成一個具有記憶的聊天機器人。 幾件事情需要注意:

  • 要小心對話內容過長,會造成回覆精確度不夠高。
  • 要小心內容會讓你的 token 爆掉,造成無法取得回覆。

目前 Gemini Pro 的收費

截至筆者寫完(2024/01/03) 目前的定價依舊是 (refer Google AI Price)

  • 一分鐘內 60次詢問都免費
  • 超過的話:
    • $0.00025 / 1K characters
    • $0.0025 / image

image-20240103223633970

透過 Render 來快速部署服務:

由於 Gemini Pro 目前在某些額度下,還是免費的。這裡也更改了專案,讓沒有信用卡的學生可以學習如何打造一個 LLM 具有記憶的聊天機器人。

Render.com 簡介:

  • 類似 Heroku 的 PaaS (Platform As A Services) 服務提供者。
  • 他有免費的 Free Tier ,適合工程師開發 Hobby Project。
  • 不需要綁定信用卡,就可以部署服務。

參考: Render.com Price

部署步驟如下:

image-20240104140246518

  • 選擇一個服務名字

image-20240104140347932

成果

image-20240103225422373

根據以上的圖片,可以知道其實 ChatSession 相當適合打造 LINE Bot。

  • 只儲存使用者跟 OA 的相關對話。
  • 回覆的內容很適合在 OA 上面跟使用者互動。

但是使用 Gemini Pro 的 Chat Session 幾件事情需要注意:

  • 因為所以的記憶是儲存在 Services 的記憶體中,由於 Render.com 是會睡眠重啟的。到時候他會忘記。
  • ChatSession 是跟著 model 走的,也就是說: “gemini-pro” 跟 gemini-pro-vision” 兩個的對話是不能共用。

謝謝大家的觀看,也期待各位一起打造出

參考資料:

[線上演講筆記] Open-Source AI Projects at UC Berkeley & LMSys: Vicuna and Chatbot Arena

講者資訊

image-20231229105428746

UC Berkeley 的 Wei-Lin Chiang (Winston Chiang) 於 12/29(五) 來陽明交大演講, 主題是有關 Large Language Model (LLM), 尤其是將會提及他們在 UC Berkeley 開發的一個十分知名 LLM – Vicuna. 該LLM今年推出後即已有+500 citations, 超過百萬次下載, 江韋霖是主要作者之一. 歡迎有興趣的老師同學踴躍參與.

時間:112.12.29(五) 10:30-12:00

地點: 陽明交大工程三館 114室

演講者: Wei-Lin Chiang, 江韋霖 (University of California, Berkeley)

演講題目: Open-Source AI Projects at UC Berkeley & LMSys: Vicuna and Chatbot Arena

演講內容

Why Vicuna ?

image-20231229105447713

image-20231229105451665

image-20231229105522393

  • GPT-3 只使用 “Few-Shot” 開始產生其他語言結果。
  • LLM 成果遠遠比 NLP 的成效更好,開始大量投入相關的開發。

image-20231229105717094

  • 一開始 GPT3 只能 complete ,無法達到 Q&A 。

image-20231229105910058

  • 透過 “Instruct-GPT” 讓只會 Complete 的 GPT3 開始能做 Q7A

image-20231229105948247

image-20231229110601205

  • Stanford 做了 Alpaca ,於是 UC Berkeyley 也想做。

image-20231229110710361

  • 七萬筆數據。

image-20231229110926813

image-20231229111404311

  • 價錢便宜一半,資料量級跟 Stanford 差不多。

Vicuna - Demo site

https://chat.lmsys.org/

  • Data 經過清洗

image-20231229112737416

  • Blog 的影響:

    • 500 引用
    • 3M 訪問
    • 看圖的 model 也做了。

Vicuna - Limitation

image-20231229113011081

  • 數學, coding 有限制,回答不好。
  • 後來多拿相關資料去優化。

接下來面對問題:

  • 成功來自於「高質量」的數據 (data)

  • 支出不便宜,但是資料搜集不易。

  • 沒有好的 Evaluation 機制。

  • Benchmark 可能已經被 LLM 看過了。

Chat Area

image-20231229114908831

  • 開放的 ChatGPT (免費)
  • 有許多 model (開源)
  • 學校希望有更多回饋,與相關 RLHF 的資料。
    • 放上所有開源 models
    • 讓使用者評分相關問題,誰回答比較好。
    • 作為資料的搜集。

Onging Effort ?

  • 開始跟 HuggingFace 合作

image-20231229115703592

Q&A

  • LMSyS 是一個學生組織,未來發展方向是做開源 LLM 的 research 。
  • 很多開源模型都是使用外部 hosted (HuggingFace …)

更多參考:

[TIL][Heroku][Golang] 使用 Github Release 來 Deploy 服務到 Heroku

image-20231228233157290

Github Action 上的 CICD - Go Build

經常在教同學要打造自己的 side Project 的時候,要透過 Github 把自己的實際產品的想法表現出來。 其中,很重要的除了「文件的撰寫上」,那麼就會是「CICD」的實踐。


範例程式 Repo:

kkdai/bookmark-makerserver: A IFTTT MakerServer to help you post your tweet to github issue as a bookmark


在 Github Action 上有一個 Golang 基本的 CICD 工具 Golang Build

name: Go

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:

  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4

    - name: Set up Go
      uses: actions/setup-go@v5
      with:
        go-version: 1.21

    - name: Build
      run: go build -v ./...

    - name: Test
      run: go test -v ./...

這個就是 Github Action 提供的基本範本 ,可以讓你在 Pull Request 的時候跟 Merge 之後來跑 Go Build 的相關指令。

image-20231229000236139

Github 上的部署到 Heroku 的設定

這邊也可以參考一下 Heroku 提供的基本設定教學與安裝 Github Action 的方法

name: Deploy

on:
  push:
    branches:
      - master

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: akhileshns/[email protected] # This is the action
        with:
          heroku_api_key: $
          heroku_app_name: "YOUR APP's NAME" #Must be unique in Heroku
          heroku_email: "YOUR EMAIL"

image-20231229000801996

原本設定: Merge 到 Master / Main 的時候 Deploy

但是裡面的設定都是 Push Master/Main 得時候才會啟動。這樣子其實有點麻煩,每一次的 Merge 到 Master/Main branch 都會發動部署。會讓像是 Document Update 的 PR 也會發動重複的 Deploy 。

如何改成透過 Github Release 來 Deploy?

這邊如果需要透過 Draft a new release 直接來選擇 deploy 到 Heroku 的話。就需要做以下修改。

name: Deploy

on:
  release:
    types: [created]

透過這個方式,就可以讓 Deploy 變得更加的直覺,

完成版之後的 CICD 流程與未來展望:

  • Pull Request –> Go Build 檢查程式碼可編輯程度。
    • 未來可以考慮加上一些 Test Coverage 工具來做單元測試,甚至是更多相關測試內容。
  • Murged 之後,也是跑 Go Build
    • 未來可以加上一些自動化文件更新的 action
  • Release 之後,就會 Deploy 到 Heroku 。
    • 目前都是 Cloud Services ,如果有多雲平台或是 Dev / Product 不同 cluster 可以分開來。

參考文件