






import pickle

import numpy as np
from matplotlib import pyplot as plt



class 				_UpperCamelCase      :


      def __init__(						self       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase=0.2       ,    __UpperCamelCase=0.2						)->						Any:
           __lowerCAmelCase             =       bp_numa
           __lowerCAmelCase             =       bp_numa
           __lowerCAmelCase             =       bp_numa
           __lowerCAmelCase             =       conva_get[:2]
           __lowerCAmelCase             =       conva_get[2]
           __lowerCAmelCase             =       size_pa
           __lowerCAmelCase             =       rate_w
           __lowerCAmelCase             =       rate_t
           __lowerCAmelCase             =       [
               np.mat(-1 * np.random.rand(self.conva[0]       ,    self.conva[0]						) + 0.5						)
               for i in range(self.conva[1]						)
           ]
           __lowerCAmelCase             =       np.mat(-1 * np.random.rand(self.num_bpa       ,    self.num_bpa						) + 0.5						)
           __lowerCAmelCase             =       np.mat(-1 * np.random.rand(self.num_bpa       ,    self.num_bpa						) + 0.5						)
           __lowerCAmelCase             =       -2 * np.random.rand(self.conva[1]						) + 1
           __lowerCAmelCase             =       -2 * np.random.rand(self.num_bpa						) + 1
           __lowerCAmelCase             =       -2 * np.random.rand(self.num_bpa						) + 1


      def 			__UpperCAmelCase		(						self       ,    __UpperCamelCase						)->						Tuple:
           # save model dict with pickle
           __lowerCAmelCase             =       {
               "num_bp1": self.num_bpa,
               "num_bp2": self.num_bpa,
               "num_bp3": self.num_bpa,
               "conv1": self.conva,
               "step_conv1": self.step_conva,
               "size_pooling1": self.size_poolinga,
               "rate_weight": self.rate_weight,
               "rate_thre": self.rate_thre,
               "w_conv1": self.w_conva,
               "wkj": self.wkj,
               "vji": self.vji,
               "thre_conv1": self.thre_conva,
               "thre_bp2": self.thre_bpa,
               "thre_bp3": self.thre_bpa,
           }
           with open(__UpperCamelCase       ,    "wb"						) as f:
                pickle.dump(__UpperCamelCase       ,    __UpperCamelCase						)

           print(F"""Model saved： {save_path}"""						)


      @classmethod
      def 			__UpperCAmelCase		(						cls       ,    __UpperCamelCase						)->						Optional[Any]:
           # read saved model
           with open(__UpperCamelCase       ,    "rb"						) as f:
                __lowerCAmelCase             =       pickle.load(__UpperCamelCase						)  # noqa: S301

           __lowerCAmelCase             =       model_dic.get("conv1"						)
           conv_get.append(model_dic.get("step_conv1"						)						)
           __lowerCAmelCase             =       model_dic.get("size_pooling1"						)
           __lowerCAmelCase             =       model_dic.get("num_bp1"						)
           __lowerCAmelCase             =       model_dic.get("num_bp2"						)
           __lowerCAmelCase             =       model_dic.get("num_bp3"						)
           __lowerCAmelCase             =       model_dic.get("rate_weight"						)
           __lowerCAmelCase             =       model_dic.get("rate_thre"						)
           # create model instance
           __lowerCAmelCase             =       CNN(__UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase						)
           # modify model parameter
           __lowerCAmelCase             =       model_dic.get("w_conv1"						)
           __lowerCAmelCase             =       model_dic.get("wkj"						)
           __lowerCAmelCase             =       model_dic.get("vji"						)
           __lowerCAmelCase             =       model_dic.get("thre_conv1"						)
           __lowerCAmelCase             =       model_dic.get("thre_bp2"						)
           __lowerCAmelCase             =       model_dic.get("thre_bp3"						)
           return conv_ins


      def 			__UpperCAmelCase		(						self       ,    __UpperCamelCase						)->						int:
           return 1 / (1 + np.exp(-1 * x						))


      def 			__UpperCAmelCase		(						self       ,    __UpperCamelCase						)->						Optional[Any]:
           return round(__UpperCamelCase       ,    3						)


      def 			__UpperCAmelCase		(						self       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase						)->						Optional[Any]:
           # convolution process
           __lowerCAmelCase             =       convs[0]
           __lowerCAmelCase             =       convs[1]
           __lowerCAmelCase             =       np.shape(__UpperCamelCase						)[0]
           # get the data slice of original image data, data_focus
           __lowerCAmelCase             =       []
           for i_focus in range(0       ,    size_data - size_conv + 1       ,    __UpperCamelCase						):
                for j_focus in range(0       ,    size_data - size_conv + 1       ,    __UpperCamelCase						):
                     __lowerCAmelCase             =       data[
                         i_focus : i_focus + size_conv, j_focus : j_focus + size_conv
                     ]
                     data_focus.append(__UpperCamelCase						)
        # calculate the feature map of every single kernel, and saved as list of matrix
           __lowerCAmelCase             =       []
           __lowerCAmelCase             =       int((size_data - size_conv) / conv_step + 1						)
           for i_map in range(__UpperCamelCase						):
                __lowerCAmelCase             =       []
                for i_focus in range(len(__UpperCamelCase						)						):
                     __lowerCAmelCase             =       (
                         np.sum(np.multiply(data_focus[i_focus]       ,    w_convs[i_map]						)						)
                         - thre_convs[i_map]
                     )
                     featuremap.append(self.sig(__UpperCamelCase						)						)
                __lowerCAmelCase             =       np.asmatrix(__UpperCamelCase						).reshape(
                    __UpperCamelCase       ,    __UpperCamelCase						)
                data_featuremap.append(__UpperCamelCase						)

           # expanding the data slice to One dimenssion
           __lowerCAmelCase             =       []
           for each_focus in data_focus:
                focusa_list.extend(self.Expand_Mat(__UpperCamelCase						)						)
           __lowerCAmelCase             =       np.asarray(__UpperCamelCase						)
           return focus_list, data_featuremap


      def 			__UpperCAmelCase		(						self       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase="average_pool"						)->						Dict:
           # pooling process
           __lowerCAmelCase             =       len(featuremaps[0]						)
           __lowerCAmelCase             =       int(size_map / size_pooling						)
           __lowerCAmelCase             =       []
           for i_map in range(len(__UpperCamelCase						)						):
                __lowerCAmelCase             =       featuremaps[i_map]
                __lowerCAmelCase             =       []
                for i_focus in range(0       ,    __UpperCamelCase       ,    __UpperCamelCase						):
                     for j_focus in range(0       ,    __UpperCamelCase       ,    __UpperCamelCase						):
                          __lowerCAmelCase             =       feature_map[
                              i_focus : i_focus + size_pooling,
                              j_focus : j_focus + size_pooling,
                          ]
                          if pooling_type == "average_pool":
                               # average pooling
                               map_pooled.append(np.average(__UpperCamelCase						)						)
                          elif pooling_type == "max_pooling":
                               # max pooling
                               map_pooled.append(np.max(__UpperCamelCase						)						)
                __lowerCAmelCase             =       np.asmatrix(__UpperCamelCase						).reshape(__UpperCamelCase       ,    __UpperCamelCase						)
                featuremap_pooled.append(__UpperCamelCase						)
           return featuremap_pooled


      def 			__UpperCAmelCase		(						self       ,    __UpperCamelCase						)->						Tuple:
           # expanding three dimension data to one dimension list
           __lowerCAmelCase             =       []
           for i in range(len(__UpperCamelCase						)						):
                __lowerCAmelCase             =       np.shape(data[i]						)
                __lowerCAmelCase             =       data[i].reshape(1       ,    shapes[0] * shapes[1]						)
                __lowerCAmelCase             =       data_listed.getA().tolist()[0]
                data_expanded.extend(__UpperCamelCase						)
           __lowerCAmelCase             =       np.asarray(__UpperCamelCase						)
           return data_expanded


      def 			__UpperCAmelCase		(						self       ,    __UpperCamelCase						)->						str:
           # expanding matrix to one dimension list
           __lowerCAmelCase             =       np.asarray(__UpperCamelCase						)
           __lowerCAmelCase             =       np.shape(__UpperCamelCase						)
           __lowerCAmelCase             =       data_mat.reshape(1       ,    shapes[0] * shapes[1]						)
           return data_expanded


      def 			__UpperCAmelCase		(						self       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase						)->						Dict:
           __lowerCAmelCase             =       []
           __lowerCAmelCase             =       0
           for i_map in range(__UpperCamelCase						):
                __lowerCAmelCase             =       np.ones((size_map, size_map)						)
                for i in range(0       ,    __UpperCamelCase       ,    __UpperCamelCase						):
                     for j in range(0       ,    __UpperCamelCase       ,    __UpperCamelCase						):
                          __lowerCAmelCase             =       pd_pool[
                              i_pool
                          ]
                          __lowerCAmelCase             =       i_pool + 1
                __lowerCAmelCase             =       np.multiply(
                    __UpperCamelCase       ,    np.multiply(out_map[i_map]       ,    (1 - out_map[i_map])						)						)
                pd_all.append(__UpperCamelCase						)
           return pd_all


      def 			__UpperCAmelCase		(						self       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase       ,    __UpperCamelCase=bool						)->						Union[str, Any]:
           # model traning
           print("----------------------Start Training-------------------------"						)
           print((" - - Shape: Train_Data  ", np.shape(__UpperCamelCase						))						)
           print((" - - Shape: Teach_Data  ", np.shape(__UpperCamelCase						))						)
           __lowerCAmelCase             =       0
           __lowerCAmelCase             =       []
           __lowerCAmelCase             =       1_0_0_0_0
           while rp < n_repeat and mse >= error_accuracy:
                __lowerCAmelCase             =       0
                print(F"""-------------Learning Time {rp}--------------"""						)
                for p in range(len(__UpperCamelCase						)						):
                     # print('------------Learning Image: %d--------------'%p)
                     __lowerCAmelCase             =       np.asmatrix(datas_train[p]						)
                     __lowerCAmelCase             =       np.asarray(datas_teach[p]						)
                     __lowerCAmelCase      ,			__lowerCAmelCase             =       self.convolute(
                         __UpperCamelCase       ,    self.conva       ,    self.w_conva       ,    self.thre_conva       ,    conv_step=self.step_conva       ,    )
                     __lowerCAmelCase             =       self.pooling(__UpperCamelCase       ,    self.size_poolinga						)
                     __lowerCAmelCase             =       np.shape(__UpperCamelCase						)
                     __lowerCAmelCase             =       self._expand(__UpperCamelCase						)
                     __lowerCAmelCase             =       data_bp_input

                     __lowerCAmelCase             =       np.dot(__UpperCamelCase       ,    self.vji.T						) - self.thre_bpa
                     __lowerCAmelCase             =       self.sig(__UpperCamelCase						)
                     __lowerCAmelCase             =       np.dot(__UpperCamelCase       ,    self.wkj.T						) - self.thre_bpa
                     __lowerCAmelCase             =       self.sig(__UpperCamelCase						)

                     # --------------Model Leaning ------------------------
                     # calculate error and gradient---------------
                     __lowerCAmelCase             =       np.multiply(
                         (data_teach - bp_outa)       ,    np.multiply(__UpperCamelCase       ,    (1 - bp_outa)						)						)
                     __lowerCAmelCase             =       np.multiply(
                         np.dot(__UpperCamelCase       ,    self.wkj						)       ,    np.multiply(__UpperCamelCase       ,    (1 - bp_outa)						)						)
                     __lowerCAmelCase             =       np.dot(__UpperCamelCase       ,    self.vji						)

                     __lowerCAmelCase             =       pd_i_all / (self.size_poolinga * self.size_poolinga)
                     __lowerCAmelCase             =       pd_conva_pooled.T.getA().tolist()
                     __lowerCAmelCase             =       self._calculate_gradient_from_pool(
                         __UpperCamelCase       ,    __UpperCamelCase       ,    shape_featuremapa[0]       ,    shape_featuremapa[1]       ,    self.size_poolinga       ,    )
                     # weight and threshold learning process---------
                     # convolution layer
                     for k_conv in range(self.conva[1]						):
                          __lowerCAmelCase             =       self._expand_mat(pd_conva_all[k_conv]						)
                          __lowerCAmelCase             =       self.rate_weight * np.dot(__UpperCamelCase       ,    __UpperCamelCase						)

                          __lowerCAmelCase             =       self.w_conva[k_conv] + delta_w.reshape(
                              (self.conva[0], self.conva[0])						)

                          __lowerCAmelCase             =       (
                              self.thre_conva[k_conv]
                              - np.sum(pd_conva_all[k_conv]						) * self.rate_thre
                          )
                     # all connected layer
                     __lowerCAmelCase             =       self.wkj + pd_k_all.T * bp_outa * self.rate_weight
                     __lowerCAmelCase             =       self.vji + pd_j_all.T * bp_outa * self.rate_weight
                     __lowerCAmelCase             =       self.thre_bpa - pd_k_all * self.rate_thre
                     __lowerCAmelCase             =       self.thre_bpa - pd_j_all * self.rate_thre
                     # calculate the sum error of all single image
                     __lowerCAmelCase             =       np.sum(abs(data_teach - bp_outa						)						)
                     error_count += errors
                     # print('   ----Teach      ',data_teach)
                     # print('   ----BP_output  ',bp_out3)
                __lowerCAmelCase             =       rp + 1
                __lowerCAmelCase             =       error_count / patterns
                all_mse.append(__UpperCamelCase						)

           def draw_error():
                __lowerCAmelCase             =       [error_accuracy for i in range(int(n_repeat * 1.2						)						)]
                plt.plot(__UpperCamelCase       ,    "+-"						)
                plt.plot(__UpperCamelCase       ,    "r--"						)
                plt.xlabel("Learning Times"						)
                plt.ylabel("All_mse"						)
                plt.grid(__UpperCamelCase       ,    alpha=0.5						)
                plt.show()

           print("------------------Training Complished---------------------"						)
           print((" - - Training epoch: ", rp, F"""     - - Mse: {mse:.6f}""")						)
           if draw_e:
                draw_error()
           return mse


      def 			__UpperCAmelCase		(						self       ,    __UpperCamelCase						)->						Optional[Any]:
           # model predict
           __lowerCAmelCase             =       []
           print("-------------------Start Testing-------------------------"						)
           print((" - - Shape: Test_Data  ", np.shape(__UpperCamelCase						))						)
           for p in range(len(__UpperCamelCase						)						):
                __lowerCAmelCase             =       np.asmatrix(datas_test[p]						)
                __lowerCAmelCase      ,			__lowerCAmelCase             =       self.convolute(
                    __UpperCamelCase       ,    self.conva       ,    self.w_conva       ,    self.thre_conva       ,    conv_step=self.step_conva       ,    )
                __lowerCAmelCase             =       self.pooling(__UpperCamelCase       ,    self.size_poolinga						)
                __lowerCAmelCase             =       self._expand(__UpperCamelCase						)

                __lowerCAmelCase             =       data_bp_input
                __lowerCAmelCase             =       bp_outa * self.vji.T - self.thre_bpa
                __lowerCAmelCase             =       self.sig(__UpperCamelCase						)
                __lowerCAmelCase             =       bp_outa * self.wkj.T - self.thre_bpa
                __lowerCAmelCase             =       self.sig(__UpperCamelCase						)
                produce_out.extend(bp_outa.getA().tolist()						)
           __lowerCAmelCase             =       [list(map(self.do_round       ,    __UpperCamelCase						)						) for each in produce_out]
           return np.asarray(__UpperCamelCase						)


      def 			__UpperCAmelCase		(						self       ,    __UpperCamelCase						)->						Dict:
           # return the data of image after convoluting process so we can check it out
           __lowerCAmelCase             =       np.asmatrix(__UpperCamelCase						)
           __lowerCAmelCase      ,			__lowerCAmelCase             =       self.convolute(
               __UpperCamelCase       ,    self.conva       ,    self.w_conva       ,    self.thre_conva       ,    conv_step=self.step_conva       ,    )
           __lowerCAmelCase             =       self.pooling(__UpperCamelCase       ,    self.size_poolinga						)

           return data_conveda, data_pooleda


if __name__ == "__main__":
 pass














lowerCamelCase      :       List[Any]    =						{
    '''meter''': '''m''',
    '''kilometer''': '''km''',
    '''megametre''': '''Mm''',
    '''gigametre''': '''Gm''',
    '''terametre''': '''Tm''',
    '''petametre''': '''Pm''',
    '''exametre''': '''Em''',
    '''zettametre''': '''Zm''',
    '''yottametre''': '''Ym''',
}
# Exponent of the factor(meter)
lowerCamelCase      :       Union[str, Any]    =						{
    '''m''': 0,
    '''km''': 3,
    '''Mm''': 6,
    '''Gm''': 9,
    '''Tm''': 12,
    '''Pm''': 15,
    '''Em''': 18,
    '''Zm''': 21,
    '''Ym''': 24,
}





def    __lowerCAmelCase   (    __snake_case       ,			__snake_case       ,			__snake_case							):
     __lowerCAmelCase             =       from_type.lower().strip("s"							)
     __lowerCAmelCase             =       to_type.lower().strip("s"							)

     __lowerCAmelCase             =       UNIT_SYMBOL.get(__snake_case       ,			__snake_case							)
     __lowerCAmelCase             =       UNIT_SYMBOL.get(__snake_case       ,			__snake_case							)

     if from_sanitized not in METRIC_CONVERSION:
          __lowerCAmelCase             =       (
              F"""Invalid 'from_type' value: {from_type!r}.\n"""
              F"""Conversion abbreviations are: {", ".join(__snake_case							)}"""
          )
          raise ValueError(__snake_case							)
     if to_sanitized not in METRIC_CONVERSION:
          __lowerCAmelCase             =       (
              F"""Invalid 'to_type' value: {to_type!r}.\n"""
              F"""Conversion abbreviations are: {", ".join(__snake_case							)}"""
          )
          raise ValueError(__snake_case							)
     __lowerCAmelCase             =       METRIC_CONVERSION[from_sanitized]
     __lowerCAmelCase             =       METRIC_CONVERSION[to_sanitized]
     __lowerCAmelCase             =       1

     if from_exponent > to_exponent:
          __lowerCAmelCase             =       from_exponent - to_exponent
     else:
          __lowerCAmelCase             =       -(to_exponent - from_exponent)

     return value * pow(10       ,			__snake_case							)


if __name__ == "__main__":
 from doctest import testmod

 testmod()






