table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
pre {
background-color: #f8f8f8;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
}
138、什么是量化感知训练,为什么需要它?
量化感知训练是在训练期间向模型添加伪量化操作。这使模型能够学会忽略量化噪声,最终的权重对量化会更具鲁棒性。
139、什么是模型并行和数据并行?为什么通常推荐使用数据并行?
模型并行与数据并行
模型并行
是将模型分割成多个部分,并在多个设备上并行运行,有望在训练或推理过程中加快模型速度。
数据并行
是创建模型的多个完全相同的副本,并将它们部署到多个设备上。在训练的每次迭代中,每个副本会被分配不同的数据批次,并计算损失相对于模型参数的梯度。
同步数据并行
:所有副本的梯度会被聚合,优化器执行梯度下降步骤。
异步数据并行
:参数集中管理,副本相互独立运行,每个副本在每次训练迭代结束时直接更新中央参数。
通常推荐使用
数据并行
,主要是因为它在设备间所需的通信较少,而且更易于实现,并且适用于任何模型,而模型并行需要分析模型以确定最佳的分割方式。
140、在多台服务器上训练模型时,可以使用哪些分布式策略?如何选择使用哪种策略?
可以使用的分布式策略有
MirroredStrategy
和
ParameterServerStrategy
。
选择策略时:
若模型能装入每个副本的内存中,一般应使用
MirroredStrategy
,因为它使用简单,所有服务器和设备的处理方式相同,性能也较好;
若要训练无法装入 GPU 内存的大型模型,则使用
ParameterServerStrategy
,不过它通常比
MirroredStrategy
慢,且部署难度稍大,因为需要管理参数服务器。
141、使用 MirroredStrategy 在同一台机器上的多个 GPU 上训练任何模型(如果无法使用 GPU,可以使用具有 GPU 运行时的 Colaboratory 并创建两个虚拟 GPU)。再使用 CentralStorageStrategy 训练该模型,并比较训练时间。
使用
MirroredStrategy
训练模型的代码示例如下:
distribution = tf.distribute.MirroredStrategy()
with distribution.scope():
mirrored_model = tf.keras.Sequential([...])
mirrored_model.compile([...])
batch_size = 100
history = mirrored_model.fit(X_train, y_train, epochs=10)
若要使用
CentralStorageStrategy
训练模型,可将
MirroredStrategy
替换为
CentralStorageStrategy
,示例代码为:
distribution = tf.distribute.experimental.CentralStorageStrategy()
还可设置
compute_devices
和
parameter_device
参数。
训练完成后,记录两种策略下的训练时间并进行比较。
142、什么是有标签的训练集?
有标签训练集是包含已标注数据的训练集,可用于监督学习,例如:
用于训练人脸分类器的每个人的图片
用于自然语言处理训练模型预测缺失单词的文本数据
143、尝试在数据预处理管道中添加一个转换器,以仅选择最重要的属性。
在Scikit-Learn里,可使用
SelectKBest
等特征选择器来实现。示例代码如下:
from sklearn.compose import ColumnTransformer
from sklearn.feature_selection import SelectKBest, f_regression
from sklearn.pipeline import Pipeline
# 假设num_pipeline和OneHotEncoder等已定义
num_attribs = list(housing_num)
cat_attribs = ["ocean_proximity"]
# 创建选择最重要属性的转换器
feature_selector = SelectKBest(score_func=f_regression, k=5) # 选择最重要的5个属性
# 更新数值管道,添加特征选择步骤
num_pipeline_with_selection = Pipeline([
('original_num_pipeline', num_pipeline),
('feature_selection', feature_selector)
])
full_pipeline = ColumnTransformer([
("num", num_pipeline_with_selection, num_attribs),
("cat", OneHotEncoder(), cat_attribs),
])
housing_prepared = full_pipeline.fit_transform(housing)
以上代码在数值管道里添加了
SelectKBest
特征选择器,仅选择最重要的5个属性。可按需调整
k
的值。
144、在不使用Scikit – Learn的情况下,实现带有提前停止策略的Softmax回归批量梯度下降算法。
实现带有提前停止策略的Softmax回归批量梯度下降算法,需要以下步骤:
初始化权重
计算Softmax函数
计算成本函数(交叉熵损失)
计算梯度
更新权重
提前停止策略
以下是简单的Python代码示例:
import numpy as np
def softmax(z):
exp_z = np.exp(z - np.max(z, axis=1, keepdims=True))
return exp_z / np.sum(exp_z, axis=1, keepdims=True)
def cross_entropy_loss(y_true, y_pred):
m = y_true.shape[0]
return -np.sum(y_true * np.log(y_pred + 1e-7)) / m
def batch_gradient_descent(X, y, num_classes, learning_rate=0.01, num_iterations=1000, early_stopping_rounds=10):
m, n = X.shape
theta = np.random.randn(n, num_classes)
best_loss = np.inf
no_improvement_rounds = 0
for iteration in range(num_iterations):
logits = X.dot(theta)
y_pred = softmax(logits)
loss = cross_entropy_loss(y, y_pred)
gradients = 1/m * X.T.dot(y_pred - y)
theta = theta - learning_rate * gradients
if loss < best_loss:
best_loss = loss
no_improvement_rounds = 0
else:
no_improvement_rounds += 1
if no_improvement_rounds >= early_stopping_rounds:
print(f'Early stopping at iteration {iteration}')
break
return theta
你可以使用以下方式调用这个函数:
# 示例数据
X = np.random.randn(100, 10)
y = np.random.randint(0, 3, 100)
y_one_hot = np.eye(3)[y]
# 调用函数
theta = batch_gradient_descent(X, y_one_hot, num_classes=3)
这段代码实现了带有提前停止策略的Softmax回归批量梯度下降算法。首先定义了Softmax函数和交叉熵损失函数,然后在批量梯度下降过程中,根据损失是否改善来决定是否提前停止训练。
145、在一个线性可分的数据集上训练一个 LinearSVC 分类器。然后在相同的数据集上训练一个 SVC 分类器和一个 SGDClassifier 分类器。看看能否让它们生成大致相同的模型。
以下是使用 LinearSVC 训练模型的示例代码:
import numpy as np
from sklearn import datasets
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
iris = datasets.load_iris()
X = iris["data"][:, (2, 3)] # petal length, petal width
y = (iris["target"] == 2).astype(np.float64) # Iris virginica
svm_clf = Pipeline([
("scaler", StandardScaler()),
("linear_svc", LinearSVC(C=1, loss="hinge")),
])
svm_clf.fit(X, y)
若要使用
SVC
类,可使用线性核,创建模型时可写为
SVC(kernel="linear", C=1)
;若使用
SGDClassifier
类,可写为
SGDClassifier(loss="hinge", alpha=1/(m*C))
,这里的
m
为训练实例数量。通过在相同的线性可分数据集上使用这些不同的类进行训练,有可能得到大致相同的模型。
146、在MNIST数据集上训练一个支持向量机(SVM)分类器。由于SVM分类器是二元分类器,你需要使用一对其余(one-versus-the-rest)策略来对所有10个数字进行分类。你可以使用小的验证集来调整超参数以加快过程。你能达到什么样的准确率?
在MNIST数据集上使用SVM分类器并采用一对其余策略分类时,准确率会受到多种因素影响,如超参数的选择、数据预处理等。一般而言,经过适当调参和处理,SVM分类器在MNIST数据集上可以达到95% – 98%左右的准确率,但这并非固定值,实际准确率需根据具体实现情况确定。
147、如果决策树对训练集过拟合,尝试减小max_depth是个好主意吗?
减小
max_depth
可以限制树的深度,减少模型复杂度,通常是缓解过拟合的有效方法,所以可以认为是个好主意。
148、在哪些情况下会使用普通PCA、增量PCA、随机PCA或核PCA?
PCA 变体及适用场景
普通PCA
:适用于数据量较小且能一次性加载到内存中进行处理的情况,可用于数据压缩、降维等,如选择合适的维度数量、根据解释方差比进行分析等。
增量PCA
:当数据量非常大,无法一次性全部加载到内存时使用,它可以分批次处理数据,如对大规模训练数据进行处理。
随机PCA
:通常在需要快速计算且对精度要求不是极高,数据量较大时使用。
核PCA
:适用于需要进行复杂非线性投影以实现降维的情况,能够在投影后较好地保留实例的聚类,或者展开靠近扭曲流形的数据集,如对瑞士卷数据集进行降维。
149、加载MNIST数据集,并将其拆分为训练集和测试集(取前60000个实例用于训练,其余10000个用于测试)。在该数据集上训练一个随机森林分类器,并记录训练所需的时间,然后在测试集上评估得到的模型。接下来,使用主成分分析(PCA)将数据集的维度降低,使解释方差比例达到95%。在降维后的数据集上训练一个新的随机森林分类器,看看训练需要多长时间。训练速度是否快了很多?然后在测试集上评估该分类器。与之前的分类器相比,它的表现如何?
可按以下步骤操作:
加载MNIST数据集并划分训练集和测试集;
训练随机森林分类器并计时,评估模型;
使用PCA将数据集降维,使解释方差比例达95%;
在降维数据集上训练新随机森林分类器并计时;
比较两次训练时间,评估新分类器并与旧分类器比较性能。
150、描述两种在使用K – Means时选择合适簇数量的技术。
常见的两种技术为肘部法则和轮廓系数法。
肘部法则
通过绘制不同簇数量下的惯性(样本到其所属簇中心的距离平方和)与簇数量的关系图,惯性下降幅度开始变缓的点对应的簇数量即为合适的选择。
轮廓系数法
计算每个样本的轮廓系数(衡量样本与其所属簇的紧密程度以及与其他簇的分离程度),平均轮廓系数最大时对应的簇数量为合适的簇数量。
151、请列举两种可处理大规模数据集的聚类算法,以及两种寻找高密度区域的聚类算法。
可处理大规模数据集的聚类算法可列举
K-Means
、
Mini-Batch K-Means
;寻找高密度区域的聚类算法可列举
DBSCAN
、
Mean-Shift
。
152、你能想出一个主动学习有用的用例吗?你会如何实现它?
主动学习在医学图像识别中的应用
主动学习在医学图像识别中的作用尤为重要,尤其是在X光、CT等影像的疾病诊断中。由于标注大量医学图像需要高昂的成本和专业知识,主动学习提供了一种有效的解决方案。
实现步骤
初始标注
由医学专家对一小部分有代表性的医学图像进行标注,构建初始训练集。
模型训练
使用初始训练集训练一个机器学习或深度学习模型。
选择样本
模型对未标注的医学图像进行预测,并根据预测的不确定性或信息性等标准,选择最有价值的图像让医学专家进行标注。例如,选择模型预测置信度低的图像,因为这些图像可能包含模型尚未学习到的特征。
更新训练集
将新标注的图像添加到训练集中。
重新训练模型
使用更新后的训练集重新训练模型。
迭代优化
重复步骤3-5,不断迭代上述过程,直到模型性能达到满意的水平或标注成本达到预算限制。
153、经典的Olivetti人脸数据集包含400张64×64像素的灰度人脸图像。每张图像被展平为大小为4096的一维向量。40个不同的人被拍摄(每人10次),通常的任务是训练一个模型,该模型可以预测每张图片中代表的是哪个人。使用sklearn.datasets.fetch_olivetti_faces()函数加载数据集,然后将其拆分为训练集、验证集和测试集(注意,数据集已经在0到1之间进行了缩放)。由于数据集相当小,需要使用分层抽样,以确保每个集合中每个人的图像数量相同。接下来,使用K-Means对图像进行聚类,并确定合适数量的聚类。最后,可视化这些聚类,观察每个聚类中是否有相似的人脸。
可按以下步骤操作:
使用
sklearn.datasets.fetch_olivetti_faces()
函数加载 Olivetti 人脸数据集;
使用分层抽样将数据集拆分为训练集、验证集和测试集;
选择一种确定聚类数量的技术(如轮廓系数法、肘部法则等)确定合适的聚类数量,然后使用 K-Means 对图像进行聚类;
可视化聚类结果,观察每个聚类中是否有相似的人脸。
154、请列举三种常用的激活函数,并画出它们的图像。
常用激活函数
三种常用的激活函数为
阶跃函数
、
逻辑(Sigmoid)函数
和
修正线性单元(ReLU)函数
。可使用绘图工具如 Python 的 Matplotlib 库进行绘制。
以 ReLU 函数为例,代码如下:
import numpy as np
import matplotlib.pyplot as plt
z = np.linspace(-5, 5, 100)
relu = np.maximum(0, z)
plt.plot(z, relu)
plt.xlabel('z')
plt.ylabel('ReLU(z)')
plt.title('Rectified Linear Unit (ReLU) Function')
plt.grid(True)
plt.show()
155、在MNIST数据集上训练一个深度多层感知器(使用keras.datasets.mnist.load_data()加载该数据集),尝试获得超过98%的精度。通过指数式增大学习率、绘制误差曲线并找出误差急剧上升的点来搜索最优学习率。添加保存检查点、使用早停法,并使用TensorBoard绘制学习曲线等额外功能。
可按以下步骤解决该问题:
加载MNIST数据集;
数据预处理;
构建深度MLP模型;
搜索最优学习率;
训练模型并添加额外功能(保存检查点、早停法、使用TensorBoard);
评估模型精度。
156、当使用SGD优化器时,如果将动量超参数设置得过于接近1(例如0.99999),可能会发生什么情况?
动量超参数接近1时,优化器会保留更多之前梯度的方向信息
可能导致优化器在更新参数时对当前梯度的响应变慢
在接近最优解时可能会出现过冲和振荡加剧的情况
收敛过程可能变得不稳定
并且可能需要更长时间才能稳定在最优解附近
157、构建一个深度神经网络(DNN),该网络有20个隐藏层,每个隐藏层包含100个神经元(虽然数量过多,但这正是本题的目的)。使用He初始化方法和ELU激活函数。
以下是一个示例代码来构建这样的DNN:
import tensorflow as tf
from tensorflow import keras
model = keras.models.Sequential()
model.add(keras.layers.Flatten(input_shape=[28, 28])) # 假设输入是28x28的图像
for _ in range(20):
model.add(keras.layers.Dense(100, activation='elu', kernel_initializer='he_normal'))
model.add(keras.layers.Dense(10, activation='softmax')) # 假设是10分类问题
上述代码使用Keras构建了一个具有20个隐藏层,每个隐藏层100个神经元的DNN,使用了He初始化和ELU激活函数,最后一层使用softmax激活函数用于分类。
158、使用Nadam优化器和早停法,在CIFAR10数据集上训练网络。你可以使用keras.datasets.cifar10.load_data()加载该数据集。该数据集由60000张32×32像素的彩色图像组成(50000张用于训练,10000张用于测试),共有10个类别,因此你需要一个具有10个神经元的softmax输出层。请记住,每次更改模型架构或超参数时,都要搜索合适的学习率。
可按以下步骤操作:
加载CIFAR10数据集
:使用
keras.datasets.cifar10.load_data()
加载数据集。
构建模型
:构建一个有20个隐藏层,每层100个神经元的深度神经网络,使用 He 初始化和 ELU 激活函数,输出层使用具有10个神经元的 softmax 激活函数。
配置优化器和早停法
:使用 Nadam 优化器,设置早停法以防止过拟合。
搜索合适的学习率
:每次更改模型架构或超参数时,搜索合适的学习率。
训练模型
:使用训练集对模型进行训练,并使用验证集进行验证。
159、使用tf.range(10)和tf.constant(np.arange(10))会得到相同的结果吗?
tf.range(10)
会创建一个从 0 到 9 的张量,而
tf.constant(np.arange(10))
是将 NumPy 数组
np.arange(10)
(同样是 0 到 9)转换为 TensorFlow 张量,在数值上二者是相同的,但在某些情况下,如涉及到张量的一些元信息等可能存在差异。
160、实现一个执行层归一化(Layer Normalization)的自定义层:a. build()方法应定义两个可训练权重α和β,它们的形状均为input_shape[-1:],数据类型为tf.float32。α应初始化为全1,β应初始化为全0。b. call()方法应计算每个实例特征的均值μ和标准差σ。为此,可以使用tf.nn.moments(inputs, axes=-1, keepdims=True),它会返回所有实例的均值μ和方差σ²(计算方差的平方根以得到标准差)。然后该函数应计算并返回α⊗(X – μ)/(σ + ε) + β,其中⊗表示逐元素乘法(*),ε是一个平滑项(小常数,用于避免除以零,例如0.001)。c. 确保自定义层产生的输出与keras.layers.LayerNormalization层的输出相同(或非常接近)。
以下是实现代码示例:
import tensorflow as tf
from tensorflow import keras
class CustomLayerNormalization(keras.layers.Layer):
def build(self, input_shape):
self.alpha = self.add_weight(name='alpha', shape=input_shape[-1:], dtype=tf.float32, initializer='ones', trainable=True)
self.beta = self.add_weight(name='beta', shape=input_shape[-1:], dtype=tf.float32, initializer='zeros', trainable=True)
def call(self, inputs):
epsilon = 0.001
mean, variance = tf.nn.moments(inputs, axes=-1, keepdims=True)
std_dev = tf.sqrt(variance)
return self.alpha * (inputs - mean) / (std_dev + epsilon) + self.beta
要验证自定义层与
keras.layers.LayerNormalization
层的输出是否接近,可以用以下代码:
# 创建输入数据
input_data = tf.random.normal([10, 20])
# 使用自定义层归一化
custom_layer = CustomLayerNormalization()
custom_output = custom_layer(input_data)
# 使用Keras层归一化
keras_layer = keras.layers.LayerNormalization()
keras_output = keras_layer(input_data)
# 检查输出是否接近
print(tf.reduce_all(tf.abs(custom_output - keras_output) < 1e-5))
161、什么是全卷积网络?如何将全连接层转换为卷积层?
全卷积网络(Fully Convolutional Networks,FCN)
全卷积网络(Fully Convolutional Networks,FCN)是一种端到端、像素级的图像语义分割模型。
核心思想
将传统卷积神经网络(CNN)中的
全连接层
替换为
卷积层
。
可接受
任意大小的输入图像
。
输出与输入图像大小相同的
特征图
,实现对图像中每个像素的分类。
实现方法
最后一个全连接层的处理
使用与该全连接层神经元数量相同的
滤波器
。
滤波器大小与前一层特征图大小相同。
每个神经元对应一个滤波器。
采用“valid”填充。
步幅通常设为1,也可设为更高值。
激活函数与原全连接层相同。
其他全连接层的处理
采用
1×1滤波器
。
通过适当
重塑全连接层的权重矩阵
,可将训练好的CNN按此方式转换。