中文

机器学习预测纤维材料力学性能:从数据准备到模型部署

问题的本质

纤维生物材料的力学性能(杨氏模量、极限强度、断裂韧性)取决于大量因素:纤维直径、取向分布、交联密度、含水量、温度、应变率……传统的单变量回归只能处理线性关系,而纤维网络的高度非线性行为需要机器学习来捕捉。

但材料科学的 ML 有个特殊挑战:数据少。你不可能像互联网公司那样收集百万条实验数据——一篇论文可能只有几十个样本。

本文的策略是:在数据稀缺的约束下,用合理的特征工程和模型选择得到可靠的预测。

第一步:数据准备

典型的数据长什么样


import pandas as pd
import numpy as np

data = pd.DataFrame({
    "fiber_diameter_nm": [45, 52, 48, 55, 50],
    "orientation_std_deg": [12, 22, 8, 18, 15],
    "crosslink_density_pct": [2.5, 1.8, 3.2, 2.0, 4.1],
    "water_content_pct": [15, 22, 10, 18, 8],
    "strain_rate_per_s": [0.01, 0.05, 0.01, 0.1, 0.01],
    "youngs_modulus_GPa": [2.8, 1.9, 3.5, 2.3, 4.0],
    "ultimate_strength_MPa": [120, 85, 150, 105, 170],
})

关键预处理步骤


from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, QuantileTransformer

# 分离特征和目标
feature_cols = [c for c in data.columns if c not in 
    ("youngs_modulus_GPa", "ultimate_strength_MPa")]
X = data[feature_cols].values
y_modulus = data["youngs_modulus_GPa"].values
y_strength = data["ultimate_strength_MPa"].values

# 小规模数据:保留 20% 测试,其余做交叉验证
X_train, X_test, y_train, y_test = train_test_split(
    X, y_modulus, test_size=0.2, random_state=42
)

# 标准化(对基于距离/梯度的模型很重要)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

第二步:特征工程

利用领域知识构造交互特征

纤维材料的力学性能通常有物理意义明确的交互关系:


def add_domain_features(df):
    """加入材料科学领域知识的交互特征"""
    df = df.copy()
    # 交联密度 × 纤维直径:粗纤维高交联的协同效应
    df["crosslink_x_diameter"] = (df["crosslink_density_pct"] * 
                                    df["fiber_diameter_nm"])
    # 取向标准差与含水量的比值:无序 + 湿态的弱化效应
    df["orient_water_ratio"] = (df["orientation_std_deg"] / 
                                 (df["water_content_pct"] + 1e-3))
    # 应变率敏感指数近似
    df["strain_rate_log"] = np.log10(df["strain_rate_per_s"] + 1e-9)
    return df

data_aug = add_domain_features(data)

第三步:模型选择与评估

核心原则:数据少 → 选偏差高的模型,配合强正则化。


from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF, WhiteKernel
from sklearn.model_selection import cross_val_score, RepeatedKFold

# 小样本交叉验证策略
cv = RepeatedKFold(n_splits=5, n_repeats=10, random_state=42)

models = {
    "RandomForest": RandomForestRegressor(
        n_estimators=200, max_depth=5, 
        min_samples_leaf=2, random_state=42
    ),
    "GradientBoosting": GradientBoostingRegressor(
        n_estimators=100, max_depth=3,
        learning_rate=0.05, random_state=42
    ),
    "GaussianProcess": GaussianProcessRegressor(
        kernel=RBF() + WhiteKernel(),
        normalize_y=True, random_state=42
    ),
}

for name, model in models.items():
    scores = cross_val_score(model, X_train_scaled, y_train, 
                             cv=cv, scoring="neg_mean_absolute_error")
    print(f"{name}: MAE = {-scores.mean():.3f} ± {scores.std():.3f} GPa")

为什么选这些模型

模型小数据优势要注意
-------------------------
Random Forest对超参数不敏感,自带特征重要性max_depth 要小
Gradient Boosting精度高,可处理非线性容易过拟合,lr 要低
Gaussian Process自带不确定性估计,适合小样本计算量 O(n³),n>1000 慎用

第四步:不确定性很重要

材料科学中,只说"预测模量 2.8 GPa"不够,你需要给出置信区间:


from sklearn.ensemble import RandomForestRegressor

def predict_with_uncertainty(model, X, n_iterations=100):
    """用 Bootstrap 估计预测不确定性"""
    predictions = np.zeros((n_iterations, len(X)))
    for i in range(n_iterations):
        idx = np.random.choice(len(X_train_scaled), len(X_train_scaled))
        model.fit(X_train_scaled[idx], y_train[idx])
        predictions[i] = model.predict(X)
    return np.mean(predictions, axis=0), np.std(predictions, axis=0)

rf = RandomForestRegressor(n_estimators=100, max_depth=5, random_state=42)
mean_pred, std_pred = predict_with_uncertainty(rf, X_test_scaled)

for i in range(len(mean_pred)):
    print(f"Sample {i}: {mean_pred[i]:.2f} ± {std_pred[i]:.2f} GPa "
          f"(actual: {y_test[i]:.2f})")

第五步:特征重要性——告诉老板为什么

ML 模型不仅要做预测,还要帮助理解物理机制:


import matplotlib.pyplot as plt

rf.fit(X_train_scaled, y_train)
importances = rf.feature_importances_
indices = np.argsort(importances)[::-1]

fig, ax = plt.subplots(figsize=(8, 5))
ax.barh(range(len(indices)), importances[indices], align="center")
ax.set_yticks(range(len(indices)))
ax.set_yticklabels([feature_cols[i] for i in indices])
ax.set_xlabel("Feature Importance")
ax.set_title("What Drives Fiber Mechanics?")
ax.invert_yaxis()
plt.tight_layout()
plt.savefig("feature_importance.pdf", dpi=150, bbox_inches="tight")

进阶方向

数据多起来之后,可以考虑:

  • 图神经网络 (GNN) —— 把纤维网络建模为图,每个纤维是节点,交点连边
  • 迁移学习 —— 在大量仿真数据上预训练,在少量实验数据上微调
  • 主动学习 —— 模型告诉你下一个该做哪组实验最有效
  • 物理信息神经网络 (PINN) —— 把本构方程作为约束注入神经网络

要点总结

  1. 数据少不是不做的理由 — 贝叶斯方法和高斯过程专为小样本设计
  2. 特征工程比模型重要 — 领域知识驱动的特征能补上数据量的不足
  3. 必须报告不确定性 — 不然审稿人会问
  4. 开源你的代码和数据 — GitHub 上的可复现代码会让论文更有说服力

代码获取

本文完整代码可在 GitHub 获取(持续更新中)。

💬 Questions or Feedback?

This blog is actively maintained by a PhD researcher. Reach out on GitHub for collaborations or corrections.

View on GitHub