iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0
AI Engineering

《矽墟》:我把一部科幻小說當成軟體專案來管系列 第 15

Day 15|先放大再縮小的解析度補齊鏈,以及它其實沒解到問題

  • 分享至 

  • xImage
  •  

模組三|AI 生圖與生片產線(Day 10–19)

Day 13 為了繞過內容審核換了模型。今天講換模型留下的爛攤子。

這篇原本要寫的是「我怎麼把不同模型的輸出統一成同一個規格」。寫到一半我去實測了 repo,發現我的處理其實沒有解到根本問題,而且最後被推翻了。所以它變成一篇不太一樣的文章。

問題:換模型之後,尺寸不一樣了

我的章節封面規格寫在工作流文件裡,很明確:

每回一張圖,尺寸 1536×1024,3:2 landscape。

原本的模型出這個尺寸沒問題。Day 13 換掉的那個新模型,出來的是:

1264 × 848

比原規格小,而且(這是我今天才算出來的)比例也不對。

1536 × 1024  →  ratio = 1.50000   (正好 3:2)
1264 ×  848  →  ratio = 1.49057   (不是)

當時我只注意到「不夠大」,沒注意到「比例不對」。

我當時的做法:先超過再縮回去

處理鏈是三段:

nano banana 出圖        1264 ×  848    (標稱 1k)
  ↓ upscale_image(bytedance,參數指定 2k)
放大結果                3216 × 2160    ← 實出遠超過標稱的 2k
  ↓ 本地 sips 縮到統一規格
落地                    2528 × 1696

為什麼不直接放大到目標尺寸

因為放大再縮小的畫質,比直接放大到目標尺寸好。

放大模型在補細節,補的解析度愈高,它能塞進去的資訊愈多。然後用單純的重採樣縮小,那些細節會被壓實,邊緣更乾淨。

直接請它放大到 2528,它就只補到 2528 的資訊量。

這在影像處理上叫 supersampling,跟遊戲的超採樣抗鋸齒是同一個原理:在比目標更高的解析度下運算,然後降下來。

標稱規格不能信

這條鏈裡有兩個地方,服務給的標籤跟實際輸出對不上:

我要求的 實際拿到的
生成 · 標稱 1k 1264 × 848
放大 · 參數指定 2k 3216 × 2160

2k 通常會讓人以為是 2048 寬。實際出來 3216。

另一次紀錄裡也一樣:同一個生成模型,參數要求 16:9、2k(換算約 1344×768),實出 2752×1536。

兩次都超出標稱值,而且倍率不一樣。

所以「2k」「1k」「high」這種標籤,在不同服務、不同模型之間根本不是同一件事。唯一可信的是實際輸出的像素數。

我後來的習慣是:新接一個模型,第一件事是生一張、量尺寸、記下來,不看文件寫什麼。

然後我實測了 repo,發現這件事沒有結束

寫這篇的時候,我想確認一下最後統一成什麼樣,於是量了所有章節封面:

=== 尺寸分布 ===
  38 檔   1536 × 1024
   1 檔   2528 × 1696
   1 檔   2496 × 1664

38 比 1。

那個 2528×1696 就是上面那條鏈的產物。它現在的檔名是:

novel-ch11-ropehold-original-cute.png

而正式在用的 novel-ch11-ropehold.png,是 1536×1024,跟其他 38 張一樣。

也就是說:我當時費力補出來的那個規格,後來被換掉了,退回原本的 1536×1024。

為什麼會被換掉

我很努力把它打大,歪的地方還是歪的,只是變大了

算一下比例就知道了:

1264 ×  848   ratio = 1.49057
2528 × 1696   ratio = 1.49057   ← 正好是 2 倍
1536 × 1024   ratio = 1.50000   ← 其他 38 張

2528 × 16961264 × 848 的精確兩倍。

放大兩倍保留了所有東西,包括錯的比例。

我以為我在解「不夠大」的問題,所以我把它變大了。**但真正的問題是「比例不對」,而放大對這個問題完全沒有效果。**我做了一整條處理鏈,然後產出一張跟其他 38 張比例不一致的圖。

(順帶一提,放大那一步自己也歪了一點:3216×2160 的比例是 1.48889,如果完全等比應該是 3216×2157.6。放大模型多給了 2.4 px 的高度。這個誤差在縮回去的時候被吃掉了,但它說明連放大都不保證嚴格等比。)

檔名沿用那招是對的

牌子一顆螺絲都沒鬆,我把它後面的東西整個掉包

這條鏈裡唯一完全正確的決定,是這個:

檔名沿用 assets/novel-ch11-ropehold.png(HTML 零改動),舊圖存 .bak-<日期>

因為 HTML 引用的是檔名。只要檔名不變,圖片怎麼重做、換幾次模型、走幾道後製,下游一行都不用改。

而這正是為什麼後來要換回 1536×1024 時,成本很低:就是換個檔案而已。

檔名是介面。 把它當成介面來守,你就可以自由地改實作。

代價

代價一:我解錯了問題,而且花了整條鏈的成本。

生成 → 放大 → 縮小,三個步驟、兩次 API 呼叫,換來一張比例不對的圖。

錯的原因很單純:我看到「1264 比 1536 小」,就認定問題是尺寸。 沒有去算比例。

如果第一步就把兩組數字相除,整條鏈根本不需要存在,直接生成或裁切到 3:2 就好。

代價二:日誌記的是當下的決定,不是最終狀態。

開發足跡.md 裡寫著「本日定稿」「封面統一規格 2528×1696」。

那是 2026-07-23 的真實狀況。但後來它被推翻了,而日誌沒有更新。

我今天如果只讀日誌不量檔案,會寫出一篇完全錯誤的文章:告訴讀者我的封面規格是 2528×1696,而實際上 38/40 是 1536×1024。

這是這個專案第三次出現同樣的問題了(Day 9 的狀態表落後 180 回、Day 12 的 json/yaml 無人同步)。「定稿」這兩個字在日誌裡的意思是「當天的定稿」。

代價三:那個 -original-cute 檔名。

被取代的檔案改名成 novel-ch11-ropehold-original-cute.png 留在目錄裡。

沒有任何地方說明它是什麼、為什麼留著、可不可以刪。三個月後我看到它,只會知道它跟 ch11 有關,而且很可愛。

被取代的東西如果要留,留的時候就要寫清楚為什麼。 不然它就是下一個沒人敢刪的東西。

帶走什麼

一、規格不符的時候,先把每個維度都算出來,再決定要修哪個。

我看到 1264×848 vs 1536×1024,只比了大小。應該要列的是:

維度 目標 實際 差在哪
1536 1264
1024 848
比例 1.5000 1.4906 不同
色彩空間 ? ? 沒查

列表格會逼你看到你沒在看的維度。 憑印象比較只會比到最顯眼的那一個。

二、外部服務的規格標籤不可信,以實測像素為準。

1k2khighstandard 這些標籤沒有跨服務的統一定義,而且我這兩次都是實出超過標稱。

接新模型的第一件事:生一張、量、記下來。文件寫什麼不重要。

三、檔名是介面,把它當介面守。

下游(HTML、設定檔、腳本)引用的是檔名。檔名不變,你就可以任意重做內容,換模型、換流程、換規格,下游零改動。

反過來,每次重做都改檔名,你就是在每次重做時都做一次 breaking change。

搭配一條:舊檔用日期後綴備份(.bak-20260723),不要用「old」「new」「final」這種會迅速失去意義的字。

四、你的工程日誌需要一個「後來被推翻了」的機制。

我的日誌是「新到舊」排列的決策紀錄,這個結構很好。但它缺一件事:沒有辦法表達「這條在三天後被否決了」。

於是舊條目永遠看起來像是有效的。

最低成本的補法:發現某個決定被推翻時,回去在舊條目上加一行「⚠️ 已於 <日期> 被 <新決定> 取代」。一行字,但它讓日誌從「事件流」變成「有狀態的紀錄」。

我準備補上這一行。這篇文章本身就是那個發現的過程。


明天 Day 16,模組三的圖產線收尾,講一個更貴的錯誤:一支腳本的「已存在就跳過」邏輯完全失效,20 個角色 100% 重生。 它不報錯、不 crash、輸出看起來完全正常,唯一的症狀是帳單。


上一篇
Day 14|參考圖怎麼傳給外部服務:我選了看起來比較笨的那條
下一篇
Day 16|「已存在就跳過」失效,20 個角色 100% 重生,而且不會報錯
系列文
《矽墟》:我把一部科幻小說當成軟體專案來管17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言