您的位置:

神经网络中的非线性

神经网络是一个被广泛运用于图像识别、语音识别、自然语言处理等领域的机器学习模型。然而,神经网络中原始的线性模型缺乏处理非线性关系的能力,这意味着不同特征之间的混合效应无法被捕捉到。因此,在神经网络中引入非线性是至关重要的。

一、激活函数

激活函数是神经网络中引入非线性的最基础的方法之一。前面我们提到,线性模型可以处理每个特征的影响,但是无法捕捉特征之间的协同关系。而激活函数不仅在单个神经元内引入了非线性,同时也使得不同神经元之间出现非线性交互。因此,如果没有激活函数,神经网络将仍然是一个线性模型。

下面是一个使用Sigmoid作为激活函数的代码示例:

 def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def sigmoid_derivative(x):
    return sigmoid(x) * (1 - sigmoid(x))

class NeuralNetwork:
    def __init__(self, num_inputs, hidden_layers_sizes, num_outputs):
        self.weights = []
        prev_layer_size = num_inputs
        for layer_size in hidden_layers_sizes:
            w = np.random.rand(prev_layer_size, layer_size)
            self.weights.append(w)
            prev_layer_size = layer_size
        w = np.random.rand(prev_layer_size, num_outputs)
        self.weights.append(w)

    def feedforward(self, inputs):
        a = inputs
        for w in self.weights:
            z = np.dot(a, w)
            a = sigmoid(z)
        return a

inputs = np.array([1, 2, 3])
network = NeuralNetwork(3, [4, 5], 2)
output = network.feedforward(inputs)
print(output)

其中,新建了一个NeuralNetwork类,用于描述具有三个输入,两个输出的多层感知机模型,并且hidden_layers_sizes参数表示隐藏层有4个神经元和5个神经元,使用sigmoid函数作为激活函数。

二、卷积神经网络

卷积神经网络(Convolutional Neural Network,CNN)是一种使用卷积方式进行特征提取的神经网络。卷积操作可以看成是一种局部的操作,在一定程度上采集的只是特征的一部分信息,因此在网络中引入了非线性。此外,池化操作等也可以看成是一种非线性变换,通过降维和筛选等操作强化了特征的表达力。

下面是一个简单的卷积神经网络的代码实现(这里使用MNIST数据集):

 from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
from keras.utils import np_utils

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1) / 255.0
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1) / 255.0
y_train = np_utils.to_categorical(y_train, 10)
y_test = np_utils.to_categorical(y_test, 10)

model = Sequential()
model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(10, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
model.fit(x_train, y_train, batch_size=32, epochs=10, verbose=1, validation_data=(x_test, y_test))

在此代码片段中,使用Keras工具包和MNIST数据集搭建了一个简单的卷积神经网络,并且使用relu函数作为激活函数。网络结构包括两层卷积、两层池化和两层全连接。

三、递归神经网络

递归神经网络(Recurrent Neural Network,RNN)是一种能够利用序列信息的神经网络。由于它们的结构中包含一个或多个循环层,所以可以捕获时间序列中的非线性关系,从而引入了非线性。在许多自然语言处理任务中,包括语音识别和文本生成等,递归神经网络是非常流行的选择。

下面是一个简单的用于文本生成的递归神经网络的代码实现(这里使用Shakespeare数据集):

 import numpy as np
from keras.layers import Dense, Activation, LSTM
from keras.models import Sequential
from keras.optimizers import RMSprop
from keras.utils.data_utils import get_file

path = get_file('shakespeare.txt', origin='https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt')
text = open(path).read().lower()
print('corpus length:', len(text))

chars = sorted(list(set(text)))
print('total chars:', len(chars))
char_indices = dict((c, i) for i, c in enumerate(chars))
indices_char = dict((i, c) for i, c in enumerate(chars))

maxlen = 40
step = 3
sentences = []
next_chars = []
for i in range(0, len(text) - maxlen, step):
    sentences.append(text[i: i + maxlen])
    next_chars.append(text[i + maxlen])
print('nb sequences:', len(sentences))

x = np.zeros((len(sentences), maxlen, len(chars)), dtype=np.bool)
y = np.zeros((len(sentences), len(chars)), dtype=np.bool)
for i, sentence in enumerate(sentences):
    for t, char in enumerate(sentence):
        x[i, t, char_indices[char]] = 1
    y[i, char_indices[next_chars[i]]] = 1

model = Sequential()
model.add(LSTM(128, input_shape=(maxlen, len(chars))))
model.add(Dense(len(chars)))
model.add(Activation('softmax'))

optimizer = RMSprop(lr=0.01)
model.compile(loss='categorical_crossentropy', optimizer=optimizer)

model.fit(x, y, batch_size=128, epochs=10)

该代码片段中,使用Keras搭建了一个只含有一个LSTM循环层的递归神经网络。该网络用于在莎士比亚文本数据集上进行训练,从而生成新的莎士比亚式的文本。

四、总结

在神经网络中引入非线性是非常重要的,它能够帮助我们在许多任务中获得更好的表现。本文中,我们介绍了三种引入非线性的方法:使用激活函数、卷积神经网络和递归神经网络。但是,这只是一个开始。未来如何引入更多的非线性将成为一个非常有趣的问题。