百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

使用Python理解基本的机器学习-感知器和人工神经元

toyiye 2024-09-04 20:11 4 浏览 0 评论

如果你正在学习机器学习,你的目标很可能是应用尖端的算法和“深度学习”来创建强大的应用程序。有了直观的API的广泛可用性,就可以实现这一点,只需对正在发生的事情或深层底层的实际工作方式进行最少的了解。

在这篇文章中,我们将介绍人工神经元和分类的起点,包括Perceptron和Adaline模型。对于每个模型,我们将讨论主要组件,然后将它们组合成完整的Python类实现。

感知器模型

机器学习最基本的起点是人工神经元。简化脑细胞的第一个模型发表于1943年,被称为McCullock-Pitts(MCP)神经元。本质上,这是一个带二进制输出('0'或'1')的基本逻辑门。如果到达神经元的输入之和超过给定阈值,则产生'1',其中每个输入乘以相应的权重系数以产生该总和。因此,神经元的激活在很大程度上取决于输入集和相应的权重系数值。

Frank Rosenblatt在出版后不久就采用了基本的MCP神经元概念,并制作了Perceptron规则算法。这 允许自动学习神经元模型的最佳权重系数。通过这样的模型,我们可以预测给定的输入是属于一个类还是另一个类(二元分类)。

感知器模型可能有任意数量的输入,也称为特征。由于我们通常具有多个特征,因此有助于将输入和权重表示为向量和矩阵。不要将输入样本与输入特征混淆; 每个数据样本都有许多特征n,它们通过我们的模型提供并一次处理一个(顺序)。例如,如果我们有100个汽车数据样本,其中每个样本具有m个特征(表示诸如最高速度,bhp,成本等),则每个数据样本x将具有m个特征的向量。每个输入要素都有相应的权重,经过训练后,这些权重将针对我们训练过的数据进行优化。

对于每个数据样本,我们的输入特征和权重作为感知器的加权和来获取,这通常称为net input function z。使用x和w上面的向量的好处是我们可以使用线性代数来紧凑地表示它,如下所示:

我们转换权重向量w,然后用我们的输入向量x进行向量乘法,它形成了我们需要的总和。 还应该注意的是,我们还使用偏差项来允许感知器模型中的阈值,该阈值等于矢量中的第一个权重项。为了实现这一点,我们的输入矩阵中的第一个x项始终设置为1.这意味着我们需要在将偏差项添加到输入向量中之前将其添加到模型中。

在净输入求和之后,我们的值被传递到感知器阈值或决策函数。在这种情况下,该功能是单位阶跃函数。如果输入高于给定值,则输出“1”,否则输出“0”。

那么我们的感知器如何实际从一组数据中学习呢?整体感知器过程如下:

  • 将权重参数初始化为初始值(通常是小的随机值,而不是零)。
  • 针对每个训练样本输入预测给定特征的二进制输出。
  • 通过Perceptron学习规则更新权重。

Perceptron的成本函数过于简单,被称为感知器学习规则。在每次训练迭代后,我们的权重向量中的每个权重都会发生很小的变化,如下所示:

:=表示法意味着我们同时更新权重向量中的所有权重,而不是迭代地更新。因此,进行输出预测,然后将所有权重参数更新为一个训练周期的一部分。上面的alpha术语也等于学习率,它决定了我们的模型在每个训练周期中学习的速度。

提供我们用于训练的数据是线性可分的,如果受到足够的训练周期(时期),感知器会将权重更新为最佳值。

Python中的Perceptron

我们首先在Python中编写Perceptron的每个组件,然后在最后将它们组合成一个更大的Perceptron类。对于这个基本模型,我们需要的唯一Python包是numpy和matplotlib。

样本数据

为此,我们将生成一个具有两个不同输出类的简单数据集,以便我们的感知器进行训练。注意:这个随机训练数据是通过随机函数生成的,并且不是完全可复制的。

为了帮助理解我们正在尝试做的事情,可视化我们的数据是很有帮助的。在这种情况下,我们的输入示例只有两个特性,因此用散点图来可视化数据很容易。数据生成,然后在散点图上绘图,如下所示

import matplotlib.pyplot as plt

import numpy as np

import pandas as pd

# make up random data for bird wingspans and weights for golden eagles and horned owls

bird_wingspans = np.concatenate([np.random.randint(170, 230, size = 50)/100.0,

np.random.randint(60, 100, size = 50)/100.0])

bird_weights = np.concatenate([(11 - 10)*np.random.randn(50)+10, np.abs(np.random.randn(50))+1])

# combine X vectors into a 2-dimensional array with 100 rows and 2 columns

X = np.vstack((bird_wingspans, bird_weights)).T

# create labels for our input data - first 50 are Golden Eagles (binary 0), last 50 are Horned Owls (binary 1)

y = np.concatenate([np.zeros(50), np.ones(50)])

# confirm shapes of generated data

print("The shape of our input matrix, X, is: {0}.".format(X.shape))

print("The shape of our output vector, y, is: {0}.".format(y.shape))

# plot our data on a scatter graph using matplotlib

# first 50 samples = Golden Eagle - plot both input features (columns 0 and 1 of X)

plt.scatter(X[:50, 0], X[:50, 1], color='r', marker='o', label='Golden Eagle')

# last 50 samples = Horned Owls

plt.scatter(X[50:, 0], X[50:, 1], color='b', marker='x', label = "Horned Owl")

plt.title("Bird Classification Sample Data")

plt.xlabel("Wingspan (metres)")

plt.ylabel("Weight (kilograms)")

plt.legend(loc = 'upper left')

plt.xlim([0, 2.5])

plt.ylim([0, 14])

plt.show()

生成初始权重

我们希望将权重初始化为小的随机数,而不是将它们初始化为零。我们需要这样做,否则我们的学习率会降低培训期间我们的分类结果。这背后的理由不会被涵盖,但是这是因为如果权重被初始化为零,学习率仅影响权重向量的尺度,而不影响方向。

这些权重可以以许多不同的方式产生。使用numpy.random的一个这样的例子是:

向X添加偏差项

对于偏差项,我们需要做的就是在输入数据X中添加1列。在numpy中,这可以使用ones和hstack numpy函数来实现。

加权和函数(净输入)

如上所述,由于我们使用矢量作为每个样本的输入特征及其相关权重,因此我们可以非常容易地计算净输入总和。在Python中使用numpy的向量化,取决于我们是否在训练数据中添加了1的偏置列,净输入函数变为:

用于预测的单位步长函数

如果我们的净输入和大于或等于零,我们想返回1,否则返回0。

感知器学习规则

使用前面图6中定义的学习规则,我们可以执行完整的训练周期。这包括循环遍历所有训练样本并根据感知器学习规则更新权重,如下所示:

把它们放在一起

使用numpy形成的Perceptron的基本组件,我们可以将它们拼凑在一起并实现完整的Perceptron二元分类器。使用分类器,我们可以在训练周期中可视化我们的错误,并且(希望!)看到随着时间的推移,当权重被优化时,错误的数量会减少。

class Perceptron(object):

""" Perceptron for demonstrating a binary classifier """

def __init__(self, learn_rate = 0.01, iterations = 100):

self.learn_rate = learn_rate

self.iterations = iterations

def fit(self, X, y, biased_X = False):

""" Fit training data to our model """

X = self._add_bias(X)

self._initialise_weights(X)

self.errors = []

for cycle in range(self.iterations):

trg_error = 0

for x_i, output in zip(X, y):

output_pred = self.predict(x_i, biased_X=True)

trg_update = self.learn_rate * (output - output_pred)

self.weights += trg_update * x_i

trg_error += int(trg_update != 0.0)

self.errors.append(trg_error)

return self

def _net_input(self, X):

""" Net input function (weighted sum) """

return np.dot(X, self.weights)

def predict(self, X, biased_X=False):

""" Make predictions for the given data, X, using unit step function """

if not biased_X:

X = self._add_bias(X)

return np.where(self._net_input(X) >= 0.0, 1, 0)

def _add_bias(self, X):

""" Add a bias column of 1's to our data, X """

bias = np.ones((X.shape[0], 1))

biased_X = np.hstack((bias, X))

return biased_X

def _initialise_weights(self, X):

""" Initialise weigths - normal distribution sample with standard dev 0.01 """

random_gen = np.random.RandomState(1)

self.weights = random_gen.normal(loc = 0.0, scale = 0.01, size = X.shape[1])

return self

# create a perceptron classifier and train on our data

classifier = Perceptron(learn_rate = 0.1, iterations = 50)

classifier.fit(X, y)

# plot our misclassification error after each iteration of training

plt.plot(range(1, len(classifier.errors) + 1), classifier.errors, marker = 'x')

plt.title("Visualisation of errors")

plt.xlabel('Epochs')

plt.ylabel('Errors')

plt.show()

正如可以在训练周期的误差图(epochs)中看到的,我们得到的误差数量随着时间的推移而减少。在大约7个周期之后,我们的模型将误差数量减少到零。我们的感知器训练后的决策边界显示在右边,它有效地将Golden Eagles和Horned Owls区分开来。我们可以使用我们训练过的模型,用一组新的输入X调用分类器预测函数,用新的数据进行预测

Perceptrons的一个问题是,如果提供的数据完全可线性分离,它们只会正确地优化权重。对于上面使用的数据,它是线性可分的。但是,如果我们使用更直观的数据(通常不能通过直线分离),那么我们的Perceptron分类器将永远不会停止尝试优化权重并且会不断出现错误。这是一个巨大的缺点,也是不使用Perceptrons的一个原因。然而,它们确实是对基本神经元和更复杂模型的良好介绍。

Adaline-自适应线性神经元

对原始感知器模型的改进是Adaline,它增加了一个用于优化权重的线性激活函数。通过此添加,使用连续成本函数而不是单位步骤。Adaline非常重要,因为它为更先进的机器学习模型奠定了基础。

unit step仍然会出现,正如您上面看到的,但是它只用于模型末尾的输出分类(' 1 '或' 0 ')。线性激活模型的连续输出值用于成本(或目标)函数。这表明我们的算法在训练数据上做得有多糟糕(或多好),并且可以通过众所周知的算法(如梯度下降)来最小化它。

成本函数

在这种情况下,我们将使用平方误差和作为我们的成本函数,可以这样实现:

梯度下降法

为了应用梯度下降,我们需要确定成本函数对每个权重的偏导数。通过微分,我们发现这个偏导数等于:

为了优化我们的权重,我们希望以我们的学习率参数选择的速率向我们的梯度的相反方向迈出一步。这背后的逻辑是最小化成本并最终达到全局最小值。因此,对于每个权重优化,我们需要应用:

我们可以将这个权重优化步骤和我们的成本计算步骤合并到一个训练周期代码片段中,如下所示:

特征标准化

除了激活功能和梯度下降优化,我们还将通过特征标准化来提高模型的性能。在机器学习中,这是一种常见的实践,它使优化过程在给定的时间内更快、更有效。为此,我们将从训练数据中的每个相关特征值中减去每个特征值的平均值,然后将特征值除以它们各自的标准偏差。

把它们放在一起

随着Adaline模型的其他组件的制定,我们可以像在Perceptron中一样在Python中生成最终实现。此Adaline实现如下所示:

class Adaline(object):

""" Adaline (Adaptive Linear Neuron) for binary classification.

Minimises the cost function using gradient descent. """

def __init__(self, learn_rate = 0.01, iterations = 100):

self.learn_rate = learn_rate

self.iterations = iterations

def fit(self, X, y, biased_X = False, standardised_X = False):

""" Fit training data to our model """

if not standardised_X:

X = self._standardise_features(X)

if not biased_X:

X = self._add_bias(X)

self._initialise_weights(X)

self.cost = []

for cycle in range(self.iterations):

output_pred = self._activation(self._net_input(X))

errors = y - output_pred

self.weights += (self.learn_rate * X.T.dot(errors))

cost = (errors**2).sum() / 2.0

self.cost.append(cost)

return self

def _net_input(self, X):

""" Net input function (weighted sum) """

return np.dot(X, self.weights)

def predict(self, X, biased_X=False):

""" Make predictions for the given data, X, using unit step function """

if not biased_X:

X = self._add_bias(X)

return np.where(self._activation(self._net_input(X)) >= 0.0, 1, 0)

def _add_bias(self, X):

""" Add a bias column of 1's to our data, X """

bias = np.ones((X.shape[0], 1))

biased_X = np.hstack((bias, X))

return biased_X

def _initialise_weights(self, X):

""" Initialise weigths - normal distribution sample with standard dev 0.01 """

random_gen = np.random.RandomState(1)

self.weights = random_gen.normal(loc = 0.0, scale = 0.01, size = X.shape[1])

return self

def _standardise_features(self, X):

""" Standardise our input features with zero mean and standard dev of 1 """

X_norm = (X - np.mean(X, axis=0)) / np.std(X, axis = 0)

return X_norm

def _activation(self, X):

""" Linear activation function - simply returns X """

return X

# create a perceptron classifier and train on our data

classifier = Adaline(learn_rate = 0.001, iterations = 50)

classifier.fit(X, y)

# plot our misclassification error after each iteration of training

plt.plot(range(1, len(classifier.cost) + 1), classifier.cost)

plt.title("Adaline: learn-rate 0.001")

plt.xlabel('Epochs')

plt.ylabel('Cost (Sum-of-Squares)')

plt.show()

我们可以看到为我们的模型设置超参数的重要性来自以下图中的基本Adaline示例; 如果我们选择0.1的学习率,则成本倾向于无穷大并且不会收敛,而如果我们选择0.001的学习率,则我们的模型成功地收敛到成本函数的全局最小值。迭代次数也很重要,应该足够高以充分降低成本。机器学习模型的这些调整方面被称为超参数,以及这些优化是我们创建任何模型的一个重要方面。

进一步改进和结束语

这种模型有很多方法可以进一步改进,包括随机梯度下降,它可以更频繁地进行优化,而不是像上面的模型那样使用整批训练数据。我们还可以使用One vs. All Muticlass Classification将其扩展到二元分类以外。

此外,还有比Adaline更好的分类器。Adaline是一个起点,您可以将其作为理解更复杂分类模型的基础,例如Logistic回归和神经网络。

在这篇文章中,我们研究了基本神经元的特征,然后使用Python和numpy构建了一个基本的Rosenblatt Perceptron模型。然后,我们构建了一个可用的Adaline分类器,通过其激活函数和成本函数优化,以多种方式改进了Perceptron。在此期间,我们还应用了一些有价值的特征处理,其中包括标准化,使梯度下降更快,更有效。

虽然这些模型不能替代通过Sci-kit Learn和其他软件包提供的专业构建和优化的模型,但它们应该提供对基本分类器如何工作的理解。我希望我们遵循的流程有助于您理解基本的机器学习分类,并为您提供使用Python实现这些模型的见解。

相关推荐

# Python 3 # Python 3字典Dictionary(1)

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中,格式如...

Python第八课:数据类型中的字典及其函数与方法

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值...

Python中字典详解(python 中字典)

字典是Python中使用键进行索引的重要数据结构。它们是无序的项序列(键值对),这意味着顺序不被保留。键是不可变的。与列表一样,字典的值可以保存异构数据,即整数、浮点、字符串、NaN、布尔值、列表、数...

Python3.9又更新了:dict内置新功能,正式版十月见面

机器之心报道参与:一鸣、JaminPython3.8的热乎劲还没过去,Python就又双叒叕要更新了。近日,3.9版本的第四个alpha版已经开源。从文档中,我们可以看到官方透露的对dic...

Python3 基本数据类型详解(python三种基本数据类型)

文章来源:加米谷大数据Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。在Python中,变量就是变量,它没有类型,我们所说的"类型"是变...

一文掌握Python的字典(python字典用法大全)

字典是Python中最强大、最灵活的内置数据结构之一。它们允许存储键值对,从而实现高效的数据检索、操作和组织。本文深入探讨了字典,涵盖了它们的创建、操作和高级用法,以帮助中级Python开发...

超级完整|Python字典详解(python字典的方法或操作)

一、字典概述01字典的格式Python字典是一种可变容器模型,且可存储任意类型对象,如字符串、数字、元组等其他容器模型。字典的每个键值key=>value对用冒号:分割,每个对之间用逗号,...

Python3.9版本新特性:字典合并操作的详细解读

处于测试阶段的Python3.9版本中有一个新特性:我们在使用Python字典时,将能够编写出更可读、更紧凑的代码啦!Python版本你现在使用哪种版本的Python?3.7分?3.5分?还是2.7...

python 自学,字典3(一些例子)(python字典有哪些基本操作)

例子11;如何批量复制字典里的内容2;如何批量修改字典的内容3;如何批量修改字典里某些指定的内容...

Python3.9中的字典合并和更新,几乎影响了所有Python程序员

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

Python3大字典:《Python3自学速查手册.pdf》限时下载中

最近有人会想了,2022了,想学Python晚不晚,学习python有前途吗?IT行业行业薪资高,发展前景好,是很多求职群里严重的香饽饽,而要进入这个高薪行业,也不是那么轻而易举的,拿信工专业的大学生...

python学习——字典(python字典基本操作)

字典Python的字典数据类型是基于hash散列算法实现的,采用键值对(key:value)的形式,根据key的值计算value的地址,具有非常快的查取和插入速度。但它是无序的,包含的元素个数不限,值...

324页清华教授撰写【Python 3 菜鸟查询手册】火了,小白入门字典

如何入门学习python...

Python3.9中的字典合并和更新,了解一下

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

python3基础之字典(python中字典的基本操作)

字典和列表一样,也是python内置的一种数据结构。字典的结构如下图:列表用中括号[]把元素包起来,而字典是用大括号{}把元素包起来,只不过字典的每一个元素都包含键和值两部分。键和值是一一对应的...

取消回复欢迎 发表评论:

请填写验证码