在机器学习中,lambda 表达式和闭包用于数据预处理、特征工程、模型构建和闭包。具体应用包括:数据规范化等数据预处理操作。创建新特征或转换现有特征。向模型添加自定义的损失函数、激活函数等组件。利用闭包访问外部变量,用于计算特定特征的平均值等目的。
C++ Lambda 表达式与闭包在机器学习中的应用
在机器学习中,lambda 表达式和闭包在以下方面发挥着至关重要的作用:
1. 数据预处理
立即学习“C++免费学习笔记(深入)”;
通过使用 lambda,您可以轻松地将数据转换、清理和归一化的操作封装成简洁的代码块。例如,以下 lambda 对数据集中的每一行进行规范化:
1
2
3
4
5
6
7
8
9
10
11
|
auto nORMalize = []( const std::vector< double >& row) {
double sum = 0;
for ( auto & value : row) {
sum += value * value;
}
double norm = sqrt (sum);
std::Transform(row.begin(), row.end(), row.begin(), [norm]( double value) {
return value / norm;
});
return row;
};
|
2. 特征工程
lambda 可用于创建新的特征或转换现有的特征。例如,以下 lambda 计算每个数据的某个特定列上的滑动平均值:
1
2
3
4
5
6
7
|
auto moving_average = []( const std::vector< double >& data, int window) {
std::vector< double > avg;
for ( int i = 0; i < data.size() - window + 1; ++i) {
avg.push_back(std::accumulate(data.begin() + i, data.begin() + i + window, 0) / window);
}
return avg;
};
|
3. 模型构建
lambda 可用于向模型添加自定义的损失函数、激活函数或其他组件。例如,以下 lambda 定义了一个用于二分类任务的自定义 sigmoid 损失函数:
1
2
3
4
5
6
7
8
|
auto sigmoid_loss = []( const std::vector< double >& true_values, const std::vector< double >& predicted_values) {
std::vector< double > losses;
for ( int i = 0; i < true_values.size(); ++i) {
double p = 1.0 / (1.0 + std:: exp (-predicted_values[i]));
losses.push_back(- true_values[i] * std:: log (p) - (1 - true_values[i]) * std:: log (1 - p));
}
return std::accumulate(losses.begin(), losses.end(), 0);
};
|
4. 闭包
闭包允许 lambda 表达式访问其创建时的外部变量。这在需要访问训练数据或其他状态时特别有用。例如,以下闭包使用 lambda 表达式计算特定特征的平均值:
1
2
3
4
5
6
7
|
auto avg_feature = []( const std::vector< double >& column) {
return std::accumulate(column.begin(), column.end(), 0) / column.size();
};
std::vector< double > features = ...;
std::vector< double > avg_values(features.size());
std::transform(features.begin(), features.end(), avg_values.begin(), avg_feature);
|
实战案例:手写数字识别
考虑使用 MNIST 数据集训练一个简单的手写数字识别器。以下代码展示了如何利用 lambda 和闭包进行数据预处理、特征工程和模型训练:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
#include <vector>
#include <numeric>
#include <functional>
#include <cmath>
#include <iOStream>
using namespace std;
typedef vector<vector< double > > Matrix;
auto normalize = []( const vector< double >& row) -> vector< double > {
double sum = 0;
for ( auto & value : row) {
sum += value * value;
}
double norm = sqrt (sum);
transform(row.begin(), row.end(), row.begin(), [norm]( double value) {
return value / norm;
});
return row;
};
auto get_features = []( const Matrix& data, const vector< int >& labels) -> Matrix {
Matrix features(data.size(), 784);
for ( int i = 0; i < data.size(); ++i) {
features[i] = normalize(data[i]);
}
return features;
};
auto sigmoid_loss = []( const vector< double >& true_values, const vector< double >& predicted_values) -> double {
vector< double > losses;
for ( int i = 0; i < true_values.size(); ++i) {
double p = 1.0 / (1.0 + exp (-predicted_values[i]));
losses.push_back(- true_values[i] * log (p) - (1 - true_values[i]) * log (1 - p));
}
return accumulate(losses.begin(), losses.end(), 0);
};
int main() {
Matrix data = ...;
vector< int > labels = ...;
Matrix features = get_features(data, labels);
}
|