text: from keras.models import Model
  from keras.layers import Dense,Input,Flatten,Conv2D,BatchNormalization,Activation,MaxPooling2D
  from keras.layers import Dropout, Lambda, GlobalAveragePooling2D
  import keras.utils
  import keras.backend
  import numpy as np
  import tensorflow as tf
  from attention import SelfAttention
  #from keras_multi_head import MultiHeadAttention
  
  ASC_CLASS=10
  
  '''
      DCASE 2019 Audio Scene Classification Task/1a baseline
      ベース(基本モデル)のクラス
  '''
  class DCASE_CNN_2019(object):
  
      # __init__ はクラスが初期化されるときに呼び出される
      def __init__(self, dropout=0.3):
          self.dropout=dropout
          # do nothing
  
      # __call__ はクラスがインスタンス化されるときに呼び出される
      def __call__(self, x):
          # xは入力
  
          # ======
          # 最初の畳み込み
          # 入力ベクトルは3次元 特徴量次元，時間次元，チャンネル次元
          # 入力ベクトルサイズ = (40, 500, 1) -> 出力ベクトルサイズ (40, 500, 32)
          # フィルタは，入力の基本的な要素を取り出す（基底）
          x=Conv2D(filters=32,    # フィルタの数
                  kernel_size=7,  # フィルタの縦横のサイズ
                  padding='same', # 出力のサイズ(同じ)
                  data_format='channels_last',
                  kernel_initializer='glorot_uniform')(x)
  
          # バッチ正則化(データが正規分布にしたがうよう，偏りをなくす)
          x=BatchNormalization(axis=-1)(x)
          # 非線形の活性関数
          x=Activation('relu')(x)
  
          # 最大値プーリング 入力ベクトルサイズ=(40, 500, 32) -> 出力ベクトルサイズ (8, 100, 32)
          x=MaxPooling2D(pool_size=(5,5), # プーリングサイズ
              data_format='channels_last')(x)
          # データの一部を欠落させる(過学習回避のため)
          x=Dropout(rate=self.dropout)(x)
          # ====== ここまでが1つの処理単位
  
          # 2つめの畳み込み---同様の処理を行う
          x=Conv2D(filters=64,    # フィルタの数 32->64
                  kernel_size=7,
                  padding='same',
                  kernel_initializer='glorot_uniform',
                  data_format='channels_last')(x)
          x=BatchNormalization(axis=-1)(x)
          x=Activation('relu')(x) # ここでは (8, 100, 64)
  
          # 最大値プーリング 入力ベクトルサイズ=(8, 100, 64) -> 出力ベクトルサイズ (2, 1, 64)
          x=MaxPooling2D(pool_size=(4,100),
              data_format='channels_last')(x)
          x=Dropout(rate=self.dropout)(x)
  
          # ベクトルの形状を1次元に変える
          # 入力ベクトルサイズ (2, 1, 64) -> 出力ベクトルサイズ (128)
          x=Flatten()(x)
  
          # アフィン変換+活性化関数 128 -> 100
          x=Dense(units=100, kernel_initializer='uniform', activation='relu')(x)
          x=Dropout(rate=self.dropout)(x)
  
          # アフィン変換+活性化関数 100 -> 10
          output=Dense(units=ASC_CLASS, kernel_initializer='uniform',activation='softmax')(x)
  
          return output   # 10個の確率がおさまったベクトル
  
  '''
      4-layer convolutional network
  '''
  class CNN4(object):
  
      def __init__(self, dropout=0.3, attention=False):
          self.dropout=dropout
          self.attention=attention
      def __call__(self, x):
  
          for depth in range(4):
              x=Conv2D(filters=64*(depth+1),  # 64, 128, 192, 256
                      kernel_size=5, padding='same',
                      data_format='channels_last',
                      kernel_initializer='glorot_uniform')(x)
              x=BatchNormalization(axis=-1)(x)
              x=Activation('relu')(x)
              # 最大値プーリング, 各軸半分にする (40, 500) -> (20, 250) -> (10, 125) -> (5, 62) -> (2, 31)
              x=MaxPooling2D(pool_size=(2,2), data_format='channels_last')(x)
              x=Dropout(rate=self.dropout)(x)
          # 出力ベクトルの形状 (40//16, 500//16, 256) = (2, 31, 256)
          if self.attention == True:
              x=SelfAttention(x, output_filters=256)
              #x=MultiHeadAttention(head_num=64)(x)
              #x=BatchNormalization(axis=-1)(x)
              #x=GaussianNoise(0.3)(x)
          # 特徴量，時間方向に平均プーリング
          x=GlobalAveragePooling2D(data_format='channels_last')(x)
          # (256) 次元 -> (10) 次元
          output=Dense(units=ASC_CLASS, kernel_initializer='uniform', activation='softmax')(x)
  
          return output   # 10個の確率がおさまったベクトル
  
  '''
      8-layer convolutional network
  '''
  class CNN8(object):
  
      def __init__(self, dropout=0.3, attention=False):
          self.dropout=dropout
          self.attention=attention
      def __call__(self, x):
  
          for depth in range(4):
              filters=64*(depth+1)
              # add 2 convolutional layers
              for cv in range(2):
                  x=Conv2D(filters=filters,
                          kernel_size=3, padding='same',
                          data_format='channels_last',
                          kernel_initializer='glorot_uniform')(x)
                  x=BatchNormalization(axis=-1)(x)
                  x=Activation('relu')(x)
              x=MaxPooling2D(pool_size=(2,2), data_format='channels_last')(x)
              x=Dropout(rate=self.dropout)(x)
  
          if self.attention == True:
              x=SelfAttention(x, output_filters=256)
              #x=MultiHeadAttention(head_num)(x)
              #x=BatchNormalization(axis=-1)(x)
              #x=GaussianNoise(0.3)(x)
  
          # global max pooling 2D
          x=GlobalAveragePooling2D(data_format='channels_last')(x)
  
          # full connection
          output=Dense(units=ASC_CLASS, kernel_initializer='uniform', activation='softmax')(x)
  
          return output
  