統計的学習方法およびPython実装(A) - パーセプトロン

統計的学習方法およびPython実装(A) - パーセプトロン

   :ブログの庭iwehdio https://www.cnblogs.com/iwehdio/

 

1.定義

  xはR&LTに属する入力するための特徴空間の仮説例N Y N次元の特徴ベクトルの値は、出力空間Y = {+1、-1}の2点が、出力空間によって出力する、出力クラスの例を表しますスペース機能:

 

  パーセプトロンが呼び出されます。

  意味Wモデルパラメータ重みベクトル内積値、bはバイアスを表します。記号(X)は≧0 +1 <-1と0をとる、符号関数です。

  線形方程式によって知覚モデルソータWX + B =超平面を分離することにより決定さ0が代入特徴ベクトルに従って、達成WX + Bを正と負の正および負の種類を分離します。

 

2、学習戦略

  明らかに、Aパーセプトロン線形分類。したがって、我々は、より良い分類結果であることが、線形分離データセットの要件を持って、絶対的に正しい部門のデータの2種類の超平面データセットがあります。

  モデルの後損失関数を定義するためにまず学ぶために、定義されています。

  図1に示すように、関数の合計損失は任意誤分類の点です。しかし、損失関数のパラメータになっていないこの時点では、最適化が容易ではありません。

  図2に示すように、超平面の総距離に任意誤分類ポイント。これは、誤分類データセット全体の程度を特徴付ける、およびパラメータがオンされてもよいです。

  総距離の超平面に誤分類点です。

  損失関数(Mは誤分類の点の数です)。

  最適化された値w及びbに最適化問題は、損失関数L.を最小化します パラメータw及びB損失関数Lの勾配を計算する選択確率的勾配降下法、。勾配は以下の通り、即ちL bは、計算され、wはそれぞれ誘導体です。

  勾配Bは-Yであり、W -Y-Xの勾配のL、見ることができます。

  パーセプトロンアルゴリズムは元の形です。

  、任意の初期値は、パラメータB0を取り、初期の超平面を得るW0。

  B、サンプル、サンプル入力タグからデータセットを選択します。

  Cがあるかどうかを確認もしそうであれば、次のステップ。それ以外の場合は2を返しました。

  D、及び勾配学習率ηに応じて選択し、誤分類ポイントが正しく分類されるまで、B、Wのパラメータを更新します。

   eは、データセットがポイントまたは精度または損失関数を誤って分類されていないまで、Lが設定された閾値に達し、ステップBに行きます。モデルを取得します

  パーセプトロンアルゴリズムのアイデアは、サンプルの誤分類が正しく分類されたまで、サンプルデータセットの選択から、パラメータは常に更新され、オリジナルです。

 

 

3、収束

  データセットが線形分離であれば、超平面の上に存在する必要があります正確に分類されているデータセットの各サンプルように。満たす超平面これは

  あります、下限が存在し、理想的な超平面があるのでということ

     Bは、Rせ、から有界データセットk上誤分類感知部の数:

  つまり、線形分離データ・セットのために、限られた検索によって、あなたは常に完全にスーパーの表面から分離されているデータの理想的なセットを見つけることができます。完成隣接する二つのパラメータと再帰的な関係の主な具体的な証拠を更新することによって。

 

4、デュアルフォーム

  デュアル形式の基本的な考え方は、パーセプトロンパラメータw及びbは、xの線形結合の形式のデータの例を表し、yはタグです。次いで、それをパラメータw及びB係数を解くことによって得られます。

  niは更新パラメータNI回の後、私番目のサンプルを示した場合、パーセプトロンは正しく分類することをパーセプトロンアルゴリズムのショーの元の形によります。あなたは覚えている場合は、パラメータを学ぶために、最後は以下のとおりです。

   デュアル形式のパーセプトロンアルゴリズム:

  A、Bは、αの初期値は0に設定されています。

  B、サンプル、サンプル入力タグからデータセットを選択します。

  C、そこにあるかどうかを確認し、そうであれば、更新パラメータ:

   Dは、データセットが誤って分類されなくなるまでポイントまたは精度や損失関数Lが設定された閾値に達し、ステップBに行きます。モデルを取得します

 

図5に示すように、Pythonのアルゴリズムは元の形を達成するために

 

  数据集选用mnist手写数字数据集,训练集60000个样本,测试集10000个样本,为0~9的手写数字,可转化为28×28的矩阵。

   第一次先采用所有的28*28个维度的特征向量作为输入。

  首先,第一步读入数据。用Keras来下载和读入数据,并将数据划分为‘0’和非‘0’两类。

from tensorflow.keras.datasets import mnist
import numpy as np

# 读入数据
(train_data, train_label), (test_data, test_label) = \
    mnist.load_data(r'E:\code\statistical_learning_method\Data_set\mnist.npz')


train_length = 60000
test_length = 10000

# 将’0‘的标签置为1,非’0‘的标签置为-1
train_data = train_data[:train_length].reshape(train_length, 28 * 28)
train_label = np.array(train_label, dtype='int8')
for i in range(train_length):
    if train_label[i] != 0:
        train_label[i] = 1
    else:
        train_label[i] = -1
train_label = train_label[:train_length].reshape(train_length, )

test_data = test_data[:test_length].reshape(test_length, 28 * 28)
test_label = np.array(test_label, dtype='int8')
for i in range(test_length):
    if test_label[i] != 0:
        test_label[i] = 1
    else:
        test_label[i] = -1
test_label = test_label[:test_length].reshape(test_length, )

 

  第二步是初始化和编写测试函数。

# 测试模型在训练集和测试集上的准确率
def test(w, b, data, label):
    loss, acc = 0, 0
    for n in range(data.shape[0]):
        x = np.mat(data[n]).T
        y = label[n]
        L = y * (w * x + b)
        L = L[0, 0]
        if L <= 0:
            loss -= L
        else:
            acc += 1
    loss /= data.shape[0] * np.linalg.norm(w)
    acc /= data.shape[0]
    print('loss', loss, '\t', 'acc', acc, '\n')
    return loss, acc

# 初始化参数
w_init = 0.01 * np.random.random([28*28])
b_init = 0.01 * np.random.random(1)[0]
yita = 1e-9
w = np.mat(w_init)
b = b_init

  

  最后,对感知机模型进行训练。 

for k in range(200):

    w_temp = np.mat(np.zeros(28*28)).reshape(-1, 1)
    b_temp = 0
    # 将数据集随机打乱
    rand = [i for i in range(train_length)]
    np.random.shuffle(rand)
    train_data_temp = train_data[rand]
    train_label_temp = train_label[rand]

    # 模型训练
    for index in range(train_length):
        x = np.mat(train_data_temp[index]).T
        y = train_label_temp[index]

        # 损失函数
        L = y * (w * x + b) / np.linalg.norm(w)
        L = L[0, 0]

        # 更新参数
        if L <= 0:
            w_temp += yita * x * y
            b_temp += yita * y
            w += w_temp.T
            b += b_temp
    print('time', k)

    # 在训练集和测试集上的表现
    train_loss, train_acc = test(w, b, train_data, train_label)
    test_loss, test_acc = test(w, b, test_data, test_label)

   经过200次迭代,最后得到的结果为:

 

   在60000个样本的训练集上准确率为0.9912,在10000个样本的测试集上准确率为0.9911。

 

6、对偶形式算法的Python实现

 

from tensorflow.keras.datasets import mnist
import numpy as np

(train_data, train_label), (test_data, test_label) = \
    mnist.load_data(r'E:\code\statistical_learning_method\Data_set\mnist.npz')


train_length = 1000
test_length = 1000

train_data = train_data[:train_length].reshape(train_length, 28 * 28)
train_label = np.array(train_label, dtype='int8')


for i in range(train_length):
    if train_label[i] != 0:
        train_label[i] = 1
    else:
        train_label[i] = -1
train_label = train_label[:train_length].reshape(train_length, )

test_data = test_data[:test_length].reshape(test_length, 28 * 28)
test_label = np.array(test_label, dtype='int8')
for i in range(test_length):
    if test_label[i] != 0:
        test_label[i] = 1
    else:
        test_label[i] = -1
test_label = test_label[:test_length].reshape(test_length, )

# 生成Gram矩阵
G = []
for i in range(train_length):
    G_temp = np.zeros(train_length)
    for j in range(train_length):
        G_temp[j] = np.mat(train_data[i]) * np.mat(train_data[j]).T
    G.append(G_temp)

# 计算参数w
def sigma(xj, ai):

    sum0 = 0
    for k in range(train_length):
        sum0 += ai[k] * train_label[k] * G[k][xj]
    return sum0

# 计算准确率
def acc_in_train(ai):
    acc = 0
    for t in range(train_length):
        yi = train_label[t]
        if yi * (sigma(t, ai) + b) > 0:
            acc += 1
    return acc / train_length


def acc_in_test(ai):
    acc = 0
    for t in range(test_length):
        sum1 = 0
        for xi in range(train_length):
            sum1 += ai[xi] * train_label[xi] * np.mat(train_data[xi]) * np.mat(test_data[t]).T
        yi = test_label[t]
        if yi * (sum1 + b) > 0:
            acc += 1
    return acc / test_length


a = np.zeros(train_length)
b = 0
yita = 1e-6

# 模型训练
for i in range(200000):
    rand = [i for i in range(train_length)]
    np.random.shuffle(rand)
    for j in range(train_length):
        index = rand[j]
        y = train_label[index]
        L = y * (sigma(index, a) + b)
        if L <= 0:
            a[index] += yita
            b += yita * y
            print(index, L)

    print(acc_in_train(a))

print(acc_in_test(a))

  但是对偶形式的算法的表现并不好,训练集上准确率最高0.89,而且尝试了许多方法都没有改善。从数值上来看,原因可能是参数w太大,而每次参数更新对损失函数的影响很小。

 

7、其他问题

  a、为什么在计算损失函数时,可以把w的模||w||固定为1?

    因为感知机只关心损失函数的符号,不关心损失函数的大小。把w的模||w||固定为1可以使得计算简便。事实上,对于误分点到超平面的距离和的几何间隔Q=L/||w||,我们取L作为损失函数且优化使它最小,但L的极小值点不一定与Q的极小值点或||w||的极大值点相同,但感知机并不关心这个信息,只要求如果数据集线性可分,将L优化到0。这样找到的解不一定是唯一解,也不一定是最优解。

  b、对偶形式的优点?

    因为可以事先计算训练集的内积Gram矩阵,可以使得训练的速度较快。(但是为什么表现不如原始形式?还是代码实现错了?)

 

 

 参考:李航 《统计学习方法(第二版)》

   感知机原理小结:https://www.cnblogs.com/pinard/p/6042320.html#!comments

 

iwehdio的博客园:https://www.cnblogs.com/iwehdio/

 

 

おすすめ

転載: www.cnblogs.com/iwehdio/p/11963056.html