> For AI agents: the complete documentation index is available at https://open-spaced-repetition.github.io/ts-fsrs/zh-TW/llms.txt, the full documentation bundle is available at https://open-spaced-repetition.github.io/ts-fsrs/zh-TW/llms-full.txt.

# 訓練與評估

訓練透過幾次 binding 呼叫把複習歷史跑完。輸入是一份複習記錄 CSV；輸出是可直接交給 `DefaultScheduler` 或自訂 `defineScheduler` 的權重陣列。

範例匯入 `@open-spaced-repetition/binding`。在 Node 中是原生 napi 模組；在瀏覽器中解析為 WASI Preview 1 的 wasm 建置（多執行緒說明見[訓練器概覽](https://open-spaced-repetition.github.io/ts-fsrs/zh-TW/guide/optimizer/index.md)）。

## 把複習記錄轉成項

`convertCsvToFsrsItems` 讀取 CSV 文字，並依卡片把各行歸併為 `FSRSItem`。欄位如下：

| 欄位                | 含義                   |
| ----------------- | -------------------- |
| `card_id`         | 卡片穩定識別碼。             |
| `review_time`     | 複習時間，epoch 毫秒。       |
| `review_rating`   | 評分，1 Again 到 4 Easy。 |
| `review_duration` | 複習耗時，毫秒。             |
| `review_state`    | 複習時的卡片狀態。            |

傳入 `nextDayStartsAt`（新一天開始的小時）以及 IANA 時區（如 `'UTC'`）或固定的 UTC 分鐘偏移。對 `Uint8Array` 輸入，該呼叫同步回傳項：

```ts file="../../../snippets/run-code/optimizer-csv.ts"
import { convertCsvToFsrsItems } from '@open-spaced-repetition/binding'

// One card with two reviews: first review today, second the next day.
const csv = [
  'review_time,card_id,review_rating,review_duration,review_state',
  '1704067200000,card-one,3,1000,0',
  '1704153600000,card-one,4,900,2',
].join('\n')

// The day starts at 04:00 local, in the UTC timezone.
const items = convertCsvToFsrsItems(
  new TextEncoder().encode(csv),
  4,
  'UTC',
  'FSRS-7'
)

console.log(
  JSON.stringify(
    {
      itemCount: items.length,
      reviewsPerItem: items.map((item) => item.reviews.length),
      ratings: items.map((item) => item.reviews.map((review) => review.rating)),
    },
    null,
    2
  )
)

```


▶ 執行程式碼

原本的轉換函式仍回傳陣列。需要一次正規化任意 CSV 卡片識別碼時，使用 `convertCsvToFsrsItemsWithCardIds`：它回傳 `{ items, cardIds }`，串流輸入則回傳 Promise。數值 ID 依本次轉換保留的卡片產生，與排序後的 items 逐項對齊，並非原始識別碼。訓練與直接評估重用同一組 IDs；不要混用不同轉換結果中的 IDs。

`computeParameters` 與 `evaluateWithTimeSeriesSplits` 接受選填的 `options.cardIds`。

```ts file="../../../snippets/run-code/optimizer-card-ids.ts"
import {
  computeParameters,
  convertCsvToFsrsItemsWithCardIds,
  evaluateWithTimeSeriesSplits,
} from '@open-spaced-repetition/binding'

const response = await fetch(`${import.meta.env.BASE_URL}/revlog.csv`, {
  cache: 'force-cache',
})
if (!response.ok) throw new Error(`revlog.csv: ${response.status}`)
if (!response.body) throw new Error('revlog.csv: empty response body')
console.log('Response received. Converting reviews and training…')

const dataset = await convertCsvToFsrsItemsWithCardIds(
  response.body,
  4,
  'UTC',
  'FSRS-7'
)
const optimizedWeights = await computeParameters(dataset.items, {
  modelVersion: 'FSRS-7',
  enableShortTerm: true,
  cardIds: dataset.cardIds,
})
const metrics = await evaluateWithTimeSeriesSplits(dataset.items, {
  modelVersion: 'FSRS-7',
  enableShortTerm: true,
  cardIds: dataset.cardIds,
})

console.log(JSON.stringify({ optimizedWeights, metrics }, null, 2))

```


▶ 執行程式碼

CSV 轉換、訓練、評估與排程必須選擇相同的 `modelVersion`（預設 `'FSRS-7'`，也可選 `'FSRS-6'`）。將它作為 `convertCsvToFsrsItems` 的第四個參數，並傳入訓練與評估選項；排程時使用 `DefaultScheduler({ version: modelVersion, weights })`。FSRS-7 產生 34 個權重，依本地學習日的實際時長正規化並保留小數與同日間隔；FSRS-6 產生 21 個權重，使用整數學習日。因此同日的後續複習也能參與 FSRS-7 訓練。

## 訓練權重

`computeParameters(items, options)` 是非同步的，回傳訓練好的權重。`enableShortTerm` 必填；`numRelearningSteps` 與 `trainingConfig` 選填，`progress` 在訓練期間回報 `(current, total)`：

```ts
const weights = await computeParameters(items, {
  modelVersion: 'FSRS-7',
  enableShortTerm: true,
  enableSchedPenalties: true,
})
```

`enableSchedPenalties` 選填，預設為 `false`。設為 `true` 會在訓練損失中加入 FSRS-7 的間隔增長和短間隔懲罰。它也適用於 `evaluateWithTimeSeriesSplits` 內部的訓練，FSRS-6 會忽略此選項；它不改變排程公式。

`trainingConfig`（epochs、batch size、seed、最大序列長度、學習率與 L2 權重）選填，缺省時使用 binding 的預設值。`computeParameters` 執行真正的訓練迴圈，因此應在 Worker 而非主執行緒中呼叫。[Playground](https://open-spaced-repetition.github.io/ts-fsrs/zh-TW/playground.md)頁的訓練器就在 Web Worker 裡執行同一路徑並即時回報進度。回傳的 `weights` 陣列就是傳給 `DefaultScheduler({ version: modelVersion, weights })` 或 `defineScheduler` 設定、用於替換模型預設值的東西。

## 評估擬合

`evaluateWithTimeSeriesSplits(items, options)` 依時間切分複習歷史，回傳帶 `logLoss` 與 `rmseBins` 的 `ModelEvaluation`，供你判斷訓練權重對留出複習的預測品質。`computeOptimalSteps` 更進一步：給定複習與目標保留率，推薦學習與再學習步驟的時長。

安裝命令與兩種執行環境見[訓練器概覽](https://open-spaced-repetition.github.io/ts-fsrs/zh-TW/guide/optimizer/index.md)。
