柚子快報邀請碼778899分享:java中使用BP網(wǎng)絡(luò)進行回歸
柚子快報邀請碼778899分享:java中使用BP網(wǎng)絡(luò)進行回歸
在神經(jīng)網(wǎng)絡(luò)中,激活函數(shù)扮演著至關(guān)重要的角色,它們?yōu)榫W(wǎng)絡(luò)引入了非線性因素,使得網(wǎng)絡(luò)能夠?qū)W習(xí)和模擬復(fù)雜的非線性關(guān)系。下面列出的各種激活函數(shù)及其特點如下:
LINEAR ("Linear"):
線性激活函數(shù)實際上就是恒等函數(shù),即?f(x)=x。它不會給網(wǎng)絡(luò)帶來任何非線性特性,因此在實際應(yīng)用中很少使用(除了在某些特殊情況下,如回歸問題或某些層作為輸出層時)。RAMP ("Ramp"):
Ramp函數(shù)是一種分段線性函數(shù),通常定義為當(dāng)?x<0?時?f(x)=0,當(dāng)?x≥0?時?f(x)=x。它與ReLU(Rectified Linear Unit)類似,但Ramp函數(shù)在?x<0?時保持輸出為0,而不是像ReLU那樣保持不變。Ramp函數(shù)有時被認(rèn)為是一個更平滑的ReLU版本。STEP ("Step"):
Step函數(shù)是一種簡單的二值激活函數(shù),通常定義為當(dāng)?x<0?時?f(x)=0,當(dāng)?x≥0?時?f(x)=1。它將任意輸入值映射到兩個輸出值之一,這種非連續(xù)性使得它在大多數(shù)現(xiàn)代神經(jīng)網(wǎng)絡(luò)中不太實用。SIGMOID ("Sigmoid"):
Sigmoid函數(shù)是一個S形曲線,定義為?f(x)=1+e?x1?。它將任意實值壓縮到區(qū)間(0, 1)內(nèi),非常適合用于二分類問題的輸出層。然而,由于梯度消失問題和計算量較大,它在深度神經(jīng)網(wǎng)絡(luò)中的使用已經(jīng)減少。TANH ("Tanh"):
Tanh函數(shù)是雙曲正切函數(shù),定義為?f(x)=ex+e?xex?e?x?。它將輸入值壓縮到區(qū)間(-1, 1)內(nèi),并且是零中心的(即,輸出的均值為0)。這有助于加快收斂速度,因此它比Sigmoid函數(shù)更受歡迎。然而,梯度消失問題仍然存在。GAUSSIAN ("Gaussian"):
高斯(或稱為高斯)激活函數(shù)使用高斯(或正態(tài))分布函數(shù),形式可能因具體實現(xiàn)而異,但通常與標(biāo)準(zhǔn)正態(tài)分布相關(guān)。它將輸入值映射到一個鐘形曲線,但這種激活函數(shù)在神經(jīng)網(wǎng)絡(luò)中不太常見,因為其他激活函數(shù)通常能提供更好的性能。TRAPEZOID ("Trapezoid"):
梯形激活函數(shù)是一種非線性函數(shù),其形狀類似于梯形。它結(jié)合了線性和非線性的部分,但在實際應(yīng)用中不太常見,可能是因為它缺乏足夠的理論依據(jù)或優(yōu)勢。SGN ("Sgn"):
Sgn(符號)函數(shù)根據(jù)輸入值的正負輸出+1、-1或0(取決于具體定義)。它是一種簡單的二值激活函數(shù),但在神經(jīng)網(wǎng)絡(luò)中并不常用,因為它的梯度在大部分輸入上都是0(除了0點附近的微小區(qū)域),這會導(dǎo)致梯度消失問題。SIN ("Sin"):
Sin函數(shù)是正弦函數(shù),將輸入值映射到[-1, 1]區(qū)間的正弦波上。它是一個周期性的非線性函數(shù),但在神經(jīng)網(wǎng)絡(luò)中不常用,因為神經(jīng)網(wǎng)絡(luò)通常希望激活函數(shù)具有單調(diào)遞增或遞減的特性,以便進行有效的梯度下降。LOG ("Log"):
Log函數(shù)(可能指的是自然對數(shù)或其他對數(shù))將輸入值映射到對數(shù)尺度上。它在某些特定領(lǐng)域(如機器學(xué)習(xí)中的某些損失函數(shù))中很有用,但在作為神經(jīng)網(wǎng)絡(luò)的激活函數(shù)時并不常見。RECTIFIED ("RectifiedLinear", ReLU):
ReLU(Rectified Linear Unit)函數(shù)是當(dāng)前深度學(xué)習(xí)中使用最廣泛的激活函數(shù)之一。它定義為?f(x)=max(0,x),即將所有負值置為0,保持正值不變。ReLU函數(shù)簡單、計算效率高,且有助于緩解梯度消失問題(在正值區(qū)域內(nèi))。然而,它也存在死亡ReLU問題(即某些神經(jīng)元在訓(xùn)練過程中永遠不會被激活)。
? ?為了分析1個y和3個自變量(x,z,? k)?(0為訓(xùn)練集,1為測試集) 的回歸問題使用java的BP網(wǎng)絡(luò)激活函數(shù)使用RECTIFIED如下使用依賴如下:
進行回歸的方法如下:
private static void poly3UseBpn(Double[] x0, Double[] z0, Double[] k0, Double[] y, Double[] x1, Double[] z1, Double[] k1, Double[] y0, Double[] y1) {
// 歸一化數(shù)據(jù)
double minX = Arrays.stream(x0).min(Double::compareTo).get();
double maxX = Arrays.stream(x0).max(Double::compareTo).get();
double rangeX = maxX - minX;
double minZ = Arrays.stream(z0).min(Double::compareTo).get();
double maxZ = Arrays.stream(z0).max(Double::compareTo).get();
double rangeZ = maxZ - minZ;
double minK = Arrays.stream(k0).min(Double::compareTo).get();
double maxK = Arrays.stream(k0).max(Double::compareTo).get();
double rangeK = maxK - minK;
// 創(chuàng)建數(shù)據(jù)集 (3 個輸入,1 個輸出)
DataSet trainingSet = new DataSet(3, 1);
for (int i = 0; i < x0.length; i++) {
double normalizedInputX = (x0[i] - minX) / rangeX;
double normalizedInputZ = (z0[i] - minZ) / rangeZ;
double normalizedInputK = (k0[i] - minK) / rangeZ;
trainingSet.add(new DataSetRow(new double[]{normalizedInputX, normalizedInputZ, normalizedInputK}, new double[]{y[i]}));
}
// 創(chuàng)建一個具有 3 個輸入層神經(jīng)元,10 個隱藏層神經(jīng)元,1 個輸出層神經(jīng)元的神經(jīng)網(wǎng)絡(luò)
MultiLayerPerceptron neuralNet = new MultiLayerPerceptron(TransferFunctionType.RECTIFIED, 3, 10, 1);
//使用固定的權(quán)重
neuralNet.randomizeWeights(new Random(1));
// 設(shè)置學(xué)習(xí)率和迭代次數(shù)
double currentLearningRate = 0.01;
int iterations = 10000;
double errorThreshold = 0.001;
double minLearningRate = 1e-5;
double decay = 0.9;
// 訓(xùn)練網(wǎng)絡(luò)
BackPropagation backPropagation = new BackPropagation();
backPropagation.setLearningRate(currentLearningRate);
neuralNet.setLearningRule(backPropagation);
for (int i = 0; i < iterations; i++) {
neuralNet.learn(trainingSet);
// 獲取當(dāng)前誤差
double error = backPropagation.getTotalNetworkError();
if (error < errorThreshold) {
System.out.println("error:" + error + "---->" + (error < errorThreshold) + "====>" + i);
break;
}
// 更新學(xué)習(xí)率(指數(shù)衰減)
currentLearningRate = Math.max(minLearningRate, currentLearningRate * decay);
backPropagation.setLearningRate(currentLearningRate);
}
// 在 x0 和 z0 上評估擬合值,并將結(jié)果存儲在 y0 中
for (int i = 0; i < x0.length; i++) {
double normalizedInputX = (x0[i] - minX) / rangeX;
double normalizedInputZ = (z0[i] - minZ) / rangeZ;
double normalizedInputK = (k0[i] - minK) / rangeZ;
neuralNet.setInput(normalizedInputX, normalizedInputZ, normalizedInputK);
neuralNet.calculate();
y0[i] = neuralNet.getOutput()[0];
}
// 在 x1 和 z1 上評估擬合值,并將結(jié)果存儲在 y1 中
for (int i = 0; i < x1.length; i++) {
double normalizedInputX = (x1[i] - minX) / rangeX;
double normalizedInputZ = (z1[i] - minZ) / rangeZ;
double normalizedInputK = (k1[i] - minK) / rangeZ;
neuralNet.setInput(normalizedInputX, normalizedInputZ, normalizedInputK);
neuralNet.calculate();
y1[i] = neuralNet.getOutput()[0];
}
由于這邊數(shù)據(jù)量比較小大概在70條左右,由于neuroph是單線程的,在執(zhí)行到neuralNet.learn(trainingSet);這里時會卡住,調(diào)整學(xué)習(xí)率和減少隱藏層單元后仍舊無法訓(xùn)練故只能換個方法如下使用deeplearning4j
修改后的訓(xùn)練方法如下:
public void poly3UseBpn(double[] x0, double[] z0, double[] k0, double[] y,
double[] x1, double[] z1, double[] k1, double[] y0, double[] y1) {
// 創(chuàng)建輸入數(shù)據(jù)集 (3個輸入,1個輸出)
List
for (int i = 0; i < x0.length; i++) {
INDArray input = Nd4j.create(new double[][]{{x0[i], z0[i], k0[i]}});
INDArray output = Nd4j.create(new double[][]{{y[i]}});
org.nd4j.linalg.dataset.DataSet DataSet = new org.nd4j.linalg.dataset.DataSet(input, output);
dataSetList.add(DataSet);
}
ListDataSetIterator
// 構(gòu)建網(wǎng)絡(luò)配置
MultiLayerNetwork model = new MultiLayerNetwork(new NeuralNetConfiguration.Builder()
.seed(42)//隨機種子
.optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT) //隨機梯度下降
.updater(new org.nd4j.linalg.learning.config.Adam(0.01)) //初始化學(xué)習(xí)率
.weightInit(WeightInit.RELU)//權(quán)重初始化
.list()
.layer(0, new DenseLayer.Builder()
.nIn(3)
.nOut(10)
.activation(Activation.RELU) //激活函數(shù)
.build()) // 輸入層 3個輸入
.layer(1, new OutputLayer.Builder(LossFunctions.LossFunction.MSE) //MSE損失函數(shù) MSE表示均方誤差
.nIn(10)
.nOut(1)
.activation(Activation.IDENTITY)
.build()) // 輸出層 1個輸出
.build());
//網(wǎng)絡(luò)初始化
model.init();
//用于輸出誤差信息 100次輸出1個
model.setListeners(new ScoreIterationListener(100));
// 設(shè)置訓(xùn)練參數(shù)
double errorThreshold = 0.001;
int maxIterations = 1000;
int patience = 10;
double bestError = Double.MAX_VALUE;
int noImprovementCount = 0;
for (int i = 0; i < maxIterations; i++) {
model.fit(trainingData);
double currentError = model.score();
System.out.println("error:" + currentError + "====>" + i);
if (currentError < bestError) {
bestError = currentError;
noImprovementCount = 0;
} else {
noImprovementCount++;
}
if (currentError < errorThreshold || noImprovementCount >= patience) {
break;
}
}
// 評估在 x0 和 z0 上的擬合值,并將結(jié)果存儲在 y0 中
for (int i = 0; i < x0.length; i++) {
INDArray input = Nd4j.create(new double[][]{{x0[i], z0[i], k0[i]}});
INDArray output = model.output(input);
y0[i] = output.getDouble(0);
}
// 評估在 x1 和 z1 上的擬合值,并將結(jié)果存儲在 y1 中
for (int i = 0; i < x1.length; i++) {
INDArray input = Nd4j.create(new double[][]{{x1[i], z1[i], k1[i]}});
INDArray output = model.output(input);
y1[i] = output.getDouble(0);
}
}
修改完后重新運行,已經(jīng)可以順利訓(xùn)練出數(shù)據(jù)了,自此記錄一下!
參考資料:
https://deeplearning4j.konduit.ai/v/zhong-wen-v1.0.0
柚子快報邀請碼778899分享:java中使用BP網(wǎng)絡(luò)進行回歸
精彩鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。