Tensorflow2.0 reuse layers - tensorflow2.0

def head(self, input, num_anchors, name, flatten=False):
out_channels = (self.num_classes + 4) * num_anchors
conv = layers.Conv2D(256, 3, 1, 'same', activation='relu', name=name+'_conv1')(input)
conv = layers.Conv2D(256, 3, 1, 'same', activation='relu', name=name+'_conv2')(conv)
conv = layers.Conv2D(256, 3, 1, 'same', activation='relu', name=name+'_conv3')(conv)
out = layers.Conv2D(out_channels, 3, 1, 'same', name=name+'output')(conv)
if flatten is True:
batch_size = tf.shape(out)[0]
out = tf.reshape(out, [batch_size, -1, num_anchors, self.num_classes+4])
out = tf.reshape(out, [batch_size, -1, self.num_classes+4])
return out
I want to know how to reuse these layers as tf.variable_scope(scope resue=tf.AUTO_REUSE) in tensorflow1
In tensorflow1
with tf.variable_scope('', resue=tf.AUTO_REUSE) as scope:
all layers here could be auto reuse

You can reuse the layers by just having a common reference. I have attached a sample code below. I am making use of a variable named as common_layer which will be used in three separate models (sequential and functional). The first model is trained and after that we subtract the weights from common_layer of all the three models. It proves that what changes happen in first model's layer gets reflected in other model's common layer.
import tensorflow as tf
import numpy as np
common_layer = tf.keras.layers.Dense(100, name='common_layer')
model1 = tf.keras.models.Sequential([
tf.keras.layers.Input((100)),
common_layer,
tf.keras.layers.Dense(1)
])
model2 = tf.keras.models.Sequential([
tf.keras.layers.Input((100)),
common_layer,
tf.keras.layers.Dense(10)
])
input_layer = tf.keras.layers.Input((100))
output_layer = common_layer(input_layer)
output_layer = tf.keras.layers.Dense(20)(output_layer)
model3 = tf.keras.Model(inputs=[input_layer], outputs=[output_layer])
model1.compile('adam', loss='mse')
model1.fit(np.random.rand(128, 100), np.random.rand(128, 1))
weights1 = model1.get_weights()[0]
weights2 = model2.get_weights()[0]
weights3 = model3.get_weights()[0]
print(np.sum(weights1 - weights2)) # 0.0
print(np.sum(weights1 - weights3)) # 0.0

Related

Input layer 0 of sequence is incompatible with the layer - CNNs

I am trying to create a CNN model using hyperparameterization for image classification. When I run the code I receive the following error:
ValueError: Input 0 of layer "sequential" is incompatible with the layer: expected shape=(None, 32, 32, 32, 3), found shape=(32, 32, 32, 3)
How to fix the error? Here is the whole code pasted below:
# first we create our actual code which requires the arguments, units, activation, dropout, lr:
def build_model(hp):
model = ks.Sequential([
# adding first conv2d layer
ks.layers.Conv2D(
#Let's tune the filters, kernel_size, activation function.
filters = hp.Int("conv_1_filter", min_value=1,max_value=100, step = 16),
kernel_size = hp.Choice("conv_1_kernel", values = [3,5]),
activation = hp.Choice("conv_1_activation", ["relu", "tanh", "softmax"]),
input_shape = (32,32,32,3)
),
# adding second conv2d layer
ks.layers.Conv2D(
#Let's tune the filters, kernel_size, activation function.
filters = hp.Int("conv_2_filter", min_value=1,max_value=50, step = 16),
kernel_size = hp.Choice("conv_2_kernel", values = [3,5]),
activation = hp.Choice("conv_2_activation", ["relu", "tanh", "softmax"]),
input_shape = (32,32,32,3)
)])
model.add(layers.Flatten())
# Let's tune the number of Dense layers.
for i in range(hp.Int("num_dense_layers", 1, 3)):
model.add(
layers.Dense(
# Let's tune the number of units separately
units = hp.Int(f"units_{i}", min_value=1, max_value = 100, step = 16),
activation = hp.Choice("activation", ["relu", "tanh", "softmax"])
))
if hp.Boolean("dropout"):
model.add(layers.Dropout(rate = 0.25))
model.add(layers.Dense(10, activation = "softmax"))
learning_rate = hp.Float("lr", min_value = 1e-4, max_value = 1e-2, sampling="log")
model.compile(
optimizer = ks.optimizers.Adam(learning_rate = learning_rate),
loss = "categorical_crossentropy",
metrics = ["accuracy"]
)
return model
build_model(keras_tuner.HyperParameters())
You are getting this error due the input shape mismatch.
Here i have implemented the hypermodel on the mnist fashion dataset which contains images of shape (28,282,1).
def build_model(hp):
model = tf.keras.Sequential([
tf.keras.Input(shape=(28,28,1)),
# adding first conv2d layer
tf.keras.layers.Conv2D(
#Let's tune the filters, kernel_size, activation function.
filters = hp.Int("conv_1_filter", min_value=1,max_value=100, step = 16),
kernel_size = hp.Choice("conv_1_kernel", values = [3,5]),
activation = hp.Choice("conv_1_activation", ["relu", "tanh", "softmax"]),
input_shape = (28,28,1)
),
tf.keras.layers.MaxPooling2D(
pool_size=hp.Choice('pooling_1',values=[2,3])),
# adding second conv2d layer
tf.keras.layers.Conv2D(
#Let's tune the filters, kernel_size, activation function.
filters = hp.Int("conv_2_filter", min_value=1,max_value=50, step = 16),
kernel_size = hp.Choice("conv_2_kernel", values = [3,5]),
activation = hp.Choice("conv_2_activation", ["relu", "tanh", "softmax"]),
input_shape = (28,28,1)
)])
tf.keras.layers.MaxPooling2D(
pool_size=hp.Choice('pooling_2',values=[2,3])),
model.add(tf.keras.layers.Flatten())
if hp.Boolean("dropout"):
model.add(tf.keras.layers.Dropout(rate = 0.25))
model.add(tf.keras.layers.Dense(10, activation = "softmax"))
learning_rate = hp.Float("lr", min_value = 1e-4, max_value = 1e-2, sampling="log")
model.compile(
optimizer = tf.keras.optimizers.Adam(learning_rate = learning_rate),
loss = "categorical_crossentropy",
metrics = ["accuracy"]
)
return model
By providing the correct shape you will not get any error.
For more details, Please refer to this gist and this documentation. Thank You!

tensorflow improper batch setup Check failed: cudnnSetTensorNdDescriptor when using upsampling

I think I am setting up my batches wrong. If I run with the generated dataset it runs fine but with my own data I get an error.
If I take out the encoder (max pooling) and decoder (UpSampling2D) I don't get an error.
input size (304, 228, 1)
Generated: RUNS
import tensorflow as tf
from tensorflow.keras import layers
from natsort import natsorted
from tensorflow.keras.models import Model
BATCH_SIZE = 4
EPOCHS = 20
LEARNING_RATE = 1e-4
RESET_TRAINING = True
INPUT_CHANNELS = 1
OUTPUT_CHANNELS = 1
LOSS_TYPE = tf.keras.losses.SparseCategoricalCrossentropy()
img_size = (304, 228)
# configure cuda
physical_devices = tf.config.experimental.list_physical_devices('GPU')
assert len(physical_devices) > 0, "Not enough GPU hardware devices available"
config = tf.config.experimental.set_memory_growth(physical_devices[0], True)
class UnetModel(Model):
def __init__(self, *args, **kwargs):
super().__init__(UnetModel, *args, **kwargs)
# -- Encoder -- #
# Block encoder 1
input_shape = (img_size[0], img_size[1], 1)
# If you want to know more about why we are using `he_normal`:
# https://stats.stackexchange.com/questions/319323/whats-the-difference-between-variance-scaling-initializer-and-xavier-initialize/319849#319849
# Or the excellent fastai course:
# https://github.com/fastai/course-v3/blob/master/nbs/dl2/02b_initializing.ipynb
initializer = 'he_normal'
inputs = layers.Input(shape=input_shape)
print("input shape ", input_shape)
conv_enc_1 = layers.Conv2D(64, 3, activation='relu', padding='same', kernel_initializer=initializer)(inputs)
conv_enc_1 = layers.Conv2D(64, 3, activation = 'relu', padding='same', kernel_initializer=initializer)(conv_enc_1)
# Block encoder 2
max_pool_enc_2 = layers.MaxPooling2D(pool_size=(2, 2))(conv_enc_1)
conv_enc_2 = layers.Conv2D(128, 5, activation = 'relu', padding = 'same', kernel_initializer = initializer)(max_pool_enc_2)
conv_enc_2 = layers.Conv2D(128, 5, activation = 'relu', padding = 'same', kernel_initializer = initializer)(conv_enc_2)
# Block decoder 1
up_dec_4 = layers.Conv2D(64, 2, activation = 'relu', padding = 'same', kernel_initializer = initializer)(layers.UpSampling2D(size = (2,2))(conv_enc_2))
merge_dec_4 = layers.concatenate([conv_enc_1, up_dec_4], axis = 3)
conv_dec_4 = layers.Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = initializer)(merge_dec_4)
conv_dec_4 = layers.Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = initializer)(conv_dec_4)
conv_dec_4 = layers.Conv2D(2, 3, activation = 'relu', padding = 'same', kernel_initializer = initializer)(conv_dec_4)
# -- Dencoder -- #
output = layers.Conv2D(1, 1, activation = 'softmax')(conv_dec_4)
self.model = tf.keras.Model(inputs = inputs, outputs = output)
def call(self, x):
return self.model(x)
model = UnetModel()
model.compile(optimizer=tf.keras.optimizers.Adam(LEARNING_RATE), loss = LOSS_TYPE, metrics= [tf.keras.metrics.get('accuracy')])
dataset_debug = tf.data.Dataset.from_tensor_slices((tf.random.normal(shape = (BATCH_SIZE, img_size[0], img_size[1], 1)), tf.random.normal(shape = (BATCH_SIZE, img_size[0], img_size[1], 1)))).batch(BATCH_SIZE)
history = model.fit(dataset_debug, epochs=EPOCHS, shuffle=True)
Does NOT run
Here I am splitting the filenames into training and validation sets using train_test_split and reading in images in the parse_img_input function
# takes image filenames of uint8 and normalizes to 0-1 range
def parse_img_input(img_file, img_file_out):
print("img file ", img_file)
def _parse_input(img_file, img_file_out):
# get img image
d_filepath = img_file.numpy().decode()
d_image_decoded = tf.image.decode_jpeg(
tf.io.read_file(d_filepath), channels=1)
d_image = tf.cast(d_image_decoded, tf.float32) / 255.0
# get img image
d_filepath_out = img_file_out.numpy().decode()
d_image_decoded_out = tf.image.decode_jpeg(
tf.io.read_file(d_filepath_out), channels=1)
d_image_out = tf.cast(d_image_decoded_out, tf.float32) / 255.0
# add channel dimension
d_image = tf.expand_dims(d_image, -1)
d_image_out = tf.expand_dims(d_image_out, -1)
return d_image, d_image_out
return tf.py_function(_parse_input,
inp=[img_file, img_file_out],
Tout=[tf.float32, tf.float32])
# depth_files_in, depth_files_out are lists of filenames
# split input data into train, test sets
X_train_file, X_test_file, y_train_file, y_test_file = train_test_split(depth_files_in, depth_files_out,
test_size=0.2,
random_state=0)
dataset_train = tf.data.Dataset.from_tensor_slices((X_train_file, y_train_file))
dataset_train = dataset_train.map(parse_img_input)
dataset_test = tf.data.Dataset.from_tensor_slices((X_test_file, y_test_file))
dataset_test = dataset_test.map(parse_img_input)
history = model.fit(dataset_train, epochs=EPOCHS, shuffle=True, batch_size = BATCH_SIZE, validation_data= dataset_test)
F tensorflow/stream_executor/cuda/cuda_dnn.cc:535] Check failed: cudnnSetTensorNdDescriptor(handle_.get(), elem_type, nd, dims.data(), strides.data()) == CUDNN_STATUS_SUCCESS (3 vs. 0)batch_descriptor: {count: 228 feature_map_count: 64 spatial: 152 0 value_min: 0.000000 value_max: 0.000000 layout: BatchDepthYX}

Model.Predict is returning same values when using TF Keras ImageDataGenerator

I am using Cat and Dog Dataset for Training a Model using Tensorflow Keras and the Files are Read using ImageDataGenerator.flow_from_directory.
Training and Validation Accuracy is Decent but when tried Predicting on Test Data, Model is predicting the Same Class for all the Images.
Code for Training is shown below:
import os, shutil
import tensorflow as tf
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dropout, Dense
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import RMSprop
from tensorflow.keras.losses import binary_crossentropy
from tensorflow.keras.preprocessing import image
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import numpy as np
import matplotlib.pyplot as plt
# Path to Training Directory
train_dir = 'Dogs_Vs_Cats_Small/train'
# Path to Validation Directory
validation_dir = 'Dogs_Vs_Cats_Small/validation'
#### Create the Convolutional Base
Max_Pool_Size = (2,2)
model = Sequential([
Conv2D(input_shape = (150, 150, 3), filters = 32, kernel_size = (3,3), activation = 'relu',
padding = 'valid', data_format = 'channels_last'),
MaxPooling2D(pool_size = Max_Pool_Size),
Conv2D(filters = 64, kernel_size = (3,3), activation = 'relu', padding = 'valid'),
MaxPooling2D(pool_size = Max_Pool_Size),
Conv2D(filters = 128, kernel_size = (3,3), activation = 'relu', padding = 'valid'),
MaxPooling2D(pool_size = Max_Pool_Size),
Conv2D(filters = 128, kernel_size = (3,3), activation = 'relu', padding = 'valid'),
MaxPooling2D(pool_size = Max_Pool_Size)
])
#### Define the Dense Layers on Top of Convolutional Base
model.add(Flatten())
model.add(Dense(units = 512, activation = 'relu'))
model.add(Dense(units = 1, activation = 'sigmoid'))
model.summary()
model.compile(optimizer = RMSprop(learning_rate = 0.001), loss = 'binary_crossentropy', metrics = 'acc')
Train_Gen = ImageDataGenerator(1./255)
Val_Gen = ImageDataGenerator(1./255)
Train_Generator = Train_Gen.flow_from_directory(train_dir, target_size = (150,150), batch_size = 20,
class_mode = 'binary')
Val_Generator = Val_Gen.flow_from_directory(validation_dir, target_size = (150, 150), class_mode = 'binary',
batch_size = 20)
batch_size = 20
target_size = (150,150)
No_Of_Training_Images = Train_Generator.classes.shape[0]
No_Of_Val_Images = Val_Generator.classes.shape[0]
steps_per_epoch = No_Of_Training_Images/batch_size
validation_steps = No_Of_Val_Images/batch_size
history = model.fit(x = Train_Generator, shuffle=True, epochs = 20,
steps_per_epoch = steps_per_epoch,
validation_data = Val_Generator
, validation_steps = validation_steps
)
Now, I Predict on the Test Data as shown below:
Test_Dir = 'Dogs_Vs_Cats_Very_Small/test'
Test_Generator = ImageDataGenerator(1./255).flow_from_directory(Test_Dir,
target_size = (150,150), batch_size = 1,
shuffle = False, class_mode = 'binary') # This outputs Found 17 images belonging to 2 classes.
No_Of_Samples = len(Test_Generator.filenames)
testPredictions = model.predict(Test_Generator, steps = No_Of_Samples)
predictedClassIndices=np.argmax(testPredictions,axis=1)
print(predictedClassIndices)
filenames = Test_Generator.filenames
for f in range(len(filenames)):
print(filenames[f],":",predictedClassIndices[f])
Output of the above Print Statement, i.e., Predicted Classes are shown below:
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
cats/cat.1546.jpg : 0
cats/cat.1547.jpg : 0
cats/cat.1548.jpg : 0
cats/cat.1549.jpg : 0
cats/cat.1550.jpg : 0
cats/cat.1566.jpg : 0
cats/cat.1593.jpg : 0
cats/cat.1594.jpg : 0
dogs/dog.1514.jpg : 0
dogs/dog.1520.jpg : 0
dogs/dog.1525.jpg : 0
dogs/dog.1551.jpg : 0
dogs/dog.1555.jpg : 0
dogs/dog.1574.jpg : 0
dogs/dog.1594.jpg : 0
dogs/dog.1597.jpg : 0
dogs/dog.1599.jpg : 0
As seen above, all the Images are Predicted as Class = 0 i.e., Cats.
I've already look into this Stack Overflow Question and my Data is Balanced (1000 Cat Images and 1000 Dog Images) so, as per my understanding, Rebalancing my dataset or Adjusting class weights doesn't apply. I've tried "Increasing the time of training" as well.
EDIT: Content of testPredictions is shown below:
[[1.0473319e-05]
[9.8473930e-01]
[2.9069009e-01]
[5.0639841e-07]
[1.8511847e-01]
[6.0166395e-01]
[4.2568660e-01]
[4.6028453e-01]
[7.8800195e-01]
[8.5675471e-02]
[8.2654454e-02]
[7.2898394e-01]
[1.5504999e-01]
[8.2106847e-01]
[8.7003058e-01]
[9.9999285e-01]
[5.1210046e-01]]
Can someone help me to correct it.
Thank you all in advance.
The problem here is in the final step when you are assigning class to the testPredictions outcome. The argmax method "returns the indices of the maximum values along an axis". In your case it's always 0 because along axis=1 you have only one element (with index 0).
Since you're doing binary classification and the classes are balanced, it makes most sense to apply 0.5 probability threshold to assign classes:
predictedClassIndices = testPredictions > 0.5
for idx, filename in enumerate(filenames):
print(filename,":",predictedClassIndices[idx])

TensorFlow Keras Optimise prediction

I'm Using tensorflow and keras to predict handwrting digits. For training I'm using nmist dataset.
the accuracy is about 98.8% after training. but sometimes in test its confuse between 4 and 9 , 7 and 3, i'm alerady optimize the image input with opencv, like remove noise, rescale, threshold etc.
What should i do next to improved this prdiction accuracy?
My plan is add more sample, and resize the sample image from 28x28 to 56x56.
Will this affect accuracy?
This my model for training:
epoc=15, batch size=64
def build_model():
model = Sequential()
# add Convolutional layers
model.add(Conv2D(filters=32, kernel_size=(3,3), activation='relu', padding='same', input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(filters=64, kernel_size=(3,3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(filters=64, kernel_size=(3,3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
# Densely connected layers
model.add(Dense(128, activation='relu'))
# output layer
model.add(Dense(10, activation='softmax'))
# compile with adam optimizer & categorical_crossentropy loss function
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
return model
You can try to add regularization:
def conv2d_bn(x,
units,
kernel_size=(3, 3),
activation='relu',
dropout=.5):
y = Dropout(x)
y = Conv2D(units, kernel_size=kernel_size, use_bias=False)(y)
y = BatchNormalization(y)
y = Activation(activation)(y)
return y
def build_model(..., dropout=.5):
x = Input(shape=[...])
y = conv2d_bn(x, 32)
y = MaxPooling2D(y)
...
y = Dropout(dropout)(y)
y = Dense(10, activation='softmax')
model = Model(x, y)
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
return model
You can tweak the class weights to force the model to pay more attention to classes 3, 4, 7 and 9 during training:
model.fit(..., class_weights={0: 1, 1: 1, 2:1, 3:2, 4:2, 5:1, 6:1, 7:2, 8:1, 9:2})
If you have some time to burn, you can also try to grid or random-search the models hyperparameters. Something in the lines:
def build(conv_layers, dense_layers, dense_units, activation, dropout):
y = x = Input(shape=[...])
kernels = 32
kernel_size = (2, 2)
for i in range(conv_layers):
y = conv2d_bn(y, kernel_size, kernels, activation, dropout)
if i % 2 == 0: # or 3 or 4.
y = MaxPooling2D(y)
kernels *= 2
kernel_size = tuple(k+1 for k in kernel_size)
y = GlobalAveragePooling2D()(y)
for i in range(dense_layers):
y = Dropout(dropout)(y)
y = Dense(dense_units)(y)
y = Dense(10, activation='softmax')(y)
model = KerasClassifier(build_model,
epochs=epochs,
validation_split=validation_split,
verbose=0,
...)
params = dict(conv_layers=[2, 3, 4],
dense_layers=[0, 1],
activation=['relu', 'selu'],
dropout=[.2, .3, .5],
callbacks=[callbacks.EarlyStopping(patience=10,
restore_best_weights=True)])
grid = GridSearchCV(model, params,
scoring='balanced_accuracy_score',
verbose=2,
n_jobs=1)
Now, combining hyperparams searching with the NumpyArrayIterator is a little tricky, because the latter assumes we have all training samples (and targets) at hand before the training steps. It's still doable, though:
g = ImageDataGenerator(...)
cv = StratifiedKFold(n_splits=3)
results = dict(params=[], valid_score=[])
for params in ParameterGrid(params):
fold_scores = []
for t, v in cv.split(train_data, train_labels):
train = g.flow(train_data[t], train_labels[t], subset='training')
nn_valid = g.flow(train_data[t], train_labels[t], subset='validation')
fold_valid = g.flow(train_data[v], train_labels[v])
nn = build_model(**params)
nn.fit_generator(train, validation_data=nn_valid, ...)
probabilities = nn.predict_generator(fold_valid, steps=...)
p = np.argmax(probabilities, axis=1)
fold_scores += [metrics.accuracy_score(valid.classes_, p)]
results['params'] += [params]
results['valid_score'] += [fold_scores]
best_ix = np.argmax(np.mean(results['valid_score'], axis=1))
best_params = results['params'][best_ix]
nn = build_model(**best_params)
nn.fit_generator(...)

Concatenating conv layers with different filter sizes in CNTK

In CNTK - how can I use several filter sizes on the same layer (e.g. filter sizes 2,3,4,5)?
Following the work done here (link to code in github below(1)), I want to take text, use an embedding layer, apply four different sizes of filters (2,3,4,5), concatenate the results and feed it to a fully connected layer.
Network architecture figure
Keras sample code:
main_input = Input(shape=(100,)
embedding = Embedding(output_dim=32, input_dim=100, input_length=100, dropout=0)(main_input)
conv1 = getconvmodel(2,256)(embedding)
conv2 = getconvmodel(3,256)(embedding)
conv3 = getconvmodel(4,256)(embedding)
conv4 = getconvmodel(5,256)(embedding)
merged = merge([conv1,conv2,conv3,conv4],mode="concat")
def getconvmodel(filter_length,nb_filter):
model = Sequential()
model.add(Convolution1D(nb_filter=nb_filter,
`enter code here`input_shape=(100,32),
filter_length=filter_length,
border_mode='same',
activation='relu',
subsample_length=1))
model.add(Lambda(sum_1d, output_shape=(nb_filter,)))
#model.add(BatchNormalization(mode=0))
model.add(Dropout(0.5))
return model
(1): /joshsaxe/eXposeDeepNeuralNetwork/blob/master/src/modeling/models.py
You can do something like this:
import cntk as C
import cntk.layers as cl
def getconvmodel(filter_length,nb_filter):
#Function
def model(x):
f = cl.Convolution(filter_length, nb_filter, activation=C.relu))(x)
f = C.reduce_sum(f, axis=0)
f = cl.Dropout(0.5) (f)
return model
main_input = C.input_variable(100)
embedding = cl.Embedding(32)(main_input)
conv1 = getconvmodel(2,256)(embedding)
conv2 = getconvmodel(3,256)(embedding)
conv3 = getconvmodel(4,256)(embedding)
conv4 = getconvmodel(5,256)(embedding)
merged = C.splice([conv1,conv2,conv3,conv4])
Or with Sequential() and a lambda:
def getconvmodel(filter_length,nb_filter):
return Sequential([
cl.Convolution(filter_length, nb_filter, activation=C.relu)),
lambda f: C.reduce_sum(f, axis=0),
cl.Dropout()
])