Skip to content

Instantly share code, notes, and snippets.

@urakozz
Created October 21, 2020 17:30
Show Gist options
  • Save urakozz/3323a0e00e932332dc4721cf38edf343 to your computer and use it in GitHub Desktop.
Save urakozz/3323a0e00e932332dc4721cf38edf343 to your computer and use it in GitHub Desktop.
ResNet.ts
import * as tf from "@tensorflow/tfjs-node";
// In my case I have 256x256 pictures
const IMG_SIZE = 256;
const NUMBER_OF_CHANNELS = 3;
// Batch normalisation and ReLU always go together, let's add them to the separate function
const batchNormRelu = (input: tf.Tensor4D) => {
const batch = tf.layers.batchNormalization().apply(input);
return tf.layers.reLU().apply(batch);
};
// Residual block
const residualBlock = (input: tf.Tensor4D, filters: number, noDownSample: boolean = false) => {
const filter1 = tf.layers
.separableConv2d({
kernelSize: 3,
filters,
activation: "relu",
padding: "same",
strides: noDownSample ? 1 : 2,
depthwiseInitializer: "glorotNormal",
pointwiseInitializer: "glorotNormal",
})
.apply(input) as tf.Tensor4D;
const filter1norm = batchNormRelu(filter1);
const filter2 = tf.layers
.separableConv2d({
kernelSize: 3,
filters,
activation: "relu",
padding: "same",
depthwiseInitializer: "glorotNormal",
pointwiseInitializer: "glorotNormal",
})
.apply(filter1norm) as tf.Tensor4D;
const dropout = tf.layers.dropout({ rate: 0.3 }).apply(filter2) as tf.Tensor4D;
const batchNorm = batchNormRelu(dropout);
// Residual connection - here we sum up first matrix and the result of 2 convolutions
const residual = tf.layers.add().apply([filter1 as any, batchNorm as any]);
return residual as tf.Tensor4D;
};
// ResNet - put all together
const modelResNet = () => {
const input = tf.input({ shape: [IMG_SIZE, IMG_SIZE, NUMBER_OF_CHANNELS] });
const conv1_filter = tf.layers
.conv2d({
kernelSize: 5,
filters: 16,
strides: 2,
activation: "relu",
padding: "same",
kernelInitializer: "glorotNormal",
})
.apply(input) as tf.Tensor4D;
const conv1 = tf.layers
.maxPooling2d({
poolSize: [3, 3],
strides: [2, 2],
padding: "same",
})
.apply(batchNormRelu(conv1_filter)) as tf.Tensor4D;
// conv 2
const residual2 = residualBlock(conv1, 16, true);
// conv3
const residual3 = residualBlock(residual2, 32);
// conv4
const residual4 = residualBlock(residual3, 64);
// conv5
const residual5 = residualBlock(residual4, 128);
const conv5 = tf.layers
.avgPool2d({
poolSize: [8, 8],
strides: [1, 1],
})
.apply(residual5) as tf.Tensor4D;
const flatten = tf.layers.flatten().apply(conv5);
const dropout = tf.layers.dropout({ rate: 0.5 }).apply(flatten);
const dense = tf.layers
.dense({
units: 2,
kernelInitializer: "glorotNormal",
activation: "softmax", // softmax for categorical / relu
})
.apply(dropout);
return tf.model({
inputs: input as any,
outputs: dense as any,
});
};
@pang-lee
Copy link

Hi, Is there any real case that can demonstrate (or run) the above resnet network?

@urakozz
Copy link
Author

urakozz commented Jan 2, 2022

Network above is an example of the resnet that could be done in tensorflow JS. I demonstrate how to implement residual blocks and implement smaller version of the resent 18, you can read more about it and its applicable areas here https://arxiv.org/abs/1512.03385 . To learn more why this peace of code exists, you can check my article https://urakozz.medium.com/residual-model-from-scratch-with-tensorflow-js-part-1-dfee9ab8cbfe

@pang-lee
Copy link

pang-lee commented Jan 3, 2022

@urakozz Your article I have already read, It's so great!
Maybe just I don't quite understand the output result after the resnet, I hope I can see some real case, for example, Yolo have the output picture after we run the code. But I'm not quite sure that the resent have the similar output or not.

@urakozz
Copy link
Author

urakozz commented Jan 3, 2022

I see, good question. First I need to correct you that for yolo Image is an input, output is category of the image (truck, bike) and frame (x1,y1,x2,y2,width, height). Image could be an output for the generative networks.
This particular network in example consumes 256x256 image and results with 2 outputs with softmax activation, so answer is 0,1 or 1,0, meaning 2 categories or yes/no answer. I used really similar lightweight network to determine if barcode exists on the image, yes/no.
But you can use residual blocks in different areas, such as nlp, image/sound recognition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment