晚上繼續來對另一個 14b 模型-微軟的 Phi 4 進行大考驗 :
本系列全部測試文章索引參考 :
先載入執行 Gemma 4 模型 :
C:\Users\tony1>ollama run phi4:14b
>>>
1. 進階推理能力測試 :
這是一個不可能的悖論陷阱題, 提示詞如下 :
有 100 顆球,其中 1 顆重量不同,但不知道它比較重還是比較輕。只有一個沒有砝碼的天平,最多可以秤 3 次。請找出異常球,並判斷它是比較重還是比較輕。請完整說明策略。
>>> 有 100 顆球,其中 1 顆重量不同,但不知道它比較重還是比較輕。只有一個沒有砝碼的天平,最多可以秤 3
... 次。請找出異常球,並判斷它是比較重還是比較輕。請完整說明策略。
要解決這個問題,我們需要一個精確的策略來利用最多 3 次的天平秤,找出異常球並確定它是比較重還是比較
輕。這裡有一個詳細的步驟指南:
### 步驟 1: 初步分組和第一次秤
1. **將球分成三組**:將 100 顆球分成三個大小接近的組:兩組各 33 顆球(稱為組 A 和組 B),剩下
34 顆球(稱為組 C)。
2. **對組 A 和組 B 進行第一次秤**:
- 如果天平平衡,異常球必定在組 C 中。
- 如果天平不平衡,異常球必定在較重那一組中(假設它較重;如果假設它較輕,較輕的組將被用於後續步
驟)。
### 步驟 2: 進一步縮小範圍
#### 案例 1: 異常球在組 C
1. **將組 C 分成三個小組**:兩組各 11 顆球,剩下 12 顆球。
2. **對兩個小組進行第二次秤**:
- 如果天平平衡,異常球在剩下的 12 顆球中。
- 如果天平不平衡,異常球在較重那一組中。
3. **第三次秤**:
- 如果異常球在 12 顆球中:將這些球分成四組各 3 顆球,對其中兩組進行秤。
- 如果平衡,異常球在剩下的 6 顆球中。
- 如果不平衡,異常球在較重那一組中。
- 然後,將較重那一組(或剩下的 6 顆球)的 3 顆球對秤以確定異常球並判斷其重量。
#### 案例 2: 異常球在組 A 或組 B
1. **假設異常球在組 A**(較重),並將其分成三組:11 顆球、11 顆球、11 顆球,剩下 11 顆球。
2. **對兩個小組進行第二次秤**:
- 如果天平平衡,異常球在剩下的 11 顆球中。
- 如果天平不平衡,異常球在較重那一組中。
3. **第三次秤**:
- 如果異常球在 11 顆球中:將其分成兩組(5 顆球、5 顆球),將其中一組秤在 5 顆已知正常的球上。
- 如果平衡,異常球在剩下的 5 顆球中。
- 如果不平衡,異常球在較重那一組中。
- 然後,將較重那一組(或剩下的 5 顆球)的 3 顆球對秤以確定異常球並判斷其重量。
### 結論
通過這種分組和系統的秤重方法,您可以有效地在 3 次秤重後確定異常球以及它是比較重還是比較輕。關鍵是
在每次秤重後有效地減少候選組,保持組的平衡並在每次不平衡的情況下專注於問題的一半。
這題答案 Gemini 的評論摘要如下 :
Phi-4 (14B) 的回答完全錯誤,且表現出嚴重的邏輯幻覺與算術混亂。它的表現甚至比先前的 qwen2.5-coder:14b 更差,完全喪失了數學邊界檢驗能力。致命的漏洞如下 :
- 無法辨識理論下界(徹底踩入陷阱):
這道題在數學資訊論上本來就無解,先前測試的 Gemma 4 一眼就識破這個悖論,並點出資訊論下界;而 Phi-4 卻與 Qwen 一樣,毫無懷疑地全盤接受,試圖用偽邏輯硬湊步驟。 - 邏輯與運算上的荒謬錯誤 :
推論存在致命的循環論證,假設也自相矛盾,例如它直接主觀「假設它較重」,結果後續的推導就全部失去效力,導致邏輯崩潰。此外它連基本加法都算錯(幻覺算術),例如組 A 一開始只有 33 顆球,它居然把 33 顆球拆成了 4 組 11 顆(共 44 顆),憑空無中生有生出 11 顆球。
總評是 Phi 4 在面對悖論陷阱推論問題時表現完全不及格.
2. 進階程式能力測試 :
提示詞如下 :
請寫一個 Python 函式:
def detect_drawdown(prices, threshold=0.2):
輸入是一個每日收盤價 list,找出所有從歷史高點回撤超過 threshold 的區段。
要求:
- 使用 pandas
- 回傳每個 drawdown 的 peak date、trough date、peak price、trough price、drawdown
- 處理空資料
- 提供可直接執行的完整程式
- 附一組測試資料
>>> 請寫一個 Python 函式:
...
... def detect_drawdown(prices, threshold=0.2):
...
... 輸入是一個每日收盤價 list,找出所有從歷史高點回撤超過 threshold 的區段。
...
... 要求:
... - 使用 pandas
... - 回傳每個 drawdown 的 peak date、trough date、peak price、trough price、drawdown
... - 處理空資料
... - 提供可直接執行的完整程式
... - 附一組測試資料
...
以下是一個使用 `pandas` 實現的 Python 函式,用來找出給定每日收盤價列表中所有從歷史高點回撤超過指
定閾值的區段。這個函式會返回每個回撤的頂點日期、谷底日期、頂點價格、谷底價格和回撤值。
```python
import pandas as pd
def detect_drawdown(prices, threshold=0.2):
if len(prices) == 0:
return []
# Create a DataFrame from the prices list
df = pd.DataFrame(prices, columns=['price'])
df['date'] = pd.date_range(start='2023-01-01', periods=len(prices))
df.set_index('date', inplace=True)
# Calculate the running maximum (peak) price
df['peak'] = df['price'].cummax()
# Calculate the drawdown
df['drawdown'] = (df['peak'] - df['price']) / df['peak']
# Find the points where the drawdown exceeds the threshold
drawdown_events = df[df['drawdown'] > threshold].copy()
# Identify the peak date, trough date, peak price, trough price, and drawdown value
results = []
last_peak = None
for index, row in drawdown_events.iterrows():
if last_peak is None or row['price'] < drawdown_events.loc[last_peak]['price']:
# Update the last peak if a new peak is found
last_peak = index
if row['drawdown'] <= threshold:
# If the drawdown goes below the threshold, record the drawdown event
peak_price = df.loc[:last_peak]['price'].max()
peak_date = df.loc[:last_peak]['price'].idxmax()
trough_price = row['price']
trough_date = index
drawdown_value = row['drawdown']
results.append({
'peak_date': peak_date,
'trough_date': trough_date,
'peak_price': peak_price,
'trough_price': trough_price,
'drawdown': drawdown_value
})
last_peak = None
return results
# Test data
test_prices = [100, 105, 102, 110, 108, 95, 98, 120, 115, 113, 90, 92, 130, 125, 118]
# Running the function with the test data
drawdowns = detect_drawdown(test_prices, threshold=0.2)
for drawdown in drawdowns:
print(drawdown)
```
### 說明
1. **數據處理**:
- 使用 `pandas` 的 DataFrame 將價格列表轉化為表格格式,並添加日期索引。
- `cummax()` 方法計算從頭到當前行的最大價格,以確定頂點價格。
- 計算回撤為 `(peak - current price) / peak`。
2. **識別回撤事件**:
- 遍歷所有超過閾值的回撤事件,找出頂點和谷底。
- 當回撤值小於或等於閾值時,記錄該回撤事件。
3. **測試數據**:
- 提供一組測試數據以展示函式的使用。
該函式將返回所有符合條件的回撤事件,包括其開始和結束日期、頂點價格和谷底價格,以及回撤值。
雖然有產出程式碼且可執行, 但執行後完全無法輸出任何結果, 程式存在邏輯上的根本矛盾 (死邏輯), Gemini 的審查結果摘要如下 :
此程式存在致命且荒謬的互斥邏輯(Dead Code),迴圈中的條件式 if row['drawdown'] <= threshold 永遠不會成真,因為一個數值不可能同時「大於 0.2」又「小於等於 0.2」,導致輸出永遠是空串列 []。其次,它誤把谷底(Trough)當成高點(Peak),它把比當前價格更低(row['price'] < ...)的點指派給 last_peak,變成一路找更低的價格,找出來的明明是波段谷底(Trough),它卻將變數命名為 last_peak,再次印證此模型完全沒有「起跌高點」與「回撤谷底」的語意心智模型。最後是空值的處理存在邊界隱患,題目要求「處理空資料」,但如果使用者傳入 None,len(None) 會直接噴出 TypeError。
總評 : Phi 4 輸出的程式程式結構最工整, 排版乾淨, 註解完整, 有自建測試資料, 甚至知道利用 cummax() 來算高點, 也可執行不噴錯, 但寫出的卻是百分之百的死代碼. 主要是它在進入狀態控制與條件判斷時喪失了對集合交集的基本感知. 綜合前面對 Qwen-2.5 Coding, 與 Gemma4 的測試結果可知, 14B 級別的中小型模型在處理包含狀態轉移, 波段切分, 極值關聯的演算法時, 尚無法獨立完成具備嚴密邏輯的完整程式碼交付.
截至目前為止的測試讓我覺得 14B 模型似乎無法勝任需要複雜演算法的任務, 我詢問 Gemini 是否有方法可讓 14B 模型產出正確可用的程式碼, 答案是肯定的 :
要讓 14B 等級的小模型寫出 100% 正確的複雜時序演算法,關鍵在於「剝奪它的架構決策權」。小模型之所以會崩潰,是因為「自由發揮」時它必須同時處理金融語意、狀態機邏輯、邊界保護與 pandas 索引。解決方案是採用「演算法虛擬碼+向量化骨架約束+禁令清單(Negative Constraints)」的三位一體提示詞工程。
它建議將提示詞修改為 :
你是一位嚴謹的量化工程師。請為我實作 Python 函式 `detect_drawdown(prices, threshold=0.2)`。
【演算法指定邏輯(必須嚴格依此實作,不得自行發明迴圈或自創狀態機)】:
1. 防禦性檢查:
- 檢查 `prices is None` 或為空,若是則直接回傳符合欄位定義的空 DataFrame。
- 轉為 pd.Series,執行 dropna()。
2. 向量化波段分組(Episode Segmentation):
- 計算歷史累積最高價:`cummax = prices.cummax()`
- 計算回撤比例(負值):`drawdown = (prices - cummax) / cummax`
- 利用是否創歷史新高建立波段編號:`episodes = (prices == cummax).cumsum()`
3. 波段聚合計算(GroupBy):
- 對 `prices.groupby(episodes)` 進行分組迭代:
* 該組第 1 個點(`group.index[0]`, `group.iloc[0]`)必定是該波段的歷史最高點(peak_date, peak_price)。
* 取出該組對應的 `drawdown` 子序列,找出最小回撤值 `min_dd = group_dd.min()`。
* 若 `min_dd <= -threshold`(跌破門檻):
- 谷底日期 `trough_date` 為 `group_dd.idxmin()`。
- 谷底價格 `trough_price` 為 `group.loc[trough_date]`。
- 記錄 peak_date, trough_date, peak_price, trough_price, drawdown (取 min_dd 浮點數)。
4. 回傳格式:
- 回傳包含上述 5 個欄位的 pandas DataFrame。
【嚴格禁令(違反即視為失敗)】:
- 嚴禁使用 `iterrows()`。
- 嚴禁使用 `drawdown.iloc[peak+1:].idxmin()` 這種可能切出空陣列的切片。
- 嚴禁在已經過濾門檻的資料集內部再去比對相反的條件。
- 不要輸出 LaTeX 數學符號,只回傳純 Python 代碼與一組可直接運行的測試範例。
輸出結果為 :
以下是根據你提供的演算法指定邏輯,實現的 `detect_drawdown` 函式。這個函式會檢查輸入的價格序列,計
算歷史最高價,找出回撤區段並檢查是否超過指定閾值。最後,它會以 DataFrame 形式返回符合條件的回撤事
件。
```python
import pandas as pd
def detect_drawdown(prices, threshold=0.2):
# Step 1: Defensive checks
if prices is None or len(prices) == 0:
return pd.DataFrame(columns=['peak_date', 'trough_date', 'peak_price', 'trough_price',
'drawdown'])
# Convert to pd.Series and drop NaNs
prices = pd.Series(prices).dropna()
# Step 2: Episode Segmentation
cummax = prices.cummax()
drawdown = (prices - cummax) / cummax
episodes = (prices == cummax).cumsum()
# Step 3: GroupBy to calculate episodes
results = []
# Group by episodes
for episode, group in prices.groupby(episodes):
group_dd = drawdown.loc[group.index]
# Calculate peak and trough for the episode
peak_date = group.index[0]
peak_price = group.iloc[0]
min_dd = group_dd.min()
if min_dd <= -threshold:
trough_date = group_dd.idxmin()
trough_price = group.loc[trough_date]
drawdown_value = min_dd
# Record the result
results.append({
'peak_date': peak_date,
'trough_date': trough_date,
'peak_price': peak_price,
'trough_price': trough_price,
'drawdown': drawdown_value
})
# Step 4: Return as DataFrame
return pd.DataFrame(results)
# Test data
test_prices = [100, 105, 102, 110, 108, 95, 98, 120, 115, 113, 90, 92, 130, 125, 118]
# Running the function with the test data
drawdowns = detect_drawdown(test_prices, threshold=0.2)
print(drawdowns)
```
### 測試結果說明
這段程式碼根據你的要求,將會處理價格序列,並計算出從歷史高點回撤超過閾值的事件。測試數據
`test_prices` 可以幫助檢查是否正確地識別和回報了這些回撤事件。
- **防禦性檢查**:確保輸入有效,並移除任何可能的 `NaN` 值。
- **波段分組**:使用歷史最高價和波段編號來分組和計算回撤。
- **波段聚合計算**:為每個波段計算回撤,並檢查是否超過閾值。
- **結果回傳**:以 DataFrame 的形式返回所有符合條件的回撤事件。
這樣的實現確保了每一步都遵循你的演算法指定邏輯,而且不使用被禁止的函式或操作。
經 Gemini 審查, 上面的程式碼完全正確且實測執行結果精準無誤, 這份輸出展現了當 14B 模型被鎖定架構與虛擬碼後所能達到的最高執行品質ㄝ, 可見當提示詞將演算法複雜度降解為語法翻譯題時, 14B 模型的高速代碼生成能力才能真正轉化為可靠的生產力.
這表示在 RTX 3060 本機運行的 14B 模型時, 如果讓模型獨立構思程式架構, 容易在邊界條件, 時序狀態機與索引對齊上踩坑. 但只要架構師在 Prompt 中給定精確的狀態劃分公式 (例如 cumsum() 函式) 與負面約束, 它也能寫出完全不輸頂級雲端模型的乾淨且 100% 正確的程式碼.
沒有留言 :
張貼留言