適合面向ChatGPT編程的架構(gòu)示例詳解
新的需求
我們前面爬蟲的需求呢,有些平臺說因?yàn)橐馉幾h,所以不讓發(fā),好吧,那我們換個(gè)需求,本來那個(gè)例子也不好擴(kuò)展了。最近AI畫圖也是比較火的,那么我們來試試做個(gè)程序幫我們生成AI畫圖的prompt。
首先講一下AI話題的prompt的關(guān)鍵要素,大部分的AI畫圖都是有一個(gè)個(gè)由逗號分割的關(guān)鍵字,也叫subject,類似下面這樣:
a cute cat, smile, running, look_at_viewer, full_body, side_view,
然后還有negative prompt,就是你不想出現(xiàn)的關(guān)鍵字,跟上面的寫法一樣,只是寫下來表示不希望它畫出來的,比如我們想畫一堆貓的圖片,不想出現(xiàn)狗,不想出現(xiàn)人,我們可以這么寫:
dog, human,
這樣大概率就不會(huì)出現(xiàn)狗和人了(當(dāng)然也不一定,懂得都懂)。
這些prompt扔給AI,我們可能得到下面這么一張圖:
但也可能會(huì)得到下面這么一張圖:
后面這張讓人san值狂減啊有沒有,所以說關(guān)鍵字的使用上還是有些學(xué)問的,我得好好研究研究。一研究我才發(fā)現(xiàn),這玩意生成速度太慢了,我做一個(gè)試驗(yàn)幾秒鐘過去了,然后才能做下一個(gè)。這就把我鎖在這電腦前面了,走也不是,等也不是。我大好的人生怎么能浪費(fèi)在這些事情上?啊不高~興!
這時(shí)我想到,我是個(gè)程序員啊。那假如,我有一個(gè)可以排列組合各種關(guān)鍵字幫我生成prompt的程序,讓它一個(gè)個(gè)去試驗(yàn),最后我只要看看哪個(gè)圖片比較靠譜,反過來看看哪些關(guān)鍵字組合更好用,豈不是美滋滋?
領(lǐng)域知識
那么說干就干,開始之前要了解一下領(lǐng)域知識。
首先是關(guān)鍵字,在這個(gè)需求里只是基礎(chǔ)知識,沒有什么難的,大概有下面幾條規(guī)則:
- 內(nèi)容,這些關(guān)鍵字呢,說是關(guān)鍵字,其實(shí)你寫一句話也沒人管你。簡化處理,我們這里就只用詞和短語。另外,空格可以用下劃線代替,這樣可能會(huì)避免被分詞,具體我也不確定,沒有深入研究。但是這個(gè)不重要,可以完全看成兩種關(guān)鍵字去排列組合好了。
- 關(guān)鍵字是可以有權(quán)重的,通常的表達(dá)方式是:
(a cute cat:1.5)
這個(gè)很重要,通常我們想嘗試好的方式,需要給每個(gè)關(guān)鍵字設(shè)置權(quán)重。
LoRA,英文全稱Low-Rank Adaptation of Large Language Models,直譯為大語言模型的低階適應(yīng),這是微軟的研究人員為了解決大語言模型微調(diào)而開發(fā)的一項(xiàng)技術(shù),在我們這個(gè)場景下就是我們多了一種關(guān)鍵字,這種關(guān)鍵字大概是這么寫:
<lora:wanostyle_2_offset:1>, monkey d luffy,
- 它多了一些尖括號,也有權(quán)重,同時(shí)他會(huì)被其他關(guān)鍵字觸發(fā),比如上面這個(gè)就可以畫個(gè)海賊王風(fēng)格的路飛出來。
- 但總的來說,對關(guān)鍵字本身的建模影響不大
接著我們來了解一下排列組合的邏輯,這個(gè)將是我們的關(guān)鍵難點(diǎn)。
- 在這個(gè)領(lǐng)域,影響生成的因素主要有幾個(gè):
- 模型
- sample
- step
- 寬高
- seed
- negative prompt
- prompt
- 在prompt中我們的關(guān)鍵字還可以根據(jù)使用目的分類,比如于生成畫面風(fēng)格的、用于生成背景的、用于生成人物的、用于成表情的等等
- 在prompt中,關(guān)鍵字的擺放順序有時(shí)候還會(huì)造成點(diǎn)不同。
- 還有更復(fù)雜的Control Net,這個(gè)例子里我們先不考慮。
- 生成的時(shí)候,某些關(guān)鍵字要獲得最好的效果,可能自己對模型、sample以及其他關(guān)鍵字的存在和權(quán)重都有自己的要求,比某關(guān)鍵字在某模型下權(quán)重為0.3,而在另一個(gè)模型下權(quán)重需要0.7。比如路飛會(huì)帶草帽,那么這個(gè)人物出現(xiàn)的時(shí)候,必須配上帽的關(guān)鍵字才對味,而其他的人物就不要跟草帽組合了,又浪時(shí)間又沒有意義。所以組合上要考慮各種因素之間的互斥和強(qiáng)依賴等場景。
架構(gòu)設(shè)計(jì)
好,這大概是一個(gè)比較復(fù)雜的需求了?;氐缴掀恼逻z留的問題,聊聊當(dāng)我們面對一個(gè)比較復(fù)雜的需求,而且我們接下來要用ChatGPT把它實(shí)現(xiàn)的時(shí)候,我們應(yīng)該怎么設(shè)計(jì)架構(gòu)。
管道架構(gòu)
在這個(gè)需求里,我們首先要知道,這類AI都是有REST API的,比如說stable diffusion WebUI,就有一個(gè)自己的API,他們的API接受一個(gè)固定格式的JSON,其結(jié)構(gòu)大概是這個(gè)樣子:
{ "prompt": "", "negative_prompt": "", "controlnet_input_image": [], "controlnet_mask": [], "controlnet_module": "", "controlnet_model": "", "controlnet_weight": 1, "controlnet_resize_mode": "Scale to Fit (Inner Fit)", "controlnet_lowvram": true, "controlnet_processor_res": 512, "controlnet_threshold_a": 64, "controlnet_threshold_b": 64, "controlnet_guidance": 1, "controlnet_guessmode": true, "enable_hr": false, "denoising_strength": 0.5, "hr_scale": 1.5, "hr_upscale": "Latent", "seed": -1, "subseed": -1, "subseed_strength": -1, "sampler_index": "", "batch_size": 1, "n_iter": 1, "steps": 20, "cfg_scale": 7, "width": 512, "height": 512, "restore_faces": true, "override_settings": {}, "override_settings_restore_afterwards": true }
那么這就是類似他們的意圖描述,可以把它看成一種DSL。
而在我們這個(gè)領(lǐng)域里,我們要做的是排列組合,那么對于排列組合,我們要設(shè)計(jì)我們排列組合的意圖描述,這可以看成另一種DSL,這種DSL只作簡單排列組合,不做復(fù)雜的互斥和強(qiáng)依賴邏輯的計(jì)算,其結(jié)構(gòu)可能是這個(gè)樣子:
- base_share_composite_intentions: base: steps: 10 batch_size: 1 width: 512 height: 512 cfg_scale: 7 sampler: "Euler a" seed: -1 restore_faces: true output_folder: output/txt2img file_full_name_strategy: date_seed_name_strategy sd_host: http://localhost:7860 negative_prompt: a dog poly: - template_prompt: template: > a cat, ${ view_angle } ${ portrait } ${ facial_expressions } ${ pose } meta: - view_angle: - side_view, - front_view, portrait: - full body, facial_expressions: - (smile:1.5), - (smile:1.2), - smile, pose: "" - view_angle: - front_view, portrait: - "" facial_expressions: - smile, pose: - run, - jump, - rolling, steps: 20
然后在這個(gè)DSL之上,我們可以再做一個(gè)DSL,這個(gè)DSL用于處理復(fù)雜的互斥和強(qiáng)依賴邏輯的計(jì)算,前面說了那么多,真正這個(gè)地方到底有多復(fù)雜我也想不清楚。那干脆,搞個(gè)模板引擎來吧,這就什么都能干了,慢慢搞明白了再封裝。最終其結(jié)構(gòu)可能是這個(gè)樣子:
<% const randomNum = Math.floor(Math.random() * 900000000) + 100000000; var intention = { is_override_settings: true, seed: randomNum, } %> <% var status = { charas:{ values_of_chara_$ref: [ "cats.yml#Abyssinian", "cats.yml#cats_in_boots", ], current_chara_index: 0, next_chara(){ this.current_chara_index++; } }, themes:{ values_of_theme: [ { $ref: "outdoor" }, ], current_theme_index: 0, next_theme(){ this.current_theme_index++; }, reset_theme(){ this.current_theme_index = 0; } } } %> <% common_theme_file = "common/chara_based_themes.yml" %> <% while (status.charas.current_chara_index < status.charas.values_of_chara_$ref.length) { %> - base_share_composite_intentions: common: theme: base: steps: 20 batch_size: 1 width: 512 height: 512 cfg_scale: 7 sampler: "DPM++ 2M Karras" seed: <%- intention.seed %> restore_faces: false output_folder: output/txt2img file_full_name_strategy: date_seed_name_strategy sd_host: http://localhost:7860 <% if(intention.is_override_settings){ %> override_settings: CLIP_stop_at_last_layers: 2 eta_noise_seed_delta: 31337 <%}%> negative_prompt: > dog, human, bad anatomy, EasyNegative,paintings, sketches, (worst quality:2), (low quality:2), (normal quality:2), lowres, normal quality, poly: <% while (status.themes.current_theme_index < status.themes.values_of_theme.length) { %> - $p_ref: $ref: "<%-common_theme_file%>#<%- status.themes.values_of_theme[status.themes.current_theme_index].$ref%>" params: base_prompt_features: $p_ref: $ref: <%- status.charas.values_of_chara_$ref[status.charas.current_chara_index] %> params: is_full_chara: true chara_weight: 0.2 pose: sit facial_expressions: (smile:1.1),(open mouth), - $p_ref: $ref: "<%-common_theme_file%>#<%- status.themes.values_of_theme[status.themes.current_theme_index].$ref%>" params: base_prompt_features: $p_ref: $ref: <%- status.charas.values_of_chara_$ref[status.charas.current_chara_index] %> params: is_full_chara: true chara_weight: 0.6 pose: run facial_expressions: (smile:1.2),(closed mouth), <% status.themes.next_theme(); %> <% } %> <% status.themes.reset_theme(); %> <% status.charas.next_chara(); %> <% } %>
于是我們有了三個(gè)DSL,他們層層轉(zhuǎn)換,最終驅(qū)動(dòng)AI畫圖。那么我們的程序可能就會(huì)是下面這個(gè)樣子:
可以看出,這樣我們就得到了大名鼎鼎的管道架構(gòu),經(jīng)常使用Linux/Unix命令行的人,可能已經(jīng)體會(huì)過管道架構(gòu)恐怖的擴(kuò)展能力,這次我們只能說,是Linux/Unix哲學(xué)再一次展現(xiàn)出威力。
我們之前講了,ChatGPT可以快速寫出一些小程序,但是長一點(diǎn)的總是會(huì)出錯(cuò),那么其實(shí)除了從規(guī)模上進(jìn)行分解將任務(wù)復(fù)雜度降低之外,通過抽象建立分層的DSL也是一種降低復(fù)雜度的方案。
分層架構(gòu)
說到分層,其實(shí)從另一個(gè)角度看,我們這個(gè)架構(gòu)也是一個(gè)分層架構(gòu)。
可以看到,我們可以輕易地替換調(diào)用不同REST API的代碼以做到對于不同AI的適配,實(shí)現(xiàn)了隔離。
同理,不但意圖執(zhí)行可以切換,意圖描述也可以跟著切換:
既可以有技術(shù)維度上的擴(kuò)展,也可以有業(yè)務(wù)維度上的擴(kuò)展:
所以從這個(gè)角度來說,每一個(gè)管段,都是可以看作是一層。
類分層神經(jīng)網(wǎng)絡(luò)的架構(gòu)
而到這還不算完,具體在執(zhí)行的時(shí)候,可能受環(huán)境的影響,可能受上層意圖影響等等,總之是需要進(jìn)行每一層的路徑選擇的。這種選擇,可能是由另一個(gè)引擎來完成的。那么最終我們的架構(gòu)的完整形態(tài)他可能是這個(gè)樣子的:
當(dāng)然其運(yùn)行視圖可能是這樣的:
到此,我們得到了我們架構(gòu)比較完整的形態(tài),他是一個(gè)集成了管道架構(gòu)和分層架構(gòu),在一個(gè)派發(fā)引擎的支撐下的一個(gè)類分層神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)。(還別說,這個(gè)結(jié)果還挺有點(diǎn)分形的味道)
總結(jié)一下
跟上一篇文章比起來,我們這篇文章的代碼寫的更少了(難道這就是ChatGPT時(shí)代的宿命嗎^_^)。
我們引入了一個(gè)新需求,這個(gè)新需求有更多的排列組合邏輯在其中,其測試也更容易在本地完成?;谶@個(gè)復(fù)雜的排列組合邏輯的問題域,我們在開始之前做了一個(gè)架構(gòu)設(shè)計(jì)。因?yàn)槲覀冞@篇文章是用ChatGPT寫程序,這個(gè)架構(gòu)設(shè)計(jì)自然是為了能用ChatGPT把這個(gè)復(fù)雜的程序給寫出來,所以我們整篇文章只講了應(yīng)該設(shè)計(jì)一個(gè)怎樣的架構(gòu)。
之所以這么設(shè)計(jì)架構(gòu),是因?yàn)镃hatGPT只能做簡單程序的代碼編寫,但是我們不能因此放棄使用它。畢竟人類社會(huì)也沒有因?yàn)檎羝麢C(jī)車不如馬耐顛所以放棄蒸汽機(jī)車?yán)^續(xù)用馬車,我們?yōu)榱耸褂盟膬?yōu)勢為他修了路。那么放到軟件領(lǐng)域,就是要為它設(shè)計(jì)適合它的架構(gòu),以最大限度的發(fā)揮它的優(yōu)勢,規(guī)避它的劣勢。
所以我們采用了分層架構(gòu)+管道架構(gòu)兩種架構(gòu)模式的組合搭建了一個(gè)類分層神經(jīng)網(wǎng)絡(luò)的架構(gòu)。盡管這個(gè)架構(gòu)要達(dá)到最完美的形態(tài),我們需要把那個(gè)派發(fā)引擎做出來,但是即便沒有那個(gè)派發(fā)引擎,剩下的兩個(gè)模式的組合也足以使得我們可以在橫向上按照代碼規(guī)模進(jìn)行分解,在縱向上按照抽象層次進(jìn)行分解,從而把需求的復(fù)雜度分解為一個(gè)個(gè)可以由ChatGPT完成的任務(wù)了。
那么接下來,我們就可以動(dòng)手工作了,我們下一篇文章講講開發(fā)這其中的每一個(gè)節(jié)點(diǎn)有什么套路。
以上就是適合面向ChatGPT編程的架構(gòu)示例詳解的詳細(xì)內(nèi)容,更多關(guān)于面向ChatGPT編程架構(gòu)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
前端算法之TypeScript包含min函數(shù)的棧實(shí)例詳解
這篇文章主要為大家介紹了前端算法之TypeScript包含min函數(shù)的棧實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09TypeScript逆變之條件推斷和泛型的應(yīng)用示例詳解
這篇文章主要為大家介紹了TypeScript逆變之條件推斷和泛型的應(yīng)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09TypeScript Module Resolution解析過程
這篇文章主要為大家介紹了TypeScript Module Resolution解析過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07Spartacus中navigation?item?reducer實(shí)現(xiàn)解析
這篇文章主要為大家介紹了Spartacus中navigation?item?reducer實(shí)現(xiàn)解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07詳解什么是TypeScript里的Constructor?signature
這篇文章主要介紹了什么是TypeScript里的Constructor?signature詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07Manipulation-TypeScript?DOM操作示例解析
這篇文章主要為大家介紹了DOM?Manipulation-TypeScript?DOM操作示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03