Custom Layer with kwargs in tfjs - tensorflow.js

I'm new to tensorflowjs and I'm struggling to implement some custom layers, if someone could point me in the right direction that would be really helpful!
For example, I have a layer in InceptionResnetV1 architecture where I'm multiplying the layer by a constant scale (this was originally an unsupported Lambda layer which I'm switching out for a custom layer), but the value of this scale changes per block. This works fine in Keras with an implementation such as below, and using load_model with ScaleLayer in the custom objects
class ScaleLayer(tensorflow.keras.layers.Layer):
def __init__(self, **kwargs):
super(ScaleLayer, self).__init__(**kwargs)
def call(self, inputs, **kwargs):
return tensorflow.multiply(inputs, kwargs.get('scale'))
def get_config(self):
return {}
x = ScaleLayer()(x, scale = tensorflow.constant(scale))
I tried defining this in a similar way in javascript and then registered the class
class ScaleLayer extends tf.layers.Layer {
constructor(config?: any) {
super(config || {});
}
call(input: tf.Tensor, kwargs: Kwargs) {
return tf.tidy(() => {
this.invokeCallHook(input, kwargs);
const a = input;
const b = kwargs['scale'];
return tf.mul(a, b);
});
}
static get className() {
return 'ScaleLayer';
}
}
tf.serialization.registerClass(ScaleLayer);
However I'm finding that the kwargs are always empty. I tried another similar method where I passed scale as another dimension of the input, then did input[0] * input[1], which again worked fine for the keras model but not in javascript.
I feel like I'm missing something key on the way to defining this kind of custom layer with a changing value per block on the javascript end, so if someone would be able to point me in the right direction it would be much appreciated! Thanks.

constructor(config?: any) {
super(config || {});
}
The config are passed to the parent constructor. But as indicated by the question, the ScaleLayer layer also needs to keep some config properties
constructor(config?: any) {
super(config || {});
// this.propertyOfInterest = config.propertyOfInterest
// make sure that config is an object;
this.scale = config.scale
}
Then for the computation, the ScaleLayer property propertyOfInterest can be used
call(input: tf.Tensor) {
return tf.tidy(() => {
this.invokeCallHook(input, kwargs);
const a = input;
return tf.mul(a, this.scale);
});
}
Use the layer this way:
const model = tf.sequential();
...
model.add(new ScaleLayer({scale: 1}));
...

Related

Tensorflow.js predict returning NaNs

I converted a keras model into a tensorflowjs model using the simple tensorflowjs_converter --input_format keras ./model/L_keypoint_classifier_final.h5 L_layer_model. I managed to get this model working on a .ts (TypeScript) file.
Now I am focused on deploying this model using React and Typescript (in a .tsx file). My app component is loading the models as such:
const [models, setModels] = useState<Models>({
L_Model: undefined,
R_Model: undefined,});
useEffect(() => {
loadModel().then((models) => {
setModels(models);
setIsLoading(false);
}); }
The loadModel() function is exported from another file and it is:
export async function loadModel() {
let result: Models = { R_Model: undefined, L_Model: undefined };
result.R_Model = await tf.loadLayersModel("/right/model.json");
result.L_Model = await tf.loadLayersModel("/left/model.json");
return result;
}
That directory of the models is in the public folder of my project. After loading the models in the app component, I pass them to a child component using props.
<Camera models={models}></Camera>
They are received in the camera component as:
const Camera: FunctionComponent<CameraProps> = (props) => {
const { R_Model, L_Model } = props.models;
In the camera component I pass in a tf.Tensor2D. This tensor does in fact contain values that I checked. But when I pass them to the model.predict() function, it just returns a tensor full of NaNs.
This is my code for preprocessing the input and passing it to the model:
//Preprocess Landmarks
//#ts-ignore
let landmark_list = calc_landmark_list(landmarks);
landmark_list = pre_process_landmarks(landmark_list);
//#ts-ignore
landmark_list = tf.tensor2d([landmark_list]);
console.log(landmarks_list.dataSync());
let prediction;
if(isRightHand){
prediction = R_Model?.predict(landmark_list);
}else{
prediction = L_Model?.predict(landmark_list);
}
const scores = prediction.arraySync()[0];
After that, I try to find the maxScore of the predictions, but since arraySync() returns a NaN array, it does not work. My team and me have try searchig for different options. Some include wrapping the predict function inside an aasync function, but that doesn't seem to work either (or maybe we have done it incorrectly, although we have followed the examples thoroughly).
The console.log of the landmark_list.dataSync() prints out:
Float32Array(42) [0, 0, -0.2683601677417755, -0.1023331806063652, -0.4781370162963867, -0.397993803024292, -0.5191399455070496, -0.6676312685012817, -0.46050554513931274, -0.8477477431297302, -0.30691489577293396, -0.9023468494415283, -0.49582260847091675, -1, -0.5734853148460388, -0.7551659941673279, -0.5509241223335266, -0.5708747506141663, -0.15572300553321838, -0.9109046459197998, -0.38624173402786255, -0.9391834735870361, -0.4641483426094055, -0.6930190920829773, -0.4609870910644531, -0.49743616580963135, -0.00984301045536995, -0.8530527353286743, -0.25299814343452454, -0.7750100493431091, -0.32405075430870056, -0.5182365775108337, -0.32825687527656555, -0.3154793083667755, 0.11740472167730331, -0.7356364130973816, -0.12479904294013977, -0.6477926969528198, -0.21985816955566406, -0.43255504965782166, -0.24492989480495453, -0.25398018956184387, buffer: ArrayBuffer(168), byteLength: 168, byteOffset: 0, length: 42, Symbol(Symbol.toStringTag): 'Float32Array']

Super keyword doesn't work with variables when trying to extend p5.js library

I want to extend the p5.js library in order to have error text on various locations on the screen. I will be using it in different places throughout my app and I believe it's better to do this than duplicating the code.
For now, almost everything is working fine, except some properties. For example, if I access super.height I'll get 0, while if I access this.height I'll get the actual window height. But, when accessing this.height I get an error saying that height isn't defined in CustomP5, which is right, but at the same time confusing.
import * as p5 from 'p5';
export class CustomP5 extends p5 {
... // private fields not related to this issue
constructor(sketch, htmlElement) {
super(sketch, htmlElement);
// Set tooltip error variables
this.resetTooltipError();
}
setSetup(setupFunction) {
super.setup = () => {
setupFunction();
this.setupAdditional();
}
}
setDraw(drawFunction) {
super.draw = () => {
drawFunction();
this.drawAdditional();
};
}
showTooltipError() {
...
}
Is there a reason why super.height, super.mouseX, and super.mouseY don't work, while super.draw or super.mousePressed are working correctly?
PS: I'm quite new to js and ts, so be patient if I'm wrong, please.
I'm not an expert, but it sounds like super only works with functions, not variables.
You say it works with super.draw and super.mousePressed. These are both functions. You say it does not work with super.height, super.mouseX, or super.mouseY. All of these are variables.
This matches the MDN docs for super:
The super keyword is used to access and call functions on an object's parent.
class Rectangle {
constructor(height, width) {
this.name = 'Rectangle';
this.height = height;
this.width = width;
}
sayName() {
console.log('Hi, I am a ', this.name + '.');
}
get area() {
return this.height * this.width;
}
set area(value) {
this.height = this.width = Math.sqrt(value);
}
}
class Square extends Rectangle {
constructor(length) {
this.height; // ReferenceError, super needs to be called first!
// Here, it calls the parent class' constructor with lengths
// provided for the Rectangle's width and height
super(length, length);
// Note: In derived classes, super() must be called before you
// can use 'this'. Leaving this out will cause a reference error.
this.name = 'Square';
}
}
So it sounds like this is working as intended. You might want to take some time to read up on how inheritance and the super keyword work in JavaScript.

Custom attributes are removed when using custom blots

I created a custom blot for links that requires to be able to set rel and target manually. However when loading content that has those attributes, quill strips them. I'm not sure why.
I created a codepen to illustrate the issue.
This is my custom blot:
const Inline = Quill.import('blots/inline')
class CustomLink extends Inline {
static create(options) {
const node = super.create()
node.setAttribute('href', options.url)
if (options.target) { node.setAttribute('target', '_blank') }
if (options.follow === 'nofollow') { node.setAttribute('rel', 'nofollow') }
return node
}
static formats(node) {
return node.getAttribute('href')
}
}
CustomLink.blotName = 'custom_link'
CustomLink.tagName = 'A'
Quill.register({'formats/custom_link': CustomLink})
Do I have to tell Quill to allow certain atttributes?
Upon initialization from existing HTML, Quill will try to construct the data model from it, which is the symmetry between create(), value() for leaf blots, and formats() for inline blots. Given how create() is implemented, you would need formats() to be something like this:
static formats(node) {
let ret = {
url: node.getAttribute('href'),
};
if (node.getAttribute('target') == '_blank') {
ret.target = true;
}
if (node.getAttribute('rel') == 'nofollow') {
ret.follow = 'nofollow';
}
return ret;
}
Working fork with this change: https://codepen.io/quill/pen/xPxGgw
I would recommend overwriting the default link as well though instead of creating another one, unless there's some reason you need both types.

Preserve null values in array of Play framework form mapping

I'm trying to get an idea how can I force Play Scala framework form mapper to save null values in array property.
Example. Request body (print out of snippet below):
AnyContentAsJson({
"entities":["ENI","GDF Suez","Procter & Gamble"],
"entityValues":[null,"42",null]
})
Resulting value of entityValues property after binding:
List(Some(42.0))
But I want to see:
List(None, Some(42.0), None)
Code snippet of controller:
def actionX = Action {implicit request =>
println(request.body)
TaskForm.form.bindFromRequest.fold(
formWithErrors => {
BadRequest("error")
},
taskData => {
println(taskData.entityValues)
}
)
}
Form class with mapping:
case class TaskForm(entities: List[String],
entityValues: List[Option[Double]]) { }
object TaskForm {
val map = mapping(
"entities" -> list(text),
"entityValues" -> list(optional(of(doubleFormat)))
)(TaskForm.apply)(TaskForm.unapply)
val form = Form(
map
)
}
I also tried some combinations of optional and default mapping parameters, but a result is still the same.
Using 0 or any another numeric value instead of null is not a case.
Does anyone have any ideas how to implement such form behaviour?
Thanks in advance for your time and attention.
It looks like you're sending JSON to a form endpoint. While this will work for simple JSON structures, you get no control over how it is done and hence get problems like the one you're seeing.
I'd be explicit about being a JSON-endpoint, and then you can define your own Reads[Option[Double]] that works precisely how you want it to:
First, define the implicits at the Controller level; here's where we get to control the null-handling; it ends up being pretty easy:
implicit val optionalDoubleReads = new Reads[Option[Double]] {
def reads(json: JsValue) = json match {
case JsNumber(n) => JsSuccess(Some(n.toDouble))
case JsString(n) => JsSuccess(Some(n.toDouble))
case JsNull => JsSuccess(None) // The important one
case _ => JsError("error.expected.jsnumber")
}
}
implicit val taskReads = Json.reads[TaskForm]
With that done, we modify your Action to require JSON (using parse.json). The function itself remains remarkably similar to the original form-binding fold:
def actionX = Action(parse.json) { implicit request =>
println(request.body)
request.body.validate[TaskForm].fold(
jsonErrors => {
BadRequest(s"Error: $jsonErrors")
},
taskData => {
println(taskData.entityValues)
Ok(taskData.entityValues.toString)
}
)
}

How to properly save self reference with ES6 classes?

Honestly, I'm not sure of what is the cause for the behavior: systemjs, babel or my own fault. I'm using class for custom control controller and saving class reference in self variable. Apparently that gets overriden by any subsequent controller instances.
I created a simple repository to demonstrate:
clone, install, run live-server or your preferred server. You will see 2 buttons, each is a custom control. Clicking on a button only affects one control.
https://github.com/alexkolt/selfIsThis
How can I get this working with ES6 class?
I should have posted the code, sorry.
The reason you'd want to save reference to self is for example in callbacks calling this might result in a different reference.
I was trying to do this:
var self;
class Test {
constructor(dependency) {
self = this;
self.dependency = dependency;
}
method() {
self.dependency().then(value => self.property = value);
}
}
Like it was mentioned before the self becomes shared when declared outside of the module. I didn't realize that would happen as files would be wrapped in a closure. Joe Clay answer is correct, but to do what I was trying to do self needs to be declared in every method that needs it.
class Test {
constructor(dependency) {
this.dependency = dependency;
}
method() {
var self = this;
this.dependency().then(value => self.property = value);
}
}
You're not really using ES6 classes right. You don't need to save a reference to this - just access it directly in class methods. The way you have it at the minute, all your instances of CustomControlController are sharing a single self variable.
class CustomControlController {
constructor() {
this.value = 0;
}
click() {
var newValue = this.value * 2;
this.value = newValue;
}
}
export default CustomControlController;

Resources