I have created ResNet Network using custom layers:
import tensorflow as tf
import numpy as np
from tensorflow.keras.layers import Layer
from tensorflow.keras import Model
class Convolution_Layer(tf.keras.layers.Layer):
def __init__(self,kernel_height,kernel_width,channel_in,channel_out,stride,padding):
super(Convolution_Layer,self).__init__()
self.kernel_height = kernel_height
self.kernel_width = kernel_width
self.channel_in = channel_in
self.channel_out = channel_out
self.stride = stride
self.padding = padding
self.initializer = tf.initializers.GlorotUniform()
#weights:
self.W = tf.Variable(self.initializer(shape = (kernel_height,kernel_width,channel_in,channel_out)))
self.b = tf.Variable(self.initializer(shape = (channel_out,)))
def call(self,x):
x = tf.nn.conv2d(x,self.W,strides = self.stride,padding = self.padding) + self.b
return x
class Batch_Normalization(tf.keras.layers.Layer):
def __init__(self,depth,decay,convolution):
super(Batch_Normalization,self).__init__()
self.mean = tf.Variable(tf.constant(0.0,shape = [depth]),trainable = False)
self.var = tf.Variable(tf.constant(1.0,shape = [depth]),trainable = False)
self.beta = tf.Variable(tf.constant(0.0,shape = [depth]))
self.gamma = tf.Variable(tf.constant(1.0,shape = [depth]))
#exponentiall moving average object
self.mov_avg = tf.train.ExponentialMovingAverage(decay = decay)
self.epsilon = 0.001
self.convolution = convolution
def call(self,x,training = True):
if training:
if self.convolution:
batch_mean,batch_var = tf.nn.moments(x, axes=[0, 1, 2],keepdims = False)
else:
batch_mean,batch_var = tf.nn.moments(x, axes=[0],keepdims = False)
as_mean = self.mean.assign(batch_mean)
as_variance = self.var.assign(batch_var)
#ensured argument to be evaluated before anything you define in the with block
with tf.control_dependencies([as_mean,as_variance]):
ma =self.mov_avg.apply([self.mean,self.var])
x = tf.nn.batch_normalization(x = x,mean = batch_mean,variance = batch_var,offset = self.beta,scale = self.gamma,variance_epsilon = self.epsilon)
else:
mean = self.mov_avg.average(self.mean)
var = self.mov_avg.average(self.var)
local_beta = tf.identity(self.beta)
local_gamma = tf.identity(self.gamma)
x = tf.nn.batch_normalization(x,mean,var,local_beta,local_gamma,self.epsilon)
return x
class MaxPool(tf.keras.layers.Layer):
def __init__(self,kernel_size,strides,padding):
super(MaxPool,self).__init__()
self.kernel_size = kernel_size
self.strides = strides
self.padding = padding
def call(self,x):
return tf.nn.max_pool2d(x,ksize = [1,self.kernel_size,self.kernel_size,1],strides = [1,self.strides,self.strides,1],padding = self.padding)
class Dense_layer(tf.keras.layers.Layer):
def __init__(self,dim_out):
super(Dense_layer,self).__init__()
self.initializer = tf.initializers.GlorotUniform()
self.dim_out = dim_out
def build(self, input_shape):
self.W = self.add_weight(shape=(input_shape[-1], self.dim_out),initializer = self.initializer,trainable=True,name='w')
self.b = self.add_weight(shape=(self.dim_out,), initializer = self.initializer, trainable=True,name='b')
def call(self,x):
return x # self.W + self.b
class Global_Average_Pooling(tf.keras.layers.Layer):
def __init__(self,axis):
super(AvgPooling,self).__init__()
self.axis = axis
def call(self,x):
return tf.reduce_mean(x, axis = self.axis)
class Flatten_layer(tf.keras.layers.Layer):
def __init__(self):
super(Flatten_layer,self).__init__()
def call(self,x,shape = False):
return tf.reshape(x, [x.shape[0],-1])
class Softmax_layer(tf.keras.layers.Layer):
def __init__(self,dim_out):
super(Softmax_layer,self).__init__()
self.initializer = tf.initializers.GlorotUniform()
self.dim_out = dim_out
def build(self, input_shape):
self.W = self.add_weight(shape=(input_shape[-1], self.dim_out),initializer = self.initializer,trainable=True,name='w_s')
self.b = self.add_weight(shape=(self.dim_out,), initializer = self.initializer, trainable=True,name='b_s')
def call(self,x):
return tf.nn.softmax(tf.matmul(x,self.W) + self.b)
class AvgPooling(tf.keras.layers.Layer):
def __init__(self,kernel_height,kernel_width,strides,padding):
super(AvgPooling,self).__init__()
self.kernel_height = kernel_height
self.kernel_width = kernel_width
self.strides = strides
self.padding = padding
def call(self,x):
return tf.nn.avg_pool(input = x,ksize = [self.kernel_height,self.kernel_width],strides = self.strides,padding = self.padding)
class Dropout_layer(Layer):
def __init__(self,rate):
super(Dropout_layer,self).__init__()
self.rate = rate
def call(self,x,training = None):
if training:
return tf.nn.dropout(x,self.rate)
return x
class Identity(tf.keras.layers.Layer):
def __init__(self,filters):
super(Identity,self).__init__()
self.initializer = tf.initializers.GlorotUniform()
#Block one
self.conv_1 = Convolution_Layer(1,1,filters[0],filters[1],1,padding = 'VALID')
self.batch_norm_1 = Batch_Normalization(filters[1],0.99,convolution = True)
#Block two
self.conv_2 = Convolution_Layer(3,3,filters[1],filters[2],1,padding = 'SAME')
self.batch_norm_2 = Batch_Normalization(filters[2],0.99,convolution = True)
#Block two
self.conv_3 = Convolution_Layer(1,1,filters[2],filters[3],1,padding = 'VALID')
self.batch_norm_3 = Batch_Normalization(filters[3],0.99,convolution = True)
#Dimension adjustment variable:
#self.dimension = Convolution_Layer(1,1,channel_in,channel_out,1,padding = 'valid')
def call(self,x,training = None):
#Block one
fx = self.conv_1(x)
fx = self.batch_norm_1(fx,training)
fx = tf.nn.relu(fx)
#Block two
fx = self.conv_2(fx)
fx = self.batch_norm_2(fx,training)
fx = tf.nn.relu(fx)
#Block three
fx = self.conv_3(fx)
fx = self.batch_norm_3(fx,training)
#add input:
#fx = tf.nn.relu(fx + self.dimension(x))
fx = tf.nn.relu(fx + x)
return fx
class Convolution_Block(tf.keras.layers.Layer):
def __init__(self,filters,stride):
super(Convolution_Block,self).__init__()
self.initializer = tf.initializers.GlorotUniform()
#Block one
self.conv_1 = Convolution_Layer(1,1,filters[0],filters[1],stride,padding = 'VALID')
self.batch_norm_1 = Batch_Normalization(filters[1],0.99,convolution = True)
#Block two
self.conv_2 = Convolution_Layer(3,3,filters[1],filters[2],1,padding = 'SAME')
self.batch_norm_2 = Batch_Normalization(filters[2],0.99,convolution = True)
#Block three
self.conv_3 = Convolution_Layer(1,1,filters[2],filters[3],1,padding = 'VALID')
self.batch_norm_3 = Batch_Normalization(filters[3],0.99,convolution = True)
#Dimension adjustment variable:
self.dimension = Convolution_Layer(1,1,filters[0],filters[3],stride,padding = 'VALID')
def call(self,x,training = None):
#Block one
fx = self.conv_1(x)
fx = self.batch_norm_1(fx,training)
fx = tf.nn.relu(fx)
#Block two
fx = self.conv_2(fx)
fx = self.batch_norm_2(fx,training)
fx = tf.nn.relu(fx)
#Block three
fx = self.conv_3(fx)
fx = self.batch_norm_3(fx,training)
#Skip connection
fx = tf.nn.relu(fx + self.dimension(x))
return fx
class Global_Average_Pooling(tf.keras.layers.Layer):
def __init__(self,axis):
super(Global_Average_Pooling,self).__init__()
self.axis = axis
def call(self,x):
return tf.reduce_mean(x, axis = self.axis)
class Resnet(tf.keras.Model):
def __init__(self,num_classes = 10):
super(Resnet,self).__init__()
#1st stage: convolution with max pooling
self.zero_padding = tf.keras.layers.ZeroPadding2D(padding=(3, 3))
self.conv_1 = Convolution_Layer(kernel_height = 7,kernel_width = 7,channel_in = 3,channel_out = 64,stride = 2,padding = 'VALID')
self.batch_norm_1 = Batch_Normalization(depth = 64,decay = 0.99,convolution = True)
self.max_pool_1 = MaxPool(kernel_size = 3,strides = 2,padding = 'VALID')
'''
self.identity_layers = []
for f in identity_blocks_filters:
#self.identity_layers.append(Identity(kernel_height = 3,kernel_width = 3,channel_in = f[0],channel_out = f[1],stride = 1,decay = 0.99))
'''
#2nd stage:
self.block_2_res_conv_1 = Convolution_Block(filters = [64,64,64,256],stride = 1)
self.block_2_res_ident_1 = Identity(filters = [256,64,64,256])
self.block_2_res_ident_2 = Identity(filters = [256,64,64,256])
#3rd stage:
self.block_3_res_conv_1 = Convolution_Block(filters = [256,128,128,512],stride = 2)
self.block_3_res_ident_1 = Identity(filters = [512,128,128,512])
self.block_3_res_ident_2 = Identity(filters = [512,128,128,512])
self.block_3_res_ident_3 = Identity(filters = [512,128,128,512])
#4th stage:
self.block_4_res_conv_1 = Convolution_Block(filters = [512,256,256,1024],stride = 2)
self.block_4_res_ident_1 = Identity(filters = [1024,256,256,1024])
self.block_4_res_ident_2 = Identity([1024,256,256,1024])
self.block_4_res_ident_3 = Identity([1024,256,256,1024])
self.block_4_res_ident_4 = Identity([1024,256,256,1024])
self.block_4_res_ident_5 = Identity([1024,256,256,1024])
#5th stage:
self.block_5_res_conv_1 = Convolution_Block(filters = [1024,512,512,2048],stride = 2)
self.block_5_res_ident_1 = Identity(filters = [1024,512,512,2048])
self.block_5_res_ident_2 = Identity(filters = [1024,512,512,2048])
self.global_avg_pool = Global_Average_Pooling(axis = [1,2])
self.avg_pool = AvgPooling(kernel_height = 2,kernel_width = 2,strides = 1,padding = 'SAME')
self.flatten = Flatten_layer()
self.dense_1 = Dense_layer(512)
self.softmax = Softmax_layer(num_classes)
def call(self,x,training = None):
#1st stage: convolution with max pooling
x = self.zero_padding(x)
x = self.conv_1(x)
x = self.batch_norm_1(x,training)
x = tf.nn.relu(x)
x = self.max_pool_1(x)
#2nd stage:
'''
for i in range(len(self.identity_layers)):
x = self.identity_layers[i](x)
'''
x = self.block_2_res_conv_1(x)
x = self.block_2_res_ident_1(x)
x = self.block_2_res_ident_2(x)
#3rd stage:
x = self.block_3_res_conv_1(x)
x = self.block_3_res_ident_1(x)
x = self.block_3_res_ident_2(x)
x = self.block_3_res_ident_3(x)
#4th stage:
x = self.block_4_res_conv_1(x)
x = self.block_4_res_ident_1(x)
x = self.block_4_res_ident_2(x)
x = self.block_4_res_ident_3(x)
x = self.block_4_res_ident_4(x)
x = self.block_4_res_ident_5(x)
#5th stage:
x = self.block_5_res_conv_1(x)
x = self.block_5_res_ident_1(x)
x = self.block_5_res_ident_2(x)
x = self.global_avg_pool(x)
#x = self.avg_pool(x)
#x = self.flatten(x)
x = self.dense_1(x)
x = tf.nn.relu(x)
x = self.softmax(x)
return x
It runs successfully on CIFAR Dataset.
But when I try to save it i get the following error:
AssertionError: Tried to export a function which references 'untracked' resource Tensor("103247:0", shape=(), dtype=resource). TensorFlow objects (e.g. tf.Variable) captured by functions must be 'tracked' by assigning them to an attribute of a tracked object or assigned to an attribute of the main object directly.
Trackable Python objects referring to this tensor (from gc.get_referrers, limited to two hops):
<tf.Variable 'Variable/ExponentialMovingAverage_99:0' shape=(64,) dtype=float32>
So the problem is in my custom Layer Batch_Normalization . It seems like tf.train.ExponentialMovingAverage is not assigned.
I found this post AssertionError: Tried to export a function which references untracked resource
But it didn't help me, because problem was different: I didn't define any class variables. What ist exactly meant by "must be 'tracked' by assigning them to an attribute of a tracked object or assigned to an attribute of the main object directly." ? How can I fix that?
tensorflow v2.8.0
Python: 3.9
I was running DSSM_N and DSSM on a dataset with batch size 512 on 2060.
However,
DSSM_N costs ~35ms per batch
DSSM. costs ~400ms per batch.
What makes this huge performance difference? I have checked profiling which said
that DSSM costs ~350ms on All Others Time. How can I fix the DSSM implementation?
Many thanks in advance.
Edited as suggested by Micheal:
The main difference is DSSM makes a hash-table-like lookup (notice tf.nn.embedding_lookup and IntegerLookup) which makes the dataset preprocess a little bit simpler while in DSSM_N this lookup was done in dataset preprocess in advance. However, I don't believe this simple hash table like makes such a big difference. What was I doing wrong?
import pickle
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow_hub as hub
import tensorflow_text as text # required for BERT hub model
from keras.layers import Layer, Embedding, Dense, Concatenate, BatchNormalization, Dropout, Dot, Hashing, TextVectorization, GRU, IntegerLookup
from keras import Model
import random
from ..config import *
from ..util import *
def embedding_sequence_reduce_mean(x, mask):
# float[B,L,E], bool[B,L] -> float[B,E]
x = tf.ragged.boolean_mask(x, mask) # (B, Lr, E) remove masked data
x = tf.reduce_mean(x, axis=1) # (B, E)
x = tf.where(tf.math.is_nan(x), 0.0, x) # nan to 0
return x
def embedding_masked_to_zero(x, mask):
mask = tf.expand_dims( # B -> B 1 align for broadcasting
tf.cast(mask, dtype=tf.float32), axis=1)
return x * mask
USER_ID_DIM = 128
MEDIA_ID_DIM = 64
GENRE_DIM = 32
ORIGIN_DIM = 32
LATENT_DIM = latent_dim
N_HASH = 8
N_BIN = 1024
print('N_HASH', N_HASH)
print('N_BIN', N_BIN)
class HashEmbedding(Layer):
# TODO: with_importance is not supported
def __init__(
self, n_hash, n_bin, output_dim,
embeddings_initializer='uniform', embeddings_regularizer=None,
activity_regularizer=None, embeddings_constraint=None,
mask_zero=False, input_length=None, **kwargs
):
super(HashEmbedding, self).__init__()
self.mask_zero = mask_zero
self.n_hash = n_hash
self.n_bin = n_bin
# salts no duplication
self.salts = random.sample(range(self.n_hash * 32), self.n_hash)
self.hashs = [Hashing(
num_bins=self.n_bin,
# if mask_zero then hash 0 to 0
mask_value=(0 if self.mask_zero else None),
salt=self.salts[i])
for i in range(self.n_hash)]
self.embedding = Embedding(
self.n_bin, output_dim,
embeddings_initializer=embeddings_initializer,
embeddings_regularizer=embeddings_regularizer,
activity_regularizer=activity_regularizer,
embeddings_constraint=embeddings_constraint,
mask_zero=mask_zero, input_length=input_length
)
def compute_mask(self, inputs, mask=None):
if not self.mask_zero:
return None
return tf.not_equal(inputs, 0)
def call(self, inputs):
shape = inputs.shape
hash = tf.stack([hash(inputs) # [I], n_hash
for hash in self.hashs], axis=len(shape))
x = self.embedding(hash) # [I], n_hash, emb_dim
x = tf.reduce_sum(x, axis=len(shape)) # [I], emb_dim
return x
class StringVectorization(Layer):
def __init__(self, vocab, embedding_dim=32, output_dim=16):
super(StringVectorization, self).__init__()
self.text_vectorization = TextVectorization(
vocabulary=vocab, split='character')
self.embedding = Embedding(
self.text_vectorization.vocabulary_size(), embedding_dim, mask_zero=True)
self.gru = GRU(output_dim)
def call(self, inputs): # B, S
x = self.text_vectorization(inputs)
x = self.embedding(x)
return self.gru(x)
class TfBertZh(Layer): # 128 - 2 input length limit
def __init__(self): # output_dim 768
super(TfBertZh, self).__init__()
self.preprocess = hub.KerasLayer(
zh_preprocessor_model_file, trainable=False)
self.encoder = hub.KerasLayer(zh_encoder_model_file, trainable=False)
def call(self, inputs):
x = self.preprocess(inputs)
x = self.encoder(x)['pooled_output']
return x
class DNN(Layer):
def __init__(self):
super(DNN, self).__init__()
self.concat = Concatenate(axis=1)
self.dense1 = Dense(64)
self.bn = BatchNormalization()
self.drop = Dropout(0.1)
self.dense2 = Dense(32)
def call(self, inputs: list):
from keras.activations import tanh
x = self.concat(inputs)
x = self.drop(tanh(self.bn(self.dense1(x))))
x = tanh(self.dense2(x))
return x
with open(stats_file_pkl, 'rb') as f:
sinfo = pickle.load(f)
with open(vocab_file_pkl, 'rb') as f:
vocab = pickle.load(f)
class DSSM_N(Model):
def __init__(self):
super(DSSM_N, self).__init__()
self.user_id = HashEmbedding(
N_HASH, N_BIN, USER_ID_DIM, mask_zero=True)
self.item_id = Embedding(
sinfo['media_id']['unique'], MEDIA_ID_DIM, mask_zero=True)
self.genre = Embedding(
sinfo['genre_id']['unique'], GENRE_DIM, mask_zero=True)
self.origin = Embedding(
sinfo['origin_id']['unique'], ORIGIN_DIM, mask_zero=True)
self.user_dnn = DNN()
self.item_dnn = DNN()
self.dot = Dot(axes=1, normalize=False)
def call(self, inputs):
u = self.compute_user_latent({'id': inputs['user']})
n_pos = inputs['pos'].shape[1]
n_neg = inputs['neg'].shape[1]
ui_pos = []
ui_neg = []
def signal(u, i):
return tf.exp(self.dot([u, i]))
for j in range(n_pos):
i = self.compute_item_latent({
'id': inputs['pos'][:, j],
'genre': inputs['pos_genre'][:, j, :], # B N 4
'origin': inputs['pos_origin'][:, j, :] # B N 2
})
ui_pos.append(signal(u, i))
ui_pos = tf.add_n(ui_pos)
for j in range(n_neg):
i = self.compute_item_latent({
'id': inputs['neg'][:, j],
'genre': inputs['neg_genre'][:, j, :],
'origin': inputs['neg_origin'][:, j, :]
})
ui_neg.append(signal(u, i))
ui_neg = tf.add_n(ui_neg)
return tf.squeeze(ui_pos / (ui_pos + ui_neg))
def compute_user_latent(self, inputs):
id = self.user_id(inputs['id'])
latent = self.user_dnn([id])
return latent
def compute_item_latent(self, inputs):
id = self.item_id(inputs['id'])
genre = self.genre(inputs['genre']) # B 4 -> B 4 E
genre = embedding_sequence_reduce_mean(genre, genre._keras_mask)
origin = self.origin(inputs['origin']) # B 2 -> B 2 E
origin = embedding_sequence_reduce_mean(origin, origin._keras_mask)
latent = self.item_dnn([id, genre, origin])
return latent
user_df = pd.read_pickle(preprocessed_user_file_pkl)
media_df = pd.read_pickle(preprocessed_media_file_pkl)
genre_df = pd.read_pickle(clean_genre_file_pkl)
origin_df = pd.read_pickle(clean_origin_file_pkl)
class MediaPreprocess(Layer):
def __init__(self):
super(MediaPreprocess, self).__init__()
self.lookup = IntegerLookup(vocabulary=list(media_df['id']))
self.genre_table = tf.Variable(
[[0] * 4] + list(media_df['genre']), dtype=tf.int32, trainable=False)
self.origin_table = tf.Variable(
[[0] * 2] + list(media_df['origin']), dtype=tf.int32, trainable=False)
self.id_embedding = Embedding(
self.lookup.vocabulary_size() + 1, MEDIA_ID_DIM, mask_zero=True)
self.genre_embedding =\
Embedding(genre_df['id'].max() + 1, GENRE_DIM, mask_zero=True)
self.origin_embedding =\
Embedding(origin_df['id'].max() + 1, ORIGIN_DIM, mask_zero=True)
def __call__(self, inputs):
index = self.lookup(inputs) # B -> B
vector = self.id_embedding(index) # B -> B E
vector = embedding_masked_to_zero(vector, vector._keras_mask)
genre = tf.nn.embedding_lookup(self.genre_table, index)
genre = self.genre_embedding(genre)
genre = embedding_sequence_reduce_mean(genre, genre._keras_mask)
origin = tf.nn.embedding_lookup(self.origin_table, index)
origin = self.origin_embedding(origin)
origin = embedding_sequence_reduce_mean(origin, origin._keras_mask)
return {
'id': vector,
'genre': genre,
'origin': origin}
class UserPreprocess(Layer):
def __init__(self):
super(UserPreprocess, self).__init__()
self.lookup = IntegerLookup(vocabulary=list(user_df['id']))
self.embedding = HashEmbedding(
N_HASH, N_BIN, USER_ID_DIM, mask_zero=True)
def __call__(self, inputs):
vector = self.embedding(inputs)
vector = embedding_masked_to_zero(vector, vector._keras_mask)
return {'id': vector}
class DSSM(Model):
def __init__(self, *args, **kwargs):
super(DSSM, self).__init__()
self.user_pp = UserPreprocess()
self.item_pp = MediaPreprocess()
self.user_nn = DNN()
self.item_nn = DNN()
dot = Dot(axes=1, normalize=False)
self.signal = lambda u, i: tf.exp(dot([u, i]))
def call(self, inputs):
user = inputs['user'] # B
pos_s = inputs['pos'] # B N_POS=1
neg_s = inputs['neg'] # B N_NEG=7
n_pos = pos_s.shape[1]
n_neg = neg_s.shape[1]
u = self.user_pp(user)['id'] # B E(uid)
u = self.user_nn([u]) # B L
def compute_ui(i_s, count):
ui = []
for j in range(count):
i = self.item_pp(i_s[:, j])
i = self.item_nn([i['id'], i['genre'], i['origin']])
ui.append(self.signal(u, i))
return tf.add_n(ui) # C B 1 -> B 1
pos_ui = compute_ui(pos_s, n_pos) # B 1
neg_ui = compute_ui(neg_s, n_neg) # B 1
return tf.squeeze(pos_ui / (neg_ui + pos_ui)) # B
I met a problem with call the value from one class into a new iterative loop outside of that class. The code is shown below: (data and newdata are vectors)
class A:
def __init__(self, k, tol=0.0001, max_iter=300):
self.k = k
self.tol = tol
self.max_iter = max_iter
def fit(self, data):
self.centroids = {}
for i in range(self.k):
self.centroids[i] = data[i+50]
for i in range(self.max_iter):
self.classifications = {}
for i in range(self.k):
self.classifications[i] = []
for featureset in data:
distances = [np.linalg.norm(featureset - self.centroids[centroid]) for centroid in self.centroids]
classification = distances.index(min(distances))
self.classifications[classification].append(featureset)
prev_centroids = dict(self.centroids)
for classification in self.classifications:
self.centroids[classification] = np.average(self.classifications[classification], axis=0)
optimized = True
for c in self.centroids:
original_centroid = prev_centroids[c]
current_centroid = self.centroids[c]
if np.sum((current_centroid - original_centroid) / original_centroid * 100.0) > self.tol:
#print(np.sum((current_centroid - original_centroid) / original_centroid * 100.0))
optimized = False
if optimized:
break
def cluster_labels(self,data):
cluster_labels = []
for featureset in data:
distances=[np.linalg.norm(featureset - self.centroids[centroid]) for centroid in self.centroids]
cluster_labels.append(distances.index(min(distances)))
return cluster_labels
def predict(self, data):
distances = [np.linalg.norm(data - self.centroids[centroid]) for centroid in self.centroids]
classification = distances.index(min(distances))
return classification
def update(self, new_data, delta):
for featureset in new_data:
distances = [np.linalg.norm(featureset - self.centroids[centroid]) for centroid in self.centroids]
if min(distances) < delta:
classification = distances.index(min(distances))
self.classifications[classification].append(featureset)
self.centroids[classification] = np.average(self.classifications[classification], axis=0)
else:
self.centroids[self.k] = featureset
self.classifications[self.k] = []
self.classifications[self.k].append(featureset)
self.k = self.k + 1
k = self.k
print (k)
return k
class Recorder:
def __init__(rec):
rec.p = pyaudio.PyAudio()
rec.stream = rec.p.open(format = pyaudio.paInt16, channels = 1, rate = 44100, input = True, input_device_index = 2, frames_per_buffer = chunk)
def write():
a = A(k=3)
a.fit(data)
k=a.update(newdata,20)
for num in range(1,100):
rec.Recorder()
rec.write()
Initially, I want to set k =3. And then, the value of k should be updated with k=a.update(newdata,20) However,now for every running, the value of K is staying at 3. And if I set k = 3 outside of the classes it always shows the error :
UnboundLocalError: local variable 'k' referenced before assignment
How could I solve this problem?
The issue is in this function:
def update(self, new_data, delta):
for featureset in new_data:
distances = [np.linalg.norm(featureset - self.centroids[centroid]) for centroid in self.centroids]
if min(distances) < delta:
classification = distances.index(min(distances))
self.classifications[classification].append(featureset)
self.centroids[classification] = np.average(self.classifications[classification], axis=0)
else:
self.centroids[self.k] = featureset
self.classifications[self.k] = []
self.classifications[self.k].append(featureset)
self.k = self.k + 1
k = self.k
You are only setting the "k" value inside the "else" block. Leaving out anything unrelated it looks like this:
def update(self, new_data, delta):
for featureset in new_data:
...
if min(distances) < delta:
...
else:
...
k = self.k
print (k) # <-- error here
return k # <-- error here
In the case where min(dinstances) >= delta, k will not be set and you will get the error you report.
You have two options:
Add a k = ... line into the if-block where min(distances) < delta
Add a k = ... line just above the if-block (still inside the for-block) to set a "default" value for k
On review it is also possible that you just need to return self.k instead of just k.
I'm trying to implement a genetic algorithm for solving the Travelling Salesman Problem (TSP).
I have 2 classes, which are City and Fitness.
I have done the code for initialization.
class City:
def __init__(self, x, y):
self.x = x
self.y = y
def distance(self, city):
xDis = abs(self.x - city.x)
yDis = abs(self.y - city.y)
distance = np.sqrt((xDis ** 2) + (yDis ** 2))
return distance
def __repr__(self):
return "(" + str(self.x) + "," + str(self.y) + ")"
class Fitness:
def __init__(self, route):
self.route = route
self.distance = None
self.fitness = None
def routeDistance(self):
if self.distance == None:
pathDistance = 0.0
for i in range(0, len(self.route)):
fromCity = self.route[i]
toCity = None
if i+1 < len(self.route):
toCity = self.route[i+1]
else:
toCity = self.route[0]
pathDistance += fromCity.distance(toCity)
self.distance = pathDistance
return self.distance
def routeFitness(self):
if self.fitness == None:
self.fitness = 1 / float(self.routeDistance())
return self.fitness
def selection(population, size=None):
if size== None:
size= len(population)
matingPool = []
fitnessResults = {}
for i in range(0, size):
fitnessResults[i] = Fitness(population[i]).routeFitness()
matingPool.append(random.choice(population))
return matingPool
The code above just randomly selects a parent in the selection method.
My question is: How to code to select a parent using roulette wheels?
You could try this [1, 2]:
from numpy.random import choice
def selection(population, size=None):
if size== None:
size= len(population)
fitnessResults = []
for i in range(0, size):
fitnessResults.append(Fitness(population[i]).routeFitness())
sum_fitness = sum(fitnessResults)
probability_lst = [f/sum_fitness for f in fitnessResults]
matingPool = choice(population, size=size, p=probability_lst)
return matingPool
Read this
So basically, the higher a fitness value, the higher are its chances to be chosen. But that is when high fitness value means a high fitness. But in TSP a lower value of fitness is better so to implement this, we need to implement the concept where probability is indirectly proportional to the fitness value.
Here is something I had implemented in python with some changes
def choose_parent_using_RWS(genes, S):
P = random.uniform(0, S)
for x in genes:
P += get_fitness_value(x)
if P > S:
return x
return genes[-1]
where S is the sum of the inverse of the fitness values of the current population (i.e, 1/f1 + 1/f2 + 1/f3 + ...)
and
get_fitness_value(x) returns the inverse of the distance, just like your routeFitness() function
TeeHee