机器学习可以解决什么问题
机器学习可以帮助我们解决两大类问题:回归问题和分类问题,它们的主要区别在于输出变量的类型和预测目标的不同。
在分类问题中,输出变量是离散值,预测目标是将样本划分到不同的类别中。例如,预测邮件是否是垃圾邮件、预测图像中的物体类别等都是分类问题。通常使用分类模型,如逻辑回归、决策树分类、支持向量机、神经网络分类等来解决这类问题。分类问题的评估指标通常是准确率、精度(Precision)、召回率(Recall)等。
同时,机器学习输入的特征参数和输出的预期结果必须有逻辑相关性,什么意思?比如说我们想预测房价,结果特征参数输入了很多没有任何逻辑相关性的数据,比如历年水稻的出产率,这就是没有逻辑相关性的数据,这样的问题再怎么调参也是无法通过机器学习来解决的。
因为,稍微有点投资经验的人都知道,股票的历史数据和未来某个时间点或者某个时间段的实际价格,并不存在因果关系,尤其像A股市场这种可被操控的黑盒环境,连具体特征都是隐藏的,或者说特征是什么都是未知的,你以为的特征只是你以为的,并不是市场或者政策以为的,所以你输入之前十年或者二十年的历史股票数据,你让它预测,就是在搞笑,机器学习没法帮你解决此类问题。
鸢尾花分类问题
鸢尾花分类问题是一个经典的机器学习问题,也是神经网络入门的常用案例之一。它的目标是通过鸢尾花的花萼长度、花萼宽度、花瓣长度和花瓣宽度这四个特征来预测鸢尾花的品种,分为三种:山鸢尾(Iris Setosa)、变色鸢尾(Iris Versicolour)和维吉尼亚鸢尾(Iris Virginica)。
在这个案例中,我们使用了一个包含一个隐藏层的神经网络,它的输入层有4个神经元,代表鸢尾花的4个特征;隐藏层有3个神经元;输出层有3个神经元,分别代表3种鸢尾花的品种:
输入层:输入层接收外部输入信号,是神经网络的起点。它的神经元数量与输入特征的数量相同,每个神经元代表一个输入特征。输入层的主要作用是将外部输入转换为神经网络内部的信号。
输出层:输出层是神经网络的终点,它的神经元数量通常与问题的输出数量相同。每个神经元代表一个输出结果,输出层的主要作用是将隐藏层处理后的信号进行进一步处理,并将最终的结果输出。
定义神经网络结构体
在开始训练之前,我们先定义一些需要的结构体和函数:
// neuralNet contains all of the information
// that defines a trained neural network.
type neuralNet struct {
config neuralNetConfig
wHidden *mat.Dense
bHidden *mat.Dense
wOut *mat.Dense
bOut *mat.Dense
}
// neuralNetConfig defines our neural network
// architecture and learning parameters.
type neuralNetConfig struct {
inputNeurons int
outputNeurons int
hiddenNeurons int
numEpochs int
learningRate float64
}
这里neuralNet是神经网络结构体,同时定义输入、隐藏和输出层神经元的配置。
func newNetwork(config neuralNetConfig *neuralNet {
return &neuralNet{config: config}
}
这里返回神经网络的指针。
// sigmoid implements the sigmoid function
// for use in activation functions.
func sigmoid(x float64 float64 {
return 1.0 / (1.0 + math.Exp(-x
}
// sigmoidPrime implements the derivative
// of the sigmoid function for backpropagation.
func sigmoidPrime(x float64 float64 {
return sigmoid(x * (1.0 - sigmoid(x
}
实现反向传播
反向传播是指在前向传播之后,计算神经网络误差并将误差反向传播到各层神经元中进行参数(包括权重和偏置)的更新。在反向传播过程中,首先需要计算网络的误差,然后通过链式法则将误差反向传播到各层神经元,以更新每个神经元的权重和偏置。这个过程也被称为“反向梯度下降”,因为它是通过梯度下降算法来更新神经网络参数的。
1 初始化权重和偏置(例如,随机初始化)。
3 将输出与正确输出进行比较,以获取误差。
5 将变化通过神经网络进行反向传播。
在步骤3-5中,我们将利用随机梯度下降(SGD)来确定权重和偏置的更新:
// train trains a neural network using backpropagation.
func (nn *neuralNet train(x, y *mat.Dense error {
// Initialize biases/weights.
randSource := rand.NewSource(time.Now(.UnixNano(
randGen := rand.New(randSource
wHidden := mat.NewDense(nn.config.inputNeurons, nn.config.hiddenNeurons, nil
bHidden := mat.NewDense(1, nn.config.hiddenNeurons, nil
wOut := mat.NewDense(nn.config.hiddenNeurons, nn.config.outputNeurons, nil
bOut := mat.NewDense(1, nn.config.outputNeurons, nil
wHiddenRaw := wHidden.RawMatrix(.Data
bHiddenRaw := bHidden.RawMatrix(.Data
wOutRaw := wOut.RawMatrix(.Data
bOutRaw := bOut.RawMatrix(.Data
for _, param := range [][]float64{
wHiddenRaw,
bHiddenRaw,
wOutRaw,
bOutRaw,
} {
for i := range param {
param[i] = randGen.Float64(
}
}
// Define the output of the neural network.
output := new(mat.Dense
// Use backpropagation to adjust the weights and biases.
if err := nn.backpropagate(x, y, wHidden, bHidden, wOut, bOut, output; err != nil {
return err
}
// Define our trained neural network.
nn.wHidden = wHidden
nn.bHidden = bHidden
nn.wOut = wOut
nn.bOut = bOut
return nil
}
接着实现具体的反向传播逻辑:
// backpropagate completes the backpropagation method.
func (nn *neuralNet backpropagate(x, y, wHidden, bHidden, wOut, bOut, output *mat.Dense error {
// Loop over the number of epochs utilizing
// backpropagation to train our model.
for i := 0; i < nn.config.numEpochs; i++ {
// Complete the feed forward process.
hiddenLayerInput := new(mat.Dense
hiddenLayerInput.Mul(x, wHidden
addBHidden := func(_, col int, v float64 float64 { return v + bHidden.At(0, col }
hiddenLayerInput.Apply(addBHidden, hiddenLayerInput
hiddenLayerActivations := new(mat.Dense
applySigmoid := func(_, _ int, v float64 float64 { return sigmoid(v }
hiddenLayerActivations.Apply(applySigmoid, hiddenLayerInput
outputLayerInput := new(mat.Dense
outputLayerInput.Mul(hiddenLayerActivations, wOut
addBOut := func(_, col int,