ニューラルネットワークは、特徴量を重み付きで組み合わせ、非線形な関係を学習するモデルです。リハビリテーション研究では、退院時 FIM 予測、歩行解析、転倒予測などに応用できます。一方で、小規模データでは過学習しやすく、線形モデルや木系モデルとの比較が欠かせません。本稿では、深層学習に進む前の基礎として、MLP・活性化関数・損失関数・バックプロパゲーションを整理します[1]。
この記事は、CNN・Transformer などを理解する前の土台です[4]。ここで扱う MLP は表形式データにも使えますが、医療データでは症例数・欠測・施設差・評価時点の違いが性能を大きく左右します。ロジスティック回帰 や 正則化線形モデル を、必ず比較の基準に置きます。表形式予測の有力候補として ランダムフォレスト や 勾配ブースティング も同じ評価設計で並べます。MLP の過学習を体感的に確認するには 14·01 過学習デモ、評価設計は 14·02 交差検証デモ と併読すると理解が早まります。
// 01 · LEARN OUTCOMESこの記事で学ぶこと
- パーセプトロンと MLP の違いを説明できるようになる。
- sigmoid・tanh・ReLU・Leaky ReLU・GELU の使い分けを理解する。
- 交差エントロピー・MSE・バックプロパゲーションの役割を整理する。
- リハ研究で MLP を使う際の過学習対策と報告項目を確認する。
// 02 · CONCLUSIONまず結論
// 03 · FIGURE図で見るニューラルネットワーク
図1では、パーセプトロンから MLP への拡張を示します。入力層では年齢・FIM・麻痺の重症度などが入り、隠れ層でそれらを重み付きで組み合わせ、出力層で自宅退院や転倒リスクなどを予測します。
図2では、活性化関数の形を比較します。sigmoid は 0〜1 に押し込む関数、tanh は −1〜1 に押し込む関数、ReLU は負の値を 0 にして正の値を通す関数、Leaky ReLU は負の側にも小さな傾きを残します。
// 04 · CLINICALリハ研究での使いどころ
退院時 FIM 合計点や歩行自立を予測する研究では、MLP を候補にできます。年齢・発症からの日数・入院時 FIM・SIAS・認知機能などを入力します。ただし、症例数が少ない場合は ロジスティック回帰 や 正則化線形モデル が安定することがあります。MLP は「比較対象のひとつ」として位置づけます。
10m 歩行・TUG・加速度・左右差・歩幅変動などを使うと、特徴量同士の関係は非線形になります。たとえば、歩行速度だけでなく、歩幅変動と認知機能の組み合わせが効く場合があります。MLP はこのような交互作用を学習しやすいモデルです。ただし、センサーデータ由来の特徴量では標準化が重要です。
小規模研究で深い MLP を使うと、訓練データを覚えやすくなります。AUC が高く見えても、外部データで下がることがあります。Dropout・L2 正則化・Early Stopping は有用ですが、症例数不足そのものを解決する方法ではありません。過学習 の典型例として確認します。
多施設データでは、MLP が線形モデルより良い場合があります。ただし、施設差を学習してしまう危険があります。GroupKFold で施設をまたいだ評価を行うと、汎化性能を確認しやすくなります。施設 ID を単純に入れるかどうかも、研究目的に応じて慎重に整理します。
// 05 · THEORY仕組みを臨床研究目線で理解する
パーセプトロンは、ニューラルネットワークの最小単位です。入力特徴量に重みをかけ、足し合わせ、バイアスを加え、活性化関数を通します。ロジスティック回帰 に近い考え方から始まります。
Perceptron:
z = w1*x1 + w2*x2 + ... + wp*xp + b
y = f(z)
x: input features
w: weights
b: bias
f: activation function
MLP は、この変換を複数段に重ねたモデルです。隠れ層が 1 つでも、十分なユニットがあれば広い関数を近似できます。これは Universal Approximation Theorem と呼ばれます[2]。ただし、近似できることと、少数例で安定して学習できることは別です。
活性化関数は、非線形性を入れる部品です。これがないと、何層重ねても線形変換に近くなります。sigmoid は出力が飽和しやすく、深い層では勾配が小さくなることがあります。ReLU は計算が軽く、深層学習でよく使われます[3]。
Common activations:
sigmoid(z) = 1 / (1 + exp(-z))
tanh(z) = (exp(z) - exp(-z)) / (exp(z) + exp(-z))
ReLU(z) = max(0, z)
LeakyReLU(z) = z if z >= 0 else 0.01*z
損失関数は、予測の外れ具合を数値化します。回帰では MSE を使うことが多く、分類では交差エントロピーを使います。医療予測では、AUC だけでなく Brier score や calibration も確認します。
Regression loss:
MSE = mean((y_true - y_pred)^2)
Binary classification loss:
LogLoss = - mean(y*log(p) + (1-y)*log(1-p))
バックプロパゲーションは、誤差を出力側から入力側へ戻す計算です。連鎖律を使い、各重みをどちらに動かすかを決めます。臨床的には、「どの特徴量が重要か」ではなく、モデル内部の重みを更新する手順です。解釈手法とは分けて考えます。
Backpropagation by chain rule:
z = w*x + b
y_hat = f(z)
L = loss(y, y_hat)
dL_dw = dL_dyhat * dyhat_dz * dz_dw
過学習対策には、L2 正則化・Dropout・Batch Normalization・Early Stopping があります。L2 正則化は大きすぎる重みに罰則をかけ、Dropout は学習中に一部のユニットを無効化、Batch Normalization は層の入力分布を安定させ、Early Stopping は検証性能が悪化する前に学習を止めます。
// 06 · IMPLEMENTATION · PYTHONscikit-learn で MLP を安全に試す
実患者データを扱う前に、倫理審査・個人情報保護・施設ルール・データ利用条件を確認します。ここでは教育用の仮想データ example_rehab_dataset.csv を使います[5]。MLP は距離や勾配のスケールに敏感です。数値特徴量は Pipeline 内で標準化します。
# Educational example only.
# Check ethics approval, privacy rules, and institutional policies
# before using real clinical data.
import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import make_scorer
from sklearn.metrics import roc_auc_score, brier_score_loss
from sklearn.model_selection import GroupKFold, GridSearchCV
from sklearn.model_selection import cross_validate
from sklearn.neural_network import MLPClassifier
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
RANDOM_STATE = 42
# Example columns:
# age, days_from_onset, fim_motor_adm, fim_cog_adm,
# sias_motor, tug_sec, gait_speed, diagnosis_group,
# facility_id, home_discharge
df = pd.read_csv("example_rehab_dataset.csv")
target = "home_discharge"
group_col = "facility_id"
numeric_features = [
"age",
"days_from_onset",
"fim_motor_adm",
"fim_cog_adm",
"sias_motor",
"tug_sec",
"gait_speed",
]
categorical_features = ["diagnosis_group"]
X = df[numeric_features + categorical_features]
y = df[target].astype(int)
groups = df[group_col]
numeric_preprocess = Pipeline(steps=[
("imputer", SimpleImputer(strategy="median")),
("scaler", StandardScaler()),
])
categorical_preprocess = Pipeline(steps=[
("imputer", SimpleImputer(strategy="most_frequent")),
("onehot", OneHotEncoder(handle_unknown="ignore")),
])
preprocess = ColumnTransformer(transformers=[
("num", numeric_preprocess, numeric_features),
("cat", categorical_preprocess, categorical_features),
])
mlp = MLPClassifier(
hidden_layer_sizes=(64, 32),
activation="relu",
alpha=1e-4,
learning_rate_init=1e-3,
max_iter=500,
early_stopping=True,
validation_fraction=0.15,
n_iter_no_change=20,
random_state=RANDOM_STATE,
)
mlp_pipe = Pipeline(steps=[
("preprocess", preprocess),
("model", mlp),
])
baseline = LogisticRegression(
penalty="l2", C=1.0,
max_iter=1000, class_weight="balanced",
)
baseline_pipe = Pipeline(steps=[
("preprocess", preprocess),
("model", baseline),
])
cv = GroupKFold(n_splits=5)
scoring = {
"roc_auc": "roc_auc",
"brier": make_scorer(
brier_score_loss,
needs_proba=True,
greater_is_better=False,
),
}
for name, pipe in [("logistic", baseline_pipe), ("mlp", mlp_pipe)]:
result = cross_validate(
pipe, X, y, groups=groups, cv=cv,
scoring=scoring,
return_train_score=True,
n_jobs=-1,
)
print("\n", name)
print("CV AUC:", result["test_roc_auc"].mean())
print("Train AUC:", result["train_roc_auc"].mean())
print("CV Brier:", -result["test_brier"].mean())
param_grid = {
"model__hidden_layer_sizes": [(32,), (64,), (64, 32)],
"model__alpha": [1e-5, 1e-4, 1e-3],
"model__learning_rate_init": [1e-4, 1e-3],
}
search = GridSearchCV(
estimator=mlp_pipe,
param_grid=param_grid,
scoring="roc_auc",
cv=cv,
n_jobs=-1,
refit=True,
)
search.fit(X, y, groups=groups)
print("Best AUC:", search.best_score_)
print("Best params:", search.best_params_)
best_model = search.best_estimator_
proba = best_model.predict_proba(X)[:, 1]
print("Apparent AUC:", roc_auc_score(y, proba))
print("Apparent Brier:", brier_score_loss(y, proba))
# Do not report the apparent scores as final performance.
# Use held-out test data or external validation for final evaluation.
このコードでは、前処理を全データで fit してから分割する手順を避けています。欠測補完・標準化・One-hot encoding は、各 fold の学習データ内で fit されます。これは データリーケージ を防ぐ基本です。
MLP の結果だけを示すのは不十分です。まずロジスティック回帰などのベースラインを置き、AUC・Brier score・calibration・外部検証を比較します。訓練 AUC と検証 AUC の差が大きい場合は、過学習を疑います。
// 07 · MYTHSよくある誤解
- 誤解: ニューラルネットなら何でも学べる
- 表現力は高いものの、小規模データでは過学習しやすい。N=100〜1,000 の臨床研究では、線形モデルや木系モデルが安定することがあります。
- 誤解: 層を深くするほど性能が上がる
- 層を増やすと表現力は増えますが、同時に計算量・勾配消失・過学習のリスクも増えます。表形式データでは、浅い MLP で十分な場合があります。
- 誤解: ReLU を使えば大丈夫
- ReLU は扱いやすい活性化関数ですが、入力が負側に偏るとユニットが反応しにくくなります(dying ReLU)。Leaky ReLU や GELU を検討する場面もあります。
- 誤解: Dropout を入れれば過学習しない
- Dropout は過学習対策の一つですが、症例数不足や施設差の問題は解決しません。交差検証・外部検証・モデルの単純化を併用します。
// 08 · WRITING論文 Methods に書くこと
MLP を論文で使う場合、モデル名だけでは不十分です。少なくとも、入力特徴量・前処理・隠れ層の構成・活性化関数・損失関数・正則化・学習条件を記載します。さらに、ハイパーパラメータの探索範囲と交差検証の方法を明記します。
- 予測対象を明記: 自宅退院、歩行自立、退院時 FIM など。
- 入力特徴量の時点を揃える: 退院後情報は入れない。
- 欠測補完・標準化・カテゴリ変数処理を記載。
- 隠れ層・ユニット数・活性化関数を記載。
- L2 正則化・Dropout・Early Stopping の設定を記載。
- 乱数 seed・CV 方法・施設分割の扱いを記載。
- 比較したベースラインモデルを記載。
- AUC・Brier score・calibration を報告。
査読では、MLP を使う理由が問われやすいです。症例数に対してモデルが複雑すぎないかも見られます。「線形では扱いにくい非線形性を検討した」だけでは弱い場合があります。ロジスティック回帰・正則化線形・Random Forest・勾配ブースティング との比較があると説明しやすくなります。
TRIPOD+AI では、予測モデルの開発・検証・報告の透明性が重視されます[6]。PROBAST+AI では、バイアスと適用可能性の評価が重視されます[7]。MLP の性能だけでなく、データ分割・欠測・過学習・外部検証の扱いを整理します。
// 09 · CHECKLIST実装前チェック
- 01MLP を使う理由を、線形モデルとの比較で説明できる
- 02数値特徴量は Pipeline 内で標準化している
- 03欠測補完を全データで fit していない
- 04症例数に対して隠れ層が大きすぎない
- 05Early Stopping の検証データがテストデータと混ざっていない
- 06AUC だけでなく calibration も確認している
- 07施設差がある場合、GroupKFold を検討している
- 08外部検証を最終評価として分けている
// 10 · QUIZ理解度チェック
-
Q1MLP で StandardScaler が重要な主な理由はどれですか。
- 木構造を作るため
- 勾配に基づく学習が特徴量スケールの影響を受けるため
- 欠測値が自動で消えるため
- 外部検証が不要になるため
SHOW ANSWER
B. MLP は勾配で重みを更新します。特徴量スケールが大きく違うと、学習が不安定になります。 -
Q2小規模データで深い MLP を使うときの主な懸念はどれですか。
- 過学習
- Gini importance の偏り
- カーネル幅の不足
- 木の剪定不足
SHOW ANSWER
A. 深い MLP はパラメータが多く、小規模データでは訓練データを覚えやすくなります。 -
Q3分類問題でよく使う損失関数はどれですか。
- 交差エントロピー
- Ward 法
- PCA の固有値
- Silhouette
SHOW ANSWER
A. 二値分類や多クラス分類では交差エントロピーがよく使われます。 -
Q4MLP の報告で特に重要な比較対象はどれですか。
- 何も比較しない
- 線形・正則化モデルなどのベースライン
- 患者 ID
- 欠測値そのもの
SHOW ANSWER
B. 医療データでは、単純なベースラインが安定することがあります。
// 11 · FAQよくある質問
- リハ研究で MLP は積極的に使うべきですか?
- 症例数や交互作用の強さに依存します。N=100〜1,000 程度の小〜中規模研究では、ロジスティック回帰 や 正則化線形・勾配ブースティング のほうが安定することが多くあります。MLP は比較対象のひとつとして位置づけ、AUC・Brier score・calibration を並べて判断します。
- 活性化関数はどれを選べばよいですか?
- 表形式データで MLP を試す場合は ReLU が標準的な選択です。深い層で勾配消失が問題になる場合や、負の側にも情報を残したい場合は Leaky ReLU や GELU を検討します。出力層は分類なら sigmoid/softmax、回帰なら線形(恒等)を使います。
- MLP で過学習を抑える基本パターンは?
- (1) 数値特徴量を Pipeline 内で標準化する、(2) L2 正則化(alpha)を入れる、(3) Early Stopping で検証性能が悪化する前に学習を止める、(4) Dropout や層を浅くしてパラメータ数を減らす、(5) 過学習 の章を参照して交差検証と外部検証で汎化性能を確認する、の組み合わせが基本です。
// REF参考文献
- Rumelhart DE, Hinton GE, Williams RJ. Learning representations by back-propagating errors. Nature 1986;323(6088):533-536.
- Hornik K, Stinchcombe M, White H. Multilayer feedforward networks are universal approximators. Neural Networks 1989;2(5):359-366.
- Glorot X, Bengio Y. Understanding the difficulty of training deep feedforward neural networks. AISTATS 2010;9:249-256.
- LeCun Y, Bengio Y, Hinton G. Deep learning. Nature 2015;521(7553):436-444.
- Pedregosa F, Varoquaux G, Gramfort A, et al. Scikit-learn: Machine learning in Python. Journal of Machine Learning Research 2011;12:2825-2830.
- Collins GS, Moons KGM, Dhiman P, et al. TRIPOD+AI statement: updated guidance for reporting clinical prediction models that use regression or machine learning methods. BMJ 2024;385:e078378.
- Moons KGM, Damen JAA, Kaul T, et al. PROBAST+AI: an updated quality, risk of bias, and applicability assessment tool for prediction models using regression or artificial intelligence methods. BMJ 2025;388:e082505.