ゼロから作るDeep Learning 5章 誤差逆伝番の実装をXorの実装に変更したい


「ゼロから作るDeep Learning 第5章」に記載してある誤差逆伝番の実装を使用して、Xorの判定を可能にしたいです。  
Google colaboratoryを使用し構築しています。

参考にしたページ:  
[ゼロから作るDeepLearning 5章を学ぶ
〜誤差逆伝播法〜](https://www.takapy.work/entry/2018/06/07/223928)

上記ページは下記コード変更前の誤差逆伝番の実装となります。  
こちらURLの実装に関して、データはGitHubに掲載してあるmnistを使用せず、kerasのデータセットを使用し、Google
Colaboratoryで正常に動作しました。  
(下記「データ読み込み」部分に記載してあるものが使用していたもの)

この上記URLの実装を下記のように変更後、コードを実行すると値は出力されますが、正答率は収束せずに終了しています。  
どのようにすれば、正確な値が出力され、学習、評価が正確に行われるのでしょうか

  * 書籍に掲載されているコードではSoftmax_WithLossを使用していますが、今回のLastLayerでは、Sigmoid_WithLossを使用しています。

  * 損失関数は交差エントロピー誤差から2乗和誤差に変更しています。

  * 書籍では入力・出力データとしてMnistを使用していますが、今回はXorの判定としてtrainとtestのデータは同じものを使用しています。

使用したコードは以下になります。

[code]

     from keras.utils.data_utils import dont_use_multiprocessing_pool
     class affine:#行列演算レイヤ
        def __init__(self,W,b):
            self.W = W
            self.b = b
    
            self.x = None
            # 重み・バイアスパラメータの微分
            self.dW = None
            self.db = None
    
        def forward(self, x):
    
             self.x = x
             out = np.dot(x, self.W) + self.b
             return out
    
        def backward(self,dout):
            dx = np.dot(dout, self.W.T)
            self.dW = np.dot(self.x.T, dout)
            self.db = np.sum(dout, axis=0)
    
            return dx
    
    class Sigmoid:
        def __init__(self):
            self.out = None
    
        def forward(self, x):
    
            self.out = 1 / (1 + np.exp(-x))
            return self.out
    
        def backward(self, dout):
            dx = dout * (1.0 - self.out) * self.out
            return dx
    
    
    def mean_squared_error(y,t):
      return 0.5 * np.sum((y - t)**2)
      
    
    
    def numerical_gradient1(f, x):
        h = 1e-4 # 0.0001
        grad = np.zeros_like(x)
    
        it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
        while not it.finished:
            idx = it.multi_index
            tmp_val = x[idx]
            x[idx] = tmp_val + h
            fxh1 = f(x) # f(x+h)
    
            x[idx] = tmp_val - h
            fxh2 = f(x) # f(x-h)
            grad[idx] = (fxh1 - fxh2) / (2*h)
    
            x[idx] = tmp_val # 値を元に戻す
            it.iternext()
    
         return grad
    
    # Sigmoid with Lossレイヤの実装
    class SigmoidWithLoss:
        
        # 初期化メソッドの定義
        def __init__(self):
            self.params = [] # パラメータ
            self.grads = []  # 勾配
            self.loss = None # 損失
            self.y = None # 正規化後の値
            self.t = None # 教師ラベル
        
        # 順伝播メソッドの定義
        def forward(self, x, t):
            self.t = t # 教師ラベル
            # 確率に変換
            self.y =self.out = 1 / (1 + np.exp(-x))
            # 2乗和誤差を計算
            self.loss =  mean_squared_error(np.c_[1 - self.y, self.y], self.t)
            
            return self.loss
        
        # 逆伝播メソッドの定義
        def backward(self, dout=1):
            # バッチサイズを取得
            batch_size = self.t.shape[0]
            
            # 勾配を計算
            dx = (self.y - self.t) * dout / batch_size # :式(A.4)
            
            return dx
    
[/code]

[code]

    from typing import Collection
    import numpy as np
    import sys, os
    import matplotlib.pyplot as plt
    from collections import OrderedDict
    
    
    class TwoLayerNet:
    
        def __init__(self, input_size, hiden_size, output_size, weight_init_std = 0.01):
            self.params = {} #辞書
            self.params['W1'] = weight_init_std * np.random.randn(input_size, hiden_size)
            self.params['b1'] = np.zeros(hiden_size)
            self.params['W2'] = weight_init_std * np.random.randn(hiden_size, output_size)
            self.params['b2'] = np.zeros(output_size)
    
    # レイヤの生成
            self.layers = OrderedDict()#OrderedDict は順番を含めて覚えるため、レイヤー名と処理を順次登録すると、その順番も含めて記憶する。
            self.layers['Affine1'] = affine(self.params['W1'], self.params['b1'])
            self.layers['Sigmoid1'] = Sigmoid()
            self.layers['Affine2'] = affine(self.params['W2'], self.params['b2'])
            self.lastLayer = SigmoidWithLoss()
            
    
        # 順伝播
        def predict(self, x):
            for layer in self.layers.values():#辞書 self.layers からレイヤー名を順番に
                x = layer.forward(x)
            return x
    
        # 順伝播・ロス計算(最終層の順伝播処理であり損失関数)
        def loss(self, x, t):
            y = self.predict(x)
            return self.lastLayer.forward(y, t)
    
     # 精度計算
        def accuracy(self, x, t):
            y = self.predict(x)
            y = np.argmax(y, axis=1) #argmaxで、数値が高いラベルのみを取り出す。
            if t.ndim != 1 :#1次元ではない場合
                 t = np.argmax(t, axis=1)# argmaxで、正解のラベルを取り出す。
    
            accuracy = np.sum(y == t) / float(x.shape[0])#y==tがTrueのものを１として合計して、それをデータの総数で割り算する。
            return accuracy
    
        # x:入力データ, t:教師データ
        # 数値微分、重みパラメータに対する勾配を求める
        def numerical_gradient(self, x, t):
            loss_W = lambda W: self.loss(x, t) # lambda 無名関数、lambda x: y ,xが引数で、yが返り値
            # def loss_W(W):self.loss(x,t) と同じ意味。つまりdefのように関数を作らず使用
    
            grads = {}
            grads['W1'] = numerical_gradient1(loss_W, self.params['W1'])# １層目の重みの勾配。損失関数と、重みから算出。
            grads['b1'] = numerical_gradient1(loss_W, self.params['b1'])# 1層目のバイアスの勾配。損失関数と、重みから算出。
            grads['W2'] = numerical_gradient1(loss_W, self.params['W2'])# 2層目の重みの勾配。損失関数と、重みから算出。
            grads['b2'] = numerical_gradient1(loss_W, self.params['b2'])# 2層目のバイアスの勾配。損失関数と、重みから算出。
    
            return grads
    
            # 重みパラメータに対する勾配を誤差逆伝播によって求める。
        def gradient(self, x, t):
            # forward
            self.loss(x, t)
            # backward
            dout = 1 
            dout = self.lastLayer.backward(dout) # 出力層の逆伝播を求める。
    
            layers = list(self.layers.values())#layersをリストにする。
            layers.reverse()# 逆の順番にする。
            for layer in layers:
                dout = layer.backward(dout) #各レイヤーの逆伝搬の値を算出する。
    
            #各レイヤの微分値取り出し(勾配の保持)
            grads ={}
            grads['W1'] = self.layers['Affine1'].dW 
            grads['b1'] = self.layers['Affine1'].db
            grads['W2'] = self.layers['Affine2'].dW
            grads['b2'] = self.layers['Affine2'].db
    
            return grads
    
[/code]

[code]

    # データの読み込み
    import numpy
    import sys, os
    import keras
    from keras.datasets import mnist
    import matplotlib.pyplot as plt
    # visualization tools
    %matplotlib inline
    import matplotlib.pyplot as plt
    
    
    #(x_train, t_train), (x_test, t_test) = mnist.load_data()#normalize=False, one_hot_label=False)
    #x_train = x_train.reshape(60000, 784)
    #x_test = x_test.reshape(10000, 784)
    #print(x_train[0,0])
    # データを float 型に変換
    #x_train = x_train.astype('float32')
    #x_test  = x_test.astype('float32')
    
    
    # 0〜255 までの範囲のデータを 0〜1 までの範囲に変更
    #x_train /= 255
    #x_test  /= 255
    #t_train = keras.utils.to_categorical(t_train, 10)
    #t_test  = keras.utils.to_categorical(t_test, 10)
    
    
    #print(x_test)
    #print(t_train.shape)
    #print(t_test.shape)
    
    x_train = np.array([[0,0],[1,0],[0,1],[1,1]])
    t_train = np.array([[0],[1],[1],[0]])
    x_test = np.array([[0,0],[1,0],[0,1],[1,1]])
    t_test = np.array([[0],[1],[1],[0]])
    x_train = x_train.astype('float32')
    x_test  = x_test.astype('float32')
    
    network = TwoLayerNet(input_size=2, hiden_size=2, output_size=2)
    iters_num = 1000 # 更新回数
    train_size = x_train.shape[0] #訓練データのサイズ
    
    batch_size = 1 # バッチサイズ
    learning_rate = 0.1 # 学習率
    
    # 正答率の表示頻度
    iter_per_epoch = max(train_size / batch_size, 1) # 1エポックあたりの繰り返し数
    
    train_loss_list = []
    train_acc_list = []
    test_acc_list = []
    
    for i in range(iters_num):#ミニバッチ生成
        # 0~(train_size-1)の中から重複ありランダムで抽出
        batch_mask = np.random.choice(train_size, batch_size)
        x_batch = x_train[batch_mask]
        t_batch = t_train[batch_mask]
        # 誤差逆伝播法によって勾配を求める
        grad = network.gradient(x_batch, t_batch)
    
        # パラメータの更新
        for key in ('W1', 'b1', 'W2', 'b2'):
            network.params[key] -= learning_rate * grad[key]
    
        loss = network.loss(x_batch, t_batch)
        train_loss_list.append(loss)
    
        if i % iter_per_epoch == 0:
            train_acc = network.accuracy(x_train, t_train)
            test_acc = network.accuracy(x_test, t_test)
            train_acc_list.append(train_acc)
            test_acc_list.append(test_acc)
            # 正答率の表示
            print(train_acc, test_acc)
    # グラフの描画
    markers = {'train': 'o', 'test': 's'}
    x = np.arange(len(train_acc_list))
    plt.plot(x, train_acc_list, label='train acc')
    plt.plot(x, test_acc_list, label='test acc', linestyle='--')
    plt.xlabel("epochs")
    plt.ylabel("accuracy")
    plt.ylim(0, 1.0)
    plt.legend(loc='lower right')
    plt.show()
    
[/code]

