我想,这不会是一篇教程,也不是一篇非常成功的可借鉴的经验
它是一份关于 我自己构建的模型,为什么一开始一定失败 的个人记录
过去的接近一周的时间,我尝试训练一个能够生成 16*16像素的Minecraft 风格 文生图的AI模型
这个目标并不宏大,甚至可以说有种朴素的美:
输入一句中文描述,生成一个符合Minecraft风格的像素贴图
但让我没有料到的是,这个看起来几乎没有什么复杂度的目标,会迫使我在短短几天内 推翻并重写代码三十多次
在这个过程中,我大量以来了Google Gemini和OpenAI Chatgpt帮我完成代码方面的实现
但真正错误的发现和问题的判断,以及为什么这一步一定不行,几乎全是来自自己与AI的反复讨论推演和否定
一、起点:一个看似“完美”的方案
最开始我的构思其实很简单,一个非常标准的方案:
将样本中的图像量化为一组离散的颜色,创建一个8*8的调色板
将16*16的训练样本展平为一个256长度的序列
使用 Transformer Decoder 做自回归生成
使用 BERT 作为文本和图像的桥梁
使用 CrossEntropy & Label Smoothing
生成阶段引入 CFG Classifier-Free Guidance
从代码角度看,这套方案几乎挑不出任何问题:
Loss稳定下降
训练正常进行
日志一切正常
但是实际上训练了100epoch的结果狠狠打了我的脸
形状完全是混乱的
颜色也完全随机,没有任何统一
略微调大CFG试图挽回,发现更乱了



作为第一次涉足这个领域的人,我的第一反应非常经典
是不是学习率不太对?
是不是模型参数太少了?
是不是训练样本不够准确或者数量太少了?
现在回头看,对于当时的我,这些问题全部问错了方向
二、真正的怀疑:这不是参数的问题
最开始的我,试图让Gemini无脑增加这个训练的参数量,结果反而变得更加糟糕了
训练速度慢如蜗牛
100Epoch需要一整天
结果更加不可控
所以我很快的放弃了这条路
真正的转折点,来自一个简单但是危险的问题:
我的模型,真的在学习形状和颜色吗?
当我开始从这个角度审视当前的训练时,问题和解决的方向才第一次变得清晰
三、在一步步的探索中解决问题
虽然我曾经从未涉足这个领域,但好在我热爱探讨问题,我去向AI询问了大量关于文生图训练的问题,自己摸着石头过河找到了一条路
问题一:Transformer根本不知道什么叫“形状”
在最初的实现中,所有图像都被flatten成了一个 一维的256长度序列
这意味着:
模型只感知一维空间
完全不知道上下左右的关系
在模型的眼里:
第17个像素
第18个像素
第200个像素
在空间中是完全等价的
但文生图的核心却是 空间上的连续性
这是一个非常隐蔽但又非常致命的错误:
我在用一个毫无空间感知力的模型,学习空间上的结构
问题二:颜色的学不会,其实是模型自己的最优解
当时模型生成了大量橙色、黑色、灰色的混合块,完全无视描述中的颜色提示。
后来我才意识到,这并不是生成策略的问题,而是 Loss 设计的问题。
在训练数据中:
背景色占据了大的地位
那些鲜艳的红蓝黄紫等非常稀有
而我最初的Loss设计默认了:
所有颜色同等重要
于是模型学到的最优策略是:
使用出现频率最高的颜色,最快地降低 Loss
下图展示了按照颜色出现频次排序的可视化调色板

从 Loss 的角度看,这个策略毫无破绽;
从模型自身的角度看,它甚至非常“聪明”。
但从最终生成结果来看,这是一场彻头彻尾的赛博灾难,我训练了一个电子垃圾
这也是我第一次认识到
模型在失败时,往往是在非常认真的完成一个你不想要的目标
问题三:自回归放大了所有的错误
最早我使用了标准的自回归生成:
从左到右,从上到下,一个接一个生成
这个在文本的生成里很自然,但是在文生图的像素里却是灾难性的:
前面几个像素一旦预测错误
后续 200 多个像素都会被持续误导
在这种结构下,CFG 的作用也发生了反转:
CFG 小 → 模糊成一团
CFG 稍大 → 直接炸成随机色块
CFG 不再是语义增强器,而变成了一个 不稳定性的放大器。



问题四:颜色过少导致信息被严重压缩
一开始我认为,对 Minecraft 风格贴图来说,64 色已经足够
而且颜色少意味着:
训练更快
更容易看到“效果”
但后来我在一次偶然的修改中,将调色板从 8×8 扩展到了 16×16,发现模型对颜色的学习速度明显提升
现在回头看原因非常清楚:
颜色数量过少,导致大量语义差异被压缩到同一个 token 中。
深蓝与浅蓝、冷色与暖色,被迫映射到同一个离散表示中
任何微小偏移都会导致颜色语义发生剧烈跳变。


四、修补:一连串的新尝试
在逐步意识到这些问题后,我做了一系列修改,包括但不限于:
改进调色板生成方式(按色相、明度排序)
将透明色作为独立 token 处理
扩充调色板规模与训练样本
尝试不同的 embedding 维度和 Transformer 深度
预计算文本 embedding,提高训练稳定性
这些改动并非毫无作用:
训练更稳定了
Loss 曲线更好看了
偶尔能看到一些模糊的形状
但模型依然陷在一个怪圈里——
它似乎在努力,但努力的方向依旧是错的。
五、承认:这不是代码缺陷,而是Transformer的特性
真正的进展来自一次认知的和考量的转变
我不再试图驯服Transformer这个狂暴的机器,而是承认他确实有一些特性使他无法完成这些任务
于是,我后来的人物开始围绕另一个核心思想:
1.图像是一个二维的场,而不是一个一维的序列
我将token reshape回了2D,建立了一个二维的坐标
引入了卷积神经网络用于建模贴图局部的连续性
开始引入空间一致性(Total Variation) Loss
2.放弃AR,转向MaskGIT
并行预测
多轮润色
先学习结构,再摸索细节
3.明确了新的Loss模式:什么重要、什么不重要
根据颜色的出现频率加权
根据饱和度再次加权
对权重截断,防止权重过高或过低
4.改变文本条件
不再使用Bert用于对其
使用Clip进行全局embedding
六、明显的信号:学习率“好调了”
有一个非常真实,但是很难提前预料到的现象:
当模型开始合理时,学习率突然变得好调了
同样的优化器,同样的scheduler
梯度方向开始稳定
结构逐渐清晰
颜色开始与文本对应
这让我更确信了一件事:
不是我不会调参,而是梯度本身是错的



ep285_3_一把蓝色的钻石剑_像素风格武器
ep290_0_一个金色的圆形徽章中心镶嵌着紫色的方形宝石
ep290_1_一把科幻风格的枪_带有紫色的枪身和白色的瞄准镜
七、回头看这一周:重要的收获
这套模型虽然现在依旧不完美
但对我来说,这一周的最大的收获不是生成了多少张合理的图,而是:
我终于开始明白,并能解释:
为什么第一版的模型一定会失败
很多时候,不是模型“没学会”,也不是数据不够,更不是算力不够,而是因为
我们让它做的事情,超出了它的能力
八、写在最后
我写下这份记录,不是为了证明我做对了什么,而是为了提醒未来可能再次走在这条路上的自己
当模型表现得像无规则的乱码时
也许不是它坏了,而是我没有告诉它如何理解这个世界
这份记录,对我来说很重要
也希望能让以后遇到相同问题的,跟我一样的新兵蛋子,可以有一点借鉴,少走一些弯路
最后,感谢 Google Gemini & OpenAI ChatGPT
让我在几乎没有 Python 基础的情况下,完成了一个真正可用的文生图模型原型
评论