Hyperparameter-Search while adding Special tokens - pytorch

# define get_model function
def get_model(params):
db_config = config
if params is not None:
db_config.update({'attention_probs_dropout_prob': params['attention_drop_out'],
'hidden_dropout_prob': params['hidden_drop_out']
})
model = AutoModelForSequenceClassification.from_pretrained(
model_args.model_name_or_path,
config=db_config,
cache_dir=model_args.cache_dir,
revision=model_args.model_revision,
use_auth_token=True if model_args.use_auth_token else None,
ignore_mismatched_sizes=model_args.ignore_mismatched_sizes,
)
if special_tokens is not None:
model.resize_token_embeddings(len(tokenizer))
# setup label_to_id
model.config.label2id = label_to_id
model.config.id2label = {
id: label for label, id in config.label2id.items()}
return model
def ray_hp_space(trial):
return {
"attention_drop_out": tune.uniform(0.1, 0.5),
"hidden_drop_out": tune.uniform(0.1, 0.5),
"learning_rate": tune.uniform(1e-5, 2e-5),
"weight_decay": tune.uniform(0.005, 0.01),
"gradient_accumulation_steps": tune.choice([1, 2, 4]),
"label_smoothing_factor": tune.choice([.7,.8,.9,.91])
}
trainer = Trainer(
model_init=get_model,
args=training_args,
train_dataset=train_dataset if training_args.do_train else None,
eval_dataset=validation_dataset if training_args.do_eval else None,
compute_metrics=compute_metrics,
tokenizer=tokenizer,
data_collator=data_collator,
callbacks = [EarlyStoppingCallback(early_stopping_patience=7)]
scheduler = ASHAScheduler(
metric="f1",
mode="max",
max_t=1,
grace_period=1,
reduction_factor=2)
reporter = CLIReporter(
parameter_columns={
"weight_decay": "w_decay",
"learning_rate": "lr",
"gradient_accumulation_steps": "gradient_accum_steps",
"label_smoothing_factor": "label_smooth",
"hidden_drop_out": "hidden_drop_out",
"attention_drop_out": "attention_drop_out"
},
metric_columns=[
"eval_accuracy", "eval_f1", "eval_loss", "steps"
])
best_trail = trainer.hyperparameter_search(direction="maximize",
backend='ray',
hp_space=ray_hp_space,
n_trials=1,
resources_per_trial={"cpu":2, "gpu":1},
scheduler=scheduler,
keep_checkpoints_num=1,
checkpoint_score_attr="training_iteration",
progress_reporter=reporter,
local_dir="experiments/ray-tune-results/"
)
The problem is at some point in the training, create a new instance from the original config (without additional special tokens) and try to copy weights from the current instance which has additional special tokens) and it throws a mismatch errors ? It looks I have to force the model creating the first instance from the original config and after that he has to start use the current config (with additional special tokens). How to fix that ?

Related

create registered model in the "staging" state

Currently, when I add a model to the MLFlow registry, the default state is "None"- I wonder if it is possible to create the model directly in "Staging" or "Production". Currently, I am registering the model as:
def log_model(
model,
artifact_path,
# conda_env=None,
# code_paths=None,
registered_model_name=None,
# signature: ModelSignature = None,
# input_example: ModelInputExample = None,
# pip_requirements=None,
# extra_pip_requirements=None,
**kwargs,
):
return Model.log(
proj_model=model,
artifact_path=str(artifact_path),
flavor=proj.mlflow.flavor,
registered_model_name=registered_model_name,
**kwargs,
)
I wonder if the staging can be specified somehow already in the log command.

FastAPI how to insert additional Information (like queries) into the Response if you use a Response Model?

I'm trying to build an API right now with FastAPI. I want to have one route (which accepts queries) return them in the response as well so the user can double check what queries he entered (also to see how many pages are there in total etc.).
I'm using the response_model response way and can not for the life of me figure out how to get additional Parameters inserted into the response.
I already tried making all the fields in the response model optional so it no longer throws an error while checking, but it still only (if it responds) responds without the added information.
Underneath you can see the route and the schema that I'm using for the response_model.
This is the route I'm wanting to have this applied to.
#router.get("/", response_model=List[schemas.StockResponse], tags=["Stocks"])
def get_stocks(response= Response, db: Session = Depends(get_db), current_user: int = Depends(oauth2.get_current_user), limit: int = 100, skip: int = 0):
utils.increase_request_counter(current_user, db)
stocks = db.query(models.Stock).limit(limit).offset(skip).all()
return stocks
What I would like to have is that it returns the list of stocks but also returns the information about the query parameters above. Like:
[{"params": {
"limit" : 10,
"skip": 0 },
{"data": [ *then list of dictionaries that it already returns*]}]
something like that but I can not get it to return anything but a list of dictionaries.
This is the schema that this model is using (StockResponse)
class StockBase(BaseModel):
name: str
ticker: str
price: float
dividends: float
dividend_yield: float
ftweek_low: Optional[float] = Body(None)
ftweek_high: Optional[float] = Body(None)
trading_market: Optional[str] = Body(None)
market_cap: Optional[int] = Body(None)
payout_ratio: Optional[float] = Body(None)
beta: Optional[float] = Body(None)
business_summary: Optional[str] = Body(None)
website: Optional[str] = Body(None)
logo: Optional[str] = Body(None)
time_updated: Optional[datetime] = Body(datetime.now())
sector: Optional[str] = Body(None)
industry: Optional[str] = Body(None)
class StockResponse(StockBase):
ID: Optional[int]
name: Optional[str]
ticker: Optional[str]
price: Optional[float]
dividends: Optional[float]
dividend_yield: Optional[float]
time_created: Optional[datetime]
class Config:
orm_mode = True
Create a response model that matches what you want to return, and populate it accordingly:
from pydantic import BaseModel
class StockRequestParams(BaseModel):
limit: int
skip: int
class StockResponseWithMetadata(BaseModel):
params: StockRequestParams
stocks: List[StockResponse]
def get_stocks(...):
...
return StockResponseWithMetadata(
params=StockRequestParams(hits=hits, limit=limit),
stocks=socks,
)

What is best practice for mapping a TF2 keras model's signaturedef to TF Serving classify/predict/regression API in TFX Pipeline?

We are building an automated TFX pipeline on Airflow and have based our model off of the Keras Tutorial . We save the keras model as follows:
model.save(fn_args.serving_model_dir, save_format='tf',
signatures=signatures,
)
That signatures dict is:
signatures = {
'serving_default':
_get_serve_tf_examples_fn(model, tf_transform_output) \
.get_concrete_function(
tf.TensorSpec(
shape=[None],
dtype=tf.string,
name='examples'
)
),
'prediction':
get_request_url_fn(model, tf_transform_output) \
.get_concrete_function(
tf.TensorSpec(
shape=[None],
dtype=tf.string,
name='prediction_examples'
)
),
}
_get_serve_tf_examples_fn serves the purpose of providing the TFX evaluator component with additional tensors, tensors not used in model, for model evaluation purposes. It is as in the Keras TFX tutorial above:
def _get_serve_tf_examples_fn(model, tf_transform_output):
model.tft_layer = tf_transform_output.transform_features_layer()
#tf.function
def serve_tf_examples_fn(serialized_tf_examples):
feature_spec = tf_transform_output.raw_feature_spec()
feature_spec.pop(_LABEL_KEY)
parsed_features = tf.io.parse_example(serialized_tf_examples, feature_spec)
transformed_features = model.tft_layer(parsed_features)
transformed_features.pop(_transformed_name(_LABEL_KEY))
return model(transformed_features)
return serve_tf_examples_fn
The above model 'interface' accepts TF.Examples as is needed by TFX Evaluator component (TFMA).
However, For TF Serving, we want to be able to send 1 raw string - just a url - to the TF Serving predictor REST API and get the predicted score for it. Currently the get_request_url_fn is:
def get_request_url_fn(model, tf_transform_output):
model.tft_layer = tf_transform_output.transform_features_layer()
#tf.function
def serve_request_url_fn(request_url):
feature_spec = tf_transform_output.raw_feature_spec()
# Model requires just one of the features made available to other TFX components
# Throw away the rest and leave just 'request_url'
feature_spec = {'request_url': feature_spec['request_url']}
parsed_features = tf.io.parse_example(request_url, feature_spec)
transformed_features = model.tft_layer(parsed_features)
transformed_features.pop(_transformed_name(_LABEL_KEY))
return model(transformed_features)
return serve_request_url_fn
This approach still requires input in the form of a TF.Example though. It necessitates a consideerable amount of overhead on behalf of the client. Namely, import tensorflow. That code does work though:
url = f'http://{server}:8501/v1/models/wrcv3:predict'
headers = {"content-type": "application/json"}
url_request = b'index'
example = tf.train.Example(
features=tf.train.Features(
feature={"request_url":
tf.train.Feature(bytes_list=tf.train.BytesList(value=[url_request]))
}
)
)
print(example)
data = {
"signature_name":"prediction",
"instances":[
{
"prediction_examples":{"b64": base64.b64encode(example.SerializeToString()).decode('utf-8')}
}
]
}
data = json.dumps(data)
print(data)
json_response = requests.post(url, data=data, headers=headers)
print(json_response.content)
print(json_response.json)
Returning as a result:
features {
feature {
key: "request_url"
value {
bytes_list {
value: "index"
}
}
}
}
{"signature_name": "prediction", "instances": [{"prediction_examples": {"b64": "ChoKGAoLcmVxdWVzdF91cmwSCQoHCgVpbmRleA=="}}]}
b'{\n "predictions": [[0.897708654]\n ]\n}'
<bound method Response.json of <Response [200]>>
When we submit a base64-encoded string en lieu of the TF.Example it obviously fails:
url = f'http://{server}:8501/v1/models/wrcv3:predict'
headers = {"content-type": "application/json"}
url_request = b'index.html'
data = {
"signature_name":"prediction",
"instances":[
{
"prediction_examples":{"b64": base64.b64encode(url_request).decode('UTF-8')}
}
]
}
data = json.dumps(data)
print(data)
json_response = requests.post(url, data=data, headers=headers)
print(json_response.content)
print(json_response.json)
returning:
{"signature_name": "prediction", "instances": [{"prediction_examples": {"b64": "aW5kZXguaHRtbA=="}}]}
b'{ "error": "Could not parse example input, value: \\\'index.html\\\'\\n\\t [[{{node ParseExample/ParseExampleV2}}]]" }'
<bound method Response.json of <Response [400]>>
Question is: what should the signaturedef/signature look like to accept raw strings? If not like get_request_url_fn . Surely the client should not have to load TF just to make a request ?
The TFX website itself goes into detail to document 3 protobufs for classify/predict/regression here , but it is not intuitive (to me) how to use these 3 protobufs to do the mapping we need.
Deep gratitude in advance.
According to your code the input to the function serve_request_url_fn is a Dense Tensor, but maybe the input of your transform graph is a Sparse Tensor.
The function tf.io.parse_example knows how to deserialise your tf.Example into a Sparse Tensor, but if you want to send a Tensor, without serialising it, then you should convert it manually to a Sparse Tensor and stop using the tf.io.parse function.
For example:
#tf.function(input_signature=[tf.TensorSpec(shape=(None), dtype=tf.string, name='examples')])
def serve_request_url_fn(self, request_url):
request_url_sp_tensor = tf.sparse.SparseTensor(
indices=[[0, 0]],
values=request_url,
dense_shape=(1, 1)
)
parsed_features = {
'request_url': request_url_sp_tensor,
}
transformed_features = self.model.tft_example_layer(parsed_features)
transformed_features.pop(_transformed_name(_LABEL_KEY))
return self.model(transformed_features)

How to create dynamic rest ModelSerializer?

I'm currently working on a big code base and i need to send emails from any potential module, that conduct in Circular Dependencies issues in python
so i tried to use apps.get_model() from django.apps but when serializers are declared the models are not ready.
So i'm trying to create a factory function who build the class at runtime instead of launch time
from rest_framework.serializers import ModelSerializer
def make_serializer(model: str, fields: tuple, options = None, **nested_fields) -> ModelSerializer:
"""Generate a new serializer "On the fly", so the model does not have to be imported at launch time.
"""
model_object = apps.get_model(model)
input_fields = fields
if options is None:
options = {}
class Serializer(ModelSerializer):
class Meta:
model = model_object
fields = input_fields
def create(self, validated_data):
# we won't permit to create data from thoses serializers.
raise NotImplementedError
# configure nested serializers.
for nested_field in nested_fields.values():
for key, nested_serializer_class in nested_field.items():
serializer_instance = nested_serializer_class(**options.get(key, {}))
print(model, key, serializer_instance)
setattr(Serializer, key, serializer_instance)
return Serializer
my tests models looks like
class Band(Model):
name = Charfield(max_length=255)
class Influencer(Model):
entity = Charfield(max_length=255)
class Submission(Model):
influencer = ForeignKey(Influencer, ...)
class Campaign(Model):
band = ForeignKey('band.Band', ...)
submissions = ManyToMany(Submission)
and my testing function is:
def test():
serializer = make_serializer(
model='submission.Campaign',
fields=['pk', 'submissions', 'band'],
options={'submissions': {'many': True}},
nested_fields={
'submissions': make_serializer(
model='submission.Submission',
fields=('influencer',),
nested_fields={
'influencer': make_serializer('influencer.Influencer', ('entity',))
},
),
'band': make_serializer('band.Band', ('name',))
}
)
return serializer
instead of having my fields correly with test()(Campaign.objects.last()).data i only got "pks" and my serialiser looks like:
Serializer():
pk = IntegerField(label='ID', read_only=True)
submissions = PrimaryKeyRelatedField(many=True, queryset=Submission.objects.all())
band = PrimaryKeyRelatedField(allow_null=True, queryset=Band.objects.all(), required=False)
i except and output like:
{
"pk": 1,
"band": {
"name": "BobMarley",
},
"submissions": [
{
"influencer": {"entity": "The influencer's name"}
}
]
}
but i got a ReturnDict containing:
{
"pk": 1,
"band": 523,
"submissions": [6, 7, 8]
}
thanks for your time
well after many headcaches i've found out that i CAN'T setattr on a class after it's declaration, so i use a trick based on a dict
def make_serializer(model: str, fields: tuple, options = None, **nested_fields) -> ModelSerializer:
"""Generate a new serializer "On the fly", so the model does not have to be imported at launch time.
"""
name = f'Serializer_{model}'
model_object = apps.get_model(model)
input_fields = fields
if options is None:
options = {}
def create(self, validated_data):
# we won't permit to create data from thoses serializers.
raise NotImplementedError
class Meta:
model = model_object
fields = input_fields
attrs = {"Meta": Meta}
# configure nested serializers.
for key, nested_serializer_class in nested_fields.items():
attrs[key] = nested_serializer_class(**options.get(key, {}))
attrs['create'] = create
return type(ModelDictSerializer)(name, (ModelDictSerializer,), attrs)
the syntax is something like:
campaign_serializer = make_serializer(
model='submission.Campaign',
fields=['pk', 'submissions', 'band'],
options={'submissions': {'many': True}},
submissions=make_serializer(
model='submission.Submission',
fields=('influencer',),
influencer=make_serializer('influencer.Influencer', ('entity',))
),
band=make_serializer('band.Band', ('name',))
)
and it's working like a charm:
Serializer_submission.Campaign(<Campaign: Campaign object (9665)>):
pk = IntegerField(label='ID', read_only=True)
submissions = Serializer_submission.Submission(many=True):
influencer = Serializer_influencer.Influencer():
entity = CharField(allow_blank=True, max_length=255, required=False)
band = Serializer_band.Band():
name = CharField(max_length=255)
i hope this will help someone else

make some model field conditionally visible in django

I have two field in my django model they should be editable only if user have selected 'type' as 'Dimention' otherwise they should not be visible to user.
My model is look like this code
from django.db import models
class Configuration(models.Model):
name = models.CharField(max_length=30)
user_defined_name = models.CharField(max_length=50)
FieldTypes = (('aD', 'Dimension'), ('aM', 'Measure'))
type = models.CharField(max_length=11, choices=FieldTypes)
is_key = models.BooleanField(default=False, editable=False)
unit = models.CharField(max_length=30, null=True, blank=True, editable=False)
def __str__(self):
return self.name
I know it is possible by using JavaScript but, I don't want to write html or js myself,Thus Can't use JavaScript for doing this.
A pure Django-only way to achieve this is to simply reset the fields from your ModelForm if type is not equal to Dimension. This will appear like magic/unintended behavior; so be careful of the implementation.
For example (assuming you are using the admin interface: the same is valid for a custom ModelForm View):
class ConfigurationAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
# At this point; the object already has the new values set; we will have to reset as needed
conditional_editable_fields = ['is_key', 'unit']
config_type = form.cleaned_data.get('type')
if config_type != 'aD':
for field in conditional_editable_fields:
if field in form.changed_data: # The value has been changed by the user
setattr(obj, field, form.initial.get(field)) # Set the initial value
self.message_user(request, "Cannot edit field: {}; value has been reset".format(field), messages.WARNING) # Inform the user that we reset the value
return super(ConfigurationAdmin, self).save_mode(request, obj, form, change)
I use similar approach for this.
I it works great
In My admin.py
`
fieldsets = (
(None, {
'fields': ('name', 'user_defined_name', 'type', 'is_active')
}),
('Advanced', {
'classes': ('toggle',),
'fields': ('is_kpi', 'unit'),
})
)
actions = [disable_multiple_column, activate_multiple_column]
class Media:
js = ("jquery.js", "my_code.js",)`
I use that JS file to show and hide .
`$(document).ready(function(){
show_hide();
$('#id_type').change(function(){
show_hide();
});
function show_hide(){
if ($("#id_type").val() == 'aM' ){
$(".module")[1].style.display="block"
}
else{
$(".module")[1].style.display="none"
}
}
});`
And in case use already entered values and then change Choice of type or from some other reason these hidden field still have data. I override the save Method of models.py
`
def save(self, *args, **kwargs):
if self.type != 'aM':
self.is_kpi = False
self.unit = None
super(Configuration, self).save(*args, **kwargs)
`

Resources