誤差逆伝播法を用いたニューラルネットワーク
#include <iostream>
#include <vector>
#include <cmath>
#include <random>
#include <ctime>
// ニューラルネットワーククラス
class NeuralNetwork {
private:
// ネットワークの構造
int input_size; // 入力層のサイズ(行動の数)
int hidden_size; // 隠れ層のニューロン数
int output_size; // 出力層のサイズ(評価値1つ)
double learning_rate;// 学習率
// 重みとバイアス
std::vector<std::vector<double>> w1; // 入力層 -> 隠れ層の重み
std::vector<double> b1; // 隠れ層のバイアス
std::vector<std::vector<double>> w2; // 隠れ層 -> 出力層の重み
std::vector<double> b2; // 出力層のバイアス
// 中間結果の保存用
std::vector<double> hidden_output; // 隠れ層の出力
std::vector<double> final_output; // 最終出力
// シグモイド活性化関数
double sigmoid(double x) {
return 1.0 / (1.0 + std::exp(-x));
}
// シグモイドの微分
double sigmoid_derivative(double x) {
double s = sigmoid(x);
return s * (1.0 - s);
}
// 重みの初期化
void initialize_weights() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(-0.1, 0.1);
// w1とb1の初期化
w1.resize(hidden_size, std::vector<double>(input_size));
b1.resize(hidden_size);
for (int i = 0; i < hidden_size; i++) {
for (int j = 0; j < input_size; j++) {
w1[i][j] = dis(gen);
}
b1[i] = dis(gen);
}
// w2とb2の初期化
w2.resize(output_size, std::vector<double>(hidden_size));
b2.resize(output_size);
for (int i = 0; i < output_size; i++) {
for (int j = 0; j < hidden_size; j++) {
w2[i][j] = dis(gen);
}
b2[i] = dis(gen);
}
}
public:
NeuralNetwork(int in_size, int hid_size, int out_size, double lr = 0.01)
: input_size(in_size), hidden_size(hid_size), output_size(out_size), learning_rate(lr) {
initialize_weights();
}
// 順伝播
std::vector<double> forward(const std::vector<double>& input) {
// 隠れ層の計算
hidden_output.resize(hidden_size);
for (int i = 0; i < hidden_size; i++) {
double z = b1[i];
for (int j = 0; j < input_size; j++) {
z += w1[i][j] * input[j];
}
hidden_output[i] = sigmoid(z);
}
// 出力層の計算
final_output.resize(output_size);
for (int i = 0; i < output_size; i++) {
double z = b2[i];
for (int j = 0; j < hidden_size; j++) {
z += w2[i][j] * hidden_output[j];
}
final_output[i] = sigmoid(z);
}
return final_output;
}
// 逆伝播
void backward(const std::vector<double>& input, const std::vector<double>& target) {
// 出力層の誤差
std::vector<double> output_errors(output_size);
for (int i = 0; i < output_size; i++) {
output_errors[i] = (target[i] - final_output[i]) * sigmoid_derivative(final_output[i]);
}
// 隠れ層の誤差
std::vector<double> hidden_errors(hidden_size);
for (int i = 0; i < hidden_size; i++) {
double error = 0.0;
for (int j = 0; j < output_size; j++) {
error += output_errors[j] * w2[j][i];
}
hidden_errors[i] = error * sigmoid_derivative(hidden_output[i]);
}
// 重みとバイアスの更新(出力層)
for (int i = 0; i < output_size; i++) {
for (int j = 0; j < hidden_size; j++) {
w2[i][j] += learning_rate * output_errors[i] * hidden_output[j];
}
b2[i] += learning_rate * output_errors[i];
}
// 重みとバイアスの更新(隠れ層)
for (int i = 0; i < hidden_size; i++) {
for (int j = 0; j < input_size; j++) {
w1[i][j] += learning_rate * hidden_errors[i] * input[j];
}
b1[i] += learning_rate * hidden_errors[i];
}
}
// 学習メソッド
void train(const std::vector<std::vector<double>>& inputs,
const std::vector<std::vector<double>>& targets, int epochs) {
for (int epoch = 0; epoch < epochs; epoch++) {
double total_error = 0.0;
for (size_t i = 0; i < inputs.size(); i++) {
std::vector<double> output = forward(inputs[i]);
backward(inputs[i], targets[i]);
total_error += std::pow(targets[i][0] - output[0], 2);
}
if (epoch % 100 == 0) {
std::cout << "Epoch " << epoch << ", Error: " << total_error / inputs.size() << std::endl;
}
}
}
};
// メイン関数
int main() {
// ネットワークの設定: 入力5(行動の数), 隠れ層10, 出力1(評価値)
NeuralNetwork nn(5, 10, 1, 0.1);
// 学習データ(例: 5つ未満の行動の組み合わせ)
std::vector<std::vector<double>> inputs = {
{1, 0, 0, 0, 0}, // 行動Aのみ
{0, 1, 0, 0, 0}, // 行動Bのみ
{1, 1, 0, 0, 0}, // 行動A+B
{0, 0, 1, 1, 0} // 行動C+D
};
std::vector<std::vector<double>> targets = {
{0.2}, // Aのみの評価値
{0.3}, // Bのみの評価値
{0.8}, // A+Bの評価値
{0.6} // C+Dの評価値
};
// 学習実行
nn.train(inputs, targets, 1000);
// テスト: 5つの行動の組み合わせを予測
std::vector<double> test_input = {1, 1, 1, 1, 1}; // 全ての行動を選択
std::vector<double> prediction = nn.forward(test_input);
std::cout << "5つの行動の予測評価値: " << prediction[0] << std::endl;
return 0;
}
・誤差逆伝播法を用いたニューラルネットワーク。
・5つの行動を扱い、2層構造(入力層、隠れ層、出力層)で評価値を予測。
1. モデルの構造
入力層: 5つの行動を表す5次元のベクトル(例: [1, 0, 1, 0, 1]は行動A, C, Eを選択)。
隠れ層: 10個のニューロン(調整可能)。
出力層: 1つの評価値(0~1の範囲)。
活性化関数: シグモイド関数を使用。
2. 学習データの準備
5つ未満の行動の組み合わせ(例: 1つや2つの行動)とその評価値を用意。
例では、{1, 0, 0, 0, 0}(行動Aのみ)や{1, 1, 0, 0, 0}(行動A+B)を学習データとして使用。
3. 学習プロセス
trainメソッドで、順伝播と逆伝播を繰り返し、重みを更新。
100エポックごとに平均誤差を表示して学習状況を確認。
4. 予測
学習後、5つの行動の組み合わせ(例: {1, 1, 1, 1, 1})を入力し、評価値を予測。
使い方と拡張
学習データの追加: 実際の用途に応じて、行動の組み合わせと評価値を増やす。
最適な組み合わせの探索: 全ての組み合わせ(2^5 = 32通り)を入力し、評価値が最も高いものを選ぶ。
スケーラビリティ: 行動数が増える場合、隠れ層のニューロン数を調整。
コメント