AI說書 - 從0開始 - 527 | Stable Diffusion 之 Keras 實現 (編碼器)

更新 發佈閱讀 14 分鐘

我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。


Keras 實現 Stable Diffusion 的 Encoder 部分為:

class TextEncoder(keras.Model):
def __init__(self, max_length, vocab_size = 49408, name = None, download_weights = True):
tokens = keras.layers.Input(shape = (max_length,), dtype = "int32", name = "tokens")
positions = keras.layers.Input(shape = (max_length,), dtype = "int32", name = "positions")
x = CLIPEmbedding(vocab_size, 768, max_length)([tokens, positions])
for _ in range(12):
x = CLIPEncoderLayer(768, 12, activation = quick_gelu)(x)
embedded = keras.layers.LayerNormalization(epsilon = 1e-5)(x)
super().__init__([tokens, positions], embedded, name = name)

if download_weights:
text_encoder_weights_fpath = keras.utils.get_file(origin = "https://huggingface.co/fchollet/stable-diffusion/resolve/main/kcv_encoder.h5",
file_hash = "4789e63e07c0e54d6a34a29b45ce81ece27060c499a709d556c7755b42bb0dc4")
self.load_weights(text_encoder_weights_fpath)


當中程式說明為:

  • keras.layers.Input(shape = (max_length,), dtype = "int32", name ="tokens")
    1. shape = (max_length,) 表示輸入的形狀是長度為 max_length 的一維向量,這通常代表 Token 序列的長度
    2. dtype = "int32" 定義輸入數據的資料型別為整數 (int32),通常用於標記 Token IDs 編碼
    3. name = "tokens" 為此輸入層指定一個名稱 "tokens",方便在模型中引用此層
  • CLIPEmbedding(vocab_size, 768, max_length)([tokens, positions])
    1. CLIPEmbedding(vocab_size, 768, max_length) 是 CLIP 模型中的嵌入層,它接收詞彙表大小 (vocab_size)、嵌入維度 (768) 和最大序列長度 (max_length) 作為參數,將標記序列和位置轉換成 768 維的嵌入表示
  • CLIPEncoderLayer(768, 12, activation = quick_gelu)(x)
    1. 12 表示多頭自注意力的頭數,即模型會使用 12 個不同的注意力頭來捕捉輸入中不同部分的相關性


漂亮的原文說明為:

raw-image


最後是原始元件的程式碼:

def quick_gelu(x):
return x * ops.sigmoid(x * 1.702)




class CLIPEmbedding(keras.layers.Layer):
def __init__(self, input_dim = 49408, output_dim = 768, max_length = 77, **kwargs)
super().__init__(**kwargs)
self.token_embedding = keras.layers.Embedding(input_dim, output_dim)
self.position_embedding = keras.layers.Embedding(max_length, output_dim)

def call(self, inputs):
tokens, positions = inputs
tokens = self.token_embedding(tokens)
positions = self.position_embedding(positions)
return tokens + positions




class CLIPEncoderLayer(keras.layers.Layer):
def __init__(self, embed_dim, num_heads, activation = None, **kwargs):
super().__init__(**kwargs)
self.layer_norm1 = keras.layers.LayerNormalization(epsilon = 1e-5)
self.clip_attn = CLIPAttention(embed_dim, num_heads, causal = True)
self.layer_norm2 = keras.layers.LayerNormalization(epsilon = 1e-5)
self.fc1 = keras.layers.Dense(embed_dim * 4) # Output Dimension is embed_dim * 4
self.fc2 = keras.layers.Dense(embed_dim)
self.activation = activation

def call(self, inputs):
residual = inputs
x = self.layer_norm1(inputs)
x = self.clip_attn(x)
x = residual + x
residual = x
x = self.layer_norm2(x)
x = self.fc1(x)
x = self.activation(x)
x = self.fc2(x)
return x + residual




class CLIPAttention(keras.layers.Layer):
def __init__(self, embed_dim = 768, num_heads = 12, causal = True, **kwargs):
super().__init__(**kwargs)
self.embed_dim = embed_dim
self.num_heads = num_heads
self.causal = causal
self.head_dim = self.embed_dim // self.num_heads
self.scale = self.head_dim**-0.5
self.q_proj = keras.layers.Dense(self.embed_dim)
self.k_proj = keras.layers.Dense(self.embed_dim)
self.v_proj = keras.layers.Dense(self.embed_dim)
self.out_proj = keras.layers.Dense(self.embed_dim)

def reshape_states(self, x, sequence_length, batch_size):
x = ops.reshape(x, (batch_size, sequence_length, self.num_heads, self.head_dim))
return ops.transpose(x, (0, 2, 1, 3)) # bs, heads, sequence_length, head_dim

def call(self, inputs, attention_mask = None):
if attention_mask is None and self.causal:
length = ops.shape(inputs)[1]
attention_mask = ops.triu(ops.ones((1, 1, length, length), dtype = self.compute_dtype)* -float("inf"), k = 1)

_, tgt_len, embed_dim = inputs.shape
query_states = self.q_proj(inputs) * self.scale
key_states = self.reshape_states(self.k_proj(inputs), tgt_len, -1)
value_states = self.reshape_states(self.v_proj(inputs), tgt_len, -1)

proj_shape = (-1, tgt_len, self.head_dim)
query_states = self.reshape_states(query_states, tgt_len, -1)
query_states = ops.reshape(query_states, proj_shape)
key_states = ops.reshape(key_states, proj_shape)

src_len = tgt_len
value_states = ops.reshape(value_states, proj_shape)
attn_weights = query_states @ ops.transpose(key_states, (0, 2, 1))

attn_weights = ops.reshape(attn_weights, (-1, self.num_heads, tgt_len, src_len))
attn_weights = attn_weights + attention_mask
attn_weights = ops.reshape(attn_weights, (-1, tgt_len, src_len))

attn_weights = ops.softmax(attn_weights, axis = -1)
attn_output = attn_weights @ value_states

attn_output = ops.reshape(attn_output, (-1, self.num_heads, tgt_len, self.head_dim))
attn_output = ops.transpose(attn_output, (0, 2, 1, 3))
attn_output = ops.reshape(attn_output, (-1, tgt_len, embed_dim))
return self.out_proj(attn_output)


當中程式說明為:

  • ops.triu(ops.ones((1, 1, length, length), dtype = self.compute_dtype)* -float("inf"), k = 1)
    1. 取得 inputs 的第二維度 (即序列長度),並將其儲存在變數 length 中
    2. 生成一個大小為 (1, 1, length, length) 的矩陣,內容為 1,並轉換為模型的計算精度 self.compute_dtype
    3. 使用 ops.triu 函數,這個矩陣會被轉換為上三角形矩陣,並乘以 -float("inf"),因此除對角線下方為 0 外,其餘位置都會變成 -inf
    4. k = 0 會將主對角線及以上的元素設為 -inf,k = 1 則從主對角線上方一條對角線開始設為 -inf,主對角線元素不變
    5. 這樣的矩陣讓模型在計算注意力分數時,忽略掉未來的序列資訊,防止模型在自回歸的情境中窺探未來的資訊
留言
avatar-img
留言分享你的想法!
avatar-img
Learn AI 不 BI
240會員
875內容數
這裡將提供: AI、Machine Learning、Deep Learning、Reinforcement Learning、Probabilistic Graphical Model的讀書筆記與演算法介紹,一起在未來AI的世界擁抱AI技術,不BI。
Learn AI 不 BI的其他內容
2025/10/17
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 Keras 實現 Stable Diffusion 的流程為: Text Embedding Random Image Creation Stable Diffu
Thumbnail
2025/10/17
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 Keras 實現 Stable Diffusion 的流程為: Text Embedding Random Image Creation Stable Diffu
Thumbnail
2025/10/16
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 讓我們從一個思想實驗開始,想像一位美術老師正在為班上的學生講述一個故事,描述他參觀過的一座擁有大花園、老樹和美麗花朵的美妙房子。 接著,老師給你一張布滿奇怪點點(
Thumbnail
2025/10/16
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 讓我們從一個思想實驗開始,想像一位美術老師正在為班上的學生講述一個故事,描述他參觀過的一座擁有大花園、老樹和美麗花朵的美妙房子。 接著,老師給你一張布滿奇怪點點(
Thumbnail
2025/10/15
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 本章節將涵蓋以下內容: Stable Diffusion 的高階概述 Stable Diffusion 的概念性數學表示 深入探討 Keras Stable Di
2025/10/15
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 本章節將涵蓋以下內容: Stable Diffusion 的高階概述 Stable Diffusion 的概念性數學表示 深入探討 Keras Stable Di
看更多
你可能也想看
Thumbnail
還在煩惱平凡日常該如何增添一點小驚喜嗎?全家便利商店這次聯手超萌的馬來貘,推出黑白配色的馬來貘雪糕,不僅外觀吸睛,層次豐富的雙層口味更是讓人一口接一口!本文將帶你探索馬來貘雪糕的多種創意吃法,從簡單的豆漿燕麥碗、藍莓果昔,到大人系的奇亞籽布丁下午茶,讓可愛的馬來貘陪你度過每一餐,增添生活中的小確幸!
Thumbnail
還在煩惱平凡日常該如何增添一點小驚喜嗎?全家便利商店這次聯手超萌的馬來貘,推出黑白配色的馬來貘雪糕,不僅外觀吸睛,層次豐富的雙層口味更是讓人一口接一口!本文將帶你探索馬來貘雪糕的多種創意吃法,從簡單的豆漿燕麥碗、藍莓果昔,到大人系的奇亞籽布丁下午茶,讓可愛的馬來貘陪你度過每一餐,增添生活中的小確幸!
Thumbnail
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 回顧 AI說書 - 從0開始 - 129 中說,Bidirectional Encoder Representations from Transformers (BER
Thumbnail
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 回顧 AI說書 - 從0開始 - 129 中說,Bidirectional Encoder Representations from Transformers (BER
Thumbnail
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 回顧 AI說書 - 從0開始 - 39 至 AI說書 - 從0開始 - 69 的第二章內容,我們拿 Encoder 出來看: 幾點注意如下: BERT 模型使用 M
Thumbnail
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 回顧 AI說書 - 從0開始 - 39 至 AI說書 - 從0開始 - 69 的第二章內容,我們拿 Encoder 出來看: 幾點注意如下: BERT 模型使用 M
Thumbnail
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 Transformer 可以透過繼承預訓練模型 (Pretrained Model) 來微調 (Fine-Tune) 以執行下游任務。 Pretrained Mo
Thumbnail
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 Transformer 可以透過繼承預訓練模型 (Pretrained Model) 來微調 (Fine-Tune) 以執行下游任務。 Pretrained Mo
Thumbnail
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 Transformers for Natural Language Processing and Computer Vision, 2024 這本書中講 Decoder
Thumbnail
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 Transformers for Natural Language Processing and Computer Vision, 2024 這本書中講 Decoder
Thumbnail
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 先做個總回顧: Transformer 架構總覽:AI說書 - 從0開始 - 39 Attention 意圖說明:AI說書 - 從0開始 - 40 Transfo
Thumbnail
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 先做個總回顧: Transformer 架構總覽:AI說書 - 從0開始 - 39 Attention 意圖說明:AI說書 - 從0開始 - 40 Transfo
Thumbnail
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 講完 Transformer 之 Encoder 架構中的 Embedding 與 Positional Encoding 部分,現在進入 Multi-Head Att
Thumbnail
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 講完 Transformer 之 Encoder 架構中的 Embedding 與 Positional Encoding 部分,現在進入 Multi-Head Att
Thumbnail
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 再度回到 Transformer 架構中的 Encoder 部分,如下圖所示: 我現在手上有的素材如下: Embedding 訓練方式:AI說書 - 從0開始
Thumbnail
我想要一天分享一點「LLM從底層堆疊的技術」,並且每篇文章長度控制在三分鐘以內,讓大家不會壓力太大,但是又能夠每天成長一點。 再度回到 Transformer 架構中的 Encoder 部分,如下圖所示: 我現在手上有的素材如下: Embedding 訓練方式:AI說書 - 從0開始
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News