文章目錄
一、Keras 模型
兩類主要的模型:Sequential 順序模型 和 使用函數式 API 的 Model 類模型。
1、共同的方法和屬性
model.layers
:包含模型網絡層的展平列表。model.inputs
:模型輸入張量的列表。model.outputs
:模型輸出張量的列表。model.summary()
:打印出模型概述信息。 它是utils.print_summary
的簡捷調用。model.get_config()
:返回包含模型配置信息的字典。通過以下代碼,就可以根據這些配置信息重新實例化模型:config = model.get_config() model = Model.from_config(config) # 或者,對於 Sequential: model = Sequential.from_config(config)
model.get_weights()
:返回模型中所有權重張量的列表,類型爲 Numpy 數組。model.set_weights(weights)
:從 Numpy 數組中爲模型設置權重。列表中的數組必須與get_weights()
返回的權重具有相同的尺寸。model.to_json()
:以 JSON 字符串的形式返回模型的表示(不包括權重,僅包含結構)。可通過以下方式從 JSON 字符串重新實例化同一模型(使用重新初始化的權重):from keras.models import model_from_json json_string = model.to_json() model = model_from_json(json_string)
model.to_yaml()
:以 YAML 字符串的形式返回模型的表示(不包括權重,僅包含結構)**。可通過以下代碼,從 YAML 字符串中重新實例化相同的模型(使用重新初始化的權重):from keras.models import model_from_yaml yaml_string = model.to_yaml() model = model_from_yaml(yaml_string)
model.save_weights(filepath)
:將模型權重存儲爲 HDF5 文件。model.load_weights(filepath, by_name=False)
:從 HDF5 文件(由save_weights
創建)中加載權重。默認情況下,模型的結構應該是不變的。 如果想將權重載入不同的模型(部分層相同), 設置by_name=True
來載入那些名字相同的層的權重。
2、Model 類繼承
自定義模型:繼承 Model 類並在 call
方法中實現你自己的前向傳播,以創建自定義的模型。
示例:用 Model
類繼承寫的簡單的多層感知器的例子。
- 網絡層定義在
__init__(self, ...)
中指定; - 前向傳播在
call(self, inputs)
中指定:可以指定自定義的損失函數,通過調用self.add_loss(loss_tensor)
實現。
import keras
from keras.layers import Dense, Dropout, BatchNormalization
class SimpleMLP(keras.Model):
def __init__(self, use_bn=False, use_dp=False, num_classes=10):
super(SimpleMLP, self).__init__(name='mlp')
self.use_bn = use_bn
self.use_dp = use_dp
self.num_classes = num_classes
self.dense1 = Dense(32, activation='relu')
self.dense2 = Dense(num_classes, activation='softmax')
if self.use_dp:
self.dp = Dropout(0.5)
if self.use_bn:
self.bn = BatchNormalization(axis=-1)
def call(self, inputs):
x = self.dense1(inputs)
if self.use_dp:
x = self.dp(x)
if self.use_bn:
x = self.bn(x)
return self.dense2(x)
model = SimpleMLP()
model.compile(...)
model.fit(...)
在類繼承模型中,模型的拓撲結構是由 Python 代碼定義的(而不是網絡層的靜態圖)。這意味着該模型的拓撲結構不能被檢查或序列化。因此,以下方法和屬性不適用於類繼承模型:
model.inputs
和model.outputs
。model.to_yaml()
和model.to_json()
。model.get_config()
和model.save()
。
關鍵點:爲每個任務使用正確的 API。Model 類繼承 API 可以爲實現複雜模型提供更大的靈活性,但它需要付出代價(比如缺失的特性):它更冗長,更復雜,並且有更多的用戶錯誤機會。如果可能的話,儘可能使用函數式 API,這對用戶更友好。
二、Sequential 模型 API
1、compile():配置訓練模型
compile(optimizer, loss=None, metrics=None, loss_weights=None, sample_weight_mode=None, weighted_metrics=None, target_tensors=None)
參數:
optimizer
: 字符串 (優化器名)或者優化器對象。詳見 optimizers。loss
: 字符串 (目標函數名)或目標函數。詳見 losses。- 多輸出模型:通過傳遞損失函數的字典或列表,在每個輸出上使用不同的損失。模型將最小化的損失值將是所有單個損失的總和。
metrics
: 在訓練和測試期間的模型評估標準。通常你會使用metrics = ['accuracy']
。- 對於多輸出模型的不同輸出指定不同的評估標準:傳遞一個字典,eg:
metrics = {'output_a':'accuracy'}
。
- 對於多輸出模型的不同輸出指定不同的評估標準:傳遞一個字典,eg:
loss_weights
: 指定標量係數(Python浮點數)的可選列表或字典,用於加權不同模型輸出的損失貢獻。- 模型將要最小化的損失值將是所有單個損失的加權和,由
loss_weights
係數加權。 - 如果是列表,則期望與模型的輸出具有 1:1 映射。 如果是張量,則期望將輸出名稱(字符串)映射到標量係數。
- 模型將要最小化的損失值將是所有單個損失的加權和,由
sample_weight_mode
:- 若執行按時間步採樣權重(2D 權重),則設置爲
temporal
。 - 默認爲
None
,爲採樣權重(1D)。 - 如果模型有多個輸出,則可以通過傳遞
mode
的字典或列表,以在每個輸出上使用不同的sample_weight_mode
。
- 若執行按時間步採樣權重(2D 權重),則設置爲
weighted_metrics
:在訓練和測試期間,由sample_weight
或class_weight
評估和加權的度量標準列表。target_tensors
:默認情況下,Keras 將爲模型的目標創建一個佔位符,在訓練過程中將使用目標數據。相反,如果你想使用自己的目標張量(反過來說,Keras 在訓練期間不會載入這些目標張量的外部 Numpy 數據),您可以通過 target_tensors 參數指定它們。它應該是單個張量(對於單輸出 Sequential 模型)。**kwargs
:- 當使用 Theano/CNTK 後端時,這些參數被傳入
K.function
。 - 當使用 TensorFlow 後端時,這些參數被傳遞到
tf.Session.run
。
- 當使用 Theano/CNTK 後端時,這些參數被傳入
異常
ValueError
:如果optimizer
,loss
,metrics
或sample_weight_mode
這些參數不合法。
2、fit():訓練模型
以固定數量的輪次(數據集上的迭代)訓練模型:
fit(x=None, y=None, batch_size=None, epochs=1, verbose=1, callbacks=None, validation_split=0.0, validation_data=None, shuffle=True, class_weight=None, sample_weight=None, initial_epoch=0, steps_per_epoch=None, validation_steps=None)
參數
x
: 訓練數據的 Numpy 數組。- 如果模型中的輸入層被命名,則可傳遞一個字典,將輸入層名稱映射到 Numpy 數組。
- 如果從本地框架張量饋送(例如 TensorFlow 數據張量)數據,x 可以是 None(默認)。
y
: 標籤數據的 Numpy 數組。- 如果模型中的輸出層被命名,你也可以傳遞一個字典,將輸出層名稱映射到 Numpy 數組。
- 如果從本地框架張量饋送(例如 TensorFlow 數據張量)數據,y 可以是 None(默認)。
batch_size
: 整數或 None。每次提度更新的樣本數。如果未指定,默認爲 32.epochs
: 整數。訓練模型迭代輪次。一個輪次是在整個x
或y
上的一輪迭代。請注意,與initial_epoch
一起,epochs 被理解爲 「最終輪次」。模型並不是訓練了 epochs 輪,而是到第 epochs 輪停止訓練。verbose
: 0, 1 或 2。日誌顯示模式。 0 = 安靜模式, 1 = 進度條, 2 = 每輪一行。callbacks
: 一系列的keras.callbacks.Callback
實例。一系列可以在訓練時使用的回調函數。詳見 callbacks。validation_split
: 用作驗證集的訓練數據的比例,範圍:[0,1]
。validation_data
: 元組(x_val, y_val)
或元組(x_val, y_val, val_sample_weights)
,用來評估損失,以及在每輪結束時的任何模型度量指標。模型將不會在這個數據上進行訓練。這個參數會覆蓋validation_split
。shuffle
: 布爾值(是否在每輪迭代之前混洗數據)或者 字符串 (batch)。batch
是處理 HDF5 數據限制的特殊選項,它對一個 batch 內部的數據進行混洗。- 當
steps_per_epoch
非 None 時,這個參數無效。
class_weight
: 可選的字典,用來映射類索引(整數)到權重(浮點)值,用於加權損失函數(僅在訓練期間)。這可能有助於告訴模型 「更多關注」來自代表性不足的類的樣本。sample_weight
: 訓練樣本的可選 Numpy 權重數組,用於對損失函數進行加權(僅在訓練期間)。您可以傳遞與輸入樣本長度相同的平坦(1D)Numpy 數組(權重和樣本之間的 1:1 映射),或者在時序數據的情況下,可以傳遞尺寸爲 (samples, sequence_length) 的 2D 數組,以對每個樣本的每個時間步施加不同的權重。在這種情況下,你應該確保在 compile() 中指定 sample_weight_mode=“temporal”。initial_epoch
: 開始訓練的輪次(有助於恢復之前的訓練)。steps_per_epoch
: 在聲明一個輪次完成並開始下一個輪次之前的總步數(樣品批次)。- 使用 TensorFlow 數據張量等輸入張量進行訓練時,默認值 None 等於數據集中樣本的數量除以 batch 的大小,如果無法確定,則爲 1。
validation_steps
: 只有在指定了steps_per_epoch
時纔有用。停止前要驗證的總步數(批次樣本)。
返回:一個 History 對象。
- 其
History.history
屬性是連續 epoch 訓練損失和評估值,以及驗證集損失和評估值的記錄(如果適用)。
異常
RuntimeError
: 如果模型從未編譯。ValueError
: 在提供的輸入數據與模型期望的不匹配的情況下。
3、evaluate():模型評估
在測試模式,返回誤差值和評估標準值。 計算逐批次進行。
evaluate(x=None, y=None, batch_size=None, verbose=1, sample_weight=None, steps=None)
參數:
x
: 訓練數據的 Numpy 數組。 如果模型中的輸入層被命名,你也可以傳遞一個字典,將輸入層名稱映射到 Numpy 數組。 如果從本地框架張量饋送(例如 TensorFlow 數據張量)數據,x 可以是 None(默認)。y
: 目標(標籤)數據的 Numpy 數組。 如果模型中的輸出層被命名,你也可以傳遞一個字典,將輸出層名稱映射到 Numpy 數組。 如果從本地框架張量饋送(例如 TensorFlow 數據張量)數據,y 可以是 None(默認)。batch_size
: 整數或 None。每次提度更新的樣本數。如果未指定,默認爲 32.verbose
: 0, 1。日誌顯示模式。0 = 安靜模式, 1 = 進度條。sample_weight
: 訓練樣本的可選 Numpy 權重數組,用於對損失函數進行加權(僅在訓練期間)。 您可以傳遞與輸入樣本長度相同的平坦(1D)Numpy 數組(權重和樣本之間的 1:1 映射),或者在時序數據的情況下,可以傳遞尺寸爲 (samples, sequence_length) 的 2D 數組,以對每個樣本的每個時間步施加不同的權重。在這種情況下,你應該確保在 compile() 中指定sample_weight_mode="temporal"
。steps
: 整數或 None。 聲明評估結束之前的總步數(批次樣本)。默認值 None。
返回
- 標量測試誤差(如果模型只有單個輸出且沒有評估指標)或標量列表(如果模型具有多個輸出和/或指標)。 屬性
model.metrics_names
將提供標量輸出的顯示標籤。
4、predict():預測
爲輸入樣本生成輸出預測。
predict(x, batch_size=None, verbose=0, steps=None)
參數
x
: 輸入數據,Numpy 數組(或者如果模型有多個輸入,則爲 Numpy 數組列表)。batch_size
: 整數。如未指定,默認爲 32。verbose
: 日誌顯示模式,0 或 1。steps
: 聲明預測結束之前的總步數(批次樣本)。默認值 None。
返回:預測的 Numpy 數組。
異常
ValueError
: 如果提供的輸入數據與模型的期望數據不匹配,或者有狀態模型收到的數量不是批量大小的倍數。
5、train_on_batch()
batch 的單次梯度更新。
train_on_batch(x, y, sample_weight=None, class_weight=None)
參數:
x
: 訓練數據的 Numpy 數組,如果模型具有多個輸入,則爲 Numpy 數組列表。如果模型中的所有輸入都已命名,你還可以傳入輸入名稱到 Numpy 數組的映射字典。y
: 目標數據的 Numpy 數組,如果模型具有多個輸入,則爲 Numpy 數組列表。如果模型中的所有輸出都已命名,你還可以傳入輸出名稱到 Numpy 數組的映射字典。sample_weight
: 訓練樣本的可選 Numpy 權重數組,用於對損失函數進行加權(僅在訓練期間)。 您可以傳遞與輸入樣本長度相同的平坦(1D)Numpy 數組(權重和樣本之間的 1:1 映射),或者在時序數據的情況下,可以傳遞尺寸爲 (samples, sequence_length) 的 2D 數組,以對每個樣本的每個時間步施加不同的權重。在這種情況下,你應該確保在 compile() 中指定 sample_weight_mode=“temporal”。class_weight
: 可選的字典,用來映射類索引(整數)到權重(浮點)值,用於加權損失函數(僅在訓練期間)。這可能有助於告訴模型 「更多關注」來自代表性不足的類的樣本。
返回:
- 標量訓練誤差(如果模型只有單個輸出且沒有評估指標)或標量列表(如果模型具有多個輸出和/或指標)。 屬性
model.metrics_names
將提供標量輸出的顯示標籤。
6、test_on_batch()
在batch上評估模型。
test_on_batch(x, y, sample_weight=None)
參數:
x
: 訓練數據的 Numpy 數組,如果模型具有多個輸入,則爲 Numpy 數組列表。如果模型中的所有輸入都已命名,你還可以傳入輸入名稱到 Numpy 數組的映射字典。y
: 目標數據的 Numpy 數組,如果模型具有多個輸入,則爲 Numpy 數組列表。如果模型中的所有輸出都已命名,你還可以傳入輸出名稱到 Numpy 數組的映射字典。sample_weight
: 訓練樣本的可選 Numpy 權重數組,用於對損失函數進行加權(僅在訓練期間)。 您可以傳遞與輸入樣本長度相同的平坦(1D)Numpy 數組(權重和樣本之間的 1:1 映射),或者在時序數據的情況下,可以傳遞尺寸爲 (samples, sequence_length) 的 2D 數組,以對每個樣本的每個時間步施加不同的權重。在這種情況下,你應該確保在 compile() 中指定 sample_weight_mode=“temporal”。
返回:
- 標量測試誤差(如果模型只有單個輸出且沒有評估指標)或標量列表(如果模型具有多個輸出和/或指標)。 屬性 model.metrics_names 將提供標量輸出的顯示標籤。
7、predict_on_batch()
返回batch上的模型預測值。
predict_on_batch(x)
參數:
x
: 輸入數據,Numpy 數組或列表(如果模型有多輸入)。
8、fit_generator()
使用 Python 生成器或 Sequence 實例逐批生成的數據,按批次訓練模型。 生成器與模型並行運行,以提高效率。
keras.utils.Sequence
的使用可以保證數據的順序, 以及當use_multiprocessing=True
時 ,保證每個輸入在每個 epoch 只使用一次。- 例如,這可以讓你在 CPU 上對圖像進行實時數據增強,以在 GPU 上訓練模型。
fit_generator(generator, steps_per_epoch=None, epochs=1, verbose=1, callbacks=None, validation_data=None, validation_steps=None, class_weight=None, max_queue_size=10, workers=1, use_multiprocessing=False, shuffle=True, initial_epoch=0)
參數:
generator
: 一個生成器或 Sequence (keras.utils.Sequence) 對象的實例,以避免在使用多進程時出現重複數據。 生成器的輸出應該爲以下之一:- 一個
(inputs, targets)
元組; - 一個
(inputs, targets, sample_weights)
元組。 這個元組(生成器的單個輸出)表示一個獨立批次。因此,此元組中的所有數組必須具有相同的長度(等於此批次的大小)。不同的批次可能具有不同的大小。例如,如果數據集的大小不能被批量大小整除,則最後一批時期通常小於其他批次。生成器將無限地在數據集上循環。當運行到第steps_per_epoch
時,記一個 epoch 結束。
- 一個
steps_per_epoch
: 整數。在聲明一個 epoch 完成並開始下一個 epoch 之前從 generator 產生的總步數(批次樣本)。它通常應該等於你的數據集的樣本數量除以批量大小。可選參數 Sequence:如果未指定,將使用 len(generator) 作爲步數。epochs
: 整數,數據的迭代總輪數。一個 epoch 是對所提供的整個數據的一輪迭代,由 steps_per_epoch 所定義。請注意,與 initial_epoch 一起,參數 epochs 應被理解爲 「最終輪數」。模型並不是訓練了 epochs 輪,而是到第 epochs 輪停止訓練。verbose
: 日誌顯示模式。0,1 或 2。0 = 安靜模式,1 = 進度條,2 = 每輪一行。callbacks
: keras.callbacks.Callback 實例列表。在訓練時調用的一系列回調。詳見 callbacks。
validation_data: 它可以是以下之一:
驗證數據的生成器或 Sequence 實例
一個 (inputs, targets) 元組
一個 (inputs, targets, sample_weights) 元組。validation_steps
: 僅當 validation_data 是一個生成器時纔可用。 每個 epoch 結束時驗證集生成器產生的步數。它通常應該等於你的數據集的樣本數量除以批量大小。可選參數 Sequence:如果未指定,將使用 len(generator) 作爲步數。class_weight
: 可選的字典,用來映射類索引(整數)到權重(浮點)值,用於加權損失函數(僅在訓練期間)。這可能有助於告訴模型 「更多關注」來自代表性不足的類的樣本。
max_queue_size: 整數。生成器隊列的最大尺寸。如果未指定,max_queue_size 將默認爲 10。workers
: 整數。使用基於進程的多線程時啓動的最大進程數。如果未指定,worker 將默認爲 1。如果爲 0,將在主線程上執行生成器。use_multiprocessing
: 如果 True,則使用基於進程的多線程。如果未指定,use_multiprocessing 將默認爲 False。請注意,因爲此實現依賴於多進程,所以不應將不可傳遞的參數傳遞給生成器,因爲它們不能被輕易地傳遞給子進程。shuffle
: 布爾值。是否在每輪迭代之前打亂 batch 的順序。只能與 Sequence (keras.utils.Sequence) 實例同用。在 steps_per_epoch 不爲 None 是無效果。initial_epoch
: 整數。開始訓練的輪次(有助於恢復之前的訓練)。
示例:
def generate_arrays_from_file(path):
while True:
with open(path) as f:
for line in f:
# 從文件中的每一行生成輸入數據和標籤的 numpy 數組
x1, x2, y = process_line(line)
yield ({'input1':x1, 'input2':x2}, {'output':y})
model.fit_generator(generate_arrays_from_file('/my_file.txt'),
steps_per_epoch=10000, epochs=10)
9、evaluate_generator
在數據生成器上評估模型。這個生成器應該返回與 test_on_batch
所接收的同樣的數據。
evaluate_generator(generator, steps=None, max_queue_size=10, workers=1, use_multiprocessing=False, verbose=0)
參數:
generator
: 返回批量輸入樣本的生成器,或 Sequence (keras.utils.Sequence
) 對象的實例,以避免在使用多進程時出現重複數據。steps
: 在停止之前,來自generator
的總步數 (樣本批次)。 可選參數Sequence
:如果未指定,將使用len(generator)
作爲步數。max_queue_size
: 生成器隊列的最大尺寸。workers
: 整數。使用基於進程的多線程時啓動的最大進程數。如果未指定,worker 將默認爲 1。如果爲 0,將在主線程上執行生成器。use_multiprocessing
: 如果True
,則使用基於進程的多線程。 請注意,因爲此實現依賴於多進程,所以不應將不可傳遞的參數傳遞給生成器,因爲它們不能被輕易地傳遞給子進程。verbose
: 日誌顯示模式, 0 或 1。
返回:
- 標量測試誤差(如果模型只有單個輸出且沒有評估指標)或標量列表(如果模型具有多個輸出和/或指標)。 屬性
model.metrics_names
將提供標量輸出的顯示標籤。
10、predict_generator
爲來自數據生成器的輸入樣本生成預測,預測值的 Numpy 數組。這個生成器應該返回與 predict_on_batch
所接收的同樣的數據。
predict_generator(generator, steps=None, max_queue_size=10, workers=1, use_multiprocessing=False, verbose=0)
參數:
generator
: 返回批量輸入樣本的生成器,或 Sequence (keras.utils.Sequence
) 對象的實例,以避免在使用多進程時出現重複數據。steps
: 在停止之前,來自generator
的總步數 (樣本批次)。 可選參數Sequence
:如果未指定,將使用len(generator)
作爲步數。max_queue_size
: 生成器隊列的最大尺寸。workers
: 整數。使用基於進程的多線程時啓動的最大進程數。如果未指定,worker 將默認爲 1。如果爲 0,將在主線程上執行生成器。use_multiprocessing
: 如果True
,則使用基於進程的多線程。 請注意,因爲此實現依賴於多進程,所以不應將不可傳遞的參數傳遞給生成器,因爲它們不能被輕易地傳遞給子進程。verbose
: 日誌顯示模式, 0 或 1。
11、get_layer()
根據名稱(唯一)或索引值查找網絡層。 索引是基於水平圖遍歷的順序(自下而上)。
get_layer(name=None, index=None)
參數
name
: 字符串,層的名字。index
: 整數,層的索引。- 注意:如果同時提供了
name
和index
,則index
將優先。
返回:一個層實例。
三、Model 類(函數式 API)
1、概述
官方文檔:函數式 API
在函數式 API 中,給定一些輸入張量和輸出張量,可以通過以下方式實例化一個 Model
:
- 示例1:這個模型將包含從
a
到b
的計算的所有網絡層。
from keras.models import Model
from keras.layers import Input, Dense
a = Input(shape=(32,))
b = Dense(32)(a)
model = Model(inputs=a, outputs=b)
- 示例2:在多輸入或多輸出模型的情況下,可以使用列表。
model = Model(inputs=[a1, a2], outputs=[b1, b3, b3])
2、Model 類模型方法
具體參數見上一節中的各函數的參數 或 官方文檔
(1)配置訓練模型
compile:配置訓練模型
- 定義:
compile(optimizer, loss=None, metrics=None, loss_weights=None, sample_weight_mode=None, weighted_metrics=None, target_tensors=None)
(2)模型訓練、評估、預測
-
fit:以給定數量的輪次(數據集上的迭代)訓練模型。
- 定義:
fit(x=None, y=None, batch_size=None, epochs=1, verbose=1, callbacks=None, validation_split=0.0, validation_data=None, shuffle=True, class_weight=None, sample_weight=None, initial_epoch=0, steps_per_epoch=None, validation_steps=None)
- 定義:
-
evaluate:在測試模式下返回模型的誤差值和評估標準值。
- 定義:
evaluate(x=None, y=None, batch_size=None, verbose=1, sample_weight=None, steps=None)
- 定義:
-
predict:爲輸入樣本生成輸出預測。
- 定義:
predict(x, batch_size=None, verbose=0, steps=None)
- 定義:
(3)batch上的模型訓練、評估、預測
- train_on_batch:batch上的單次梯度更新。
- 定義:
train_on_batch(x, y, sample_weight=None, class_weight=None)
- 定義:
- test_on_batch:batch上測試模型。
- 定義:
test_on_batch(x, y, sample_weight=None)
- 定義:
- predict_on_batch:返回batch上的模型預測值
- 定義:
predict_on_batch(x)
- 定義:
(4)生成器上的訓練、評估、預測
- fit_generator
- 目的:使用 Python 生成器(或 Sequence 實例)逐批生成的數據,按批次訓練模型。
- 定義:
fit_generator(generator, steps_per_epoch=None, epochs=1, verbose=1, callbacks=None, validation_data=None, validation_steps=None, class_weight=None, max_queue_size=10, workers=1, use_multiprocessing=False, shuffle=True, initial_epoch=0)
- evaluate_generator:在數據生成器上評估模型。
- 定義:
evaluate_generator(generator, steps=None, max_queue_size=10, workers=1, use_multiprocessing=False, verbose=0)
- 定義:
- predict_generator:爲來自數據生成器的輸入樣本生成預測。
- 定義:
predict_generator(generator, steps=None, max_queue_size=10, workers=1, use_multiprocessing=False, verbose=0)
- 定義:
(5)獲取某網絡層
get_layer:根據名稱(唯一)或索引值查找網絡層,返回一個層實例。
- 定義:
get_layer(self, name=None, index=None)
- 參數:
name
: 字符串,層的名字。index
: 整數,層的索引。索引值來自於水平圖遍歷的順序(自下而上)。
- 注意:如果同時提供了 name 和 index,則 index 將優先。