清華開源中文對話模型ChatGLM-6B簡略試驗及迫真優(yōu)化解決爆顯存
在該視頻中,UP用賽揚G5905+32GB內(nèi)存嘗試部署ChatGLM并成功運行,但是時間有限,所以沒有嘗試此模型多輪對話等能力:

有用顯卡運行的小伙伴反映,多輪對話會爆顯存,于是就粗略做了一些不太嚴(yán)謹(jǐn)?shù)?/strong>測試。本文末尾也會提供一種臨時的解決辦法,通過拋棄部分對話歷史記錄的方法來緩解顯存問題。
測試內(nèi)容包括:多輪短對話,代碼相關(guān)對話,多輪長對話,對話的另一端是ChatGPT,事先對內(nèi)容和輸出長度做了約束。
CPU這邊的話,目前沒有發(fā)現(xiàn)爆內(nèi)存的問題,使用單精度方式運行時,Python進(jìn)程的內(nèi)存占用穩(wěn)定在23.5GB,波動不超過正負(fù)1GB。有可能是垃圾回收機制比較激進(jìn),而CUDA那邊對應(yīng)的策略比較保守?
首先對web_demo.py做了簡單改造,使得它能夠在終端打印對話輪次、輸入字符數(shù)、輸出字符數(shù)、消耗時間,基本邏輯如下:
在展示結(jié)果之前,貼一下CPU和內(nèi)存的參數(shù)與跑分,供參考:


如果有打算使用CPU跑的小伙伴,可以根據(jù)跑分換算速度。但只能粗估,因為不是嚴(yán)格的正比關(guān)系:
比如i3/5/7,銳龍等CPU有AVX指令集(賽揚沒有),一些服務(wù)器CPU甚至有AVX512,對這些CPU有優(yōu)化的話,速度會更快;
對于多核CPU,需要看對多核優(yōu)化的程度如何,如果利用率不高,且單核性能不佳的話,也許效果反而不如這破賽揚;
推理很吃浮點性能,像推土機這樣閹割一半FPU的設(shè)計,效果不會太理想。
另外有內(nèi)存帶寬,總線帶寬等制約性能的要素。





對話內(nèi)容,以及用Excel做了點簡單的分析,貼在下面供參考。
1.簡單短對話


用戶:你好,開始對話。
ChatGLM-6B:你好,有什么我可以為你效勞的嗎?
用戶:請問你能告訴我現(xiàn)在是幾點嗎?
ChatGLM-6B:很抱歉,我無法提供當(dāng)前時間,因為我只是一個計算機程序,沒有直接訪問實時時間的能力。不過,你可以使用任何時間戳或當(dāng)前日期來查詢當(dāng)前時間。
用戶:好的,謝謝你的回答。那請告訴我如何制作一杯美味的拿鐵咖啡?
ChatGLM-6B:制作一杯美味的拿鐵咖啡,可以參考下述步驟:
材料:
1個杯子
1包(約4克)濃縮咖啡
1/2杯牛奶
1/4杯糖
適量冰塊
適量肉桂或可可粉(可選)
步驟:
預(yù)熱杯子,并在杯底倒入一些牛奶,加入糖和冰塊。
把濃縮咖啡放入杯子中,用吸管攪拌均勻。
根據(jù)個人口味,加入適量的肉桂或可可粉。
繼續(xù)攪拌均勻,直到咖啡和牛奶充分混合。
如果喜歡,可以在咖啡上撒上一些肉桂粉或可可粉作為裝飾。
拿鐵咖啡的特色在于牛奶和咖啡的混合,以及肉桂或可可粉的味道??梢愿鶕?jù)自己的口味和喜好進(jìn)行調(diào)整,制作出自己喜歡的拿鐵咖啡。
用戶:非常感謝你提供的詳細(xì)步驟,我會嘗試按照你的建議制作一杯美味的拿鐵咖啡。
ChatGLM-6B:不客氣,很高興能幫助制作出一杯美味的拿鐵咖啡。如果有任何其他問題或需要進(jìn)一步的幫助,請隨時告訴我。
用戶:好的,謝謝你的熱心幫助。請問你有什么推薦的書籍或電影嗎?
ChatGLM-6B:當(dāng)然,我很樂意為您提供推薦。以下是一些我個人喜歡的的書籍和電影:
書籍:
《1984》喬治·奧威爾
《追風(fēng)箏的人》卡勒德·胡賽尼
《人類群星閃耀時》劉慈欣
《小王子》安托萬·德·圣??颂K佩里
電影:
《教父》弗朗西斯·福特·科波拉
《辛德勒的名單》史蒂文·斯皮爾伯格
《肖申克的救贖》弗蘭克·德拉邦特
《阿甘正傳》羅伯特·澤米吉斯
《星際穿越》克里斯托弗·諾蘭
這些都是我非常推薦的書籍和電影,它們都有自己獨特的風(fēng)格和主題,可以帶給您不同的閱讀和觀影體驗。希望這些推薦能夠?qū)δ兴鶐椭?
用戶:非常感謝您提供的這些推薦,我會盡快去閱讀和觀看。如果我有任何其他問題或需要進(jìn)一步的建議,我會再次與你聯(lián)系。
ChatGLM-6B:不客氣,很高興能夠為您提供幫助。如果有任何其他問題或需要進(jìn)一步的建議,隨時都可以聯(lián)系我。祝您閱讀愉快!
用戶:謝謝,祝您也有愉快的一天!
ChatGLM-6B:不客氣,祝您也度過愉快的一天!如果有任何其他問題,隨時都可以聯(lián)系我。
時間有限,沒有去一一檢驗?zāi)P蜕傻膬?nèi)容中是否存在常識性錯誤,若有請在評論區(qū)指出,謝謝。

2.代碼相關(guān)對話
一開始問了一些Python相關(guān)的問題,結(jié)果ChatGLM的表現(xiàn)不盡人意,而且最后收斂(復(fù)讀)了,就只測了四輪:


用戶:會Python嗎?
ChatGLM-6B:是的,我可以使用Python編程語言。Python是一種高級、通用、解釋型編程語言,易于學(xué)習(xí)和使用,并且廣泛應(yīng)用于各種領(lǐng)域,包括數(shù)據(jù)科學(xué)、機器學(xué)習(xí)、人工智能、Web開發(fā)等。如果您需要使用Python,我可以提供一些幫助或建議。
用戶:那您能否介紹一下Python中的Lambda函數(shù)是什么?何時使用它們?
ChatGLM-6B:Lambda函數(shù)是Python中的匿名函數(shù),也稱為匿名內(nèi)部函數(shù)。它們可以作為函數(shù)對象返回,但不需要定義外部或外部的函數(shù)對象。Lambda函數(shù)通常用于簡化代碼或?qū)崿F(xiàn)邏輯,其語法如下:
其中,表達(dá)式是一個可選的參數(shù),表示Lambda函數(shù)要返回的值。Lambda函數(shù)可以用于許多場景,例如:
匿名函數(shù):在函數(shù)內(nèi)部定義一個Lambda函數(shù),可以簡化代碼的可讀性和邏輯性。
生成器表達(dá)式:生成器表達(dá)式是一個Lambda函數(shù),用于返回一個序列或集合。
條件表達(dá)式:條件表達(dá)式可以使用Lambda函數(shù)作為內(nèi)部函數(shù),實現(xiàn)遞歸條件判斷。
以下是一個簡單的例子,展示了如何使用Lambda函數(shù):
在這個例子中,my_function是一個生成器表達(dá)式,它使用條件表達(dá)式判斷x是否大于10,如果大于10,返回一個字符串,否則返回另一個字符串。Lambda函數(shù)被定義在生成器表達(dá)式內(nèi)部,這樣外部就可以使用生成的字符串,而不需要知道具體的生成器表達(dá)式。
用戶:Lambda函數(shù)是Python中的匿名函數(shù),通常用于簡化代碼或?qū)崿F(xiàn)邏輯。它們可以作為函數(shù)對象返回,但不需要定義外部或外部的函數(shù)對象。
ChatGLM-6B:Lambda函數(shù)是Python中的匿名函數(shù),也稱為匿名內(nèi)部函數(shù)。它們可以作為函數(shù)對象返回,但不需要定義外部或外部的函數(shù)對象。Lambda函數(shù)通常用于簡化代碼或?qū)崿F(xiàn)邏輯,其語法如下:
其中,表達(dá)式是一個可選的參數(shù),表示Lambda函數(shù)要返回的值。Lambda函數(shù)可以用于許多場景,例如:
匿名函數(shù):在函數(shù)內(nèi)部定義一個Lambda函數(shù),可以簡化代碼的可讀性和邏輯性。
生成器表達(dá)式:生成器表達(dá)式是一個Lambda函數(shù),用于返回一個序列或集合。
條件表達(dá)式:條件表達(dá)式可以使用Lambda函數(shù)作為內(nèi)部函數(shù),實現(xiàn)遞歸條件判斷。
以下是一個簡單的例子,展示了如何使用Lambda函數(shù):
在這個例子中,my_function是一個生成器表達(dá)式,它使用條件表達(dá)式判斷x是否大于10,如果大于10,返回一個字符串,否則返回另一個字符串。Lambda函數(shù)被定義在生成器表達(dá)式內(nèi)部,這樣外部就可以使用生成的字符串,而不需要知道具體的生成器表達(dá)式。
用戶:Lambda函數(shù)是Python中的匿名函數(shù),通常用于簡化代碼或?qū)崿F(xiàn)邏輯。它們可以作為函數(shù)對象返回,但不需要定義外部或外部的函數(shù)對象。
ChatGLM-6B:Lambda函數(shù)是Python中的匿名函數(shù),也稱為匿名內(nèi)部函數(shù)。它們可以作為函數(shù)對象返回,但不需要定義外部或外部的函數(shù)對象。Lambda函數(shù)通常用于簡化代碼或?qū)崿F(xiàn)邏輯,其語法如下:
匿名函數(shù):在函數(shù)內(nèi)部定義一個Lambda函數(shù),可以簡化代碼的可讀性和邏輯性。
生成器表達(dá)式:生成器表達(dá)式是一個Lambda函數(shù),用于返回一個序列或集合。
條件表達(dá)式:條件表達(dá)式可以使用Lambda函數(shù)作為內(nèi)部函數(shù),實現(xiàn)遞歸條件判斷。
以下是一個簡單的例子,展示了如何使用Lambda函數(shù):
在這個例子中,my_function是一個生成器表達(dá)式,它使用條件表達(dá)式判斷x是否大于10,如果大于10,返回一個字符串,否則返回另一個字符串。my_generator是一個生成器表達(dá)式,它使用for循環(huán)生成1到11的整數(shù)。my_condition是一個條件表達(dá)式,它使用條件表達(dá)式判斷x是否大于10,如果大于10,返回True,否則返回False。result是my_condition的返回值,如果my_condition返回True,則result為"x is greater than 10",否則為"x is less than or equal to 10"。
本想看看ChatGPT怎么吐槽的:


后來問了一些關(guān)于C語言的問題,ChatGLM表現(xiàn)好一些(國內(nèi)大學(xué)多以C語言作為計算機入門課程之一,所以語料較為豐富?),但也有瑕疵。然而這段回答已經(jīng)讓ChatGPT折服了,我刷新了十多遍都是回一句謝謝,于是沒有再往下試、或者重開了,不然各位今天就看不到這篇專欄了:

用戶:C語言的變量可以在哪些地方定義?
ChatGLM-6B:變量定義語句:在C語言中,變量定義語句是用來聲明變量的語句,通常放在程序的開頭。例如:
int a; ?// 聲明一個整型變量a
double b; ?// 聲明一個雙精度浮點型變量b
char c; ?// 聲明一個字符型變量c
變量聲明:在變量定義語句之前,可以使用變量聲明語句來聲明一個變量,聲明時需要指定變量的類型和名稱。例如:
int a = 10; ?// 聲明一個整型變量a,并將其初始化為10
double b = 0.1; ?// 聲明一個雙精度浮點型變量b,并將其初始化為0.1
char c = 'X'; ?// 聲明一個字符型變量c,并將其初始化為X
變量定義后:在變量定義語句之后,可以使用變量來訪問和修改它的值。例如:
int a = 10;
printf("%d\n", a); ?// 輸出a的值是10
a = 20;
printf("%d\n", a); ?// 輸出a的值是20
上面的代碼中,變量a的值在定義后可以被修改。 需要注意的是,在程序中只能有一個變量定義語句,定義語句之后不能再進(jìn)行變量聲明或變量賦值。
用戶:明白了,謝謝你的解釋。

3.多輪長對話
內(nèi)容是兩個AI在聊人生經(jīng)驗,由于聊天內(nèi)容篇幅極長,就不在這里發(fā),只貼數(shù)據(jù),我會另投一篇專欄,通過后在這里貼鏈接;內(nèi)容沒有明顯的問題,而且可以直接拿來應(yīng)付大學(xué)心理課作業(yè),只是ChatGLM復(fù)讀現(xiàn)象嚴(yán)重,就像在附和ChatGPT;但也可能因為用了現(xiàn)成語料,輸出速度有提升。



簡單改造代碼,通過拋棄部分對話歷史記錄的方法來緩解顯存問題
目前在CPU上沒有遇到OOM,但是爆顯存的現(xiàn)象是客觀存在的,在清華項目組迭代之前,可以用這種方式來應(yīng)急。
甲.直接擠掉前面的記憶,只保留最近3輪對話的內(nèi)容
簡單粗暴,邏輯清晰。
以下是web_demo.py修改的位置:

將原版代碼第15行修改如下:
若要修改保留對話的輪數(shù),可自行修改小于等于號、負(fù)號后的數(shù)字。
乙.保留第一輪對話以及最近2輪對話
大多數(shù)用戶本地部署都有將AI調(diào)教為貓娘等需求,進(jìn)而接入vits、智能音響、物聯(lián)網(wǎng)設(shè)備等,而第一句話通常用于樹立人設(shè)(貓設(shè)?),有其重要性,需要保留。
修改位置如圖:

對應(yīng)代碼如下: